战舰游戏开发Bug求助:4格战舰重复生成问题
Hey there! I’ve dug into your code and found two key issues causing the 4-length battleship to sometimes spawn incorrectly (either overlapping the 5-length ship or triggering repeated spawns):
1. Broken Overlap Check Selector
In your generateBoat4 function, you’re using $("#nID").hasClass("boat") to check if a cell is already occupied. The problem here is that #nID is looking for an element with the literal id "nID", not the value stored in your nID variable. You need to concatenate the variable into the selector like this: $("#" + nID).hasClass("boat"). Without this fix, your overlap check always returns false, so the 4-length ship never avoids the 5-length ship’s cells.
2. Risky Full Reset Recursion
When a ship can’t fit within the grid bounds, you’re calling generateBoats() which resets and regenerates all ships. This can lead to repeated spawns of the 5-length ship, and in worst cases, infinite recursion if random values keep picking invalid positions. Instead, you should only re-run the current ship’s generation function (e.g., generateBoat4() instead of generateBoats()).
Fixed Full Code
<!DOCTYPE html> <html> <head> <title>Battle Ships</title> <meta charset="UTF-8"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <style> th, td { width: 32px; height: 32px; background-color: grey; } .boat { width: 32px; height: 32px; background-color: red; } </style> <script> $(document).ready(function(){ for (var vr = 0; vr < 11; vr++) { var vrsta = document.getElementById('tabela').insertRow(vr); for (var st = 0; st < 11; st++) { var okvir = vrsta.insertCell(st); okvir.id = "x=" + st + "&y=" + vr; okvir.setAttribute("onclick", "koord(this.id)"); okvir.innerHTML = "x-" + st + " y-" + vr; } } }); function generateBoats() { console.log("Generating all battleships..."); $("tr").children().removeClass("boat"); generateBoat5(); generateBoat4(); } function generateBoat5() { // Spawn 5-length battleship var rotation = Math.floor(Math.random() * 2); var randX = Math.floor(Math.random() * 11); var randY = Math.floor(Math.random() * 11); if (rotation === 0) { // Horizontal placement if (randX <= 10 - 4) { // Ensure enough space (5 cells: randX to randX+4) const cells = [ `x=${randX}&y=${randY}`, `x=${randX+1}&y=${randY}`, `x=${randX+2}&y=${randY}`, `x=${randX+3}&y=${randY}`, `x=${randX+4}&y=${randY}` ]; cells.forEach(cellId => $(`#${cellId}`).addClass("boat")); } else { generateBoat5(); // Retry with new position } } else { // Vertical placement if (randY <= 10 - 4) { const cells = [ `x=${randX}&y=${randY}`, `x=${randX}&y=${randY+1}`, `x=${randX}&y=${randY+2}`, `x=${randX}&y=${randY+3}`, `x=${randX}&y=${randY+4}` ]; cells.forEach(cellId => $(`#${cellId}`).addClass("boat")); } else { generateBoat5(); } } } function generateBoat4() { // Spawn 4-length battleship var rotation = Math.floor(Math.random() * 2); var randX = Math.floor(Math.random() * 11); var randY = Math.floor(Math.random() * 11); let cells = []; if (rotation === 0) { // Horizontal if (randX <= 10 - 3) { // 4 cells: randX to randX+3 cells = [ `x=${randX}&y=${randY}`, `x=${randX+1}&y=${randY}`, `x=${randX+2}&y=${randY}`, `x=${randX+3}&y=${randY}` ]; } else { generateBoat4(); return; // Stop current function execution after retry } } else { // Vertical if (randY <= 10 - 3) { cells = [ `x=${randX}&y=${randY}`, `x=${randX}&y=${randY+1}`, `x=${randX}&y=${randY+2}`, `x=${randX}&y=${randY+3}` ]; } else { generateBoat4(); return; } } // Check if any cell is already occupied by another ship const isOverlapping = cells.some(cellId => $(`#${cellId}`).hasClass("boat")); if (isOverlapping) { generateBoat4(); // Retry if overlapping } else { cells.forEach(cellId => $(`#${cellId}`).addClass("boat")); } } // Missing click handler (prevents console errors) function koord(cellId) { console.log(`Clicked cell: ${cellId}`); } </script> </head> <body onload="generateBoats()"> <table id="tabela"></table> </body> </html>
Extra Improvements I Added
- Template Literals: Used backticks
`for cleaner string concatenation (e.g.,`x=${randX}&y=${randY}`instead of"x=" + randX + "&y=" + randY). - Array-Based Cell Handling: Stored ship cells in arrays to avoid repetitive code and make updates easier.
- Explicit Boundary Logic: Changed
randX < 7torandX <= 10 - 4to make the grid space check more intuitive (10 is the maximum cell index, subtract (ship length - 1) for valid starting positions). - Early Return Statements: Added
returnafter recursive calls to prevent leftover code from running. - Fixed Missing
koordFunction: The original code had a click event bound but no function implementation, which caused console errors. I added a basic version to fix this.
内容的提问来源于stack exchange,提问作者progg24

