Skip to content

feat: implement Phase 1b — Bi-Planetary game engine#5

Merged
countercheck merged 1 commit into
mainfrom
feature/phase-1b-game-engine
Apr 13, 2026
Merged

feat: implement Phase 1b — Bi-Planetary game engine#5
countercheck merged 1 commit into
mainfrom
feature/phase-1b-game-engine

Conversation

@countercheck

Copy link
Copy Markdown
Owner
  • movement.ts: pure helpers (getValidDestinations, resolveMovement, checkLanding) + 33-test suite covering coasting, thrust, gravity, win detection, and multi-turn integration
  • types/game.ts: expand Ship (maxFuel, cs, pendingGravity), add PlotEntry, flesh out TriplanetaryState (plots, turnNumber, winner, mapSnapshot, scenarioId)
  • TriplanetaryGame.ts: astrogation phase with simultaneous plotCourse / lockIn moves; onEnd calls resolveMovement; endIf detects winner
  • shared/index.ts: export movement lib
  • LobbyPage.tsx: fetch canonical map, create match with setupData, join endpoint, store playerID+credentials in sessionStorage
  • HexGrid.tsx: add overlays?: ReactNode prop for ship/vector overlays
  • GameRoom.tsx: wire boardgame.io/react Client with SocketIO transport
  • Board.tsx: game board with ship counters, vector arrows, valid-dest highlights, plot lines, and hex-click course-plotting flow
  • HUD.tsx: turn/fuel/phase display, Lock In button, win/loss banner
  • vite.config.ts: optimizeDeps for boardgame.io CJS modules

https://claude.ai/code/session_01DeLbhCjrgM6A71jTPZCrsn

- movement.ts: pure helpers (getValidDestinations, resolveMovement,
  checkLanding) + 33-test suite covering coasting, thrust, gravity,
  win detection, and multi-turn integration
- types/game.ts: expand Ship (maxFuel, cs, pendingGravity), add
  PlotEntry, flesh out TriplanetaryState (plots, turnNumber, winner,
  mapSnapshot, scenarioId)
- TriplanetaryGame.ts: astrogation phase with simultaneous plotCourse /
  lockIn moves; onEnd calls resolveMovement; endIf detects winner
- shared/index.ts: export movement lib
- LobbyPage.tsx: fetch canonical map, create match with setupData,
  join endpoint, store playerID+credentials in sessionStorage
- HexGrid.tsx: add overlays?: ReactNode prop for ship/vector overlays
- GameRoom.tsx: wire boardgame.io/react Client with SocketIO transport
- Board.tsx: game board with ship counters, vector arrows, valid-dest
  highlights, plot lines, and hex-click course-plotting flow
- HUD.tsx: turn/fuel/phase display, Lock In button, win/loss banner
- vite.config.ts: optimizeDeps for boardgame.io CJS modules

https://claude.ai/code/session_01DeLbhCjrgM6A71jTPZCrsn
Copilot AI review requested due to automatic review settings April 13, 2026 19:43
@countercheck
countercheck merged commit 0fd48e6 into main Apr 13, 2026
5 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements “Phase 1b” of the Bi-Planetary Triplanetary engine by adding shared movement resolution + win detection, integrating those rules into a boardgame.io game phase, and wiring a playable client UI (lobby → join/create → game room → board/HUD rendering).

Changes:

  • Expanded shared game state/types and introduced movement helpers (getValidDestinations, resolveMovement, checkLanding) with a dedicated test suite.
  • Implemented an astrogation phase in TriplanetaryGame (simultaneous plotting + lock-in) and exported the new movement library from shared.
  • Built client flow for match creation/joining + session credential storage, and added board/HUD rendering with hex overlays.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/shared/src/types/game.ts Extends Ship and TriplanetaryState to support plotting, turn tracking, winner state, and map snapshots.
packages/shared/src/lib/movement.ts Adds core movement/landing resolution logic for Bi-Planetary.
packages/shared/src/lib/tests/movement.test.ts Adds Vitest coverage for movement rules, gravity, and win/draw detection.
packages/shared/src/index.ts Re-exports movement library from shared package entrypoint.
packages/shared/src/game/TriplanetaryGame.ts Adds boardgame.io phase + moves for simultaneous plotting/locking and movement resolution.
packages/client/vite.config.ts Adds optimizeDeps includes to improve boardgame.io module handling in Vite.
packages/client/src/pages/lobby/LobbyPage.tsx Fetches canonical map, creates + joins matches, stores credentials, and joins existing matches.
packages/client/src/pages/lobby/GameRoom.tsx Wires boardgame.io React client with SocketIO transport using stored seat credentials.
packages/client/src/pages/game/HUD.tsx Adds a HUD with turn/phase/fuel display and lock-in/win/loss UI.
packages/client/src/pages/game/Board.tsx Renders the hex board with overlays (ships, vectors, valid destinations, plot lines) and click-to-plot interaction.
packages/client/src/components/map/HexGrid.tsx Adds overlays prop to render SVG overlays above the hex layer.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +85 to +88
players: Array<{ id: number; name?: string }>;
};

const freeSeat = matchData.players.find((p) => !p.name);
Comment on lines +47 to +55
const ProtoHex = defineHex({
dimensions: hexSize,
orientation: Orientation.POINTY,
origin: 'topLeft',
});
const grid = new Grid(
ProtoHex,
rectangle({ width: qMax - qMin + 1, height: rMax - rMin + 1, start: { q: qMin, r: rMin } }),
);
Comment on lines +47 to +61
plotCourse: ({ G, ctx }, destination: [number, number]) => {
const ship = G.ships[Number(ctx.currentPlayer)];
if (!ship) return INVALID_MOVE;
const valid = getValidDestinations(ship, G.mapSnapshot?.hexes ?? {});
if (!valid.has(`${destination[0]},${destination[1]}`)) return INVALID_MOVE;
G.plots[ctx.currentPlayer] = { destination, locked: false };
},

lockIn: ({ G, ctx, events }) => {
const plot = G.plots[ctx.currentPlayer];
if (!plot) return INVALID_MOVE;
plot.locked = true;
const allLocked = Object.keys(ctx.activePlayers ?? {})
.every(pid => G.plots[pid]?.locked === true);
if (allLocked) events.endPhase();
Comment on lines +122 to +139
// Step 2 — cost: coast (no thrust) is free; any other destination costs 1 fuel
const coastQ = ship.position[0] + ship.vector[0];
const coastR = ship.position[1] + ship.vector[1];
const [destQ, destR] = plot.destination;
const isCoasting = destQ === coastQ && destR === coastR;
const fuelCost = isCoasting ? 0 : 1;

// Step 3 — new velocity = destination − current position
ship.vector[0] = destQ - ship.position[0];
ship.vector[1] = destR - ship.position[1];

// Step 4 — move
ship.position[0] = destQ;
ship.position[1] = destR;

// Step 5 — consume fuel
ship.fuel = Math.max(0, ship.fuel - fuelCost);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants