Skip to content

Commit 3cfb893

Browse files
hopshackleclaude
andcommitted
Clickable maps and planned moves for Diplomacy, Risk and Pandemic, on the desktop and in the browser
- Shared structure for maps (gui.MapRegion, MapMove, AbstractGUIManager.getMapRegions/getMapMove) and for planning several decisions on a copy of the state before sending them (gui.IMovePlanner, web.MovePlan, web.BrowserPlayer) - The page: select a piece then where it goes, a menu where several actions apply, a follow-on menu for the next choice, and a plan panel to review, change and send the plan - Diplomacy: all orders planned in any order and sent together, with warnings - Risk: the Swing map drawn from the CMG Lee SVG (CC BY-SA 4.0, credited on the map), tooltips, clicking on the map, actions described in words with exact odds, reinforcements planned - Pandemic: city tooltips, the ways to a city and their cost, the turn's actions planned - Fix: the page was not sent a decision offering the same actions as the one before Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 5148a5e commit 3cfb893

38 files changed

Lines changed: 3477 additions & 129 deletions

‎AGENTS.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ page (via read-only accessors on `AbstractGUIManager`). See the README's "Playin
5050
must not open modal dialogs directly: use `gui.GUIMessages`, which the web server turns into
5151
messages in the page. A GUI that lets a human click on its views to act (via `ClickableActions`) may also
5252
override `AbstractGUIManager.getClickRegions()`, so that the page outlines those regions and answers clicks itself.
53+
A GUI whose board is a map may instead override `getMapRegions()` and `getMapMove(action)` (the page then offers each
54+
action by pointing at its piece and then where it acts), and `getPlanner()` (a `gui.IMovePlanner`, with which the
55+
browser player plans a run of decisions on a copy of the game and sends them together; see `web.MovePlan` and
56+
`web.BrowserPlayer`). Diplomacy, Risk and Pandemic do both. A GUI may describe its actions in words (with what bears
57+
on the choice, such as Risk's odds) by overriding `actionLabel`, which the buttons, the page and a plan's steps use.
5358
A game's rules are Markdown files in `data/rules/<GameType>/` (`1-rules.md`, `2-how-to-play.md`, ...), a template
5459
filled in from the game's parameters (`{param}` values and `<!-- if ... -->` sections; see `gui.RulesPages`). The GUI
5560
adds them as tabs with `RulesView.addTabs(tabs, GameType.<Game>, params, height)`; the web server shows the same pages

‎README.md‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,16 @@ The page also:
5353
- works by touch: a tap clicks, a long press is the right button, a drag drags, and two fingers zoom and pan;
5454
- reconnects to the same game when the connection drops (a phone asleep, a network change) or the page is reloaded;
5555
- outlines and answers clicks on the parts of the board a GUI offers as click regions (see
56-
`AbstractGUIManager.getClickRegions`; Diplomacy, Go Fish and Hearts do), without waiting for the image, with a menu
57-
when a click there could mean several actions.
56+
`AbstractGUIManager.getClickRegions`; Go Fish and Hearts do), without waiting for the image, with a menu
57+
when a click there could mean several actions;
58+
- on a board that is a map (`AbstractGUIManager.getMapRegions` and `getMapMove`; Diplomacy, Risk and Pandemic), lets
59+
the player point at a piece and then at where it goes: the piece's choices are outlined and listed, and a menu offers
60+
them when there are several; the action list is grouped by piece. A choice that follows one made on the map (the
61+
dice for an attack, the armies to move) is offered in a menu where the player clicked;
62+
- lets the player plan several decisions and send them together, where the game offers a planner
63+
(`AbstractGUIManager.getPlanner`, `gui.IMovePlanner`): Diplomacy's orders, in any order, each changeable, with
64+
warnings such as a support for a move not ordered; Risk's reinforcements; the actions of a Pandemic turn. The board
65+
shows the planned state; nothing is sent until the player presses the button.
5866

5967
```bash
6068
java -jar target/TAG.jar WebServer token=some-long-secret

‎WEBSERVER_PLAN.md‎

Lines changed: 154 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ choice still reaches `HumanGUIPlayer` through the `ActionController`, and is one
245245
- **Click regions** (Tier 2): `AbstractGUIManager.getClickRegions()` (default none) lists the parts of the views a click
246246
may choose an action on, each with its offered actions; `chooseClicked` submits one through `ClickableActions`. The
247247
page outlines a region under the pointer and answers a click itself: one action is chosen at once, several give a
248-
menu. Presses on a region are not passed to the GUI unless they become drags. Implemented for Diplomacy (provinces,
249-
traced from the map's region image), Go Fish and Hearts (cards).
248+
menu. Presses on a region are not passed to the GUI unless they become drags. Implemented for Go Fish and Hearts
249+
(cards); Diplomacy had them too, until its map (Stage 8) replaced them.
250250
- **Server load.** The GUI is no longer repainted twice per tick (`game.updateGUI` repainted the off-screen window as
251251
well as the streamer painting it); the GUI is updated only while the game is moving, after input, and every 2 s; and a
252252
frame is painted only when Swing has been asked to repaint something in it (`DirtyTracker`), or every 2 s. An idle
@@ -289,6 +289,158 @@ choice still reaches `HumanGUIPlayer` through the `ActionController`, and is one
289289
- Found: at its own preferred height Hearts' GUI draws its "0 points" over the player titles (a layout bug of the GUI,
290290
seen when zoomed in beyond the fit or in a small window).
291291

292+
### Stage 8 (Tier 3): easier decisions on map games
293+
294+
Make the page feel native to the browser where that makes deciding easier, without redrawing what the Swing GUI already
295+
draws well. The streamed image stays, and the board is still the GUI's; the page adds, over and beside it, what helps a
296+
player decide and enter a decision: information where the pointer is, direct ways of entering moves, and a plan of
297+
several moves made and checked before it is sent. Every move still reaches the engine through `HumanGUIPlayer` as one
298+
the forward model offered. Start with three games whose boards are clickable maps: **Diplomacy, Risk and Pandemic**.
299+
300+
**What gets in the player's way now.** A decision means scanning a long action list (Diplomacy offers every support and
301+
convoy of the next unit), or clicking a region and choosing from a menu. The engine sets the order of the decisions
302+
(Diplomacy asks for the units one by one in its own order; Pandemic takes each of the 4 actions as it comes), and a
303+
choice cannot be taken back. What a player needs to judge a move (the armies next door, a continent's bonus, the cubes
304+
on a city and what an outbreak would reach) is spread across the board, the side panels and the player's memory.
305+
306+
**Principles**
307+
308+
- **Information where you look.** Hovering over a region shows a card with what matters there; the GUI already knows
309+
it. Only what the player could see in the GUI: no hidden information.
310+
- **Point at the thing, then at where it goes.** Select a unit or territory, and the places it can act on are lit up;
311+
click (or drag to) one. Choices that remain (a support or a move, how many armies) come in a small menu at the target,
312+
with a sensible default.
313+
- **Plan, then commit**, wherever the engine would take a run of the player's own decisions with nothing random or
314+
hidden revealed between them. The page builds the run in any order, shows it, and lets each step be changed or undone;
315+
a button sends it all.
316+
- **Show the consequence before it happens**: orders as arrows, the planned state on the board, the odds of an attack.
317+
- **Fewer, clearer steps**: keys for the common actions, defaults that are usually right, the phase and what remains
318+
(armies to place, actions left) always in view.
319+
320+
**Shared structure**
321+
322+
- **Map regions.** The Tier 2 `ClickRegion` grows into a map description from the GUI manager: each region has an id, a
323+
name, its shape, an anchor (where an arrow or badge goes), and its card (lines of text from the GUI, as the player
324+
sees them). The page draws its overlays (highlights, arrows, badges, cards) in the browser, over the image.
325+
- **Actions in map terms.** A per-game mapping from an action to the regions it involves (from, to, and the region it
326+
acts through, e.g. the unit supported), so that the page can offer an action by selecting and dragging, and draw it as
327+
an arrow. Actions that involve no region stay in the action list.
328+
- **The planner.** A `GameSession` keeps a copy of the game from the player's view (`getCopy(player)`), advances it with
329+
the forward model as moves are planned, and sends the actions available next, the regions, and a frame of the GUI
330+
drawing the planned state (marked as a plan). Undo replays the plan less its last step on a fresh copy. The game says
331+
how far a plan may run (a hook: true while the next decision is still the player's and nothing random or hidden has
332+
been revealed). On commit, each planned action is given to `HumanGUIPlayer` when the engine asks; if one is no longer
333+
offered (an event card, a reaction), the plan stops there and the page shows what is left of it.
334+
335+
**Diplomacy**
336+
337+
- Orders for all units in any order, shown as arrows (move, support, convoy) and markers (hold, disband, build) on the
338+
map. Click a unit, then a province: one order is made at once; when there are several (move or support someone else's
339+
move there, a convoyed move) a menu at the province. Units without an order are marked, and Hold is their default.
340+
- A unit's orders do not depend on the other orders, so the planner finds each unit's options on a copy where it is the
341+
next to order; the plan is sent in the engine's unit order. Builds and disbands work the same way.
342+
- Warnings before sending, not errors: a support for a move nobody ordered, a convoy with no matching move, two own
343+
units ordered into one province.
344+
- Province card: name, supply centre and its owner, unit, and the orders given to or involving it.
345+
346+
**Risk**
347+
348+
- **Swing first**: the map becomes shaped territories like Diplomacy's, from
349+
`claude_game_creator/Risk_game_board.svg` (one path per territory, ids such as `alaska`, `eastern_united_states`;
350+
`Risk_board.svg` is the Inkscape original it is based on), tinted by owner with the army counts on them. This gives the
351+
click regions and the shapes for both the desktop and the page.
352+
- **Reinforce**: click a territory to place one army, Shift for 5 (or the batch the engine offers), with the armies left
353+
to place in view; the placements are a plan, sent together. Card trades are offered when they are possible and forced
354+
when the hand is full.
355+
- **Attack**: drag from a territory to an enemy neighbour. The dice default to the most allowed, with the odds of
356+
winning the roll and of taking the territory shown; Attack once or Blitz. Rolls are random, so attacks are not planned
357+
ahead. After a capture, a slider over the numbers `MoveArmiesChoice` offers, defaulting to the most.
358+
- **Fortify**: drag between connected territories, slider for the armies.
359+
- Territory card: owner, armies, continent with its bonus and who holds the rest of it, the enemy armies next door.
360+
361+
**Pandemic**
362+
363+
- The 4 actions are a plan with the actions left in view; cards are drawn and cities infected only after them, so the
364+
plan is exact. Click a city to see how to get there and what it costs (drive steps, or which card a direct or charter
365+
flight uses, or a shuttle) and choose one; then treat, build, share or cure there from a menu or keys. Undo any step.
366+
- City card: cubes by colour, research station, pawns there, which cards in the players' hands are that city, and
367+
whether it is in the infection discard. Outbreak warnings on cities with 3 cubes of a colour.
368+
- The discard choice (hand over the limit) shows what each card would be needed for (cures, flights).
369+
370+
**Order of work.** The shared regions and planner with Diplomacy first (its shapes and click regions exist, and
371+
planning all orders is the largest gain), then Risk (the SVG map in Swing, then drag and odds), then Pandemic (routes).
372+
373+
**Status:** implemented for all three games.
374+
375+
- **Map regions.** `AbstractGUIManager.getMapRegions()` (all the regions, id, name, view and shape) and
376+
`getMapMove(action)` (the regions an offered action involves, `from` and `to`). `ChromeReader` sends the regions
377+
(`map`, again only when a shape or view position changes) and adds `from`/`to` to each action. The page: click a
378+
piece to select it (outlined; the places it can act on dashed; the action list narrowed to it, with Show all), then
379+
a place: one action is chosen, several give a menu (with "Select X instead" when the place has a piece of its own).
380+
After a choice on the map, a next decision with nothing on the map (Risk's dice, the armies to move) is offered in a
381+
menu where the player clicked (`offerFollowOn`).
382+
Actions all on the spot (builds) are offered as soon as the piece is selected. Escape clears the selection, and a
383+
click that closes a menu does nothing else. The action list is grouped by piece rather than by kind. The Swing
384+
tooltips stay as the region cards.
385+
- **The planner.** `gui.IMovePlanner` (the game's rules for a plan: when one starts, the options at the planned state,
386+
applying a step, what replaces what, the fallback for a decision with no planned action, warnings, the button's
387+
label) from `AbstractGUIManager.getPlanner()`. `web.MovePlan` keeps the steps on a copy of the decision the game is
388+
waiting for (rebuilt from the decision on every change, dropping steps no longer offered); the GUI is updated with
389+
the planned state and offered the plan's options (`AbstractGUIManager.offerInstead`), and the session's action
390+
controller diverts choices to the plan. The page shows the steps (each removable), the warnings, Clear and Send.
391+
`web.BrowserPlayer` (the seat's `HumanGUIPlayer`) answers the run's decisions from the sent plan on the game thread:
392+
the first planned action offered, else the fallback, else the plan stops (with a message) and the player is asked.
393+
The run is the player's turn (turn, round and current player as when it was sent).
394+
- **Diplomacy** (`DiplomacyPlanner`): all the power's orders at once, in any order, from the first decision of the
395+
phase; a new order for a unit replaces its old one; unordered units hold (retreats: disband; unused builds are
396+
waived). Warnings: units holding for want of an order, own units ordered into one province, a support for an own
397+
unit's move it is not ordered to make, a hold support for an own unit ordered to move, a convoy with no matching
398+
move. `DiplomacyForwardModel.ordersFor(state, unit)` gives any unit's orders. The map draws the planned orders as the
399+
pending (purple) ones; with several units' orders offered it outlines the units only, not every province an order
400+
could aim at.
401+
- Tests: `DiplomacyPlannerTest`, `web.MovePlanTest` (the plan, and the browser player carrying it out by hand, as the
402+
game loop would ask). Checked in Chrome: selecting, a menu, the plan and its warnings, sending (the orders reached
403+
the game, and Fall's plan began). Not yet checked: retreats and builds in the page, touch.
404+
- Found: the planned orders were thin purple lines, hard to see at the fitted size; they are now drawn more strongly.
405+
- **Risk** (Swing first, then the page):
406+
- The map is drawn from `data/risk/worldMap.svg` (the map file's new optional `"svg"`; a copy of
407+
`claude_game_creator/Risk_game_board.svg`, by CMG Lee on Wikimedia Commons, under CC BY-SA 4.0,
408+
whose credit, with the licence's address, the map file's `"svgCredit"` gives and the map shows in its bottom right
409+
corner): `RiskBoardShapes` reads the territory paths (any path command but arcs, with
410+
translate and scale transforms) and finds a label point well inside each. `RiskMapView` tints each territory in
411+
its owner's colour with its armies in a disc, outlines the continents (painted at the device's scale: Java's
412+
`Area` goes wrong on these many curves, leaving stripes), and dashes the connections across the sea. A map file
413+
without an SVG keeps the discs.
414+
- Desktop: a territory's tooltip (continent and bonus, how much of it the owner holds, owner and armies, the
415+
neighbours); clicking on the map (a click places or claims; or picks a territory to attack or fortify from, then a
416+
click on a target chooses, with a menu when there are several ways; a right click drops the pick).
417+
- Labels in words, with the odds (`RiskOdds`, exact): "Attack Alberta (1) from Ontario (25): taken >99% of the
418+
time by attacking until it falls"; a roll's chance of each number of armies lost; a Blitz's chance of taking it.
419+
`AbstractGUIManager.actionLabel` is the new hook, used by the buttons and the plan's steps.
420+
- The page: claim, place, attack and fortify on the map, the dice and the armies to move in the follow-on menu;
421+
`RiskPlanner` plans the reinforce phase (trades and placements; nothing random happens in it).
422+
- **Pandemic**:
423+
- The cities are discs a little larger than the board's (`PandemicBoardView.cityAreas`, following the board's own
424+
zoom and pan); a move goes from the moving pawn's city to its destination, treating, building, sharing and curing
425+
are on the acting player's city. Selecting one's city and then another gives the ways there and what each costs
426+
("Direct flight to Istanbul (discard Istanbul)"); clicking one's city again gives what can be done there.
427+
- `PandemicPlanner` plans the turn's actions (not Forecast, which looks at the infection deck; nothing once a hand
428+
is over its limit). The forward model is rule-based and keeps its place in the turn in itself, so a planned action
429+
is carried out as its PlayerAction rule does (with the Medic's treating, and a step of the turn), never by running
430+
the game's forward model on a copy. While a plan offers the actions, the GUI offers all of them (its desktop
431+
buttons only offer those matching what the player has picked out on the board).
432+
- A city's tooltip: its cubes (and which another would make an outbreak), research station, pawns, who holds its
433+
card, and whether it is in the infection discard pile. A card to discard says its colour, how many of it the
434+
player holds and how many a cure needs.
435+
- Found and fixed: the page was not sent a decision that offered the same actions as the one before (placing armies
436+
again, after an opponent's quick turn), and stayed with its buttons disabled; the actions are now sent again
437+
whenever the game has moved on.
438+
- Tests: `RiskPlannerTest`, `RiskMapDrawingTest` (shapes, label points, odds), `RiskMapClickTest` (the desktop map,
439+
headless), `PandemicPlannerTest`. Checked in Chrome: Risk placing, planning and sending reinforcements, an attack
440+
with its dice and move-in menus, a fortifying move; Pandemic selecting a city, the ways to another, planning and
441+
sending, the city tooltip. Not yet checked: Diplomacy's retreats and builds in the page, Pandemic's sharing and
442+
curing on the map, touch.
443+
292444
## Testing
293445

294446
- **Unit tests** (`web.SessionConfigTest`, no display needed): reading a setup from a link, defaults, refusals with their

‎data/risk/worldMap.json‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
{"territories": 18, "armies": 2}
2424
],
2525
"backupTerritories": 24,
26+
"svg": "data/risk/worldMap.svg",
27+
"svgCredit": "Map adapted from Risk game board by CMG Lee, Wikimedia Commons\nCC BY-SA 4.0: creativecommons.org/licenses/by-sa/4.0",
2628
"nodes": [
2729
{"name": ["String", "Alaska"], "position": ["Vector2D", [55, 95]], "continent": ["String", "North America"], "symbol": ["String", "Infantry"],
2830
"neighbours": ["String[]", ["Northwest Territory", "Alberta", "Kamchatka"]]},

0 commit comments

Comments
 (0)