Results 1 to 2 of 2

Thread: Contest 15 - Battleship - Peter Porter

  1. #1

    Thread Starter
    Fanatic Member Peter Porter's Avatar
    Join Date
    Jul 2013
    Location
    Germany
    Posts
    581

    Contest 15 - Battleship - Peter Porter

    Here is my Battleship entry:
    https://jsfiddle.net/dgewaLj0

    Looking at my code, you wont see textareas for all the cells that make up the play area grid, because I had the script create them for me. Saved me the pain of manually hardcoding 100 individual textareas.

    HTML
    Code:
    <div class="game-wrapper">
      <!-- Left: game board -->
      <div>
      <h1>Battleship</h1>
    
        <div id="game"></div>
    
        <div id="controls">
          <input type="text" id="coordInput" placeholder="e.g. A5" maxlength="3">
          <button onclick="fire()">Fire</button>
        </div>
    
        <p id="status">Chances left: 40 | Hits: 0 | Misses: 0 | Ships sunk: 0</p>
        <button id="restartBtn" style="display:none;" onclick="initGame()">Play Again</button>
      </div>
    
      <!-- Right: side column with textarea -->
      <div class="side-column">
        <textarea>
    Objective:
    
    Sink all of the hidden ships on the 10×10 grid before you run out of chances.
    
    Fleet:
    
    There are 5 ships of different lengths. They are placed randomly on the grid, either horizontally or vertically.
                                                  
    Taking a Shot:
    
    Type the coordinate of the cell you want to target into the input box, for example:
    A5 ? Column A, Row 5.
    
    Press Enter on your keyboard or click the Fire button.
    
    The cell will update, X ? you hit part of a ship, 0 ? you missed.
    
    Below the input box you’ll see:
    • Chances left
    • Hits
    • Misses
    • Ships sunk
    </textarea>
      </div>
    </div>
    Style
    Code:
    body {
        font-family: monospace;
        text-align: center;
        background-color: #f0f8ff;
      }
    
      table {
        border-collapse: collapse;
        margin: auto;
      }
    
      td {
        padding: 0;
        margin: 0;
        text-align: center;
      }
    
      .row-header {
        padding-right: 8px;  
        min-width: 25px;      
        text-align: right;    
      }
    
      textarea {
        resize: none;
        width: 30px;
        height: 30px;
        text-align: center;
        font-size: 18px;
        background-color: #add8e6; 
        border: none; /* no visible borders */
        margin-right: 5px;
        margin-bottom: 3px;
      }
    
      .miss {
        background-color: #add8e6; 
        color: white;
    
      .hit {
        background-color: #add8e6; 
        color: red;
      }
    
      #controls {
        margin-top: 20px;
      }
    
      .game-wrapper {
      display: flex; 
      justify-content: center;  
      gap: 10px;                  
      margin-top: 20px;
      height: 600px;
    }
    
    .side-column {
      background-color: #E0E0E0; 
      border-radius: 8px;         
      padding: 10px;              
      margin-top: 81px;
    }
    
    .side-column textarea {
      background-color: #E0E0E0; 
      width: 350px;
      height: 100%;
      resize: none;
      font-family: monospace;
      font-size: 14px;
      box-sizing: border-box;
      text-align: left;
    }
    Javascript
    Code:
    const SIZE = 10;  // Size of the board (10x10 grid)
    const CHANCES = 40;  // Number of shots the player has
    let grid = [];  // 2D array representing the board cells
    let ships = [];  // Array holding all ships and their coordinates
    let chancesLeft, hits, misses, sunk;  // Counters for game progress
    
    // Initialize a new game
    function initGame() {
      chancesLeft = CHANCES;
      hits = 0;
      misses = 0;
      sunk = 0;
      grid = Array.from({length: SIZE}, () => Array(SIZE).fill("~"));
      ships = [];
      placeShips();
      drawBoard();
      updateStatus();
      document.getElementById("restartBtn").style.display = "none";
    }
    
    // Draw the board as an HTML table
    function drawBoard() {
      let html = "<table><tr><td></td>";
      for (let c=0; c<SIZE; c++) {
        html += `<td>${String.fromCharCode(65+c)}</td>`;
      }
      html += "</tr>";
      for (let r=0; r<SIZE; r++) {
        html += `<tr><td class="row-header">${r+1}</td>`;
        for (let c=0; c<SIZE; c++) {
          html += `<td><textarea id="cell-${r}-${c}" readonly>${grid[r][c]}</textarea></td>`;
        }
        html += "</tr>";
      }
      html += "</table>";
      document.getElementById("game").innerHTML = html;
    }
    
    // Update status line
      document.getElementById("status").innerText =
        `Chances left: ${chancesLeft} | Hits: ${hits} | Misses: ${misses} | Ships sunk: ${sunk}`;
    }
    
    // Handle firing at a coordinate
    function fire() {
      let input = document.getElementById("coordInput").value.trim().toUpperCase();
      document.getElementById("coordInput").value = "";
      if (!/^[A-J](10|[1-9])$/.test(input)) {
        alert("Invalid coordinate! Use format like A5.");
        return;
      }
      let col = input.charCodeAt(0) - 65;
      let row = parseInt(input.slice(1)) - 1;
      let cell = document.getElementById(`cell-${row}-${col}`);
    
      if (cell.classList.contains("hit") || cell.classList.contains("miss")) {
        alert("Already targeted!");
        return;
      }
    
      let hitShip = ships.find(ship => ship.some(([r,c]) => r===row && c===col));
      if (hitShip) {
        cell.value = "X";
        cell.classList.add("hit");
        hits++;
        hitShip.hitCount = (hitShip.hitCount || 0) + 1;
        if (hitShip.hitCount === hitShip.length) {
          sunk++;
          alert("You sunk a ship!");
        }
        chancesLeft--; // <-- lose a chance even on a hit
      } else {
        cell.value = "0";
        cell.classList.add("miss");
        misses++;
        chancesLeft--;
    }
    
      updateStatus();
      checkGameOver();
    }
    
    // Check win/lose conditions
    function checkGameOver() {
      let totalShipCells = ships.reduce((sum, s) => sum + s.length, 0);
      if (hits === totalShipCells) {
        alert("You win!");
        document.getElementById("restartBtn").style.display = "inline";
      } else if (chancesLeft <= 0) {
        alert("Game over! You lose.");
        document.getElementById("restartBtn").style.display = "inline";
      }
    }
    
    // Randomly place ships
    function placeShips() {
      const shipSizes = [2,3,3,4,5];
      for (let size of shipSizes) {
        let placed = false;
        while (!placed) {
          let orientation = Math.random() < 0.5 ? "H" : "V";
          let row = Math.floor(Math.random()*SIZE);
          let col = Math.floor(Math.random()*SIZE);
          let coords = [];
          for (let i=0; i<size; i++) {
            let r = row + (orientation==="V"?i:0);
            let c = col + (orientation==="H"?i:0);
            if (r>=SIZE || c>=SIZE) { coords=[]; break; }
            coords.push([r,c]);
          }
          if (coords.length===size && validPlacement(coords)) {
            ships.push(coords);
            placed = true;
          }
        }
      }
    }
    
    // Ensure ships don't overlap or touch
    function validPlacement(coords) {
      for (let [r,c] of coords) {
        for (let dr=-1; dr<=1; dr++) {
          for (let dc=-1; dc<=1; dc++) {
            let nr=r+dr, nc=c+dc;
            if (nr>=0 && nr<SIZE && nc>=0 && nc<SIZE) {
              if (ships.some(ship => ship.some(([sr,sc]) => sr===nr && sc===nc))) {
                return false;
              }
            }
          }
        }
      }
      return true;
    }
    
    // Allow Enter key to fire
    document.getElementById("coordInput").addEventListener("keydown", e => {
      if (e.key==="Enter") fire();
    });
    
    // Start game on load
    initGame();

  2. #2
    Frenzied Member 2kaud's Avatar
    Join Date
    May 2014
    Location
    England
    Posts
    1,169

    Re: Contest 15 - Battleship - Peter Porter

    Shouldn't contest submissions be private until after the contest closes?


    This is a hidden post waiting to be moderated. (steve)
    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++23 Compiler: Microsoft VS2022 (17.6.5)

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width