434ea86605feceafcddd4fa9278b79df04e1893d
14
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
27af034095 |
Add cribbage for two, three or four players
The whole game: the crib, the cut, the play and the show, pegging on a board drawn with both pegs so the last score is visible as well as the total. Three tables rather than one. Two play head to head with six cards and lay two away; three play singly with five and lay one, with a fourth card dealt straight into the crib because three hands cannot fill it; four play in partnerships pegging on one score, where your partner's crib is your crib. Every table keeps four cards and every crib holds four, which is what lets one engine serve all three. The rule that shapes the code is that a game ends on the point that reaches the target, mid-count if that is where it falls. Every award goes through one function that stops the game there and refuses everything after it, so a non-dealer who counts out wins before the dealer's hand and crib are counted at all — the show reports those as never counted rather than adding them on. A go is called by the engine rather than tapped. The count only rises within a series, so a hand that cannot play now cannot play later in it, and there is nothing to decide; the log says who went past. The opponent works out its lay-away rather than guessing: every way of keeping four is scored against all forty-six cards that could still be cut, and what goes to the crib is valued separately and added or subtracted depending on whose crib it is. It takes 114 games out of 120 against random legal play, from either seat. teamForSeat now takes the seat count, because cribbage is only a partnership game at four — reading seat % 2 at a table of three would have put the first and third players on the same side. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01DCuRESmSZeJoJond43itw2 |
||
|
|
7cd2b412e2 |
Let each Mastermind player set their own code
A generated code takes away half the game. Whether to repeat a colour, whether to leave one out, whether to do the thing this opponent will not expect — those are real decisions, and no random number generator makes them. So a game now opens in a SETTING phase: each player chooses the code their opponent will have to break, one after the other, and the guessing starts once both are down. They choose in turn rather than at once because the engine only ever has one seat on the clock, and it costs nothing — neither can see the other's, so going second is not an advantage. The same move carries both: while the codes are being set it is your code, and after that it is a guess at theirs. Which one it means comes from the phase rather than from a flag on the move, because the phase is the thing that actually knows — a flag could disagree with it. An empty code used to mean one thing and now means two — not chosen yet, or chosen and hidden from the device this copy was sent to — so the state carries a flag per player. Whether the other player is ready is not a secret, and a screen has to be able to say "waiting for them" rather than sit blank. The computer sets a code at random and does not try to be clever about it: a code chosen to beat a particular solver has a pattern in it, and a pattern is the one thing a code should not have. That single choice is the only random in the app drawn from a source nobody else can see — every other one is seeded from the position so a host and a client agree, but a code seeded from anything on the wire could be worked out by the player who is meant to be guessing it. A code set on a guest's device reaches the host as a move and stops there: moves are intents sent to the host and are never relayed to the other player, so the only copy that reaches an opponent is redacted. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019Pr6B8xDDtJJcb6WJMw7Ud |
||
|
|
284f9f3f95 |
Add Checkers, Backgammon, Mastermind, and Pirates and Bulgars
The four games that were listed but not written. Nothing in the catalogue is marked "coming soon" any more. Checkers is English draughts on the thirty-two dark squares, numbered the way the game is written down. Captures are compulsory and a multiple jump is one move object, so a player cannot stop halfway through one — true by construction rather than by a rule that has to be enforced somewhere. The move generator matches the published perft counts at one to four ply (7, 49, 302, 1469), which fold in compulsory capture, crowning and the men's forward-only rule all at once. Backgammon's hard rule is not how a checker moves but that a player must use as much of the roll as they can, and that cannot be checked one move at a time: a move can be illegal precisely because playing it strands the other die. So the generator works backwards from whole turns — memoised depth-first over the remaining dice — and offers only the first steps of the longest plays. Recomputing it after each checker is what makes the rule true by construction. Every die comes from the table's seed and a count of rolls made, which is in the state rather than beside it so a game is reproducible from what crosses the wire. There is no doubling cube; the rules document says so plainly. Mastermind is played as a duel — both players are set a code and both are breaking one — because the pencil-and-paper game gives the codemaker nothing to do. It ends at the foot of a round, never mid-round, or going first would be worth half a guess. It is the one game here with anything to hide, so viewFor does real work: the host sends each device only its own code, and a device that was never given a code refuses to score a guess against it rather than quietly answering "nothing". Pirates and Bulgars is Sackson's theming of Asalto, and the rules document is explicit about which parts are attested and which had to be chosen — the book could not be obtained. Two hunters who take by jumping against twenty-four who cannot take at all, on a thirty-three point cross whose drawn lines come from the same adjacency table the moves come from, so the board and the rules cannot disagree. 130 unit tests across the four engines, all run locally as well as in CI: game/ has no Android in it, which is what makes that possible. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019Pr6B8xDDtJJcb6WJMw7Ud |
||
|
|
94b51347c3 |
Add Nine Men's Morris
Nine pieces each on twenty-four points: place them, then move them, and every line of three takes an enemy piece off the board. Two pieces left, or no legal move, and the game is over. See docs/RULES-morris.md. The board is numbered ring * 8 + index, so its geometry falls out arithmetically rather than being typed in as a table of twenty-four rows: neighbours around a square are the index either side, the ladders between squares run through the odd indices alone, and a mill is three consecutive points centred on an odd one. A table would say the same thing and could be wrong in one row. A turn is one move object — the piece placed or stepped, and the enemy piece taken when that closes a mill. Generating the removal as part of the move rather than as a turn of its own means there is no moment where a player is halfway through a turn, so a device that drops off the network between closing a mill and choosing what to take cannot leave the table stuck, and the search counts one ply for what is one decision. Three rules about mills are easy to get backwards and all three are tested: the piece that arrives is what closes a mill, so stepping out takes nothing and stepping back in pays again; a slide along the line being completed is not a mill, because the third piece it needs is the one that just moved; and a piece in a mill is spared unless every enemy piece is in one, without which a player could never be reduced and the game would not end. The AI is negamax with alpha-beta and iterative deepening over the same rules engine, with a node budget so the placing phase does not stall a phone. It has no quiescence tail and does not need one: there are no exchanges in Morris. Its evaluation knows that being down to three is dangerous even with flying on — without that term the search reads three pieces going anywhere as freedom and starts steering towards losing pieces to get there, which is a real game it would throw away. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019Pr6B8xDDtJJcb6WJMw7Ud |
||
|
|
cdd515afc6 |
Add Ta Yü
Rivers laid out from the centre of an 18x18 board on 1x3 tiles, each with three mouths that must line up with whatever they touch. One side runs water north and south, the other east and west, and a side's score is one edge multiplied by the other — so reaching only one of your two edges is worth nothing, which is the whole tension of the game. Two things fell out of the geometry rather than needing to be tabulated. The tile set is generated: three mouths chosen from the eight places one can sit on a 1x3 tile gives 56 arrangements, turning a tile end for end pairs them off with none fixed, so there are exactly 28 distinct tiles and the box's 84 is three of each. And because every tile joins the network by a mouth while all three of its own mouths interconnect, the board is always one connected river system — so scoring never traces connectivity, and a mouth at the edge is an exit by construction. Both properties are asserted over whole games. The placement check is one comparison doing two jobs: where a new tile abuts an old one, both sides must agree. That refuses a river dead-ending against stone and, read the other way, refuses a blank flank that would wall off a river already down. 18x18 comes out under 20dp a cell on a phone, too fine to tap, so laying a tile is a tap to line it up and a button to commit. Tapping the same cell again cycles the other legal ways the tile could cover it, which is also how it gets turned — a rotate control would have landed on illegal positions. A tap on a cell the tile cannot cover is ignored rather than treated as a deselection, so a fingertip one cell wide of the mark does not throw away a placement. Two AI settings, not three. A blocking-heavy variant was written and dropped because it played the full setting dead even over 30 games; shipping it as a step up would have been a claim that could not be backed. What ships is held to measured numbers: full strength won 20 of 20 against random placement from either axis, gentle beats random about three games in four and loses to full strength about four in five, and random against random comes out even, which is what makes the rest of those numbers mean anything. The reconstruction's uncertainties stay called out in the rules doc rather than being smoothed over now that the code exists: the 18x18 board reading, the marked exits placed at 3, 8 and 13 by choice, and the three-player flood variant left out because nothing found says how the flood scores. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015pyhC1KyFkQk6hUnnX2Tof |
||
|
|
9f71e0844b |
Specify Ta Yü ahead of building it, and list it as coming
Ta Yü has been out of print since the 2009 Goliath reissue, so the rulebook had to be reconstructed from secondary sources — and this machine's network policy blocks everything but search summaries, so BGG's rules files were out of reach too. The tile set fell out of the geometry rather than needing a component list. A 1x3 tile has eight places a river mouth can sit; three mouths chosen from eight gives 56 arrangements, and turning a tile end for end pairs them off with no arrangement fixed, leaving exactly 28 distinct tiles. The reissue has 84 tiles and the 1999 original had 112 — 3x28 and 4x28. Twelve of the 28 touch three flanks of the rectangle, which is what the ringed centre stud on the reissued tiles marks. Three independent numbers agreeing is why the geometry is worth trusting. What could not be pinned down is called out in the doc rather than smoothed over: the board is taken as 18x18 because that is the reading under which "the four centre indentations" is true, the marked exits are placed at 3, 8 and 13 by choice, and the three-player flood variant is left out entirely because nothing found says how the flood scores, and inventing that would be shipping a different game. Same posture as the Sequence board layout. The catalogue entry is added with available = false, so it shows as coming soon on dev builds and stays out of production until the engine lands. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015pyhC1KyFkQk6hUnnX2Tof |
||
|
|
d6e237ce4a |
Add chess
The full game: castling with every condition, en passant including the case where taking would expose your own king, promotion to any of the four, pins, checkmate, stalemate, insufficient material, the fifty-move rule and threefold repetition. Move generation is checked against the published perft counts rather than against hand-written cases — the opening array to depth four (197,281 positions) plus four standard test positions chosen precisely because they break generators. Those counts are exact, so matching them leaves very little room for a rule to be subtly wrong. The opponent is a negamax search with alpha-beta, iterative deepening and a capture-only quiescence tail, at three strengths. The quiescence tail is the part that stops it hanging pieces: a fixed-depth search that stops mid-exchange scores the position as though the recapture never comes. Two supporting changes: The AI now thinks off the caller's thread. A card AI answers instantly, but a chess search runs for a second or more, and the match controller's scope belongs to the screen — searching there would freeze the board it is drawn on. Offline setup can seat the local player somewhere other than seat 0, which is what lets you play Black. Seat 0 is White by definition, so choosing a colour has to choose a seat. FEN is read and written, so a table can start from a set position. 203 engine tests pass locally. |
||
|
|
fb70396d09 |
Add Kaiser, Crazy 8s and Wizard
Three more card games, engine to screen. Kaiser: 32-card prairie trick-taking with bidding, the five of hearts worth five and the three of spades costing three. Bidding is capped at ten because ten is all a hand can be worth, and a losing score gives the game a floor — without one a table that keeps bidding and going down never reaches a result. Crazy 8s: eights are wild and name the suit in force, which is why the table states that suit in words rather than leaving it to be read off the pile. Blocked rounds are scored rather than hanging. Wizard: the 60-card deck, one more card dealt each round until the pack runs out, bid your tricks exactly. The shared card model gains WIZARD and JESTER ranks, so every ordinary deck now builds from Rank.standard rather than walking the whole enum. Also fixes a lobby bug this would have hit: hosting seated the catalogue minimum rather than the table the host had just set up, so a six-handed game would have been rejected by its own rules engine. 164 engine tests pass locally. |
||
|
|
d30ea8656f |
Fix section ordering in the Golf rules
The opening-cards section had been dropped into the middle of the table setup list, stranding the discard pile and deck-count bullets after it. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN |
||
|
|
d989907d7e |
Golf: 8-card grids, chosen openers, final putt, end-of-hole score card
- An 8-card variant, laid out as two rows of four. The existing column scoring covers it without change. - Opening cards are now chosen rather than dealt face up. Nothing starts revealed; each player in turn turns over their allowance, and the hole begins once everyone has picked. This needed a new SETUP phase in the engine, since it is a real decision and has to be validated like any other move rather than being decided at deal time. - "Line up the final putt", off by default: throw a drawn card away without turning your last face-down card over, so you are not forced to close the hole on a card you did not choose. Only offered on the last face-down card. Because a whole table could otherwise decline forever, two full laps of nothing but thrown cards calls the hole and scores it where it stands. - The end of a hole now shows a score card — every player's strokes for the hole and their running total, lowest first — and the next hole is not dealt until it is dismissed. MatchController gained a general awaitsConfirmation hook for this, so any game wanting a scoreboard between rounds can stop the table the same way. Only the host waits; clients render what they are sent. Nine more Golf tests, covering the 8-card layout, the opening choice, when the putt option is and is not offered, and that a table refusing to putt out still finishes. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN |
||
|
|
532c3ea48a |
Add President and Golf
Two more games on the existing framework — no changes were needed to the lobby, networking, settings or update layers, which is what the shared GameRules/GameAi contract was for. President - Threes low, twos high. Lead any number of one rank; follow with the same count of a higher rank, or pass. When everyone has passed the pile comes down and the last player to play leads again. - Toggles: player count, rounds, twos clear the pile, four of a kind bombs, and the between-round card exchange. - Plays are offered as whole sets rather than by selecting cards. A set is the unit of the game, so choosing from the legal sets is both easier to operate and impossible to get wrong. Golf - 4, 6 or 9 card grids. Draw from stock or discard, then either swap the card in or — only if it came off the stock — throw it and turn one of your own over. A card taken from the discard pile has to be used. - Matching columns cancel to nothing; on the 3x3 board rows do too, but not on the shallower grids where three cards are not a line. - Face-down cards are hidden from everyone including their owner, which is the point of the game: viewFor masks them with a fixed placeholder so the real card never reaches the device that has not turned it over. Both engines are pure Kotlin and unit tested — 71 tests now, covering ranking, legal moves, pile and hole resolution, scoring, redaction, wire round-trips, and full random and AI playthroughs. The Golf test also checks the AI actually beats random play rather than merely being legal. Also widened the setup screen's option chips to wrap: the reveal-count row carries up to ten, and a chip off the edge of the screen is a setting that cannot be changed — the same failure as the Euchre Pass button. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN |
||
|
|
dbe76c34c4 |
Brand the app with the Wallace tartan and a Celtic splash
- The launcher icon is a single square of the tartan, drawn as a vector so it stays sharp at any density and ships no PNGs. The adaptive icon's foreground is deliberately empty: the cloth is the icon. - Tartan.kt draws the sett as warp, then as weft at half opacity. That overlap is what gives the blended squares and reads as woven cloth rather than a printed grid, and it is reused by both the icon and the splash. - The app opens on the tartan under "Pro Libertate Games" in Uncial Antiqua, holds two seconds, then fades. It is an overlay rather than a destination, so the menu is already composed behind it and the fade reveals a live screen. The window background is set to a dark red so launch does not flash white before Compose draws. Two things to be aware of: - WallaceSett is an approximation. It reads as Wallace — bold red and black check with a narrow gold overstripe — but the registered threadcount could not be verified here, so the counts were chosen to look right. They are plain data and can be swapped for the registered ones without touching anything else. - Uncial Antiqua is bundled under the SIL Open Font License 1.1, with the full licence at docs/licenses/UncialAntiqua-OFL.txt. The OFL requires that to be distributed with the font, so it must not be separated from it. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN |
||
|
|
60ddcdf67f |
Caption Sequence jacks as WILD or REMOVE
A jack's power is carried by its artwork on a real deck — drawn in profile it shows one eye and removes a chip, drawn face-on it shows two and is wild. These cards render as rank and suit only, so J♦ and J♠ were indistinguishable in hand despite doing opposite things. Jacks in hand now carry the word on their face, and the hint under the hand says what tapping will do rather than the generic "tap a highlighted square", which was wrong for a one-eyed jack anyway — those target an opponent's chip, not a highlighted empty square. The caption is a general PlayingCardView option, so any later game whose cards carry meaning beyond rank and suit can use it. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN |
||
|
|
487c68419e |
Add app shell with Euchre and Sequence, LAN/Bluetooth play
First vertical slice: the whole shell plus two games playable end to end, so every layer is exercised before the other nine games are built on it. Games - Euchre: bowers, ordering up, dealer discard, going alone, stick the dealer, and full scoring. Rule variants (deck size, points to win, stick the dealer, going alone) are toggles in game setup. - Sequence: two-eyed and one-eyed jacks, free corners, locked sequences, the shared-chip limit, and dead-card exchange. Teams, players per team and the sequence target are toggles. - The board layout in SequenceBoard is generated, not the commercial board — it holds every structural property the rules need, but does not match a physical board. Documented in docs/RULES-sequence.md. Multiplayer - One transport abstraction over newline-delimited JSON, implemented twice: LAN via NSD discovery and TCP, Bluetooth via Classic RFCOMM. A lobby advertises on both at once, so a table can mix them. - Host-authoritative: clients send move intents, the host re-validates every one against the rules, and each client receives a state redacted for its own seat so hidden information never crosses the wire. - Seats start as AI and are handed to people as they join, which is what makes any mix of humans and AI work without a separate code path. Shell - Main menu lists all eleven games; the nine without engines are marked coming soon and are driven entirely by GameCatalog. - Settings: sound, animation speed (one multiplier drives card movement and AI thinking time), and OTA updates from the latest GitHub release. - Layouts measure available space rather than assuming an orientation. The game package is free of Android types, so the rules engines and AI run under plain JUnit; 43 tests cover ranking, following suit, scoring, sequence detection, redaction, wire round-trips and full random and AI playthroughs. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN |