Conversation
WalkthroughThis refactoring restructures the Battleship game from a monolithic codebase into a modular, component-based architecture. New modules for Board, Ship, AIController, and UIController handle game logic. The CSS is reorganized using CSS variables and responsive design. Documentation guidelines are added. Changes
Sequence Diagram(s)sequenceDiagram
participant Player
participant UI as UIController
participant Game as BattleshipGame
participant Board
participant AI as AIController
rect rgb(200, 230, 255)
Note over Player,Game: Ship Placement Phase
Player->>Game: setOrientation(HORIZONTAL)
Player->>Game: selectShip(length)
Player->>Game: previewPlayerPlacement(index)
Game->>Board: previewPlacement(index, length, orientation)
Board-->>Game: {cells, inBounds, overlaps, isValid}
Game->>UI: showPlacementPreview(cells, isValid)
Player->>Game: placePlayerShip(index)
Game->>Board: placeShip(length, index, orientation)
Game->>UI: updateShipCount(counterId, remaining)
end
rect rgb(200, 230, 200)
Note over Player,Game: Battle Phase (Player Turn)
Player->>Game: playerAttack(index)
Game->>Board: receiveAttack(index)
Board-->>Game: {hit, sunk, alreadyAttacked}
Game->>UI: renderHit(board, index)
alt Victory Check
Game->>Game: allShipsSunk?
Game->>UI: showVictory()
else Continue to CPU
Game->>Game: cpuTurn()
end
end
rect rgb(230, 200, 200)
Note over Game,AI: CPU Turn
AI->>AI: nextAttack()
alt Focus Queue Has Targets
AI-->>Game: index from queue
else Random Selection
AI-->>Game: random index
end
Game->>Board: receiveAttack(index)
Board-->>Game: {hit, sunk, ...}
Game->>AI: handleAttackResult(index, result)
alt Hit Detected
AI->>AI: enqueueNeighbors(index)
end
alt Sunk Detected
AI->>AI: reset()
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes The refactoring spans six new modular files introducing interconnected game logic (Board, Ship, AIController, Game orchestration), a restructured UI layer, CSS variable system with responsive design, and module-based script loading. The changes require understanding the new architecture's control flow, validation logic across placement/attack paths, AI targeting strategy, and CSS-to-JS integration points. Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // does this need to commented back in to work? | ||
| // import { BattleshipGame } from "./src/game.js"; | ||
| // import { UIController } from "./src/ui-controller.js"; | ||
| // import { ORIENTATION } from "./src/constants.js"; | ||
| // | ||
| // const uiController = new UIController(document); | ||
| // const game = new BattleshipGame(uiController); | ||
| // | ||
| // const yearEl = document.getElementById("current-year"); | ||
| // if (yearEl) { | ||
| // yearEl.textContent = new Date().getFullYear(); | ||
| // } | ||
| // | ||
| // const bridge = { | ||
| // clickTarget(index) { | ||
| // game.placePlayerShip(Number(index)); | ||
| // }, | ||
| // clickCpuBoard(index) { | ||
| // game.playerAttack(Number(index)); | ||
| // }, | ||
| // selectShip(size) { | ||
| // game.selectShip(Number(size)); | ||
| // }, | ||
| // turnVertical() { | ||
| // game.setOrientation(ORIENTATION.VERTICAL); | ||
| // }, | ||
| // turnHorizontal() { | ||
| // game.setOrientation(ORIENTATION.HORIZONTAL); | ||
| // }, | ||
| // clickStartGame() { | ||
| // game.startGame(); | ||
| // }, | ||
| // }; | ||
| // | ||
| // Object.entries(bridge).forEach(([key, handler]) => { | ||
| // window[key] = handler; |
There was a problem hiding this comment.
Restore initialization and global handlers
The main entry script is now entirely commented out, so BattleshipGame and UIController are never instantiated and the bridge that exposes clickTarget, selectShip, turnVertical, etc. on window is never registered. However, index.html still calls those functions through inline onclick attributes, so any click on the orientation buttons or board squares throws a ReferenceError and the game cannot start at all. The previous revision executed this code; in this commit the application is left non-functional.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (8)
AGENTS.md (1)
6-10: Add a reproducible dev script.Recommend adding an npm script (e.g., "dev": "http-server . -p 3000") and documenting it to avoid relying on global binaries.
src/ship.js (2)
4-9: Validate inputs and ensure length matches occupied cells.Guard against bad state and normalize cells before assignment.
export class Ship { constructor(length, cells) { - this.id = `ship-${shipIdCounter++}`; - this.length = length; - this.cells = new Set(cells); - this.hits = new Set(); + this.id = `ship-${shipIdCounter++}`; + if (!Number.isInteger(length) || length <= 0) { + throw new TypeError("length must be a positive integer"); + } + if (!cells || typeof cells[Symbol.iterator] !== "function") { + throw new TypeError("cells must be an iterable of indices"); + } + const cellSet = new Set(cells); + if (cellSet.size !== length) { + throw new RangeError("length must equal number of unique occupied cells"); + } + this.length = length; + this.cells = cellSet; + this.hits = new Set(); }
15-19: Have recordHit report whether it registered a new hit.Returning a boolean simplifies board logic and prevents duplicate-hit side effects.
recordHit(index) { - if (this.occupies(index)) { - this.hits.add(index); - } + if (!this.occupies(index)) return false; + const before = this.hits.size; + this.hits.add(index); + return this.hits.size > before; }src/constants.js (2)
3-8: Harden constant data (freeze) and clarify IDs.
- Freeze SHIP_DEFINITIONS and its entries to prevent accidental mutation.
- Verify counterId "Patrolship" matches the DOM id exactly (it does now); consider documenting this coupling.
-export const SHIP_DEFINITIONS = [ - { name: "Battleship", length: 5, count: 1, counterId: "Battleship" }, - { name: "Destroyer", length: 4, count: 2, counterId: "Destroyer" }, - { name: "Frigate", length: 3, count: 1, counterId: "Frigate" }, - { name: "Patrol Ship", length: 2, count: 1, counterId: "Patrolship" }, -]; +export const SHIP_DEFINITIONS = [ + { name: "Battleship", length: 5, count: 1, counterId: "Battleship" }, + { name: "Destroyer", length: 4, count: 2, counterId: "Destroyer" }, + { name: "Frigate", length: 3, count: 1, counterId: "Frigate" }, + { name: "Patrol Ship", length: 2, count: 1, counterId: "Patrolship" }, +].map(Object.freeze); +Object.freeze(SHIP_DEFINITIONS);
1-1: Add derived board constants and freeze orientation.Exposing BOARD_CELLS helps avoid magic numbers; freezing ORIENTATION avoids accidental reassignment.
export const BOARD_SIZE = 10; +export const BOARD_CELLS = BOARD_SIZE * BOARD_SIZE; @@ -export const ORIENTATION = { - HORIZONTAL: "horizontal", - VERTICAL: "vertical", -}; +export const ORIENTATION = Object.freeze({ + HORIZONTAL: "horizontal", + VERTICAL: "vertical", +});Also applies to: 15-18
src/ai-controller.js (1)
12-20: Consider using a queue-optimized approach for better performance.The
shift()operation on arrays is O(n), though for the typical small queue sizes in this game (up to a few neighbors), the performance impact is negligible. If you anticipate larger queues or want to optimize, consider using an index-based approach or a dedicated queue structure.src/ui-controller.js (2)
1-10: Consider adding null checks for DOM element queries.The constructor caches DOM elements but doesn't verify they exist. If any required elements are missing from the HTML, methods that use them will fail silently or throw errors. Consider adding validation or defensive checks, especially for critical elements.
Example defensive approach:
constructor(doc = document) { this.doc = doc; this.messageEl = doc.querySelector(".message"); this.announcementEl = doc.getElementById("announce"); this.selectionWrapper = doc.getElementById("remove-on-start"); this.headerEl = doc.getElementById("header"); this.containerMain = doc.querySelector(".container-main"); this.previewedCells = new Map(); + + // Validate critical elements exist + if (!this.messageEl || !this.containerMain) { + console.warn("UIController: Some required DOM elements are missing"); + } }
40-52: Replace inline event handlers with addEventListener for CSP compatibility.The
onclick='location.reload()'inline handlers inshowVictory()andshowDefeat()would be blocked by Content Security Policy and are less maintainable. Consider usingaddEventListenerinstead.Refactored approach:
showVictory() { if (this.announcementEl) { this.announcementEl.innerHTML = - "<span class='announcement'><br/>YOU WIN!</span><span onclick='location.reload()' class='retry'>RETRY</span>"; + "<span class='announcement'><br/>YOU WIN!</span><span class='retry'>RETRY</span>"; + const retryBtn = this.announcementEl.querySelector('.retry'); + if (retryBtn) { + retryBtn.addEventListener('click', () => location.reload()); + } } } showDefeat() { if (this.announcementEl) { this.announcementEl.innerHTML = - "<span class='announcement'><br/>YOU LOSE!</span><span onclick='location.reload()' class='retry'>RETRY</span>"; + "<span class='announcement'><br/>YOU LOSE!</span><span class='retry'>RETRY</span>"; + const retryBtn = this.announcementEl.querySelector('.retry'); + if (retryBtn) { + retryBtn.addEventListener('click', () => location.reload()); + } } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
AGENTS.md(1 hunks)battleship.css(1 hunks)battleship.js(1 hunks)index.html(3 hunks)src/ai-controller.js(1 hunks)src/board.js(1 hunks)src/constants.js(1 hunks)src/game.js(1 hunks)src/ship.js(1 hunks)src/ui-controller.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/board.js (2)
src/constants.js (4)
BOARD_SIZE(1-1)BOARD_SIZE(1-1)ORIENTATION(15-18)ORIENTATION(15-18)src/ship.js (1)
Ship(3-24)
src/game.js (3)
src/constants.js (6)
SHIP_DEFINITIONS(3-8)SHIP_DEFINITIONS(3-8)ORIENTATION(15-18)ORIENTATION(15-18)TOTAL_SHIP_CELLS(10-13)TOTAL_SHIP_CELLS(10-13)src/board.js (1)
Board(4-142)src/ai-controller.js (1)
AIController(1-59)
🔇 Additional comments (35)
src/ship.js (1)
21-23: isSunk logic is correct.index.html (2)
341-341: Footer year depends on JS; confirm it’s set.Make sure battleship.js assigns current year to #current-year; otherwise the span renders empty.
10-12: Good use of preconnect and font loading with display=swap.src/ai-controller.js (4)
1-5: LGTM!The constructor properly stores the board reference and delegates initialization to
reset(), which is a clean pattern for potential re-initialization.
7-10: LGTM!Clean state reset implementation.
22-33: LGTM!The attack result handling is well-structured with appropriate early returns and correct state management when ships are sunk.
35-58: LGTM!The neighbor enqueueing logic correctly generates orthogonal neighbors, validates bounds, and deduplicates using the registry.
battleship.css (5)
1-52: LGTM!The CSS variables and global styles are well-organized, providing a solid foundation for theming and consistent styling.
54-252: LGTM!The container, layout, and board styling is well-structured with proper use of CSS Grid, Flexbox, and visual hierarchy.
552-583: LGTM!The keyframe animations are lightweight and appropriate for the game's visual feedback.
585-645: LGTM!The responsive breakpoints provide good adaptation across device sizes, with thoughtful adjustments to cell sizes for touch-friendly interactions on smaller screens.
443-465: Image assets verified—no action needed.Both SVG files (
explosion.svgandsplash-1.svg) are present in theimages/directory. The CSS references are valid and will render correctly.src/ui-controller.js (5)
12-27: LGTM!The message and ship count methods include appropriate null checks before DOM manipulation.
29-38: LGTM!The battle preparation logic properly cleans up placement state and transitions the UI, including nulling the removed element reference.
60-88: LGTM!The placement preview logic correctly manages preview state using a Map and properly cleans up classes.
90-110: LGTM!The rendering methods follow a clean delegation pattern with controlled HTML generation.
112-116: LGTM!The element lookup correctly handles the different ID conventions for player and CPU boards.
src/board.js (9)
4-15: LGTM!The constructor and reset logic properly initialize the board state using appropriate data structures (Map for lookup, Sets for tracking).
17-29: LGTM!The coordinate conversion methods are mathematically correct and the bounds checking is comprehensive.
31-36: LGTM!The bounds checking correctly validates that ships fit within the grid for both orientations.
38-48: LGTM!The ship cell generation correctly creates sequential cells based on orientation.
50-56: LGTM!The placement validation correctly checks both bounds and overlap conditions.
58-76: LGTM!The ship placement logic is comprehensive with proper validation, error reporting, and state management across multiple data structures.
78-101: LGTM!The preview placement logic correctly provides validation feedback without mutating board state, and the
cells.length === lengthcheck ensures all cells fit within the grid.
103-121: LGTM!The attack handling correctly manages state and returns detailed results for hit/miss/sunk conditions.
123-141: LGTM!The random index selection and victory condition check are correctly implemented. The O(n) complexity of
randomUnattackedIndex()is acceptable for a 10×10 board.src/game.js (9)
1-12: LGTM!The imports and SHIPS_TO_PLACE calculation correctly count the total number of individual ships to be placed.
14-42: LGTM!The initialization logic properly sets up all game state, correctly assigns the player board to the AI controller, and initializes the UI.
44-73: LGTM!The ship selection methods include appropriate validation and user feedback, with correct preview management.
75-108: LGTM!The placement preview logic includes comprehensive guards and correctly delegates to the board and UI layers.
110-155: LGTM!The ship placement logic is comprehensive with proper validation, error handling, state management, and good UX by auto-deselecting fully-placed ship types.
157-177: LGTM!The game start logic properly validates prerequisites and transitions state appropriately.
179-206: LGTM!The player attack logic correctly handles all cases with defensive victory checking and proper game flow to the CPU turn.
208-242: LGTM!The CPU turn logic includes excellent defensive programming with the fallback loop (lines 220-226) that handles potential AI bugs safely, with proper null checking to prevent infinite loops.
244-270: LGTM!The CPU fleet deployment uses a simple random placement strategy that's adequate for the game's constraints (18 ship cells on a 100-cell board). The while loop is safe given the low board occupancy.
| ## Project Structure & Module Organization | ||
| `index.html` is the single-page shell; it links the modern styling in `battleship.css` and boots `battleship.js` as an ES module. Gameplay logic lives under `src/`: `game.js` orchestrates turns and win states, `board.js` tracks ship placement and attacks, `ship.js` models individual vessels, `ai-controller.js` handles smart CPU targeting, and `ui-controller.js` updates the DOM. Shared constants (ship specs, orientations, board size) are defined in `src/constants.js` so both players stay in sync. `battleship.js` wires the controllers together, exposes the global bridge required by the existing `onclick` handlers, and inserts the current year into the footer. Static assets (splash/explosion SVGs, icons, screenshots) live in `images/`; prefer `.webp` for screenshots and keep SVGs optimized (`svgo` or similar) when adding new art. | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
Docs out of sync with code (bridge is disabled).
AGENTS.md says battleship.js wires controllers and exposes a global bridge, but the file has all wiring commented out in this PR. Either re-enable the bridge (preferred) or update this section to reflect current state.
I'll verify the review comment by checking both AGENTS.md and battleship.js to confirm whether there's a documentation-code mismatch.
🏁 Script executed:
#!/bin/bash
# Check AGENTS.md content, especially around the mentioned section
cat AGENTS.md 2>/dev/null || echo "AGENTS.md not found"Length of output: 3383
🏁 Script executed:
#!/bin/bash
# Check battleship.js for bridge wiring and commented code
if [ -f "battleship.js" ]; then
echo "=== Full battleship.js ==="
cat battleship.js
elif [ -f "src/battleship.js" ]; then
echo "=== Full src/battleship.js ==="
cat src/battleship.js
else
echo "Searching for battleship.js..."
find . -name "battleship.js" -type f 2>/dev/null | head -5
fiLength of output: 1638
🏁 Script executed:
#!/bin/bash
# Also search for any commented wiring or bridge references
echo "=== Searching for bridge/wiring references and commented code ==="
rg -n "bridge|wiring|onclick|global" -i --type=js 2>/dev/null | head -30Length of output: 462
🏁 Script executed:
#!/bin/bash
# Check if there's an index.html to understand the structure
if [ -f "index.html" ]; then
echo "=== index.html ==="
cat index.html
fiLength of output: 20632
🏁 Script executed:
#!/bin/bash
# List directory structure to understand layout
echo "=== Repository structure ==="
ls -la
echo ""
echo "=== src/ directory ==="
ls -la src/ 2>/dev/null || echo "src/ not found"Length of output: 1408
🏁 Script executed:
#!/bin/bash
# Check git status or diff to see what's commented in this PR
echo "=== Recent git changes involving battleship or bridge ==="
git diff HEAD~1 --no-ext-diff 2>/dev/null | grep -A5 -B5 -i "bridge\|wiring\|battleship" | head -50 || echo "Git diff not available"Length of output: 401
🏁 Script executed:
#!/bin/bash
# More targeted search for battleship.js location and commented sections
echo "=== Looking for commented code patterns in JS files ==="
rg -n "\/\/" --type=js -A2 -B2 "controllers|bridge|wiring" 2>/dev/null | head -40Length of output: 55
🏁 Script executed:
#!/bin/bash
# Final check: Find and display the actual battleship.js file
echo "=== Finding battleship.js ==="
fd -t f "battleship.js" -x cat {} \; 2>/dev/nullLength of output: 1641
🏁 Script executed:
#!/bin/bash
# Check AGENTS.md for the exact claim about the bridge
echo "=== AGENTS.md content ==="
if [ -f "AGENTS.md" ]; then
cat AGENTS.md
else
echo "AGENTS.md not found; checking for similar files..."
find . -name "*AGENT*" -o -name "*agent*" 2>/dev/null | head -10
fiLength of output: 3409
🏁 Script executed:
#!/bin/bash
# List all markdown files in root
echo "=== Root-level markdown files ==="
ls -1 *.md 2>/dev/nullLength of output: 53
🏁 Script executed:
#!/bin/bash
# Check all JS files in root and src
echo "=== JS files in repository ==="
fd -t f "\.js$" 2>/dev/null | head -20Length of output: 140
🏁 Script executed:
#!/bin/bash
# Comprehensive check: show directory tree
echo "=== Directory tree ==="
find . -type f \( -name "*.js" -o -name "*.md" -o -name "*.html" \) | sort | head -30Length of output: 183
🏁 Script executed:
#!/bin/bash
# Direct approach: cat all candidate files
echo "=== Attempting to read AGENTS.md ==="
cat AGENTS.md 2>&1
echo ""
echo "=== Attempting to read battleship.js ==="
cat battleship.js 2>&1Length of output: 5074
🏁 Script executed:
#!/bin/bash
# Check if files exist and show what we have
for f in AGENTS.md battleship.js src/battleship.js index.html; do
echo "Checking $f..."
[ -f "$f" ] && echo "EXISTS" || echo "NOT FOUND"
doneLength of output: 131
Re-enable the global bridge in battleship.js; it is actively required by index.html's onclick handlers.
AGENTS.md correctly documents that battleship.js exposes a global bridge for onclick handlers. index.html relies on this—it calls turnVertical(), turnHorizontal(), selectShip(), clickStartGame(), clickTarget(), and clickCpuBoard() from inline event attributes. All that wiring is currently commented out in battleship.js, so these functions are undefined at runtime and the game will not work. The PR comment itself ("does this need to commented back in to work?") signals uncertainty. Either uncomment the bridge code (preferred) or refactor index.html to remove inline onclick handlers and use event listeners instead.
🤖 Prompt for AI Agents
In AGENTS.md around lines 3 to 5: the documentation notes that battleship.js
exposes a global bridge required by index.html's inline onclick handlers, but
the actual bridge in battleship.js has been commented out so functions like
turnVertical, turnHorizontal, selectShip, clickStartGame, clickTarget, and
clickCpuBoard are undefined at runtime; re-enable the global bridge by restoring
(uncommenting) the code that assigns these functions to window (or otherwise
attaches them to the global object) so index.html's inline handlers work, or
alternatively remove all inline onclick attributes from index.html and replace
them with proper addEventListener wiring—prefer restoring the bridge for minimal
change.
| // does this need to commented back in to work? | ||
| // import { BattleshipGame } from "./src/game.js"; | ||
| // import { UIController } from "./src/ui-controller.js"; | ||
| // import { ORIENTATION } from "./src/constants.js"; | ||
| // | ||
| // const uiController = new UIController(document); | ||
| // const game = new BattleshipGame(uiController); | ||
| // | ||
| // const yearEl = document.getElementById("current-year"); | ||
| // if (yearEl) { | ||
| // yearEl.textContent = new Date().getFullYear(); | ||
| // } | ||
| // | ||
| // const bridge = { | ||
| // clickTarget(index) { | ||
| // game.placePlayerShip(Number(index)); | ||
| // }, | ||
| // clickCpuBoard(index) { | ||
| // game.playerAttack(Number(index)); | ||
| // }, | ||
| // selectShip(size) { | ||
| // game.selectShip(Number(size)); | ||
| // }, | ||
| // turnVertical() { | ||
| // game.setOrientation(ORIENTATION.VERTICAL); | ||
| // }, | ||
| // turnHorizontal() { | ||
| // game.setOrientation(ORIENTATION.HORIZONTAL); | ||
| // }, | ||
| // clickStartGame() { | ||
| // game.startGame(); | ||
| // }, | ||
| // }; | ||
| // | ||
| // Object.entries(bridge).forEach(([key, handler]) => { | ||
| // window[key] = handler; | ||
| // }); | ||
| // | ||
| // window.battleshipGame = game; | ||
| // | ||
| // const playerSquares = document.querySelectorAll(".player-board .square"); | ||
| // playerSquares.forEach((square) => { | ||
| // square.addEventListener("mouseenter", () => { | ||
| // game.previewPlayerPlacement(Number(square.id)); | ||
| // }); | ||
| // square.addEventListener("mouseleave", () => { | ||
| // game.clearPlacementPreview(); | ||
| // }); | ||
| // }); | ||
| // | ||
| // const playerBoardTable = document.querySelector(".player-board table"); | ||
| // if (playerBoardTable) { | ||
| // playerBoardTable.addEventListener("mouseleave", () => { | ||
| // game.clearPlacementPreview(); | ||
| // }); | ||
| // } |
There was a problem hiding this comment.
All gameplay wiring is commented out → UI is broken (globals undefined).
Inline handlers in index.html (e.g., turnVertical, selectShip, clickCpuBoard) won’t exist. Re-enable the module imports and bridge.
-// does this need to commented back in to work?
-// import { BattleshipGame } from "./src/game.js";
-// import { UIController } from "./src/ui-controller.js";
-// import { ORIENTATION } from "./src/constants.js";
-//
-// const uiController = new UIController(document);
-// const game = new BattleshipGame(uiController);
-//
-// const yearEl = document.getElementById("current-year");
-// if (yearEl) {
-// yearEl.textContent = new Date().getFullYear();
-// }
-//
-// const bridge = {
-// clickTarget(index) {
-// game.placePlayerShip(Number(index));
-// },
-// clickCpuBoard(index) {
-// game.playerAttack(Number(index));
-// },
-// selectShip(size) {
-// game.selectShip(Number(size));
-// },
-// turnVertical() {
-// game.setOrientation(ORIENTATION.VERTICAL);
-// },
-// turnHorizontal() {
-// game.setOrientation(ORIENTATION.HORIZONTAL);
-// },
-// clickStartGame() {
-// game.startGame();
-// },
-// };
-//
-// Object.entries(bridge).forEach(([key, handler]) => {
-// window[key] = handler;
-// });
-//
-// window.battleshipGame = game;
-//
-// const playerSquares = document.querySelectorAll(".player-board .square");
-// playerSquares.forEach((square) => {
-// square.addEventListener("mouseenter", () => {
-// game.previewPlayerPlacement(Number(square.id));
-// });
-// square.addEventListener("mouseleave", () => {
-// game.clearPlacementPreview();
-// });
-// });
-//
-// const playerBoardTable = document.querySelector(".player-board table");
-// if (playerBoardTable) {
-// playerBoardTable.addEventListener("mouseleave", () => {
-// game.clearPlacementPreview();
-// });
-// }
+import { BattleshipGame } from "./src/game.js";
+import { UIController } from "./src/ui-controller.js";
+import { ORIENTATION } from "./src/constants.js";
+
+const uiController = new UIController(document);
+const game = new BattleshipGame(uiController);
+
+const yearEl = document.getElementById("current-year");
+if (yearEl) yearEl.textContent = String(new Date().getFullYear());
+
+const bridge = {
+ clickTarget(index) {
+ game.placePlayerShip(Number(index));
+ },
+ clickCpuBoard(index) {
+ game.playerAttack(Number(index));
+ },
+ selectShip(size) {
+ game.selectShip(Number(size));
+ },
+ turnVertical() {
+ game.setOrientation(ORIENTATION.VERTICAL);
+ },
+ turnHorizontal() {
+ game.setOrientation(ORIENTATION.HORIZONTAL);
+ },
+ clickStartGame() {
+ game.startGame();
+ },
+};
+
+Object.entries(bridge).forEach(([key, handler]) => {
+ window[key] = handler;
+});
+
+window.battleshipGame = game;
+
+const playerSquares = document.querySelectorAll(".player-board .square");
+playerSquares.forEach((square) => {
+ square.addEventListener("mouseenter", () => {
+ game.previewPlayerPlacement(Number(square.id));
+ });
+ square.addEventListener("mouseleave", () => {
+ game.clearPlacementPreview();
+ });
+});
+
+const playerBoardTable = document.querySelector(".player-board table");
+if (playerBoardTable) {
+ playerBoardTable.addEventListener("mouseleave", () => {
+ game.clearPlacementPreview();
+ });
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // does this need to commented back in to work? | |
| // import { BattleshipGame } from "./src/game.js"; | |
| // import { UIController } from "./src/ui-controller.js"; | |
| // import { ORIENTATION } from "./src/constants.js"; | |
| // | |
| // const uiController = new UIController(document); | |
| // const game = new BattleshipGame(uiController); | |
| // | |
| // const yearEl = document.getElementById("current-year"); | |
| // if (yearEl) { | |
| // yearEl.textContent = new Date().getFullYear(); | |
| // } | |
| // | |
| // const bridge = { | |
| // clickTarget(index) { | |
| // game.placePlayerShip(Number(index)); | |
| // }, | |
| // clickCpuBoard(index) { | |
| // game.playerAttack(Number(index)); | |
| // }, | |
| // selectShip(size) { | |
| // game.selectShip(Number(size)); | |
| // }, | |
| // turnVertical() { | |
| // game.setOrientation(ORIENTATION.VERTICAL); | |
| // }, | |
| // turnHorizontal() { | |
| // game.setOrientation(ORIENTATION.HORIZONTAL); | |
| // }, | |
| // clickStartGame() { | |
| // game.startGame(); | |
| // }, | |
| // }; | |
| // | |
| // Object.entries(bridge).forEach(([key, handler]) => { | |
| // window[key] = handler; | |
| // }); | |
| // | |
| // window.battleshipGame = game; | |
| // | |
| // const playerSquares = document.querySelectorAll(".player-board .square"); | |
| // playerSquares.forEach((square) => { | |
| // square.addEventListener("mouseenter", () => { | |
| // game.previewPlayerPlacement(Number(square.id)); | |
| // }); | |
| // square.addEventListener("mouseleave", () => { | |
| // game.clearPlacementPreview(); | |
| // }); | |
| // }); | |
| // | |
| // const playerBoardTable = document.querySelector(".player-board table"); | |
| // if (playerBoardTable) { | |
| // playerBoardTable.addEventListener("mouseleave", () => { | |
| // game.clearPlacementPreview(); | |
| // }); | |
| // } | |
| import { BattleshipGame } from "./src/game.js"; | |
| import { UIController } from "./src/ui-controller.js"; | |
| import { ORIENTATION } from "./src/constants.js"; | |
| const uiController = new UIController(document); | |
| const game = new BattleshipGame(uiController); | |
| const yearEl = document.getElementById("current-year"); | |
| if (yearEl) yearEl.textContent = String(new Date().getFullYear()); | |
| const bridge = { | |
| clickTarget(index) { | |
| game.placePlayerShip(Number(index)); | |
| }, | |
| clickCpuBoard(index) { | |
| game.playerAttack(Number(index)); | |
| }, | |
| selectShip(size) { | |
| game.selectShip(Number(size)); | |
| }, | |
| turnVertical() { | |
| game.setOrientation(ORIENTATION.VERTICAL); | |
| }, | |
| turnHorizontal() { | |
| game.setOrientation(ORIENTATION.HORIZONTAL); | |
| }, | |
| clickStartGame() { | |
| game.startGame(); | |
| }, | |
| }; | |
| Object.entries(bridge).forEach(([key, handler]) => { | |
| window[key] = handler; | |
| }); | |
| window.battleshipGame = game; | |
| const playerSquares = document.querySelectorAll(".player-board .square"); | |
| playerSquares.forEach((square) => { | |
| square.addEventListener("mouseenter", () => { | |
| game.previewPlayerPlacement(Number(square.id)); | |
| }); | |
| square.addEventListener("mouseleave", () => { | |
| game.clearPlacementPreview(); | |
| }); | |
| }); | |
| const playerBoardTable = document.querySelector(".player-board table"); | |
| if (playerBoardTable) { | |
| playerBoardTable.addEventListener("mouseleave", () => { | |
| game.clearPlacementPreview(); | |
| }); | |
| } |
🤖 Prompt for AI Agents
In battleship.js lines 1-56 the gameplay wiring (module imports, game/ui
initialization, bridge handlers, and DOM event listeners) is fully commented out
causing inline handlers in index.html (turnVertical, selectShip, clickCpuBoard,
etc.) to be undefined; uncomment the imports for BattleshipGame, UIController,
and ORIENTATION, instantiate UIController(document) and new
BattleshipGame(uiController), set current year element if present, recreate the
bridge object mapping handlers to game methods, attach each bridge handler to
window (window[key] = handler), assign window.battleshipGame = game, and
re-enable the player board event listeners and table mouseleave handler so the
UI functions correctly.
| <script type="module" src="battleship.js"></script> | ||
| </html> |
There was a problem hiding this comment.
🧩 Analysis chain
Module script + inline handlers require explicit globals.
With type="module", functions aren’t global unless assigned to window. Until battleship.js re-enables the bridge (window.turnVertical, etc.), clicks will throw ReferenceError.
is not applicable here—repository files are needed.
🏁 Script executed:
#!/bin/bash
# Get full context around lines 350-351 and search for inline event handlers
if [ -f "index.html" ]; then
echo "=== Lines 340-360 of index.html ==="
sed -n '340,360p' index.html
echo ""
echo "=== Searching for inline event handlers (onclick, onchange, etc.) ==="
grep -nE 'on(click|change|submit|input|blur|focus|mousedown|mouseup|keydown|keyup|load|error)' index.html | head -20
fiLength of output: 2125
🏁 Script executed:
#!/bin/bash
# Check battleship.js for function definitions and window assignments
if [ -f "battleship.js" ]; then
echo "=== Searching for window assignments in battleship.js ==="
grep -nE 'window\.[a-zA-Z_]|export\s+(function|const|let)' battleship.js | head -30
echo ""
echo "=== Searching for turnVertical and similar function definitions ==="
grep -nE '(function\s+(turnVertical|turnHorizontal)|turnVertical\s*[:=]|turnHorizontal\s*[:=])' battleship.js
fiLength of output: 162
🏁 Script executed:
#!/bin/bash
# Count total lines in both files to understand structure
echo "=== File sizes ==="
wc -l index.html battleship.js 2>/dev/nullLength of output: 67
🏁 Script executed:
#!/bin/bash
# Display full battleship.js to see actual content
if [ -f "battleship.js" ]; then
echo "=== Full content of battleship.js ==="
cat battleship.js
fiLength of output: 1649
Uncomment battleship.js or refactor inline handlers—functions are not accessible in module scope.
index.html contains inline onclick handlers (turnVertical, turnHorizontal, selectShip, clickStartGame, clickTarget) on lines 31, 34, 41–52, 56, 66+. However, battleship.js is entirely commented out, and the bridge code that assigns these functions to window is never executed. With type="module", these inline handlers will throw ReferenceError on click.
Either uncomment the battleship.js code (lines 1–50) to activate the window bridge assignment, or replace inline handlers with addEventListener calls in the module.
🤖 Prompt for AI Agents
In index.html around lines 350–351, the script tag loads battleship.js as a
module but that file is currently commented out so the bridge that assigns
turnVertical, turnHorizontal, selectShip, clickStartGame and clickTarget to
window never runs; fix by either uncommenting the battleship.js implementation
at the top of the file so it executes the window assignments when imported, or
(preferable) remove the inline onclick attributes and instead in the module file
addEventListener bindings to the DOM elements (or explicitly attach needed
functions to window) so the handlers are available at runtime.
code rabbit pr
Summary by CodeRabbit
Release Notes
New Features
Style
Documentation
Chores