// Game of Pyrga // Reimplemented using Absolute directions // because the add popup for pieces with a defined placement orientation show the pieces without their orientation - // So redefined them with absolute orientations and rotation in meta data instead, // but this meant setting restrictions for next placement locations could not be based on piece orientation. (define "SetupHands" (start { (place "Disc1" (handSite P1 0)) (place "Disc1" (handSite P1 1)) (place "Disc1" (handSite P1 2)) (place "Disc1" (handSite P1 3)) (place "Disc1" (handSite P1 4)) (place "SquareOrtho1" (handSite P1 5)) (place "SquareOrtho1" (handSite P1 6)) (place "SquareOrtho1" (handSite P1 7)) (place "SquareOrtho1" (handSite P1 8)) (place "SquareOrtho1" (handSite P1 9)) (place "TriangleN1" (handSite P1 10)) (place "TriangleN1" (handSite P1 11)) (place "TriangleN1" (handSite P1 12)) (place "TriangleN1" (handSite P1 13)) (place "TriangleN1" (handSite P1 14)) (place "Disc2" (handSite P2 0)) (place "Disc2" (handSite P2 1)) (place "Disc2" (handSite P2 2)) (place "Disc2" (handSite P2 3)) (place "Disc2" (handSite P2 4)) (place "SquareOrtho2" (handSite P2 5)) (place "SquareOrtho2" (handSite P2 6)) (place "SquareOrtho2" (handSite P2 7)) (place "SquareOrtho2" (handSite P2 8)) (place "SquareOrtho2" (handSite P2 9)) (place "TriangleN2" (handSite P2 10)) (place "TriangleN2" (handSite P2 11)) (place "TriangleN2" (handSite P2 12)) (place "TriangleN2" (handSite P2 13)) (place "TriangleN2" (handSite P2 14)) }) ) (define "RemoveFromHand" (remove (min (array (forEach (sites Hand Mover) if:(= (id #1 Mover) (what at:(site))))))) ) (define "AddDisc" (move Add (piece (id #1 Mover)) #2 stack:True (then (and { (forget Value All) (set State at:(last To) level:(topLevel at:(last To)) 1) ("RemoveFromHand" #1) (remember Value (last To)) }) ) ) ) (define "AddSquare" (forEach Value (array #1) (move Add (piece (if (= 0 (value)) (id "SquareOrtho" Mover) (id "SquareDiag" Mover) ) ) #2 stack:True (then (and { (forget Value All) (set State at:(last To) level:(topLevel at:(last To)) 2) ("RemoveFromHand" "SquareOrtho") (if (= (id "SquareOrtho" Mover) (what at:(last To) level:(topLevel at:(last To)))) (forEach Site (sites Around (last To) Orthogonal) (remember Value (site)) ) (forEach Site (sites Around (last To) Diagonal) (remember Value (site)) ) ) }) ) ) ) ) (define "AddTriangle" (do (move Add (piece (id #2 Mover)) #3 stack:True (then (and { (forget Value All) (set State at:(last To) level:(topLevel at:(last To)) 3) ("RemoveFromHand" "TriangleN") } (then (and (forEach Site (sites Distance (step #1 (to (sites Board))) from:(last To) ) (remember Value (site)) ) (forEach Site (remember Value (site)) ) ) ) ) ) ) ifAfterwards:(< 0 (size Array (values Remembered))) // use remember to work around bug for (is Pending) ) ) (define "EmptySite4" (to (sites Empty) if:(< 0 (count Pieces Mover #1 in:(sites Hand Mover)))) ) (define "ToSitesAllowedFor" (to (sites (values Remembered)) if:(and { (> 3 (count Stack at:(to))) (!= #2 (state at:(to) level:0)) (!= #2 (state at:(to) level:1)) (< 0 (count Pieces Mover #1 in:(sites Hand Mover))) }) ) ) //------------------------------------------------------------ (game "Pyrga" (players 2) (equipment { (board (square 4) use:Cell) (hand Each size:15) (piece "Disc" Each) (piece "SquareOrtho" Each) (piece "SquareDiag" Each) (piece "TriangleN" Each) (piece "TriangleS" Each) (piece "TriangleE" Each) (piece "TriangleW" Each) }) (rules ("SetupHands") (play (priority (or { ("AddDisc" "Disc" ("ToSitesAllowedFor" "Disc" 1)) ("AddSquare" ("ToSitesAllowedFor" "SquareOrtho" 2)) ("AddTriangle" N "TriangleN" ("ToSitesAllowedFor" "TriangleN" 3) SW SE) ("AddTriangle" E "TriangleE" ("ToSitesAllowedFor" "TriangleN" 3) NW SW) ("AddTriangle" S "TriangleS" ("ToSitesAllowedFor" "TriangleN" 3) NW NE) ("AddTriangle" W "TriangleW" ("ToSitesAllowedFor" "TriangleN" 3) NE SE) }) (or { ("AddDisc" "Disc" ("EmptySite4" "Disc")) ("AddSquare" ("EmptySite4" "SquareOrtho")) ("AddTriangle" N "TriangleN" ("EmptySite4" "TriangleN") SW SE) ("AddTriangle" E "TriangleE" ("EmptySite4" "TriangleN") NW SW) ("AddTriangle" S "TriangleS" ("EmptySite4" "TriangleN") NW NE) ("AddTriangle" W "TriangleW" ("EmptySite4" "TriangleN") NE SE) }) (then (and { ( (mover)) ( (next)) }) ) ) ) (end (if (or { (>= (score Mover) 300) (>= (score Next) 300) (no Moves Next) }) (byScore) ) ) ) ) // ------------------- // Scoring (define "UpdateScoreOfMajority" (set Score (player #1) 0 (then (forEach Site (sites Board) // bug work-around Addscore was picking up the empty sites before I added the difference... (if (> (+ { (if (= #1 (who at:(site) level:0)) 1 0) (if (= #1 (who at:(site) level:1)) 1 0) (if (= #1 (who at:(site) level:2)) 1 0) }) (/ (+ 1 (topLevel at:(site))) 2) ) (addScore (player #1) (^ 10 (topLevel at:(site)))) ) ) ) ) ) (define "UpdateScoreOfTop" (set Score (player #1) 0 (then (forEach Site (sites Board) (if (= #1 (who at:(site))) (addScore (player #1) (^ 10 (topLevel at:(site)))) ) ) ) ) ) //----------------------------------------- //Defines for Options (define "NoTails" (sites {}) ) (define "RayTails" (union (sites Distance (step (directions { #2 }) (to (sites Board))) from:(last To) #1) (sites Distance (step (directions { #3 }) (to (sites Board))) from:(last To) #1) ) ) (define "KnightTails" (difference (sites { (ahead (ahead (ahead (last To) #2) #1) #2) (ahead (ahead (ahead (last To) #3) #1) #3) }) (sites Around (last To)) // to reject the cases where the off-board sites are relocated by (ahead) ) ) //---------------------------- // Options (option "Control" args:{ } { (item "Majority Control" <"UpdateScoreOfMajority"> "Stack is owned by player with majority of pieces there.")*** (item "Top Control" <"UpdateScoreOfTop"> "Stack is owned by player with piece on top.") // my mis-reading - but reduces the connection between material on board and control. - more chaotic? } ) (option "Square Influence" args:{ } { (item "Orthogonally only" <{0}> "Square is placed orthogonally - next piece goes on adjacent spaces.")** //<{0}> <(!= 1 1)> (item "Diagonally only" <{1}> "Square is placed diagonally - next piece goes on diagonally adjacent spaces.") (item "Choice" <{0 1}> "Square may be placed Either way") } ) (option "Triangle Ahead" args:{ } { (item "Any distance" <(range 1 Infinity)> "Next piece may be placed any distance ahead of triangle")** (item "Adjacent only" <(exact 1)> "Next piece may be placed directly in front of triangle") (item "At distance 2 only" <(exact 2)> "Next piece may be placed directly in front of triangle") (item "Non-adjacent only" <(range 2 Infinity)> "Next piece may be placed at least 2 ahead of triangle") } ) (option "Triangle Tails" args:{ } { (item "No tail placements" <"NoTails"> "but may not be placed around its tails.")** (item "Knight's Move" <("KnightTails" #1 #4 #5)> "and-or may be placed at a knight's distance from the tails.") (item "Diagonal ray" <("RayTails" (range 1 Infinity) #4 #5)> "and-or may be placed diagonally from the tails.") (item "Diagonal adjacent" <("RayTails" (exact 1) #4 #5)> "and-or may be placed diagonally adjacent to the tails.")* (item "Diagonal ray, non-adjacent" <("RayTails" (range 2 Infinity) #4 #5)> "and-or may be placed diagonally from the tails, but not adjacent.")* } ) //---------------------------- (metadata (info { (description "Pyrga is a 2 player abstract 4x4 square stacking game with a limited supply of 5 each of 3 types of pieces per player. There is no movement, nor capture. Shapes and their orientation restrict the locations of the subsequent placements. Stacks ownership is by majority. Duplicate shapes are not allowed in the same stack. Goal is ownership of 3 complete stacks, or if not possible, ownership of the majority of the tallest non-tied stacks Draws are possible.") (rules "White starts by playing any piece on any space. Players take turns to play one of their pieces. Each space of the board can support only one Tower. Each Tower is made of one piece of each kind (Square, Triangle, Circle), and pieces may be played in any order. If the active player cannot play according to the last piece's rule, they may play on any empty space. A Tower is controlled by the player with the most pieces. SQUARES The opponent must play in an orthogonally adjacent space. TRIANGLES The active player selects the orientation, it must point to at least one space. The opponent must play in the line indicated by the Triangle. CIRCLES The opponent must play on the same space. SCORES: The scores show the column counts. For example: 211 means 2 Towers, 1 controlled pair and 1 singleton GAME END The first player to control 3 completed Towers wins (i.e. a score of 300+). If the active player has no possible moves the game ends with tiebreaks: most completed towers, or most two-piece towers, or most one-piece towers.") (id "1964") (source "BGG") (version "1.3.12") (classification "board/space/territory") (author "Mathias Daval") (publisher "Argyx Games") (credit "Dale W. Walton") (date "2014") } ) (graphics { (player Colour P2 (colour DarkRed)) (player Colour P1 (colour Cream)) (piece Scale "Disc" scaleX:.85 scaleY:.85) (piece Scale "SquareOrtho" scaleX:.75 scaleY:.75) (piece Scale "SquareDiag" scaleX:.75 scaleY:.75) (piece Rotate "SquareDiag" degrees:45) (piece Scale "TriangleN" scaleX:.9 scaleY:.9) (piece Rotate "TriangleN" degrees:0) (piece Scale "TriangleE" scaleX:.9 scaleY:.9) (piece Rotate "TriangleE" degrees:90) (piece Scale "TriangleS" scaleX:.9 scaleY:.9) (piece Rotate "TriangleS" degrees:180) (piece Scale "TriangleW" scaleX:.9 scaleY:.9) (piece Rotate "TriangleW" degrees:270) (hand Placement P2 scale:.8 offsetX:0.95 offsetY:0.10 vertical:True) (hand Placement P1 scale:.8 offsetX:0.05 offsetY:0.10 vertical:True) } ) (ai (heuristics (score weight:1))) )