// Sprout-R-Out -- First Placement on non-eyes, not against more than one enemy group // But if can't - must pass // Possibilities: // If a group could not be placed against in the beginning, remove at the end. // If group was not played against, remove at end of turn // If group cannot be played against in the beginning / whenever // A) simultaneously remove all applicable before turn // B) remove one-by-one until all are playable before placement // Place then remove any that become SURROUNDED as it happens // Place then remove all that are not yet done and are now unplayable // if a group cannot be played to WHEN YOU SELECT IT remove it. ***** //------------------------------------------------- (define "EyesOf" // "P1" / "P2" (sites (values Remembered #1)) ) (define "ScoreOf" (size Array (array (union ("EyesOf" #1) (sites Group from:(sites Around ("EyesOf" #1) ) ))))) (define "ValueOf" (- (* 2 ("ScoreOf" #1)) (count Sites in:(sites Board)) )) (define "AppendThisSingletonEyeSite" // (site) (if (= 0 (size Array (array (difference (sites Around #2 ) (sites Group at:(regionSite (sites Around #2 if:(is Mover (who at:(to)))) index:0 ) ))))) (remember Value #1 #2 unique:True) )) (define "RecordEyesOf" (if (not (no Pieces Mover in:(sites Around (last To) ))) (forEach Site (intersection (sites Empty) (sites Around (last To) includeSelf:True) ) ("AppendThisSingletonEyeSite" #1 (site)) ))) (define "RecordEyesMover" (if (is Mover P1) ("RecordEyesOf" "P1") ("RecordEyesOf" "P2") )) //----------------------------- (define "PlayableGroupSites" (intersection (sites Empty) (sites Around (sites) //** if:(not (is In (to) (sites Around (difference (sites Occupied by:Next) (sites)) )))))) (define "PlaceAbuttingOneGroupOfNext" (move Add (to "PlayableGroupSites" (apply (forEach Site (sites) (set State at:(site) 0) ))) (then "RecordEyesMover") )) (define "RemoveGroupOfNext" (forEach Group if:(and { (= (next) (who at:(to))) (= 1 (state at:(to))) } ) (if (not (can Move "PlaceAbuttingOneGroupOfNext")) (do (set Pending (sites)) next:(move Remove (regionSite (sites) index:0) (then (remove (sites Pending))) ) (then "RecordEyesMover") )))) //----------------------------------------------------------------------------- // - Alternative sellection styles: // -- AI has less work if sequence of selection is fixed. // -- Humansmay find it easier to place if they can place in any order. (define "Play2RemainingGroupsOfNext" (or "RemoveGroupOfNext" (forEach Group if:(and { (= (next) (who at:(to))) (= 1 (state at:(to))) } ) "PlaceAbuttingOneGroupOfNext" ) (then (if (not (no Pieces Next in:(sites State 1))) (moveAgain) )))) (define "Play2RemainingGroupsOfNextAI" (priority "RemoveGroupOfNext" (forEach Group if:(and { (= (next) (who at:(to))) (= 1 (state at:(to))) } ) (if (is In (min (array (intersection (sites Occupied by:Next) (sites State 1)))) (sites) ) "PlaceAbuttingOneGroupOfNext" )) (then (if (not (no Pieces Next in:(sites State 1))) (moveAgain) )))) // //--------------------------------- (define "IsNextToMultipleOpponentGroupsAtLastTo" (< 1 (count Groups if:(is In (to) (sites Distance (step (to if:(is In (to) (sites Occupied by:Next))) ) from:(last To) (min 0) ))))) (define "SitesFirstPlacement" (difference (union (difference (sites Empty) (sites Around (sites Occupied by:Next) includeSelf:True) //* ) (sites To (forEach Group if:(= (next) (who at:(to))) (move Add (to ("PlayableGroupSites" Next (to)) ))))) (union ("EyesOf" "P1") ("EyesOf" "P2") ))) (define "PlaceOutsideImmortalTerritory" (move Add (to "SitesFirstPlacement" (apply (forEach Site (sites Group from:(sites Around (to) ) if:(is Next (who at:(to))) ) (set State at:(site) 0) ))) (then (and { "RecordEyesMover" (if (not (no Pieces Next in:(sites State 1))) (moveAgain) ) } )))) (define "Placements" (if (is Mover P1) )) //--------------------------------------- (game "Sprout-R-Out" (players 2) (equipment { (board (trim ) use:Cell) (piece "Ball" Each ) } ) (rules (meta (no Repeat Positional)) (play (if "SameTurn" "Placements" (do (forEach Site (sites Occupied by:Next) (set State at:(site) 1) ) next:(priority { "PlaceOutsideImmortalTerritory" "RemoveGroupOfNext" (move Pass) } )) (then (and { (set Score P1 ("ScoreOf" "P1")) (set Score P2 ("ScoreOf" "P2")) (if (is Mover P1) (set Value Mover ("ValueOf" "P1")) (set Value Mover ("ValueOf" "P2")) ) (if (not (is Next Mover)) (forEach Site (sites Occupied by:Next) (set State at:(site) 0) )) } )) )) (end (if "EndCondition" { (if (= (score P1) (score P2) ) (result Mover Win) ) (if "EndCondition" (byScore) ) } )))) (define "MoverMajorityOfBoard" (< 0 (value Player Mover)) ) (define "EndCondition" (or "MoverMajorityOfBoard" (all Passed) )) //------------------------------------ (option "StrictSequenceforAI" args:{ } { (item "P1 and P2" <"Play2RemainingGroupsOfNextAI"> <"Play2RemainingGroupsOfNextAI"> "Select groups in order for both players") (item "P1" <"Play2RemainingGroupsOfNextAI"> <"Play2RemainingGroupsOfNext"> "Select groups in order for Player 1") (item "P2" <"Play2RemainingGroupsOfNext"> <"Play2RemainingGroupsOfNextAI"> "Select groups in order for Player 2") (item "Both Human" <"Play2RemainingGroupsOfNext"> <"Play2RemainingGroupsOfNext"> "Select groups in any order - human play.")** } ) (define "Perf2" (remove (hex 4 5) cells:{0 1 15 20 25 32 36 39 44 })) (define "Perf4" (remove (hex 6) cells:{0 1 5 12 17 23 30 37 40 45 50 53 60 67 73 78 85 89 90})) (option "Board Size" args: { } { (item "Limping 3 (27)" <(hex 3 4)> "Order 3 limping board (27 cell)") (item "Limping 5 (75)" <(hex 5 6)> "Order 5 limping board (75 cell)")** (item "Limping 7 (147)" <(hex 7 8)> "Order 7 limping board (147 cell)") (item "Hex 6 (91)" <(hex 6)> "Order 6 Hex board (91 cell)") (item "Triangle 9 (45)" <(hex Triangle 10)> "Order 9 Triangle board (45 cell)") (item "Epoxy (39)" <"Perf2"> "Perforated Hex board (39 cell)") (item "Epoxy (72)" <"Perf4"> "Perforated Hex board (72 cell)") (item "Square (diagonal-groups) 9 (81)" <(square 9)> "Omni-groups Square 9 (81 cell)") (item "Square (ortho-groups) 9 (81)" <(square 9)> "Ortho-groups Square 9 (81 cell)") (item "Cairo 1" <(remove (dual (tiling T33434 5)) cells: {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 20 21 24 27 28 29 35 36 39 40 44 45 46 47 53 54 55 59 60 64 65 71 72 76 79 85 90 93 94 95 96 97 98 99})> "Using an order 1 Cairo board with 48 cells" ) (item "Cairo 1 diagonal groups" <(remove (dual (tiling T33434 5)) cells: {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 20 21 24 27 28 29 35 36 39 40 44 45 46 47 53 54 55 59 60 64 65 71 72 76 79 85 90 93 94 95 96 97 98 99})> "Using an order 1 Cairo board with 48 cells" ) (item "Cairo 2 diagonal groups (160)" <(remove (dual (tiling T33434 9)) cells: {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 50 51 54 55 60 65 66 67 77 78 83 84 90 91 92 93 103 104 105 111 112 113 119 120 121 122 123 133 134 135 136 137 143 144 145 146 151 152 153 154 155 156 157 167 168 169 170 171 172 173 178 179 180 181 186 187 188 189 190 191 201 202 203 204 205 210 211 212 218 219 220 221 231 232 233 239 240 246 247 257 258 264 269 279 288 291 292 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323})> "Using an order 2 Cairo board with 160 cells" ) (item "Cairo 2 (160)" <(remove (dual (tiling T33434 9)) cells: {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 50 51 54 55 60 65 66 67 77 78 83 84 90 91 92 93 103 104 105 111 112 113 119 120 121 122 123 133 134 135 136 137 143 144 145 146 151 152 153 154 155 156 157 167 168 169 170 171 172 173 178 179 180 181 186 187 188 189 190 191 201 202 203 204 205 210 211 212 218 219 220 221 231 232 233 239 240 246 247 257 258 264 269 279 288 291 292 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323})> "Using an order 2 Cairo board with 160 cells" ) } ) //---------------------------------------------------------- (metadata (info { (description "This is a needed overhaul of both the rules and implementation. Sprout-R-Out was a newly invented territorial game for Cairo and limping Hex boards based on an original placement protocol: Players place one stone next to each opponent's group, but without touching any other group. Any group that cannot be played beside is removed. This creates an capture dynamic superficially like Go where groups get overgrown and die. Unlike Go, a single, isolated eye, once formed, is enough to give life. On the other hand, even multiple larger eyes can be insufficient for life, because the timing of capture and the requirement to play against every opponent's group if possible, can leave multiple eyes filled with uncaptured stones. The feeling of the game definitely not like Go. The game is more tactical because placements are constrained to be adjacent to existing pieces, and multiple pieces are played per turn. Spreading pieces out to quickly surround the opponent during your turn can easily backfire, as it leads to more opponent placements and fewer locations needed by the opponent to surround your pieces. The rules have been revised on the following points. 1) Previously groups for removal were marked at the beginning of the turn and removed at the end. Now they may occur at any point during the turn, and thus one removal may prevent the removal of a nearby group. 2) The need to always play against the opponent limited play and gave strong advantage to a player with the initiative. Therefore, a first move was added to allow play to non-adjacent board sites. This adds tactics of bridging to make holes, 2-hole infill, blocking placements, and expanding play to multiple non-adjacent zones. 3) The game previously ended when score oscillations stopped, which prevented cycles, but took a long time to achieve in practice. Also, this meant that a player could win by getting boxed in with a majority, by an immortal group. This has been changed by forcing the first move to be outside of the immortal territory, leading to a finite end to the moves of the game (if one player makes some effort to create holes), and ending when no moves are possible. The new end condition is then a score of more than half the board covered by immortal groups, with exceptional cases ending in a double pass.") (rules "Goal: The most Territory. Definitions: -- A 'group' is any set of a stones that is comprised of a starting stone and all the stones which can be reached from it by a series steps between adjacent stones, where the mentioned stones are all the same color. -- An 'eye' is either of: 1) a single empty site around which all the adjacent sites are occupied by pieces of a single group; or 2) an occupied site that was previously an eye. -- An 'Immortal group' is a group with at least one eye. -- Your 'territory' is the combination of your Immortal groups and their eyes. Normal Play Play starts on the empty board. Turns are a series of placements and/or captures. All placements are onto empty sites and adjacent to at most 1 enemy group. On a normal turn, 1) the player must first place a stone onto a site outside of both players' territories. 2) Thereafter, a series of placements are made, each placement adjacent to a different enemy group, until all the enemy groups have been played to once during the turn; -- EXCEPT THAT, if no placement can be made adjacent to the selected group, that group is removed instead. The removals can be made in any order. The chosen order can be important, since removing one group might prevent a different one from being removed. -- Note that except for the first placement, the placements CAN be made into the eyes. Passing is not allowed, except as allowed in the special cases below. When the turn is complete the next player plays, until the winning player's territory covers over half the board. Exceptional Cases: Since territory is only those groups with eyes, when the score is close and/or there are many pieces that are not connected to eyes, exceptional cases may arise. These are dealt with in order of priority, as follows: 1) If at the start of their turn, a player finds the position of all the pieces on the board to be the same as at the beginning of their last turn, the player must pass (unless the previous player just passed.) 2) If the player cannot legally place the first piece of their move, they must remove one eyeless enemy group and then pass. 3) If there is no group to remove, they must pass. If both players pass consecutively before one has achieved majority territory, the game ends, and the territories are compared to see who has more. This can only occur if there is at least one unplayable site on the board between 2 friendly and 2 enemy territories, and the scores are very close. In such cases a tie is possible. ") (id "1649") (source "Dale W. Walton (BGG)") (version "1.3.12") (classification "experimental") (author "Dale W. Walton") (credit "Dale W. Walton") (date "30-01-2023") } ) (define "ColourP1" (colour Black)) (define "ColourP2" (colour 252 255 234 #1)) (graphics { (player Colour P1 ("ColourP1" ~)) (player Colour P2 ("ColourP2" ~)) (piece Scale P1 "Ball" 0.99) (piece Scale P2 "Ball" 0.97) (piece Colour P1 "Ball" state:0 fillColour:(colour Black)) (piece Colour P2 "Ball" state:0 fillColour:(colour White)) (piece Colour P1 "Ball" state:1 fillColour:(colour 0 0 0 80)) (piece Colour P2 "Ball" state:1 fillColour:(colour 255 255 255 100)) (piece Colour P1 "Ball" state:2 fillColour:(colour 60 0 0 100)) (piece Colour P2 "Ball" state:2 fillColour:(colour 255 180 180 100)) (board Colour Phase0 (colour 202 189 171))// (colour 246 236 213)) (region Colour ("EyesOf" "P1") (colour 60 0 0 100)) (region Colour ("EyesOf" "P2") (colour 255 180 180 80)) (board Colour OuterEdges (colour 0 0 0)) (board Colour InnerEdges (colour 0 0 0)) (board StyleThickness OuterEdges 1.0) (board StyleThickness InnerEdges 0.5) } ))