Back to Game

Battleship - Source Code

Play Game
JavaScript
const BOARD_SIZE = 10;
const SHIPS = [
  { name: 'Carrier', size: 5 },
  { name: 'Battleship', size: 4 },
  { name: 'Cruiser', size: 3 },
  { name: 'Submarine', size: 3 },
  { name: 'Destroyer', size: 2 }
];

let playerBoard = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(''));
let aiBoard = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(''));
let playerShips = [];
let aiShips = [];
let gamePhase = 'setup';
let aiTargetQueue = [];
let aiLastHit = null;

function generateAiShips() {
  const board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(''));
  const ships = [];
  
  for (const shipTemplate of SHIPS) {
    let placed = false;
    let attempts = 0;
    
    while (!placed && attempts < 100) {
      const direction = Math.random() < 0.5 ? 'horizontal' : 'vertical';
      const row = Math.floor(Math.random() * BOARD_SIZE);
      const col = Math.floor(Math.random() * BOARD_SIZE);
      
      if (canPlaceShip(board, row, col, shipTemplate, direction)) {
        const positions = [];
        
        for (let i = 0; i < shipTemplate.size; i++) {
          const newRow = direction === 'vertical' ? row + i : row;
          const newCol = direction === 'horizontal' ? col + i : col;
          board[newRow][newCol] = 'S';
          positions.push({ row: newRow, col: newCol });
        }
        
        ships.push({
          name: shipTemplate.name,
          size: shipTemplate.size,
          positions,
          hits: Array(shipTemplate.size).fill(false)
        });
        
        placed = true;
      }
      attempts++;
    }
  }
  
  aiShips = ships;
}

function canPlaceShip(board, row, col, ship, direction) {
  for (let i = 0; i < ship.size; i++) {
    const newRow = direction === 'vertical' ? row + i : row;
    const newCol = direction === 'horizontal' ? col + i : col;
    
    if (newRow >= BOARD_SIZE || newCol >= BOARD_SIZE || board[newRow][newCol] !== '') {
      return false;
    }
    
    for (let dr = -1; dr <= 1; dr++) {
      for (let dc = -1; dc <= 1; dc++) {
        const checkRow = newRow + dr;
        const checkCol = newCol + dc;
        if (checkRow >= 0 && checkRow < BOARD_SIZE && 
            checkCol >= 0 && checkCol < BOARD_SIZE && 
            board[checkRow][checkCol] === 'S') {
          return false;
        }
      }
    }
  }
  return true;
}

function smartAiAttack() {
  if (aiTargetQueue.length > 0) {
    const target = aiTargetQueue.shift();
    return target;
  }
  
  if (aiLastHit) {
    const { row, col } = aiLastHit;
    const directions = [
      { row: row - 1, col },
      { row: row + 1, col },
      { row, col: col - 1 },
      { row, col: col + 1 }
    ];
    
    for (const dir of directions) {
      if (dir.row >= 0 && dir.row < BOARD_SIZE && 
          dir.col >= 0 && dir.col < BOARD_SIZE &&
          playerBoard[dir.row][dir.col] !== 'H' && 
          playerBoard[dir.row][dir.col] !== 'M') {
        return dir;
      }
    }
    
    aiLastHit = null;
  }
  
  const availableSquares = [];
  for (let row = 0; row < BOARD_SIZE; row++) {
    for (let col = 0; col < BOARD_SIZE; col++) {
      if (playerBoard[row][col] !== 'H' && playerBoard[row][col] !== 'M') {
        if ((row + col) % 2 === 0) {
          availableSquares.push({ row, col });
        }
      }
    }
  }
  
  if (availableSquares.length === 0) {
    for (let row = 0; row < BOARD_SIZE; row++) {
      for (let col = 0; col < BOARD_SIZE; col++) {
        if (playerBoard[row][col] !== 'H' && playerBoard[row][col] !== 'M') {
          availableSquares.push({ row, col });
        }
      }
    }
  }
  
  return availableSquares[Math.floor(Math.random() * availableSquares.length)];
}

function aiAttack() {
  const target = smartAiAttack();
  if (!target) return;
  
  const { row, col } = target;
  let hit = false;
  
  if (playerBoard[row][col] === 'S') {
    hit = true;
    playerBoard[row][col] = 'H';
    aiLastHit = { row, col };
    
    const directions = [
      { row: row - 1, col },
      { row: row + 1, col },
      { row, col: col - 1 },
      { row, col: col + 1 }
    ];
    
    for (const dir of directions) {
      if (dir.row >= 0 && dir.row < BOARD_SIZE && 
          dir.col >= 0 && dir.col < BOARD_SIZE &&
          playerBoard[dir.row][dir.col] !== 'H' && 
          playerBoard[dir.row][dir.col] !== 'M') {
        aiTargetQueue.push(dir);
      }
    }
    
    for (const ship of playerShips) {
      for (let i = 0; i < ship.positions.length; i++) {
        if (ship.positions[i].row === row && ship.positions[i].col === col) {
          ship.hits[i] = true;
          
          if (ship.hits.every(hit => hit)) {
            aiTargetQueue = [];
            aiLastHit = null;
          }
          break;
        }
      }
    }
  } else {
    playerBoard[row][col] = 'M';
  }
  
  const allPlayerShipsSunk = playerShips.every(ship => ship.hits.every(hit => hit));
  if (allPlayerShipsSunk) {
    alert('AI wins!');
    resetGame();
  }
}

function playerAttack(row, col) {
  if (aiBoard[row][col] !== '' || gamePhase !== 'playing') return;
  
  let hit = false;
  
  for (const ship of aiShips) {
    for (let i = 0; i < ship.positions.length; i++) {
      if (ship.positions[i].row === row && ship.positions[i].col === col) {
        ship.hits[i] = true;
        hit = true;
        break;
      }
    }
  }
  
  aiBoard[row][col] = hit ? 'H' : 'M';
  
  const allAiShipsSunk = aiShips.every(ship => ship.hits.every(hit => hit));
  if (allAiShipsSunk) {
    alert('You win!');
    resetGame();
    return;
  }
  
  setTimeout(aiAttack, 1000);
}

function resetGame() {
  playerBoard = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(''));
  aiBoard = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(''));
  playerShips = [];
  aiShips = [];
  gamePhase = 'setup';
  aiTargetQueue = [];
  aiLastHit = null;
}

generateAiShips();

This code demonstrates the core game logic. The actual implementation may include additional features and optimizations.