(define "Inward" (> (max (count Sites in:(sites Direction from:(from) #1 ) ) (count Sites in:(sites Direction from:(from) #2 ) ) ) (max (count Sites in:(sites Direction from:(to) #1 ) ) (count Sites in:(sites Direction from:(to) #2 ) ) ) ) ) (define "Hop" (move Hop (from #1) Orthogonal (between if:(is Occupied (between)) (apply (remove (between))) ) (to if:(and { (is Empty (to)) (= 0 (count Sites in:(sites Around (to) Own Orthogonal))) }) ) (then (and { (remove (sites Outer)) (set Var 1) (if (can Move (move Hop (from (last To)) Orthogonal (between if:(is Occupied (between)) (apply (remove (between))) ) (to if:(and { (is Empty (to)) (= 0 (count Sites in:(sites Around (to) Own Orthogonal))) }) ) ) ) (moveAgain) (set Var 0) ) }) ) ) ) (define "Step" (move Step (from) (to if:(and { (is Empty (to)) (= 0 (count Sites in:(difference (sites Around (to) Own Orthogonal) (sites {(from)}) ) ) ) (not (and (< 0 (count Sites in:(sites Around (from) Enemy Orthogonal) ) ) (= 0 (count Sites in:(sites Around (to) Enemy Orthogonal) ) ) ) ) (or { (and (= 0 (count Sites in:(sites Around (from) Enemy Orthogonal) ) ) (< 0 (count Sites in:(sites Around (to) Enemy Orthogonal) ) ) ) (or { (and (or (= (from) (+ (to) )) (= (from) (- (to) )) ) ("Inward" N S) ) (and (or (= (from) (+ (to) 1)) (= (from) (- (to) 1)) ) ("Inward" E W) ) (and (or (= (from) (+ (to) (+ 1))) (= (from) (- (to) (+ 1))) ) ("Inward" SW NE) ) (and (or (= (from) (+ (to) (- 1))) (= (from) (- (to) (- 1))) ) ("Inward" SE NW) ) }) }) }) ) ) ) //------------------------------------------------------------------------------ (game "Cage" (players 2) (equipment { (board (square )) (piece "Disc" Each) }) (rules (start { (place "Disc1" (difference (sites Phase 0) (sites Outer) ) ) (place "Disc2" (difference (sites Phase 1) (sites Outer) ) ) }) (play (forEach Piece (if (!= 1 (var)) (or ("Hop" ~) ("Step") ) ("Hop" if:(= (from) (last To))) ) ) ) (end (if (or (= 0 (count Sites in:(sites Occupied by:P1)) ) (= 0 (count Sites in:(sites Occupied by:P2)) ) ) (result Mover Win) ) ) ) ) //------------------------------------------------------------------------------ (option "Board Size" args:{ } { (item "10" <12> "A 10x10 board is currently selected")* (item "8" <10> "A 8x8 board is currently selected") (item "6" <8> "A 6x6 board is currently selected") } ) //------------------------------------------------------------------------------ (metadata (info { (description "Cages is a drawless checkers variant that always ends in one player eliminating the other. Mark Steere designed Cage in 2010.") (rules "Cage is a checkers variant for two players played on a square 10x10 board. In this implementation you also have the option of playing on smaller boards. In the initial position, 50 checkers of one color and 50 checkers of a different color fill up the board in a checkered pattern. The goal of the game is to capture all your opponent's checkers. On your turn, if you can, you must choose one of two different kinds of moves to perform: • a single step, or • a sequence of jumps. Note: A single jump is considered a jump sequence of length 1. Universal restriction: All moves are subject to the following restriction: • At no time may a checker be orthogonally adjacent to a checker of the same color. Stepping: Stepping is moving one of your checkers to an orthogonally or diagonally adjacent empty square, and this kind of move is subject to the following two additional restrictions: • A step my never bring the number of orthogonal enemy neighbors of the moved checker down to 0. • The only condition under which a step may fail to bring the moved checker closer to the center of the line you are moving along is if it brings its number of orthogonal enemy neighbors up from 0. (Some elaboration on this last restriction: In general, a step must decrease the moved checker's straight line distance to the board's central intersection. That's the same as bringing it closer to the center of the orthogonal or diagonal line you are moving along. (Note: The center of a diagonal line is an intersection if it is an even number of squares long, and a square otherwise. The center of an orthogonal line is an edge if it is an even number of squares long, and a square otherwise.) Here is a different way of putting it: Whatever diagonal or orthogonal line you are stepping along, the largest distance to an edge square on this line before the step must be bigger than the largest distance to an edge square on the same line after the step. The only exception to this rule, as explained in the last restriction, is if your checker has no orthogonal neighbors and can step into such a relationship – then you may step in any direction.) Jumping sequences: If a checker of your color is orthogonally adjacent to an enemy checker, and immediately on the opposite side of that enemy checker is either an empty square or the outside of the board, your checker may initiate a sequence of jumps. You do this by jumping your checker over to the opposite side of the enemy checker and immediately removing the jumped piece. If your checker lands outside the board, it too is removed from the board. Note: If your last checker is removed when you capture your opponent's last checker, you still win. If the jumping checker lands in a position where it can jump again, your turn does not end, and the checker must make yet a jump. If there are several ways to continue the sequence, you may choose freely between these. The sequence of jumps only ends when the checker lands on a square where it can make no further jump.") (id "1270") (source "www.marksteeregames.com/") (version "1.3.12") (classification "board/war/leaping/orthogonal") (author "Mark Steere") (publisher "Mark Steere Games (used with permission)") (credit "Designed by Mark Steere and implemented by Michael Amundsen.") (date "2010") } ) (graphics { (player Colour P1 (colour Red)) (player Colour P2 (colour Blue)) (region Colour (sites Outer) (colour 0 0 0 0)) (board Colour InnerEdges (colour 0 0 0 0)) (board Colour OuterEdges (colour 0 0 0 0)) (board Style Chess) (no Sunken) }) (ai "Cage_ai" ) )