include chess; // Same input restrictions as Chess except for allowing drops allow drops 1; // May be changed for games with different Pawn drop rules than Chessgi set pawndropfunc lambda (#0 onlyif onboard where #0 0 var forward); // This is a modification to the regular checks routine for Chessgi. The main // change is that it does not check for revealed checks from drop moves. sub checks king; if not dest: return false; endif; my checks c; set checks (); if fn space dest dest #king: setelem checks dest space dest; endif; if isalnum origin: set c sub checkedthru #king origin; if #c: setelem checks #c space #c; elseif #epc: set c sub checkedthru #king #epc; if #c: setelem checks #c space #c; endif; endif; endif; return var checks; endsub; // This is a modification to the regular checkmated routine for Chessgi. The main change // is that it will check whether a check can be blocked by a piece drop before checking // for anything else. It first checks for any piece but a Pawn, then if none is found, // it checks whether a Pawn is in hand, and if so, it checks whether any of the blocking // spaces is one a Pawn could be dropped on. If it turns out that no piece drop can // block the check, pieces held in hand are skipped over for the rest of the routine. sub checkmated king checks; // Is the King in check at all? verify checks; store; if isupper space #king: def friends onlyupper; def friend isupper #0; set attacked ATTACKEDBYB; set pat [A-NQ-Z]; set forward 1; set pawn P; else: def friends onlylower; def friend islower #0; set attacked ATTACKEDBYW; set pat [a-nq-z]; set forward -1; set pawn p; endif; // Is there only one checking piece? // Two checking pieces cannot both be blocked or captured. if == count var checks 1: // Can the check be captured or blocked without revealing another check? // Loops once through single element of array. key is coordinate, val is piece. for (key enemy) var checks: set possible path #king #key; set piecedrops var possible; set pawndrops aggregate var pawndropfunc #piecedrops; push possible #key; // Is the checking piece a Pawn that may be captured by en passant? // If so, push the space it passed over onto the possible array. if == #key #ep: push possible cond isupper space #ep where #ep 0 -1 where #ep 0 1; endif; for (from piece) fn friends: if == #from #king: continue; elseif isalnum #from: for to #possible: if fn #piece #from #to: move #from #to; set incheck fn var attacked #king; if not #incheck: setlegal #from #to; endif; endif; restore; next; elseif == #piece #pawn: for to #pawndrops: setlegal #from #to; next; else: for to #piecedrops: setlegal #from #to; next; endif; next; next; endif; // Find Legal King Moves set kingmoves fn KL #king; for to #kingmoves: if not fn friend space #to and onboard #to: move #king #to; set incheck fn var attacked #to; restore; if not #incheck: setlegal #king #to; endif; endif; next; // All done. Set $legalmoves and return; return cond count system legalmoves false true; endsub; // Checks whether player is stalemated and stores list of all legal moves // Same as subroutine in chess except it includes code for drops. // Since this is used when the King is not in check, drop moves are // added without calculating whether the move leaves the King in check. sub stalemated king; local legalmove temp from piece to attacked ra; if isupper space #king: def friend isupper #0; def friends onlyupper; set attacked ATTACKEDBYB; set cspaces var wcastle; set pawn P; set forward 1; else: def friend islower #0; def friends onlylower; set attacked ATTACKEDBYW; set cspaces var bcastle; set pawn p; set forward -1; endif; store; // Find Legal King Moves set kingmoves fn KL #king; for to #kingmoves: if not fn friend space #to and onboard #to: move #king #to; set incheck fn var attacked #to; restore; if not #incheck: setlegal #king #to; endif; endif; next; for to var cspaces: if sub castlepos #king #to: set incheck fn var attacked #to; restore; if not #incheck: setlegal #king #to; endif; endif; next; // Calculates legal drop spaces set piecedrops aggregate lambda (#0 onlyif and empty #0 isalnum #0) spaces; set pawndrops aggregate var pawndropfunc #piecedrops; // Can another piece legally move? restore; for (from piece) fn friends: if == #from #king: continue; endif; if isalnum #from: for to fn join #piece L #from: if fn #piece #from #to and not fn friend space #to and onboard #to and isvisible #to: move #from #to; set incheck fn var attacked #king; if not #incheck: setlegal #from #to; endif; endif; restore; next; elseif == #piece #pawn: for to #pawndrops: setlegal #from #to; next; else: for to #piecedrops: setlegal #from #to; next; endif; next; // All done. Return true if there are no legal moves. return cond count system legalmoves false true; endsub;