You are not logged in. login register
Game chessFiftyMove
name chessFiftyMove
creator TheCat
number of roles 2
stylesheet generic/generic.xsl
GDL v1
enabled
matches show matches
statistics show game statistics
description Chess with the fifty-move rule

Game Description

; Chess (with fifty-move rule)

; Initial version (with 200-step time limit) by Alex Landau 
; Modified by Jakub Kowalski
; Instead of steplimit and two kings endconditions, there is the fifty-move rule, that is, the game ends in a draw after 50 moves by a non-pawn and without capture.
; 
; This version incorporates all rules of chess, including check, pawn
; promotion, castling, and en passant.

(role white)
(role black)

; Bases and inputs

(<= (base (control ?player))
    (role ?player))
(base (fiftymove 1))
(<= (base (fiftymove ?np1))
    (succ ?n ?np1))

(<= (base (cell ?x ?y ?player ?piece))
    (file ?x)
    (rank ?y)
    (role ?player)
    (pieceType ?piece))
(pieceType king)
(pieceType queen)
(pieceType rook)
(pieceType bishop)
(pieceType knight)
(<= (base (cell ?x ?y ?player pawn))
    (file ?x)
    (rank ?y)
    (distinct ?y 1)
    (distinct ?y 8)
    (role ?player))

(<= (base (canEnPassantCapture ?x))
    (file ?x))
(<= (base (kingHasMoved ?player))
    (role ?player))
(<= (base (aRookHasMoved ?player))
    (role ?player))
(<= (base (hRookHasMoved ?player))
    (role ?player))
    
(<= (input ?player noop)
    (role ?player))
(<= (input ?player castleKingside)
    (role ?player))
(<= (input ?player castleQueenside)
    (role ?player))
(<= (input ?player (move king ?x1 ?y1 ?x2 ?y2))
    (role ?player)
    (kingMove ?x1 ?y1 ?x2 ?y2))
(<= (input ?player (move knight ?x1 ?y1 ?x2 ?y2))
    (role ?player)
    (knightMove ?x1 ?y1 ?x2 ?y2))
(<= (input ?player (move bishop ?x1 ?y1 ?x2 ?y2))
    (role ?player)
    (diagonal ?dir)
    (alongDirection ?x1 ?y1 ?x2 ?y2 ?dir))
(<= (input ?player (move rook ?x1 ?y1 ?x2 ?y2))
    (role ?player)
    (straight ?dir)
    (alongDirection ?x1 ?y1 ?x2 ?y2 ?dir))
(<= (input ?player (move queen ?x1 ?y1 ?x2 ?y2))
    (role ?player)
    (dir ?dir)
    (alongDirection ?x1 ?y1 ?x2 ?y2 ?dir))
(<= (alongDirection ?x1 ?y1 ?x2 ?y2 ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir))
(<= (alongDirection ?x1 ?y1 ?x3 ?y3 ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (alongDirection ?x2 ?y2 ?x3 ?y3 ?dir))

; Pawn move type 1: Normal advancement (not to last rank)
(<= (input white (move pawn ?x ?y1 ?x ?y2))
    (oneInDir ?x ?y1 ?x ?y2 n)
    (distinct ?y2 8))
(<= (input black (move pawn ?x ?y1 ?x ?y2))
    (oneInDir ?x ?y1 ?x ?y2 s)
    (distinct ?y2 1))
; Pawn move type 2: Advance and promote
(<= (input white (move ?promotedType ?x 7 ?x 8))
    (file ?x)
    (promotableType ?promotedType))
(<= (input black (move ?promotedType ?x 2 ?x 1))
    (file ?x)
    (promotableType ?promotedType))
; Pawn move type 3: Capture (not to last rank)
(<= (input white (move pawn ?x1 ?y1 ?x2 ?y2))
    (or (oneInDir ?x1 ?y1 ?x2 ?y2 nw)
        (oneInDir ?x1 ?y1 ?x2 ?y2 ne))
    (distinct ?y2 8))
(<= (input black (move pawn ?x1 ?y1 ?x2 ?y2))
    (or (oneInDir ?x1 ?y1 ?x2 ?y2 sw)
        (oneInDir ?x1 ?y1 ?x2 ?y2 se))
    (distinct ?y2 1))
; Pawn move type 4: Capture and promote
(<= (input white (move ?promotedType ?x1 7 ?x2 8))
    (or (nextFile ?x1 ?x2)
        (nextFile ?x2 ?x1))
    (promotableType ?promotedType))
(<= (input black (move ?promotedType ?x1 2 ?x2 1))
    (or (nextFile ?x1 ?x2)
        (nextFile ?x2 ?x1))
    (promotableType ?promotedType))
; Pawn move type 5: Advance two from initial position
(<= (input white (move pawn ?x 2 ?x 4))
    (file ?x))
(<= (input black (move pawn ?x 7 ?x 5))
    (file ?x))


; Initial state

(init (control white))

(init (cell a 1 white rook))
(init (cell b 1 white knight))
(init (cell c 1 white bishop))
(init (cell d 1 white queen))
(init (cell e 1 white king))
(init (cell f 1 white bishop))
(init (cell g 1 white knight))
(init (cell h 1 white rook))
(init (cell a 2 white pawn))
(init (cell b 2 white pawn))
(init (cell c 2 white pawn))
(init (cell d 2 white pawn))
(init (cell e 2 white pawn))
(init (cell f 2 white pawn))
(init (cell g 2 white pawn))
(init (cell h 2 white pawn))
(init (cell a 7 black pawn))
(init (cell b 7 black pawn))
(init (cell c 7 black pawn))
(init (cell d 7 black pawn))
(init (cell e 7 black pawn))
(init (cell f 7 black pawn))
(init (cell g 7 black pawn))
(init (cell h 7 black pawn))
(init (cell a 8 black rook))
(init (cell b 8 black knight))
(init (cell c 8 black bishop))
(init (cell d 8 black queen))
(init (cell e 8 black king))
(init (cell f 8 black bishop))
(init (cell g 8 black knight))
(init (cell h 8 black rook))
(init (fiftymove 1))

; Which moves are legal?

(<= (legal ?player noop)
    (role ?player)
    (not (true (control ?player))))

(<= (legal ?player ?move)
    (true (control ?player))
    (legalMove ?player ?move))

(<= (legalMove ?player ?move)
    (legalIgnoringCheck ?player ?move)
    (not (inCheck ?player)))

; When in check:
; - King moves along the line of check aren't legal, unless it's capturing the checking piece
; - Otherwise, king moves to non-threatened spaces are fine
; - Other pieces may only move if 1) there is only one source of check and 2) the move either
;   captures that piece or interposes the check (pins are already taken care of)
; - Castling is illegal
(<= (legalMove ?player (move king ?x1 ?y1 ?x2 ?y2))
    (inCheck ?player)
    (legalIgnoringCheck ?player (move king ?x1 ?y1 ?x2 ?y2))
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (not (alongLineOfCheck ?dir)))
(<= (legalMove ?player (move king ?x1 ?y1 ?x2 ?y2))
    (inCheck ?player)
    (legalIgnoringCheck ?player (move king ?x1 ?y1 ?x2 ?y2))
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (oppDir ?dir ?checkDir)
    (checkSource ?x2 ?y2 ?checkDir))
    ;TODO: What if the king is checked from opposite directions at once?
    ; Pretty sure that's impossible, though (in normal chess)
(<= (legalMove ?player (move ?piece ?x1 ?y1 ?x2 ?y2))
    (inCheck ?player)
    (legalIgnoringCheck ?player (move ?piece ?x1 ?y1 ?x2 ?y2))
    (distinct ?piece king)
    (not multipleCheckSources)
    (checkSource ?x2 ?y2 ?dir)) ;i.e. move is a capture of the checker
(<= (legalMove ?player (move ?piece ?x1 ?y1 ?x2 ?y2))
    (inCheck ?player)
    (legalIgnoringCheck ?player (move ?piece ?x1 ?y1 ?x2 ?y2))
    (distinct ?piece king)
    (not multipleCheckSources)
    (checkSource ?x3 ?y3 ?dir)
    (true (cell ?x4 ?y4 ?player king))
    (dir ?dir)
    ;interposition... between the checker and king?
    (isAlongDir ?x3 ?y3 ?x2 ?y2 ?dir)
    (isAlongDir ?x2 ?y2 ?x4 ?y4 ?dir))

(<= (alongLineOfCheck ?dir)
    (sameOrOppDir ?dir ?checkDir)
    (checkSource ?x1 ?y1 ?checkDir))

(<= multipleCheckSources
    (checkSource ?x1 ?y1 ?dir1)
    (checkSource ?x2 ?y2 ?dir2)
    (or (distinct ?x1 ?x2)
        (distinct ?y1 ?y2)))

(<= (legalIgnoringCheck ?player (move king ?x1 ?y1 ?x2 ?y2))
    (true (cell ?x1 ?y1 ?player king))
    (kingMove ?x1 ?y1 ?x2 ?y2)
    (not (playerInCell ?player ?x2 ?y2))
    (not (threatenedByOpp ?player ?x2 ?y2)))
(<= (kingMove ?x1 ?y1 ?x2 ?y2)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?anyDir))

(<= (threatenedByOpp ?player ?x ?y)
    (opponent ?player ?opponent)
    (threatens ?opponent ?x ?y))

; Simple cases: knights, pawns, kings
; Don't have to deal with causing pins
(<= (threatens ?owner ?x2 ?y2)
    (true (cell ?x1 ?y1 ?owner knight))
    (knightMove ?x1 ?y1 ?x2 ?y2))
(<= (threatens white ?x2 ?y2)
    (nwOrNe ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (true (cell ?x1 ?y1 white pawn)))
(<= (threatens black ?x2 ?y2)
    (swOrSe ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (true (cell ?x1 ?y1 black pawn)))
(<= (threatens ?owner ?x2 ?y2)
    (true (cell ?x1 ?y1 ?owner king))
    (kingMove ?x1 ?y1 ?x2 ?y2))
(<= (threatens ?owner ?x2 ?y2)
    (threatensLine ?owner ?x2 ?y2 ?dir))

(<= (checkSource ?x ?y ?dir)
    (true (cell ?x ?y ?owner bishop))
    (opponent ?owner ?opponent)
    (true (cell ?xk ?yk ?opponent king))
    (diagonal ?dir)
    (openBetween ?x ?y ?xk ?yk ?dir))
(<= (checkSource ?x ?y ?dir)
    (true (cell ?x ?y ?owner rook))
    (opponent ?owner ?opponent)
    (true (cell ?xk ?yk ?opponent king))
    (straight ?dir)
    (openBetween ?x ?y ?xk ?yk ?dir))
(<= (checkSource ?x ?y ?dir)
    (true (cell ?x ?y ?owner queen))
    (opponent ?owner ?opponent)
    (true (cell ?xk ?yk ?opponent king))
    (dir ?dir)
    (openBetween ?x ?y ?xk ?yk ?dir))
(<= (checkSource ?x ?y knight)
    (true (cell ?x ?y ?owner knight))
    (opponent ?owner ?opponent)
    (true (cell ?xk ?yk ?opponent king))
    (knightMove ?x ?y ?xk ?yk))
(<= (checkSource ?x ?y pawn)
    (true (cell ?xk ?yk black king))
    (nwOrNe ?dir)
    (oneInDir ?x ?y ?xk ?yk ?dir)
    (true (cell ?x ?y white pawn)))
(<= (checkSource ?x ?y pawn)
    (true (cell ?xk ?yk white king))
    (swOrSe ?dir)
    (oneInDir ?x ?y ?xk ?yk ?dir)
    (true (cell ?x ?y black pawn)))

; And openBetween works well here... though we should also do something for pins
; TODO: Make legalIgnoringCheck depend on this?
(<= (threatensLine ?owner ?x2 ?y2 ?dir)
    (true (cell ?x1 ?y1 ?owner bishop))
    (diagonal ?dir)
    (openBetween ?x1 ?y1 ?x2 ?y2 ?dir))
(<= (threatensLine ?owner ?x2 ?y2 ?dir)
    (true (cell ?x1 ?y1 ?owner rook))
    (straight ?dir)
    (openBetween ?x1 ?y1 ?x2 ?y2 ?dir))
(<= (threatensLine ?owner ?x2 ?y2 ?dir)
    (true (cell ?x1 ?y1 ?owner queen))
    (dir ?dir)
    (openBetween ?x1 ?y1 ?x2 ?y2 ?dir))

(<= (guardingKing ?player ?x2 ?y2 ?oppDir)
    (true (cell ?x1 ?y1 ?player king))
    (openBetween ?x1 ?y1 ?x2 ?y2 ?dir)
    (true (cell ?x1 ?y1 ?player ?anyPiece))
    (oppDir ?dir ?oppDir))

(<= (pinned ?player ?x ?y)
    (pinnedInDir ?player ?x ?y ?dir))
(<= (pinnedInDir ?player ?x ?y ?dir)
    (guardingKing ?player ?x ?y ?dir)
    (opponent ?player ?opponent)
    (threatensLine ?opponent ?x ?y ?dir))
; True if not pinned
; True if pinned only in dir
; False if pinned in any other dir
; Luckily pins can only happen in one direction at a time...
(<= (notPinnedUnlessInDir ?player ?x ?y ?dir)
    (role ?player)
    (file ?x)
    (rank ?y)
    (dir ?dir)
    (not (pinned ?player ?x ?y)))
(<= (notPinnedUnlessInDir ?player ?x ?y ?dir)
    (pinnedInDir ?player ?x ?y ?pinDir)
    (sameOrOppDir ?dir ?pinDir))

(<= (legalIgnoringCheck ?player (move knight ?x1 ?y1 ?x2 ?y2))
    (true (cell ?x1 ?y1 ?player knight))
    (knightMove ?x1 ?y1 ?x2 ?y2)
    (not (playerInCell ?player ?x2 ?y2))
    (not (pinned ?player ?x1 ?y1)))
(<= (knightMove ?x1 ?y1 ?x2 ?y3)
    (nextFile ?x1 ?x2)
    (nextRank ?y1 ?y2)
    (nextRank ?y2 ?y3))
(<= (knightMove ?x2 ?y1 ?x1 ?y3)
    (nextFile ?x1 ?x2)
    (nextRank ?y1 ?y2)
    (nextRank ?y2 ?y3))
(<= (knightMove ?x1 ?y3 ?x2 ?y1)
    (nextFile ?x1 ?x2)
    (nextRank ?y2 ?y3)
    (nextRank ?y1 ?y2))
(<= (knightMove ?x2 ?y3 ?x1 ?y1)
    (nextFile ?x1 ?x2)
    (nextRank ?y2 ?y3)
    (nextRank ?y1 ?y2))
(<= (knightMove ?x1 ?y1 ?x3 ?y2)
    (nextFile ?x1 ?x2)
    (nextFile ?x2 ?x3)
    (nextRank ?y1 ?y2))
(<= (knightMove ?x1 ?y2 ?x3 ?y1)
    (nextFile ?x1 ?x2)
    (nextFile ?x2 ?x3)
    (nextRank ?y1 ?y2))
(<= (knightMove ?x3 ?y1 ?x1 ?y2)
    (nextFile ?x2 ?x3)
    (nextFile ?x1 ?x2)
    (nextRank ?y1 ?y2))
(<= (knightMove ?x3 ?y2 ?x1 ?y1)
    (nextFile ?x2 ?x3)
    (nextFile ?x1 ?x2)
    (nextRank ?y1 ?y2))

; Bishops, rooks, queens...
(<= (legalIgnoringCheck ?player (move bishop ?x1 ?y1 ?x2 ?y2))
    (true (cell ?x1 ?y1 ?player bishop))
    (diagonal ?dir)
    (openBetween ?x1 ?y1 ?x2 ?y2 ?dir)
    (not (playerInCell ?player ?x2 ?y2))
    (notPinnedUnlessInDir ?player ?x1 ?y1 ?dir))
(<= (legalIgnoringCheck ?player (move rook ?x1 ?y1 ?x2 ?y2))
    (true (cell ?x1 ?y1 ?player rook))
    (straight ?dir)
    (openBetween ?x1 ?y1 ?x2 ?y2 ?dir)
    (not (playerInCell ?player ?x2 ?y2))
    (notPinnedUnlessInDir ?player ?x1 ?y1 ?dir))
(<= (legalIgnoringCheck ?player (move queen ?x1 ?y1 ?x2 ?y2))
    (true (cell ?x1 ?y1 ?player queen))
    (dir ?dir)
    (openBetween ?x1 ?y1 ?x2 ?y2 ?dir)
    (not (playerInCell ?player ?x2 ?y2))
    (notPinnedUnlessInDir ?player ?x1 ?y1 ?dir))

; (openStretch ?x1 ?y1 ?x2 ?y2 ?dir) indicates that the spaces between 1 and 2 are
; empty, including 1 and 2, and that 2 is in direction ?dir from 1. openBetween
; is similar, except that the spaces 1 and 2 themselves may be occupied. 
(<= (openStretch ?x ?y ?x ?y ?dir)
    (file ?x)
    (rank ?y)
    (not (occupied ?x ?y))
    (dir ?dir))
(<= (openStretch ?x1 ?y1 ?x3 ?y3 ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (not (occupied ?x1 ?y1))
    (openStretch ?x2 ?y2 ?x3 ?y3 ?dir))
(<= (openBetween ?x1 ?y1 ?x2 ?y2 ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir))
(<= (openBetween ?x1 ?y1 ?x4 ?y4 ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (openStretch ?x2 ?y2 ?x3 ?y3 ?dir)
    (oneInDir ?x3 ?y3 ?x4 ?y4 ?dir))

; Constant; goes from x1, y1 to x2, y2 in direction
(<= (isAlongDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir))
(<= (isAlongDir ?x1 ?y1 ?x3 ?y3 ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (isAlongDir ?x2 ?y2 ?x3 ?y3 ?dir))

(<= (occupied ?x ?y)
    (true (cell ?x ?y ?player ?piece)))

; Then pawns
; Pawn move type 1: Normal advancement (not to last rank)
(<= (legalIgnoringCheck white (move pawn ?x ?y1 ?x ?y2))
    (true (cell ?x ?y1 white pawn))
    (oneInDir ?x ?y1 ?x ?y2 n)
    (distinct ?y2 8)
    (not (occupied ?x ?y2))
    (notPinnedUnlessInDir white ?x ?y1 n))
(<= (legalIgnoringCheck black (move pawn ?x ?y1 ?x ?y2))
    (true (cell ?x ?y1 black pawn))
    (oneInDir ?x ?y1 ?x ?y2 s)
    (distinct ?y2 1)
    (not (occupied ?x ?y2))
    (notPinnedUnlessInDir black ?x ?y1 s))
; Pawn move type 2: Advance and promote
(<= (legalIgnoringCheck white (move ?promotedType ?x 7 ?x 8))
    (true (cell ?x 7 white pawn))
    (not (occupied ?x 8))
    (promotableType ?promotedType)
    (notPinnedUnlessInDir white ?x 7 n))
(<= (legalIgnoringCheck black (move ?promotedType ?x 2 ?x 1))
    (true (cell ?x 2 black pawn))
    (not (occupied ?x 1))
    (promotableType ?promotedType)
    (notPinnedUnlessInDir black ?x 2 s))
; Pawn move type 3: Capture (not to last rank)
(nwOrNe nw)
(nwOrNe ne)
(<= (legalIgnoringCheck white (move pawn ?x1 ?y1 ?x2 ?y2))
    (true (cell ?x1 ?y1 white pawn))
    (nwOrNe ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (distinct ?y2 8)
    (playerInCell black ?x2 ?y2)
    (notPinnedUnlessInDir white ?x1 ?y1 ?dir))
(swOrSe sw)
(swOrSe se)
(<= (legalIgnoringCheck black (move pawn ?x1 ?y1 ?x2 ?y2))
    (true (cell ?x1 ?y1 black pawn))
    (swOrSe ?dir)
    (oneInDir ?x1 ?y1 ?x2 ?y2 ?dir)
    (distinct ?y2 1)
    (playerInCell white ?x2 ?y2)
    (notPinnedUnlessInDir black ?x1 ?y1 ?dir))
; Pawn move type 4: Capture and promote
(<= (legalIgnoringCheck white (move ?promotedType ?x1 7 ?x2 8))
    (true (cell ?x1 7 white pawn))
    (nwOrNe ?dir)
    (oneInDir ?x1 7 ?x2 8 ?dir)
    (playerInCell black ?x2 8)
    (notPinnedUnlessInDir white ?x1 7 ?dir)
    (promotableType ?promotedType))
(<= (legalIgnoringCheck black (move ?promotedType ?x1 2 ?x2 1))
    (true (cell ?x1 2 black pawn))
    (swOrSe ?dir)
    (oneInDir ?x1 2 ?x2 1 ?dir)
    (playerInCell white ?x2 1)
    (notPinnedUnlessInDir black ?x1 2 ?dir)
    (promotableType ?promotedType))
; Pawn move type 5: Advance two from initial position
(<= (legalIgnoringCheck white (move pawn ?x 2 ?x 4))
    (true (cell ?x 2 white pawn))
    (not (occupied ?x 3))
    (not (occupied ?x 4))
    (notPinnedUnlessInDir white ?x 2 n))
(<= (legalIgnoringCheck black (move pawn ?x 7 ?x 5))
    (true (cell ?x 7 black pawn))
    (not (occupied ?x 6))
    (not (occupied ?x 5))
    (notPinnedUnlessInDir black ?x 7 s))
; Pawn move type 6: En passant capture
(<= (legalIgnoringCheck white (move pawn ?x1 5 ?x2 6))
    (true (cell ?x1 5 white pawn))
    (nwOrNe ?dir)
    (oneInDir ?x1 5 ?x2 6 ?dir)
    (true (canEnPassantCapture ?x2))
    (notPinnedUnlessInDir white ?x1 5 ?dir))
(<= (legalIgnoringCheck black (move pawn ?x1 4 ?x2 3))
    (true (cell ?x1 4 black pawn))
    (swOrSe ?dir)
    (oneInDir ?x1 4 ?x2 3 ?dir)
    (true (canEnPassantCapture ?x2))
    (notPinnedUnlessInDir black ?x1 4 ?dir))

; Castling

(<= (legalIgnoringCheck white castleKingside)
    (true (cell e 1 white king))
    (not (true (kingHasMoved white)))
    (true (cell h 1 white rook))
    (not (true (hRookHasMoved white)))
    (not (occupied f 1))
    (not (occupied g 1))
    (not (threatenedByOpp white e 1))
    (not (threatenedByOpp white f 1))
    (not (threatenedByOpp white g 1)))
(<= (legalIgnoringCheck black castleKingside)
    (true (cell e 8 black king))
    (not (true (kingHasMoved black)))
    (true (cell h 8 black rook))
    (not (true (hRookHasMoved black)))
    (not (occupied f 8))
    (not (occupied g 8))
    (not (threatenedByOpp black e 8))
    (not (threatenedByOpp black f 8))
    (not (threatenedByOpp black g 8)))
(<= (legalIgnoringCheck white castleQueenside)
    (true (cell e 1 white king))
    (not (true (kingHasMoved white)))
    (true (cell a 1 white rook))
    (not (true (aRookHasMoved white)))
    (not (occupied b 1))
    (not (occupied c 1))
    (not (occupied d 1))
    (not (threatenedByOpp white c 1))
    (not (threatenedByOpp white d 1))
    (not (threatenedByOpp white e 1)))
(<= (legalIgnoringCheck black castleQueenside)
    (true (cell e 8 black king))
    (not (true (kingHasMoved black)))
    (true (cell a 8 black rook))
    (not (true (aRookHasMoved black)))
    (not (occupied b 8))
    (not (occupied c 8))
    (not (occupied d 8))
    (not (threatenedByOpp black c 8))
    (not (threatenedByOpp black d 8))
    (not (threatenedByOpp black e 8)))

(<= (playerInCell ?player ?x ?y)
    (true (cell ?x ?y ?player ?piece)))

; Next state logic

(<= (next (control ?opponent))
    (true (control ?player))
    (opponent ?player ?opponent))

; Cells: Pieces stay where they are unless they're affected by the given move.
; Castling and en passant have special rules for what's affected.

(<= (next (cell ?x ?y ?player ?piece))
    (true (cell ?x ?y ?player ?piece))
    (not (affected ?x ?y)))
(<= (affected ?x1 ?y1)
    (does ?player (move ?piece ?x1 ?y1 ?x2 ?y2)))
(<= (affected ?x2 ?y2)
    (does ?player (move ?piece ?x1 ?y1 ?x2 ?y2)))
(<= (affected e 1)
    (does white castleKingside))
(<= (affected h 1)
    (does white castleKingside))
(<= (affected e 1)
    (does white castleQueenside))
(<= (affected a 1)
    (does white castleQueenside))
(<= (affected e 8)
    (does black castleKingside))
(<= (affected h 8)
    (does black castleKingside))
(<= (affected e 8)
    (does black castleQueenside))
(<= (affected a 8)
    (does black castleQueenside))
; En passant captures cause the instigating pawn to be captured.
(<= (affected ?x2 5)
    (does white (move pawn ?x1 5 ?x2 6))
    (true (canEnPassantCapture ?x2)))
(<= (affected ?x2 4)
    (does black (move pawn ?x1 4 ?x2 3))
    (true (canEnPassantCapture ?x2)))
; Moves cause the listed piece to end up in the later position.
; In the case of promoted pawns, the move will list the promoted type.
(<= (next (cell ?x2 ?y2 ?player ?piece))
    (does ?player (move ?piece ?x1 ?y1 ?x2 ?y2)))
(<= (next (cell g 1 white king))
    (does white castleKingside))
(<= (next (cell f 1 white rook))
    (does white castleKingside))
(<= (next (cell c 1 white king))
    (does white castleQueenside))
(<= (next (cell d 1 white rook))
    (does white castleQueenside))
(<= (next (cell g 8 black king))
    (does black castleKingside))
(<= (next (cell f 8 black rook))
    (does black castleKingside))
(<= (next (cell c 8 black king))
    (does black castleQueenside))
(<= (next (cell d 8 black rook))
    (does black castleQueenside))

(<= fiftymovereset
    (does ?player (move ?piece ?x1 ?y1 ?x2 ?y2))
    (occupied ?x2 ?y2))
(<= fiftymovereset
    (does ?player (move ?piece ?x1 ?y1 ?x2 ?y2))
    (true (cell ?x1 ?y1 ?player pawn)))
(<= (next (fiftymove 1)) 
    fiftymovereset)
(<= (next (fiftymove ?np1))
    (not fiftymovereset)
    (true (fiftymove ?n))
    (succ ?n ?np1))

(<= (next (canEnPassantCapture ?x))
    (does white (move pawn ?x 2 ?x 4)))
(<= (next (canEnPassantCapture ?x))
    (does black (move pawn ?x 7 ?x 5)))

(<= (next (kingHasMoved ?player))
    (true (kingHasMoved ?player)))
(<= (next (kingHasMoved ?player))
    (does ?player (move king e ?y1 ?x2 ?y2)))
(<= (next (aRookHasMoved ?player))
    (true (aRookHasMoved ?player)))
(<= (next (aRookHasMoved white))
    (does white (move rook a 1 ?x2 ?y2)))
(<= (next (aRookHasMoved black))
    (does black (move rook a 8 ?x2 ?y2)))
(<= (next (hRookHasMoved ?player))
    (true (hRookHasMoved ?player)))
(<= (next (hRookHasMoved white))
    (does white (move rook h 1 ?x2 ?y2)))
(<= (next (hRookHasMoved black))
    (does black (move rook h 8 ?x2 ?y2)))

; Terminality and goal values
(<= terminal
    (true (fiftymove 51)))
(<= terminal
    (stuck ?player))
(<= (stuck ?player)
    (true (control ?player))
    (not (hasAnyLegalMove ?player)))
(<= (hasAnyLegalMove ?player)
    (legalMove ?player ?move))

; 100/0 for checkmate, 50/50 for stalemate or draw
(<= (goal ?eachPlayer 50)
    (not anyoneInCheck)
    (role ?eachPlayer))
(<= (goal ?eachPlayer 50)
    (not anyoneStuck)
    (role ?eachPlayer))
(<= (goal ?player 0)
    (stuck ?player)
    (inCheck ?player))
(<= (goal ?opponent 100)
    (stuck ?player)
    (inCheck ?player)
    (opponent ?player ?opponent))

(<= anyoneStuck
    (stuck ?player))

(<= anyoneInCheck
    (inCheck ?player))
(<= (inCheck ?player)
    (true (cell ?x ?y ?player king))
    (threatenedByOpp ?player ?x ?y))

; Constants

(opponent white black)
(opponent black white)

(file a)
(file b)
(file c)
(file d)
(file e)
(file f)
(file g)
(file h)
(nextFile a b)
(nextFile b c)
(nextFile c d)
(nextFile d e)
(nextFile e f)
(nextFile f g)
(nextFile g h)
(rank 1)
(rank 2)
(rank 3)
(rank 4)
(rank 5)
(rank 6)
(rank 7)
(rank 8)
(nextRank 1 2)
(nextRank 2 3)
(nextRank 3 4)
(nextRank 4 5)
(nextRank 5 6)
(nextRank 6 7)
(nextRank 7 8)


(dir n)
(dir s)
(dir e)
(dir w)
(dir nw)
(dir ne)
(dir se)
(dir sw)
(straight n)
(straight s)
(straight e)
(straight w)
(diagonal nw)
(diagonal ne)
(diagonal se)
(diagonal sw)
(oppDir n s)
(oppDir s n)
(oppDir e w)
(oppDir w e)
(oppDir nw se)
(oppDir ne sw)
(oppDir se nw)
(oppDir sw ne)
(<= (sameOrOppDir ?dir ?dir)
    (dir ?dir))
(<= (sameOrOppDir ?dir1 ?dir2)
    (oppDir ?dir1 ?dir2))

(<= (oneInDir ?x ?y1 ?x ?y2 n)
    (file ?x)
    (nextRank ?y1 ?y2))
(<= (oneInDir ?x1 ?y1 ?x2 ?y2 ne)
    (nextFile ?x1 ?x2)
    (nextRank ?y1 ?y2))
(<= (oneInDir ?x1 ?y ?x2 ?y e)
    (nextFile ?x1 ?x2)
    (rank ?y))
(<= (oneInDir ?x1 ?y2 ?x2 ?y1 se)
    (nextFile ?x1 ?x2)
    (nextRank ?y1 ?y2))
(<= (oneInDir ?x ?y2 ?x ?y1 s)
    (file ?x)
    (nextRank ?y1 ?y2))
(<= (oneInDir ?x2 ?y2 ?x1 ?y1 sw)
    (nextFile ?x1 ?x2)
    (nextRank ?y1 ?y2))
(<= (oneInDir ?x2 ?y ?x1 ?y w)
    (nextFile ?x1 ?x2)
    (rank ?y))
(<= (oneInDir ?x2 ?y1 ?x1 ?y2 nw)
    (nextFile ?x1 ?x2)
    (nextRank ?y1 ?y2))
    
(promotableType queen)
(promotableType knight)
(promotableType rook)
(promotableType bishop)

; Successor function for the step counter
(succ 1 2)
(succ 2 3)
(succ 3 4)
(succ 4 5)
(succ 5 6)
(succ 6 7)
(succ 7 8)
(succ 8 9)
(succ 9 10)
(succ 10 11)
(succ 11 12)
(succ 12 13)
(succ 13 14)
(succ 14 15)
(succ 15 16)
(succ 16 17)
(succ 17 18)
(succ 18 19)
(succ 19 20)
(succ 20 21)
(succ 21 22)
(succ 22 23)
(succ 23 24)
(succ 24 25)
(succ 25 26)
(succ 26 27)
(succ 27 28)
(succ 28 29)
(succ 29 30)
(succ 30 31)
(succ 31 32)
(succ 32 33)
(succ 33 34)
(succ 34 35)
(succ 35 36)
(succ 36 37)
(succ 37 38)
(succ 38 39)
(succ 39 40)
(succ 40 41)
(succ 41 42)
(succ 42 43)
(succ 43 44)
(succ 44 45)
(succ 45 46)
(succ 46 47)
(succ 47 48)
(succ 48 49)
(succ 49 50)
(succ 50 51)

sees_XML(...) rules

(<= (sees_xml random ?t) (true ?t))
(<= (sees_xml ?p ?t) (role ?p) (distinct ?p random) (true ?t))