Validating a Battleship board

JavaScript (ES6),  162  158 bytes

Returns 0 if the grid is invalid, or a positive integer otherwise.

m=>(o=0,g=u=>m.some((r,y)=>r.some((v,x)=>v&&[0,1].map(d=>(r=(w,X=x+!d*w,R=m[y+d*w]||0)=>R[X]&&R[R[X]--,u&(k=1<<w*3)*7&&g(u-k),r(-~w),X]++)``)))|u||++o)(668)*o

Try it online!

Commented

m => (                       // m[] = input matrix
  o = 0,                     // o = result
  g = u =>                   // g is a recursive function taking a bit mask u
                             // holding the ship counters on 4 x 3 bits
  m.some((r, y) =>           //   for each row r[] at position y in m[]:
    r.some((v, x) =>         //     for each value v at position x in r[]:
      v &&                   //       abort if v is not set
      [0, 1].map(d =>        //       otherwise, look for a horizontal ship (d = 0)
        (                    //       or a vertical ship (d = 1):
          r = (              //         r is a recursive function taking:
            w,               //           w = ship width - 1
            X = x + !d * w,  //           X = position of the cell in ...
            R = m[y + d * w] //           ... R[] = row of the cell
                || 0         //           (force it to 0 if undefined)
          ) =>               //
          R[X] &&            //           abort if R[X] is not set
          R[                 //
            R[X]--,          //           otherwise, set the cell to 0
            u & 7 *          //           if there's still at least one ship of
            (k = 1 << w * 3) //           width w to be found in the grid:
            && g(u - k),     //             do a recursive call to g with u updated
            r(-~w),          //           do a recursive call to r with w + 1
            X                //
          ]++                //           restore the cell afterwards
        )``                  //         initial call to r with u zero'ish
      )                      //       end of map()
    )                        //     end of some()
  )                          //   end of some()
  | u || ++o                 //   increment o if the grid has been cleared and all
                             //   boats have been found
)(668)                       // initial call to g with u = 668 (001 010 011 100)
* o                          // multiply by o

R, 211 bytes

v=function(b,f=c(3:1,2,1,1))`if`(any(f),{any(sapply(list(b,t(b)),function(m)any(apply(h<-which(m[1:(dim(m)[1]-f[1]),]>0,T),1,function(x)`if`(all(m[y<-t(x+rbind(0:f[1],0))]),{m[y]=0;v(m,f[-1])},F)))))},sum(b)==4)

Try it online!

How?
Pseudo-code version:

# recursive function:
validate_battleships= 
v=function(board,fleet_without_submarines)
    if there's nothing left in the fleet,
    and the board contains the right number of submarines:
        return(TRUE)                        
    else if any of these:
        try all positions:
            if we can place the first ship in the fleet:
                return result of recursive call
                after removing this ship from the board and the fleet
        return(TRUE)
    else return(FALSE)

And the actual, ungolfed R code:

validate_battleships= 
v=function(b,f=c(3:1,2,1,1))        # f=fleet=ship sizes minus 1, without submarines
  `if`(any(f),{                     # if there are any ships in the fleet:
    any(                            # return TRUE if any of these are true:
      sapply(list(b,t(b)),          # test the board and the transpose of the board (to try horizontal & vertical ship-placements)
        function(m)any(             # check if any of these are true:
          apply(h<-                 # test each nonzero position on the board (excluding the last rows that would make the ship go off the edge)
            which(m[1:(dim(m)[1]-f[1]),]>0,T),1,
              function(x)           # consider the first ship: f[1] (first item in fleet argument)
                `if`(all(m[y<-t(x+rbind(0:f[1],0))]),
                                    # if all the adjacent positions up to the ship size are nonzero (so we can place this ship),
                  {m[y]=0;          # set all these positions to zero
                   v(m,f[-1])}      # and return the result of a recursive call without this ship;
                ,F)                 # otherwise return FALSE
                ))))}
  ,sum(b)==4)                       # if there were no ships in the fleet, check that the nonzero positions on the board 
                                    # add-up to 4 (number of submarines): if they do, return TRUE.

Here is my answer in Java, I am definitely not skilled enough to get it down to a minimal amount of bytes and I prefer not to say(shortest byte solution for this code is down at the bottom of this post, credit to @ceilingcat for getting my code down to 482 bytes:P) try it, it works!

thanks to ceilingcat with the 482bytes solution:

int k,R[][],a[]=new int[]{4,3,3,2,2,2},d,e,s,x,y;boolean H(int[][]b,int I){var q=I==6;if(!q)for(int L=a[I++],r=d=b.length,c,M,N,i;r-->0;)for(c=e;c-->0;)for(M=N=i=1;b[x=r][y=c]>0&i<L;i++)q|=(M+=r+(s=L)>d?0:b[r+i][c])==L&&H(R(b,1),I)||(N+=c+L>e?0:b[r][c+i])==L&&H(R(b,0),I);return q;}int[][]R(int[][]n,int o){for(R=new int[k=d][e];k-->0;)R[k]=n[k].clone();for(;s-->0;)R[x+s*o][y-s*~-o]=0;return R;}boolean v(int[][]f){e=f[k=0].length;for(var y:f)for(var x:y)k+=x;return k==20&H(f,0);}

so here is my solution. (I went with a recursive solution for finding the ships)

public class BF {
    private static int[][] fields;
    public BF(int[][] field) {
        fields=field;
    }
    public boolean validate() {
        int cnt=counter(fields);
        if(cnt!=20)return false;
        return checkBoard(fields, new int[]{4,3,3,2,2,2},0);
    }


    public static boolean checkBoard(int[][] board,int[] allBoats,int index){
        if (index == allBoats.length) {
            return true;
        }
        int boatLen = allBoats[index];
        for (int row = 0; row < board.length; row++) {
            for (int col = 0; col < board[0].length; col++) {
                if(board[row][col]==1 && row+ boatLen <=board.length) {//vertically
                    int cnt=1;
                    for(int i=1;i<boatLen;i++) {//check vertically
                        if(board[row+i][col]==1) {cnt++;}
                    }
                    if(cnt>=boatLen) {
                        int[][] newBoard = deepcopy(board);
                        newBoard= remove(newBoard , row, col, boatLen, "ver");
                        if(checkBoard(newBoard,allBoats,index+1)) { return true;}
                    }
                }
                if(board[row][col]==1 && col+boatLen<=board[0].length) {//horizontally
                    int cnt=1;
                    for(int i=1;i<boatLen;i++) {//check horizontally
                        if(board[row][col+i]==1) {cnt++;}
                    }
                    if(cnt>=boatLen) {
                        int[][] newBoard = deepcopy(board);
                        newBoard= remove(newBoard , row, col, boatLen, "hor");
                        if(checkBoard(newBoard,allBoats,index+1)) { return true;}
                    }
                }
            }
        }
        return false;
    }
      
    
   public static int[][] remove(int[][] newBoard,int row,int col,int size,String orien){
       int[][] removedBoard= deepcopy(newBoard);
       if(orien=="ver") {
           for(int i=0;i<size;i++) {
               removedBoard[row+i][col]=0;
           }
           return removedBoard;
       }
       else if(orien=="hor") {
           for(int i=0;i<size;i++) {
               removedBoard[row][col+i]=0;
           }
           return removedBoard;
       }
       return removedBoard;
   }
   public static int[][] deepcopy(int[][] fields){
    int[][] copy= new int[fields.length][fields[0].length];
    for (int row = 0; row < fields.length; row++) {
        for (int col = 0; col < fields[0].length; col++) {
                   copy[row][col]= fields[row][col];
               }
            }
    return copy;
   }
   public static int counter(int[][] f) {// counts amount of tiles on the board with 1's
          int cnt=0;
        for (int col = 0; col < f[0].length; col++) {
            for (int row = 0; row < f.length; row++) {
                if (f[row][col] == 1) {
                 cnt++; 
                }
                }
        }
        return cnt;
      }
}

here is my Pseudo code on the Check board function

/*
 * 
 * function gets length of boat(field, size, ships){{3,2,1};
 * loop go through each position in field
 * checks vertically {
 *  finds option for where the boat can be 
 *  copies the board
 *  removes the boat from the copy
 *  call remove boat(function gets length of boat) for size-1, deepcopy
 *  if true then return true
 * }
 * check horizontal{
 *  finds option for where the boat can be 
 *  copies the board
 *  removes the boat from the copy
 *  call remove boat(function gets length of boat) for size-1, deepcopy
 *  if true then return true
 * }
 * else find next size 4 option
 * }
 */

let me know what u think:P

if you want to test it, here is some code for testing in my Java Solution:

import org.junit.Test;
import static org.junit.Assert.*;
public class SolutionTest {
    @Test
    public void testContact() {
          int[][] field = {};
        assertTrue("Must return true", new BF(field).validate());
    }
}