bs_claude_fire
Fire cannons at specified coordinates to attack pirate fleet. Returns hit, miss, or sunk status; sunk ships reveal their cargo.
Instructions
Fire the Navy cannons at the given coordinates on the pirate fleet. Claude chooses the target — reason about it in chat first, then call this. Returns hit/miss/sunk — and if sunk, reveals what the pirate ship was carrying.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| row | Yes | Row index: 0 = top, 9 = bottom | |
| col | Yes | Column index: 0 = left, 9 = right |
Implementation Reference
- src/games/battleship.ts:264-293 (handler)The handler function for the bs_claude_fire tool. It fires the Navy's cannons at specified coordinates, validates the game is in progress and it's the Navy's turn, checks for duplicate shots, executes the shot via fireShot(), checks for a Navy victory (all pirate ships sunk), and updates game state.
server.tool( "bs_claude_fire", "Fire the Navy cannons at the given coordinates on the pirate fleet. Claude chooses the target — reason about it in chat first, then call this. Returns hit/miss/sunk — and if sunk, reveals what the pirate ship was carrying.", { row: z.number().int().min(0).max(9).describe("Row index: 0 = top, 9 = bottom"), col: z.number().int().min(0).max(9).describe("Column index: 0 = left, 9 = right"), }, async ({ row, col }) => { if (bsGame.status !== "in_progress") { return { content: [{ type: "text", text: `The battle is over (${bsGame.status}). Call bs_new_game to sail again.` }], isError: true }; } if (bsGame.currentTurn !== "navy") { return { content: [{ type: "text", text: `It's the pirates' turn, Captain. Call bs_human_fire first.` }], isError: true }; } if (bsGame.navyAttacks[row][col] !== "?") { return { content: [{ type: "text", text: `The Navy already fired at (row ${row}, col ${col}). Choose different waters.\n\n${renderState(bsGame)}` }], isError: true }; } const { summary } = fireShot(bsGame.navyAttacks, bsGame.pirateGrid, bsGame.pirateShips, row, col); if (allSunk(bsGame.pirateShips)) { bsGame.status = "navy_wins"; return { content: [{ type: "text", text: `${summary}\n\n${renderState(bsGame)}` }] }; } bsGame.currentTurn = "pirate"; bsGame.roundNumber++; return { content: [{ type: "text", text: `${summary}\n\n${renderState(bsGame)}` }] }; } ); - src/games/battleship.ts:267-270 (schema)Input schema for bs_claude_fire — validates row and col as integers between 0-9.
{ row: z.number().int().min(0).max(9).describe("Row index: 0 = top, 9 = bottom"), col: z.number().int().min(0).max(9).describe("Column index: 0 = left, 9 = right"), }, - src/games/battleship.ts:264-293 (registration)Registration of the bs_claude_fire tool via server.tool() within registerBattleshipTools(), which is called from src/index.ts:18.
server.tool( "bs_claude_fire", "Fire the Navy cannons at the given coordinates on the pirate fleet. Claude chooses the target — reason about it in chat first, then call this. Returns hit/miss/sunk — and if sunk, reveals what the pirate ship was carrying.", { row: z.number().int().min(0).max(9).describe("Row index: 0 = top, 9 = bottom"), col: z.number().int().min(0).max(9).describe("Column index: 0 = left, 9 = right"), }, async ({ row, col }) => { if (bsGame.status !== "in_progress") { return { content: [{ type: "text", text: `The battle is over (${bsGame.status}). Call bs_new_game to sail again.` }], isError: true }; } if (bsGame.currentTurn !== "navy") { return { content: [{ type: "text", text: `It's the pirates' turn, Captain. Call bs_human_fire first.` }], isError: true }; } if (bsGame.navyAttacks[row][col] !== "?") { return { content: [{ type: "text", text: `The Navy already fired at (row ${row}, col ${col}). Choose different waters.\n\n${renderState(bsGame)}` }], isError: true }; } const { summary } = fireShot(bsGame.navyAttacks, bsGame.pirateGrid, bsGame.pirateShips, row, col); if (allSunk(bsGame.pirateShips)) { bsGame.status = "navy_wins"; return { content: [{ type: "text", text: `${summary}\n\n${renderState(bsGame)}` }] }; } bsGame.currentTurn = "pirate"; bsGame.roundNumber++; return { content: [{ type: "text", text: `${summary}\n\n${renderState(bsGame)}` }] }; } ); - src/games/battleship.ts:140-142 (helper)Helper function used by the handler to check if all pirate ships have been sunk (Navy victory condition).
function allSunk(ships: ShipState[]): boolean { return ships.every(s => s.sunk); } - src/games/battleship.ts:111-138 (helper)Core game logic helper that processes a shot — checks hit/miss/sunk on the target grid, updates attack grid and ship state, returns a summary string.
function fireShot( attackGrid: AttackCell[][], targetGrid: boolean[][], targetShips: ShipState[], row: number, col: number ): { result: "miss" | "hit" | "sunk"; ship?: ShipState; summary: string } { if (!targetGrid[row][col]) { attackGrid[row][col] = "O"; return { result: "miss", summary: `Cannonball splashes into the water at (row ${row}, col ${col}). Miss!` }; } const ship = targetShips.find(s => s.positions.some(([r, c]) => r === row && c === col))!; ship.hitCount++; attackGrid[row][col] = "X"; if (ship.hitCount === ship.size) { ship.sunk = true; for (const [r, c] of ship.positions) attackGrid[r][c] = ship.letter; return { result: "sunk", ship, summary: `DIRECT HIT at (row ${row}, col ${col})! **${ship.name}** has been sent to the bottom!\n💀 Recovered from the wreck: *${ship.cargo}*`, }; } return { result: "hit", summary: `Hit! (row ${row}, col ${col}) — ${ship.name} is taking on water!` }; }