(define "NotFrozen" ("NoSites" (sites Around (from) Orthogonal if:(and ("IsEnemyAt" (to)) (> (value Piece at:(to)) (value Piece at:(from))) ) ) ) ) (define "Frozen" (not "NotFrozen")) (define "NotProtectedBy" ("NoSites" (sites Around #1 Orthogonal if:(= (who at:(to)) #2) ) ) ) (define "ProtectedBy" (not ("NotProtectedBy" (from) #1))) (define "NotMyLastMove" (< (count MovesThisTurn) 3)) (define "WillPushAPiece" (and { "NotMyLastMove" (not ("NoSites" (sites Around (to) Orthogonal if:(is Empty (to))))) // Not if the to location is orthogonally surrounded ("IsEnemyAt" (to)) // if on the to location, an enemy is there (< (value Piece at:(to)) (value Piece at:(from))) // Only if the from value is higher to the to value }) ) (define "PieceMove" (move Step #1 (to if:(and (or "NotFrozen" (and ("Frozen") ("ProtectedBy" Mover)) ) (or (is Empty (to)) "WillPushAPiece" ) ) (apply // We store the piece pushed to place it somewhere around in the next move. (fromTo (from (to)) (to (handSite Mover)) ) ) ) ) ) (define "AllPieceInATrapAreRemoved" (forEach Site (sites "Traps") (if (or (and (= (who at:(to)) P1) ("NotProtectedBy" (site) P1)) (and (= (who at:(to)) P2) ("NotProtectedBy" (site) P2)) ) (do (set Pending (value Piece at:(to))) next:(remove (to))) ) ) ) (define "HasToPushAPiece" (is Occupied (handSite Mover))) (define "PushThePiece" (move (from (handSite Mover)) (to (sites Around (last To) Orthogonal if:(and (!= (last From) (to)) (is Empty (to))))) // Any empty site around but not the previous position of the piece pushing. (then (and "AllPieceInATrapAreRemoved" (if "NotMyLastMove" (moveAgain) (remember State) ) ) ) ) ) (define "PullAPiece" (move (from (sites Around (last From) Orthogonal if:(and ("IsEnemyAt" (to)) // An enemy piece. (if (and (is In (last To) (sites "Traps")) (is Pending)) (< (value Piece at:(to)) (value Pending)) // With a lower value of mine. (< (value Piece at:(to)) (value Piece at:(last To))) // With a lower value of mine. ) ) ) ) (to (last From)) ) ) (define "FinishMyTurn" (move Pass (then (remember State)))) (define "RabbitReachedGoal" (if (!= 0 (count Sites in:(forEach (sites Occupied by:#1 component:"Rabbit") if:(is In (site) (sites #1 "Goal")) ) ) ) (result #1 #2) ) ) (define "NoRabbit" (if (and (not ("IsPieceAt" "Rabbit" #1 (handSite #2))) ("NoSites" (sites Occupied by:#1 component:"Rabbit")) ) (result #2 #3) ) ) //------------------------------------------------------------------------------ (game "Arimaa" ("TwoPlayersNorthSouth") (equipment { (board (square 8)) (hand Each size:6) (piece "Rabbit" Each ("PieceMove" (directions {Forward Rightward Leftward}))) (piece "Cat" Each ("PieceMove" Orthogonal)) (piece "Dog" Each ("PieceMove" Orthogonal)) (piece "Horse" Each ("PieceMove" Orthogonal)) (piece "Camel" Each ("PieceMove" Orthogonal)) (piece "Elephant" Each ("PieceMove" Orthogonal)) (regions "Traps" (sites {"C3" "C6" "F3" "F6"})) (regions "Home" P1 (expand (sites Bottom))) (regions "Home" P2 (expand (sites Top))) (regions "Goal" P1 (sites Top)) (regions "Goal" P2 (sites Bottom)) } ) (rules (start { (place "Rabbit" "Hand" count:8 value:1) (place "Cat" "Hand" count:2 value:2) (place "Dog" "Hand" count:2 value:3) (place "Horse" "Hand" count:2 value:4) (place "Camel" "Hand" count:1 value:5) (place "Elephant" "Hand" count:1 value:6) }) phases:{ (phase "PlacementP1" (play (move (from (sites Occupied by:Mover container:(mover))) // pieces in the hand of P1. (to (forEach (sites Mover "Home") if:(is Empty (site)))) (then (if ("HandOccupied" P1) (moveAgain))) ) ) (nextPhase ("HandEmpty" P1) "PlacementP2") ) (phase "PlacementP2" (play (move (from (sites Occupied by:Mover container:(mover))) // pieces in the hand of P2. (to (forEach (sites Mover "Home") if:(is Empty (site)))) (then (if ("HandEmpty" P2) (remember State) (moveAgain))) ) ) (nextPhase ("HandEmpty" P2) "Movement") ) (phase "Movement" (play (avoidStoredState (if "HasToPushAPiece" "PushThePiece" (or (or (if (and "SameTurn" (is In (last From) (sites Board)) ) "PullAPiece" ) (forEach Piece) (then (and "AllPieceInATrapAreRemoved" (if "NotMyLastMove" (moveAgain) (remember State) ) ) ) ) "FinishMyTurn" ) ) ) ) (end (if (not (is Next Mover)) { ("RabbitReachedGoal" P1 Win) ("RabbitReachedGoal" P2 Win) ("NoRabbit" P1 P2 Win) ("NoRabbit" P2 P1 Win) ("NoMoves" Loss) } ) ) ) } ) ) //------------------------------------------------------------------------------ (metadata (info { (description "Invented in 2003 by Omar Syed, Arimaa was invented as a Chess variant to be difficult for computers to learn, but easy for humans.") (rules "Played on an 8x8 board with \"trap\" squares at C6, F6, C3 and F3. Each player has 16 pieces, in order from strongest to weakest: Elephant (1) Camel (1) Horse (2) Dog (2) Cat(2) Rabbit (8) Each player places their pieces in any configuration on their side of the board. Pieces can move one space orthogonally, except rabbits cannot move backward. The goal is for one of a player's rabbits to reach the opposing player's edge of the board. Players can capture an opponent's pieces by pulling or pushing them into one of the trap squares as long as there is no piece friendly to the piece being pulled or pushed adjacent to the trap square. Pieces can only push and pull adjacent opponent's pieces of a lower rank than the piece making the move. Pushing and pulling cannot happen simultaneously. Pieces can be frozen, or prevented from moving, when they are adjacent to an opposing stronger piece.") (source "Wikipedia") (id "43") (version "1.3.12") (classification "board/race/reach") (author "Omar Syed and Aamir Syed") (credit "Eric Piette") (date "2003") } ) (graphics { (player Colour P1 (colour Gold)) (player Colour P2 (colour LightGrey)) (region Colour "Traps" Cell (colour "#644B32")) (board Colour InnerEdges (colour Black)) (board Colour OuterEdges (colour Black)) (board Colour Phase0 (colour LightGrey)) }) (ai "Arimaa_ai" ) )