# Katan — implemented rules This is the ruleset the engine enforces. Anything marked **toggle** is exposed in the game setup screen. Katan is this app's name for the island game the collection is built around. The catalogue id is `catan` (so this file is `RULES-catan.md` and the code lives in `game/catan/`), but the printed name is trademarked, so the game is listed and titled **Katan**. The rules themselves are the base game for three to four players, as published. The engine is a pure state machine (`CatanRules`) with no Android types, and its behaviour is pinned by `CatanBoardTest`, `CatanRulesTest` and `CatanAiTest`. ## Table - **Players — *toggle*.** Three or four. `CatanOptions.playerCount`; the engine refuses anything else. - **Points to win — *toggle*.** Defaults to 10. `CatanOptions.pointsToWin`, at least 2. A lower target makes a test game short. The setup screen that exposes these lands with the screen task; the engine reads them from the table configuration today. ## Board The island is the standard layout, derived once from axial hex coordinates in `CatanBoard` and checked at class-init: - **19 hexes**, the hexes within distance 2 of the centre. - **54 vertices** and **72 edges**, shared between neighbouring hexes by exact integer position, not floating point. `HEX_CORNERS`, `EDGE_VERTICES`, `VERTEX_EDGES`, `VERTEX_HEXES` and `EDGE_HEXES` are the shared graph. - **30 coastal edges**, one closed ring. - **9 harbours**, on fixed positions around the coast. Terrain is dealt from the physical mix and shuffled: **4 forest, 4 pasture, 4 fields, 3 hills, 3 mountains, 1 desert**. Number tokens are the 18 the game ships, shuffled over the land hexes: four red tokens (**6, 6, 8, 8**) and fourteen others (**2, 3, 3, 4, 4, 5, 5, 9, 9, 10, 10, 11, 11, 12**). Seven never appears. The desert bears no token and the robber starts on it. ### Keeping 6s and 8s apart The published game asks that the two red numbers not sit on adjacent hexes, and `generate` guarantees it rather than hoping for it: 1. Shuffle the land and take four hexes; accept the draw if none of the four touch each other. Retry up to 60 times. 2. If no draw separates them, fall back to four of the six board-corner hexes, which are pairwise non-adjacent by construction and at most one of which can be the desert. `no seed puts two red tokens on adjacent hexes` runs the whole thing over seeds 1..500. Harbours: the nine **positions** are fixed (the physical frame is not shuffled), but the nine **types** are shuffled onto them — **five 2:1 resource harbours** (one per resource) and **four generic 3:1 harbours**. The frame positions are chosen so no two harbours sit closer than three coastal edges apart. ## Setup Placement runs in snake order: seats `0, 1, …, n-1` then `n-1, …, 1, 0`, each placing one settlement and one road. During setup the distance rule still holds (a settlement may not sit one edge from any other building) but the road need not connect to anything already placed. A player's **second** settlement earns one resource card for each adjacent producing hex, supply permitting — duplicates counted, so a second settlement on two forests earns two lumber. The first pass earns nothing. After the last placement, seat 0 leads and the first real turn begins. ## Turn A turn runs through the phases in `CatanPhase`: 1. **AWAIT_ROLL** — the player on the clock rolls. 2. A seven goes to **DISCARDING** and then **ROBBER**; anything else produces and goes straight to **PLAYING**. 3. **PLAYING** — build, trade, buy and play development cards, then end the turn. 4. **FREE_ROADS** is a detour inside PLAYING while a Road Building card is being spent. ### Rolling The dice are derived from the game seed and a monotonic counter (`rngStep`), not from a random generator stored in the state: the same seed and the same moves replay identically. `RollDice(forced = …)` exists so tests can stage a number; it is deliberately **not** a member of the enumerated move list, so a client cannot send one over the network — only code holding the state directly can use it. ### Production For a non-seven total, each hex whose number matches pays its producing terrain: a settlement takes **1**, a city takes **2**. The robber's hex pays nothing. **When the bank cannot meet the demand for a resource, nobody receives that resource this roll.** This is the official ruling, implemented per-resource: demand is totalled first and, if it exceeds the bank's supply, every gain of that resource is dropped. ## The robber A **seven** sends the robber: first every player holding **more than seven** resource cards discards half their hand (rounded down, so nine cards means four gone), in seat order starting from the lowest overfull seat; then the roller moves the robber and may steal. The robber **must move to a different hex**. Moving onto a hex lets the roller steal one card from one opponent who has a building on that hex and at least one card in hand. The card stolen is chosen at random, derived like the dice. A hex with no opponent holding cards offers only the move, no steal. A played Knight enters the same ROBBER phase, so the robber move after a Knight is the same code path. ## Trading ### Domestic An offer names **one** addressee and two card multisets: what the offerer gives, what they want. There are no counter-offers and no open auctions in v1. An offer is legal only when the offerer's turn is in PLAYING, the addressee is another seat, both legs are non-empty, the two legs are not the same multiset (`countOf(give) != countOf(get)` — like-for-like is not a trade), and the offerer actually holds the cards being offered. The addressee may **accept** only if they hold what was asked and the offerer still holds what was promised; otherwise only **decline** is offered. A decline clears the table and leaves every card where it was. Offers are free-form intents rather than enumerated moves (the space of card multisets is combinatorial), so they are validated structurally by `CatanRules.isLegalMove` and checked by the network driver's gate like any other move. ### Maritime Bank trade gives `ratio` of one resource for one of another, where the ratio is the best the seat can get: **4:1** through the bank, **3:1** through a generic harbour, **2:1** through a harbour matching the resource being given. A harbour counts when the seat owns a settlement or city on **either** endpoint vertex of its edge. ## Building and development cards | Build | Cost | | --- | --- | | Road | 1 lumber + 1 brick | | Settlement | 1 lumber + 1 brick + 1 wool + 1 grain | | City | 2 grain + 3 ore | | Development card | 1 wool + 1 grain + 1 ore | A settlement goes on an **empty vertex** at least two edges from every standing building and connected to the seat's own road network. A city upgrades one of the seat's own settlements. A road goes on an empty edge that connects to the seat's network (a road or a building at one of its ends). The development deck is the published 25 cards: **14 Knights, 2 Road Building, 2 Monopoly, 2 Year of Plenty, 5 Victory Point**. Cards are bought blind from the top of the deck. Timing rules the engine enforces: - **One development card per turn.** `devCardPlayedThisTurn` gates every play. - **A card cannot be played the turn it was bought.** Each card records `boughtTurn` and is skipped while that equals the current turn. - **Victory Point cards are never played.** They are counted straight from the hand by `victoryPoints`, and are only revealed by winning. - **Knight** → the robber phase, and counts toward Largest Army. - **Road Building** → two free road placements (FREE_ROADS); the player may forfeit any that remain. - **Monopoly** → seizes every card of the named resource from the other seats. - **Year of Plenty** → takes up to two cards from the bank; taking two of a kind requires the bank to hold both. ## Scoring and winning Victory points are: - **Settlement 1, city 2.** - **Longest Road 5** — the longest single road of **five or more** segments. - **Largest Army 5** — first to **three** played knights. - **Victory Point cards**, one each. A seat wins on reaching **points to win** (default 10). The win is checked after every build, when a turn ends, and when a seat's turn arrives — the last covers points that changed on someone else's turn, such as a broken Longest Road being re-awarded. A seat already at the target therefore wins at the start of its own turn rather than having to act. ### Longest Road The award goes to the longest **simple path** over a seat's own roads. The path never passes *through* an opponent's building (it may run up to one) and never revisits a vertex — so a figure of two loops sharing an intersection counts as one road of five, not two roads, because the intersection is a branch. Once held, the award is kept until another seat builds a **strictly longer** road; an equal length leaves it where it is. If the holder's road falls below five segments the award reopens to the longest road of five or more, lowest seat first on a tie. A settlement placed across an opponent's road breaks it, and the award is recomputed for everyone after any settlement. ### Largest Army First to three knights takes it. It is stolen only by a **strictly larger** army: a tie leaves the incumbent ahead, exactly as Longest Road does. ## The computer opponent `CatanAi` plays a legal, mildly strategic game so a solo player can host against computers, with the lobby filling empty seats. It reads **only public information** — terrain, numbers, buildings, roads, resource counts, development-card counts and knights played — plus its own hand. It never looks into the deck, another seat's development cards, or the seed beyond the roll the rules derive from it. That is a design constraint, not an accident: it runs on the host, where the authoritative state is fully visible. What it does: - **Setup.** Rates a settlement by the production its three hexes give (weighted by the token odds and by how much it wants each resource), plus a bonus for resource variety and for sitting on a harbour, plus a small term for where the accompanying road points. - **Main phase**, in priority order: raise a city, build a settlement, play a knight, play Year of Plenty or Monopoly when it closes a gap, play Road Building when two segments are useful, buy a development card, build a road that reaches a spot worth settling, trade at the bank only when the trade completes a build this turn, make one domestic offer that closes a build, else end the turn. - **The robber.** Moves onto the hex where it blocks the most opposing production (weighted by token odds), preferring to rob whoever is holding the most cards and the most points. - **Trades.** Accepts an offer when what arrives is worth more than what leaves by its own resource valuations; a mild table, not a shark. - **Discards.** Throws away what it values least (wool, then brick, then lumber, before grain and ore). It makes **at most one domestic offer a turn**. A declined offer changes nothing, so re-offering the same thing would only bounce between two seats forever; the engine allows more offers, the AI chooses not to. `CatanAiTest` plays three- and four-seat tables of engines out to a result from several seeds, refusing any illegal move the AI chooses, and checks the winner reached the target. ## Provenance and rule choices The rules are the published base game. Where the published rules leave room, the engine picks one reading and records it here. **Followed from the published rules:** the board and its component mix; the number tokens; 6s and 8s not adjacent; snake-order setup and second-settlement income; production weighting; the robber on a seven; discard half over seven; domestic and maritime trade; build costs; the 25-card development deck and its timing rules; Longest Road and Largest Army worth five; victory at ten. **Choices made here, and why:** - **A bank short of a resource pays nobody that roll.** This is the official ruling, and it is implemented per-resource rather than per-player. - **Longest Road and Largest Army are kept on a tie**, and stolen only by a strictly longer road or a strictly larger army. The alternative reading lets a tie steal the award; "strictly better" is the common tournament reading and keeps the award from flickering. - **A ring road counts as a simple path.** No vertex is revisited, so six segments around one hex are worth five, not six. - **The win is checked when a seat's turn arrives**, not only on that seat's own action, so points that move on another player's turn still win. - **A bought Victory Point card does not win immediately.** It is counted when the win is next checked (a build or the end of the turn), which is when the holder would reveal it. - **Year of Plenty two-of-a-kind needs the bank to hold both cards**, not one. - **The robber must move.** Some printings allow staying put; this engine always requires a different hex. - **Offers are one-to-one, no auctions or counter-offers** in v1. ## Known gaps - **No domestic auction or counter-offer.** An offer is addressed to a single seat. Open trading to the whole table, and counter-offers, are the obvious next step and are not implemented. - **No player-to-player trade over the wire beyond accept/decline.** The engine supports it; whether the UI surfaces it is the screen task's concern. - **No trading away a development card.** Not part of the base game. - **The setup screen is not part of this task.** `CatanOptions` (players, target points) is read from the table configuration; the screen that sets it, and the catalogue descriptor's `available` flag, land with the screen and verification tasks. - **The AI does not look ahead.** It scores one move deep with a fixed resource valuation. It plays legally and plausibly; it is not a strong opponent, and no strength claim is made. - **The board is the standard published layout, generated.** Unlike the Sequence board there is no unverified substitute here — the geometry is the real one — but the *island* (terrain and token placement) is freshly generated each game, so it will not match any particular physical set-up. That is the intent.