From 516bdbe21324ed1a52c4fa4c2a0939c022b2ff79 Mon Sep 17 00:00:00 2001 From: Carl Pearson Date: Tue, 9 Sep 2025 08:24:02 -0600 Subject: [PATCH] README.md --- README.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index cb6cc24..70433f6 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,7 @@ build/candyland ```text games played: 1000000 -player 0 won: 274882 -player 1 won: 257248 -player 2 won: 240726 -player 3 won: 227144 -total draws: 31659948 -backwards moves: 940653 -shortcuts taken: 1277005 -didn't move: 18 empty BoW: 3576 -landed on another: 2966229 longest game: 81 draws shortest game: 6 draws 0: 0 @@ -120,4 +111,68 @@ Here's ours, featuring two shortcuts and a split path: ![](board.jpg) +The simulation code has two interesting points of complexity: + +### Handling the Split Path + +The 83 board spaces are laid out in a 1D array. +It's appealing to just search forward from the player position to find the next space of the appropriate color, however, the forked path means this will occasionally produce an invalid move. +If the left branch (blue/green/purple) is stored before the right branch (yellow/orange/red), and a player on the left branch draws a red card, this would cause them to jump over to a space on the right branch. + +To avoid this, each space also stores 1 or 2 following spaces: the forking space has two, and all other spaces have one. +Before a piece can be moved, this simple graph of spaces needs to be traversed to actually determine the pool of reachable spaces. + +### Disallowing Shared Occupancy + +The second source of complexity is disallowing two pieces from sharing a space on the board. + +The basic logic is wrapped up in a function like this: +* Inputs: starting location, target color +* Output: ending location +* Examine all reachable spaces starting from the start location + * If the space is the target color, return its index unless it's already occupied. + +In the case of landing on a shortcut, it takes sadvantage of the fact that both shortcuts on this board jump the player to the next space of the same color. +We just restart this logic from the shortcut start location with the same target color. + +In the case of a candy card, we scan the whole board to look up the target space (since it might be behind the starting location). +Then, apply the move logic starting from immediately before the target space, targeting the next pink space. +This handles the case where the target space is occupied by a player, and needs to be skipped to land on the next pink space. + +## Results + +I ran 1,000,000 simulations + +| Player Won | % Observed (raw) | +|-|-| +| 1 | 27.5% (274882) | +| 2 | 25.7% (257248) | +| 3 | 24.1% (240726) | +| 4 | 22.7% (227144) | + +Going first (i.e., being the youngest player) confers a 1.8pp advantage relative to the closest competition. +If you go last, you can expect to win only 22.7% of games. + +Other statistics over 1M games: + +| Stat | Value | +|-|-| +| Cards drawn | 31,659,948 | +| Backwards Moves | 940,653 (2.97% of draws) | +| Shortcuts Taken | 1,277,005 (4.03% of draws) | +| Didn't move | 18 | +| Empty Bag of Wonders | 3,576 | +| Landed on Another Player | 2,966,229 | + +The longest observed game was 81 draws, and the shortest was 6. + ![](histo.png) + +The six turn game goes like this, and requires player 1 to do certain moves first. + +1. Player 1 goes to ice cream +2. Player 2 goes to mint +3. ... +4. ... +5. Player 1 draws double red: first one takes him across the shortcut, second takes him to the red ahead of player 2. +6. Player 2 draws double red: lands on player 1 to skip to next red, second red takes him to the end.