/* Chess in Picat. Port of Trealla's samples/chess.pl https://github.com/infradig/trealla/blob/master/samples/chess.pl """ % PVR 20/07/92: Added entry declaration for move/5 (it is used in a bagof). % ------------------------------------------------------------------------------ % Chess -- Mar. 1, 1987 Mike Carlton % """ Changes from the Prolog program: - a lot of $ escaping, especially the $X-Y constructs - changed the bagof/3 to findall/2 in collect_moves/3 - write/1 -> print/1 - tabling on plus_one/2 and plus_two/2 seems to be slightlt faster (1.88s vs 1.93s) - I also fixed all singleton warnings. What I can see, this Picat program outputs exactly the same moves as the Trealla program (but is faster). * The Trealla program took 10.8s running as $ time ../tpl -g "main,halt." chess.pl SWI-Prolog takes about 4.16s * Picat takes 1.93s (or 1.88s with tabling, see above) Output from this Picat program: $ time picat chess.pi """ My move: e7e5, Rating: book +----+----+----+----+----+----+----+----+ 8 | *r | *n | *b | *q | *k | *b | *n | *r | +----+----+----+----+----+----+----+----+ 7 | *p | *p | *p | *p | | *p | *p | *p | +----+----+----+----+----+----+----+----+ 6 | | | | | | | | | +----+----+----+----+----+----+----+----+ 5 | | | | | *p | | | | +----+----+----+----+----+----+----+----+ 4 | | | | | p | | | | +----+----+----+----+----+----+----+----+ 3 | | | | | | | | | +----+----+----+----+----+----+----+----+ 2 | p | p | p | p | | p | p | p | +----+----+----+----+----+----+----+----+ 1 | r | n | b | q | k | b | n | r | +----+----+----+----+----+----+----+----+ a b c d e f g h Working... xxxxxxxxxxxxxxxxxxxxxx My move: g8f6, Rating: 100 +----+----+----+----+----+----+----+----+ 8 | *r | *n | *b | *q | *k | *b | | *r | +----+----+----+----+----+----+----+----+ 7 | *p | *p | *p | *p | | *p | *p | *p | +----+----+----+----+----+----+----+----+ 6 | | | | | | *n | | | +----+----+----+----+----+----+----+----+ 5 | | | | | *p | | | | +----+----+----+----+----+----+----+----+ 4 | | | | | p | | | | +----+----+----+----+----+----+----+----+ 3 | | | | p | | | | | +----+----+----+----+----+----+----+----+ 2 | p | p | p | | | p | p | p | +----+----+----+----+----+----+----+----+ 1 | r | n | b | q | k | b | n | r | +----+----+----+----+----+----+----+----+ a b c d e f g h Working... xxxxxxxxxxx My move: h7h5, Rating: 100 +----+----+----+----+----+----+----+----+ 8 | *r | *n | *b | *q | *k | *b | | *r | +----+----+----+----+----+----+----+----+ 7 | *p | *p | *p | *p | | *p | *p | | +----+----+----+----+----+----+----+----+ 6 | | | | | | *n | | | +----+----+----+----+----+----+----+----+ 5 | | | | | *p | | | *p | +----+----+----+----+----+----+----+----+ 4 | | | | | p | | | | +----+----+----+----+----+----+----+----+ 3 | | | | p | b | | | | +----+----+----+----+----+----+----+----+ 2 | p | p | p | | | p | p | p | +----+----+----+----+----+----+----+----+ 1 | r | n | | q | k | b | n | r | +----+----+----+----+----+----+----+----+ a b c d e f g h Goodbye. """ * Testing: I changed ply_depth/1 to 4. Then it took 27.8s and the following moves were generated: - My move: e7e5, Rating: book (same) - My move: h7h5, Rating: -300 - My move: g7g6, Rating: -100 Note that the opposite moves are the same. This model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import v3_utils. main => go. % This is main/0 defined below go ?=> init_board(InBoard), test_play(InBoard, _), fail, nl. go => true. % % From https://github.com/infradig/trealla/blob/master/samples/chess.pl % % PVR 20/07/92: Added entry declaration for move/5 (it is used in a bagof). % ------------------------------------------------------------------------------ % Chess -- Mar. 1, 1987 Mike Carlton % % Standard rules of chess apply with the following exceptions: % en passant captures are not allowed, % pawns are promoted to queens only, % draw by repetition or no capture are not allowed, % kings may castle out of or through check (but not into). % % Files are numbered a to h, ranks are numbered 1 to 8, % and white is assumed to play from the rank 1 side. % The program always plays black. % % Positions are specified with the structure: File-Rank. % The board is a list containing two state structures of the form: % state(white, WhiteKing, WhiteKingRook, WhiteQueenRook), % state(black, BlackKing, BlackKingRook, BlackQueenRook), % followed by a list of the piece positions of the form: % piece(File-Rank, Color, Type), % where the state variables will be bound to an atom once the % corresponding piece has been moved. % A move is stored internally as: move(From_File-From_Rank, To_File-To_Rank). % % Commands available: % Move: entered in the form FRFR (where F is in a..h and R is in 1..8) % board: prints the current board % quit: quits the game % move(Move): makes any move and does not respond % % The program has a very small book, it will play much better if you stick % to the book opening! The opening it plays is: % White Black % ----- ----- % e2e4 e7e5 % g1f3 b8c6 % f1b5 a7a6 /* main :- init_board(InBoard), test_play(InBoard, _), fail. main. */ play :- init_board(InBoard), play(InBoard), fail. play. test_play --> execute_command(e2e4), !, execute_command(d2d3), !, execute_command(c1e3), !, % execute_command(f2f3), !, % hakank execute_command(quit). play(Board) :- get_command(Command), execute_command(Command, Board, NewBoard), !, play(NewBoard). get_command(Command) :- nl, print('-> '), bp.read(Command), !. get_command(Command) :- get_command(Command). execute_command(bad, Board, Board) :- % To catch vars print('What?'). execute_command(set1, _, Board) :- % DEBUG Board = $([state(white, king_moved, king_rook_moved, queen_rook_moved), state(black, king_moved, king_rook_moved, queen_rook_moved), piece($a-1, white, king), piece($b-1, white, queen), piece($c-1, black, king)]). execute_command(set2, _, Board) :- % DEBUG Board = $([state(white, king_moved, king_rook_moved, queen_rook_moved), state(black, king_moved, king_rook_moved, queen_rook_moved), piece($a-2, white, king), piece($b-1, white, queen), piece($h-8, black, king), piece($b-8, black, rook), piece($c-3, black, night)]). execute_command(clear, _, Board) :- % DEBUG Board = $([state(white, king_moved, king_rook_moved, queen_rook_moved), state(black, king_moved, king_rook_moved, queen_rook_moved) ]). execute_command(piece(S,C,T), Board, [piece(F-R,C,T)|Board]) :- % DEBUG parse_square(S, $F-R), member(F, [a, b, c, d, e, f, g, h]), member(R, [1, 2, 3, 4, 5, 6, 7, 8]), member(C, [white, black]), member(T, [king, queen, rook, night, bishop, pawn]). % execute_command(stats, Board, Board) :- % DEBUG % statistics. execute_command(ply(N), Board, Board) :- % DEBUG abolish($ply_depth/1), assertz($ply_depth(N)). execute_command(rate, Board, Board) :- % DEBUG computer(ComputerColor), evaluate(Board, ComputerColor, Val), print(' Rating: '), print(Val), nl. execute_command(rawboard, Board, Board) :- % DEBUG print(Board), nl. execute_command(move(Move), Board, NewBoard) :- parse_move(Move, From, To), make_move(Board, From, To, NewBoard). execute_command(quit, _, _) :- print('Goodbye.'), nl, !, fail. execute_command(board, Board, Board) :- print_board(Board). execute_command(Move, Board, NewBoard) :- parse_move(Move, From, To), respond_to(Board, From, To, NewBoard). execute_command(_, Board, Board) :- print('What?'). % ------------------------------------------------------------------------------ % Parameters ply_depth(3). % Depth of alpha-beta search % ply_depth(4). % Depth of alpha-beta search % hakank: testing (see comment above) player(white). computer(black). value(king, 10000) :- ! . value(queen, 900) :- ! . value(rook, 500) :- ! . value(night, 300) :- ! . value(bishop, 300) :- ! . value(pawn, 100) :- ! . % ------------------------------------------------------------------------------ % Chess procedures respond_to(Board, From, To, OutBoard) :- player(PlayerColor), legal_move(Board, PlayerColor, From, To), print('Working...'), nl, make_move(Board, From, To, NewBoard), % statistics, select_move(NewBoard, ComputerFrom, ComputerTo, Rating), % statistics, finish_move(NewBoard, ComputerFrom, ComputerTo, Rating, OutBoard), true, !. respond_to(Board, _, _, Board) :- print('Illegal move.'). finish_move(Board, _ComputerFrom, _ComputerTo, -32000, Board) :- in_check(Board, black), print('Checkmate, you win.'), nl, print_board(Board). finish_move(Board, _ComputerFrom, _ComputerTo, -32000, Board) :- print('Stalemate.'), nl, print_board(Board). finish_move(NewBoard, ComputerFrom, ComputerTo, Rating, OutBoard) :- make_move(NewBoard, ComputerFrom, ComputerTo, OutBoard), report_move(OutBoard, ComputerFrom, ComputerTo, Rating). select_move(Board, From, To, book) :- % Use book book(Board, From, To). select_move(Board, From, To, Rating) :- % time for ALPHA-BETA computer(ComputerColor), ply_depth(Depth), alpha_beta(Board, ComputerColor, Depth, -32000, 32000, $move(From, To), Rating). alpha_beta(Board, _Color, 0, _Alpha, _Beta, _BestMove, MoveVal) :- computer(ComputerColor), evaluate(Board, ComputerColor, MoveVal). % write('.'). % write(' val: '), write(MoveVal), nl. alpha_beta(Board, Color, Depth, Alpha, Beta, BestMove, MoveVal) :- collect_moves(Board, Color, MoveList), !, %writeln(MoveList), nl, find_best(Board, Color, MoveList, Depth, Alpha, Beta, BestMove, MoveVal). find_best(Board, Color, [move(From, To)|Moves], Depth, Alpha, Beta, BestMove, BestVal) :- make_move(Board, From, To, NewBoard), % write('*'), % write(Color),write(' '),write(From),write(' '),write(To), % write(' '),write(Alpha), write(' '),write(Beta),write(' '), NextDepth is Depth - 1, opposite(Color, OppositeColor), alpha_beta(NewBoard, OppositeColor, NextDepth, Alpha, Beta, _, Val), sufficient(Board, Color, Moves, Depth, Alpha, Beta, $move(From,To), Val, BestMove, BestVal). sufficient(_Board, _Color, [], _Depth, _Alpha, _Beta, Move, Val, Move, Val). sufficient(_Board, Color, _Moves, _Depth, Alpha, _Beta, Move, Val, Move, Val) :- player(Color), Val < Alpha, print('x'). % write(' Pruning for player- val:'), write(Val), % write(' '),write(Alpha),write(' '),write(Beta),nl. sufficient(_Board, Color, _Moves, _Depth, _Alpha, Beta, Move, Val, Move, Val) :- computer(Color), Val > Beta, true. % write('X'),nl. % write(' Pruning for computer- val:'), write(Val), % write(' '),write(Alpha),write(' '),write(Beta),nl. sufficient(Board, Color, Moves, Depth, Alpha, Beta, Move, Val, BestMove, BestVal) :- new_bounds(Color, Alpha, Beta, Val, NewAlpha, NewBeta), find_best(Board, Color, Moves, Depth, NewAlpha, NewBeta, Move1, Val1), better_of(Color, Move, Val, Move1, Val1, BestMove, BestVal). new_bounds(Color, Alpha, Beta, Val, Val, Beta) :- computer(Color), % Maximizing Val > Alpha. new_bounds(Color, Alpha, Beta, Val, Alpha, Val) :- player(Color), % Minimizing Val < Beta. new_bounds(_, Alpha, Beta, _, Alpha, Beta). better_of(Color, Move, Val, _Move1, Val1, Move, Val) :- player(Color), % Minimizing Val < Val1. better_of(Color, Move, Val, _Move1, Val1, Move, Val) :- computer(Color), % Maximizing Val > Val1. better_of(_, _, _, Move1, Val1, Move1, Val1). evaluate(Board, Color, -32000) :- in_check(Board, Color). evaluate(Board, Color, Rating) :- opposite(Color, OppositeColor), strength(Board, Color, OppositeColor, Rating). strength([], _, _, 0). strength([state(_, _, _, _)|Board], Color, OppositeColor, Strength) :- strength(Board, Color, OppositeColor, Strength). strength([piece(_, Color, Type)|Board], Color, OppositeColor, Strength) :- value(Type, Value), strength(Board, Color, OppositeColor, PartialStrength), Strength is PartialStrength + Value. strength([piece(_, OppositeColor, Type)|Board], Color, OppositeColor, Strength) :- value(Type, Value), strength(Board, Color, OppositeColor, PartialStrength), Strength is PartialStrength - Value. legal_move(Board, Color, From, To) :- move(Board, From, To, Color, _Piece), make_move(Board, From, To, NewBoard), !, \+ in_check(NewBoard, Color). in_check(Board, Color) :- member($piece(KingSquare, Color, king), Board), opposite(Color, OppositeColor), move(Board, _, KingSquare, OppositeColor, _). %:- entry((move(Board,From,To,Color,Piece) :- nonvar(Board), atom(Color))). collect_moves(Board, Color, Moves) :- % bagof($move(From,To), $Piece^move(Board,From,To,Color,Piece), Moves). Moves = findall(move(From,To), $move(Board,From,To,Color,_Piece)). % hakank make_move(Board, From, To, OutBoard) :- make_move(Board, From, To, Color, Type, NewBoard), update_state(NewBoard, From, Color, Type), check_castling(NewBoard, From, To, Color, Type, OutBoard). make_move([], _From, File-8, white, pawn, [piece(File-8, white, queen)]). make_move([], _From, File-1, black, pawn, [piece(File-1, black, queen)]). make_move([], _From, To, Color, Type, [piece(To, Color, Type)]). % Add To sq. make_move([piece(From, Color, Type)|Board], From, To, Color, Type, OutBoard) :- make_move(Board, From, To, Color, Type, OutBoard). % Skip From make_move([piece(To, _, _)|Board], From, To, Color, Type, OutBoard) :- make_move(Board, From, To, Color, Type, OutBoard). % Skip To sq make_move([Piece|Board], From, To, Color, Type, [Piece|OutBoard]) :- make_move(Board, From, To, Color, Type, OutBoard). % Copy check_castling(Board, e-Rank, g-Rank, _Color, king, OutBoard) :- % King side make_move(Board, $h-Rank, $f-Rank, OutBoard). % castling check_castling(Board, e-Rank, c-Rank, _Color, king, OutBoard) :- % Queen side make_move(Board, $a-Rank, $d-Rank, OutBoard). % castling check_castling(Board, _, _, _, _, Board). parse_square(Square, File-Rank) :- name(Square, [F,R]), name(File, [F]), myname(Rank, [R]), on_board($File-Rank). parse_move(Move, From_File-From_Rank, To_File-To_Rank) :- name(Move, [FF,FR,TF,TR]), name(From_File, [FF]), myname(From_Rank, [FR]), name(To_File, [TF]), myname(To_Rank, [TR]), on_board($From_File-From_Rank), on_board($To_File-To_Rank). on_board(File-Rank) :- member(File, [a, b, c, d, e, f, g, h]), member(Rank, [1, 2, 3, 4, 5, 6, 7, 8]). not_moved(Board, Color, king) :- member($state(Color, King, _, _), Board), !, var(King). not_moved(Board, Color, king, rook) :- member($state(Color, _, KingRook, _), Board), !, var(KingRook). not_moved(Board, Color, queen, rook) :- member($state(Color, _, _, QueenRook), Board), !, var(QueenRook). update_state(Board, _From, Color, king) :- % Was king moved? member($state(Color, king_moved, _, _), Board). update_state(Board, h-_Rank, Color, rook) :- % Was king rook moved? member($state(Color, _, king_rook_moved, _), Board). update_state(Board, a-_Rank, Color, rook) :- % Was queen rook moved? member($state(Color, _, _, queen_rook_moved), Board). update_state(_, _, _, _). % Else, ignore % ------------------------------------------------------------------------------ % Printing utilities report_move(Board, From_File-From_Rank, To_File-To_Rank, Rating) :- nl, print('My move: '), print(From_File), print(From_Rank), print(To_File), print(To_Rank), print(', Rating: '), print(Rating), nl, print_board(Board). %% print_board(Board) :- %% !. print_board(Board) :- print_rank(Board, 8), print_dashes, nl, print_letters, nl, !. print_rank(Board, 1) :- print_dashes, nl, print(1), print(' | '), print_squares(Board, a, 1). print_rank(Board, Rank) :- print_dashes, nl, print(Rank), print(' | '), print_squares(Board, a, Rank), minus_one(Rank, NextRank), % Next_Rank is Rank - 1, % the void variable NextRank is Rank - 1, print_rank(Board, NextRank). print_squares(Board, h, Rank) :- print_a_square(Board, h, Rank), print(' |'), nl. print_squares(Board, File, Rank) :- print_a_square(Board, File, Rank), print(' | '), plus_one(File, NextFile), print_squares(Board, NextFile, Rank). print_a_square(Board, File, Rank) :- member($piece(File-Rank, Color, Type), Board), (Color = white -> print(' ') ; print('*')), name(Type, [T|_]), bp.put(T). print_a_square(_Board, _File, _Rank) :- print(' '). print_dashes :- print(' +----+----+----+----+----+----+----+----+'). print_letters :- print(' a b c d e f g h'). myname(X,[Y]) :- myname2(Y,X), !. myname2(48,0). myname2(49,1). myname2(50,2). myname2(51,3). myname2(52,4). myname2(53,5). myname2(54,6). myname2(55,7). myname2(56,8). myname2(57,9). % ------------------------------------------------------------------------------ % Initialization stuff init_board( [ state(white, _WhiteKing, _WhiteKingRook, _WhiteQueenRook), state(black, _BlackKing, _BlackKingRook, _BlackQueenRook), piece(a-8, black, rook ), piece(b-8, black, night ), piece(c-8, black, bishop), piece(d-8, black, queen ), piece(e-8, black, king ), piece(f-8, black, bishop), piece(g-8, black, night ), piece(h-8, black, rook ), piece(a-7, black, pawn ), piece(b-7, black, pawn ), piece(c-7, black, pawn ), piece(d-7, black, pawn ), piece(e-7, black, pawn ), piece(f-7, black, pawn ), piece(g-7, black, pawn ), piece(h-7, black, pawn ), piece(a-1, white, rook ), piece(b-1, white, night ), piece(c-1, white, bishop), piece(d-1, white, queen ), piece(e-1, white, king ), piece(f-1, white, bishop), piece(g-1, white, night ), piece(h-1, white, rook ), piece(a-2, white, pawn ), piece(b-2, white, pawn ), piece(c-2, white, pawn ), piece(d-2, white, pawn ), piece(e-2, white, pawn ), piece(f-2, white, pawn ), piece(g-2, white, pawn ), piece(h-2, white, pawn ) ]). % ------------------------------------------------------------------------------ % Valid move checkers and generators move(Board, F_File-F_Rank, T_File-T_Rank, Color, Piece) :- occupied_by(Board, $F_File-F_Rank, Color, Piece), can_move(Board, $F_File-F_Rank, $T_File-T_Rank, Color, Piece), \+ occupied_by(Board, $T_File-T_Rank, Color, _). can_move(Board, File-F_Rank, File-T_Rank, white, pawn) :- % White pawn plus_one(F_Rank, T_Rank), % move \+ occupied_by(Board, $File-T_Rank, black, _). can_move(Board, File-2, File-4, white, pawn) :- \+ occupied_by(Board, $File-3, black, _), \+ occupied_by(Board, $File-4, black, _). can_move(Board, F_File-F_Rank, T_File-T_Rank, white, pawn) :- % White pawn plus_one(F_File, T_File), % capture plus_one(F_Rank, T_Rank), occupied_by(Board, $T_File-T_Rank, black, _). can_move(Board, F_File-F_Rank, T_File-T_Rank, white, pawn) :- minus_one(F_File, T_File), plus_one(F_Rank, T_Rank), occupied_by(Board, $T_File-T_Rank, black, _). can_move(Board, File-F_Rank, File-T_Rank, black, pawn) :- % Black pawn minus_one(F_Rank, T_Rank), % move \+ occupied_by(Board, $File-T_Rank, white, _). can_move(Board, File-7, File-5, black, pawn) :- \+ occupied_by(Board, $File-6, white, _), \+ occupied_by(Board, $File-5, white, _). can_move(Board, F_File-F_Rank, T_File-T_Rank, black, pawn) :- % Black pawn minus_one(F_File, T_File), % capture minus_one(F_Rank, T_Rank), occupied_by(Board, $T_File-T_Rank, white, _). can_move(Board, F_File-F_Rank, T_File-T_Rank, black, pawn) :- plus_one(F_File, T_File), minus_one(F_Rank, T_Rank), occupied_by(Board, $T_File-T_Rank, white, _). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, night) :- % Knight move plus_one(F_File, T_File), plus_two(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, night) :- plus_one(F_File, T_File), minus_two(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, night) :- minus_one(F_File, T_File), plus_two(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, night) :- minus_one(F_File, T_File), minus_two(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, night) :- plus_two(F_File, T_File), plus_one(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, night) :- plus_two(F_File, T_File), minus_one(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, night) :- minus_two(F_File, T_File), plus_one(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, night) :- minus_two(F_File, T_File), minus_one(F_Rank, T_Rank). can_move(Board, F_File-F_Rank, T_File-T_Rank, _Color, bishop) :- % Bishop move can_step(Board, 1, 1, $F_File-F_Rank, $T_File-T_Rank). can_move(Board, F_File-F_Rank, T_File-T_Rank, _Color, bishop) :- can_step(Board, 1, -1, $F_File-F_Rank, $T_File-T_Rank). can_move(Board, F_File-F_Rank, T_File-T_Rank, _Color, bishop) :- can_step(Board, -1, 1, $F_File-F_Rank, $T_File-T_Rank). can_move(Board, F_File-F_Rank, T_File-T_Rank, _Color, bishop) :- can_step(Board, -1, -1, $F_File-F_Rank, $T_File-T_Rank). can_move(Board, F_File-F_Rank, T_File-T_Rank, _Color, rook) :- % Rook move can_step(Board, 1, 0, $F_File-F_Rank, $T_File-T_Rank). can_move(Board, F_File-F_Rank, T_File-T_Rank, _Color, rook) :- can_step(Board, -1, 0, $F_File-F_Rank, $T_File-T_Rank). can_move(Board, F_File-F_Rank, T_File-T_Rank, _Color, rook) :- can_step(Board, 0, 1, $F_File-F_Rank, $T_File-T_Rank). can_move(Board, F_File-F_Rank, T_File-T_Rank, _Color, rook) :- can_step(Board, 0, -1, $F_File-F_Rank, $T_File-T_Rank). can_move(Board, F_File-F_Rank, T_File-T_Rank, Color, queen) :- % Queen move can_move(Board, $F_File-F_Rank, $T_File-T_Rank, Color, bishop). can_move(Board, F_File-F_Rank, T_File-T_Rank, Color, queen) :- can_move(Board, $F_File-F_Rank, $T_File-T_Rank, Color, rook). can_move(_Board, File-F_Rank, File-T_Rank, _Color, king) :- % King move plus_one(F_Rank, T_Rank). can_move(_Board, File-F_Rank, File-T_Rank, _Color, king) :- minus_one(F_Rank, T_Rank). can_move(_Board, F_File-Rank, T_File-Rank, _Color, king) :- % King move plus_one(F_File, T_File). can_move(_Board, F_File-Rank, T_File-Rank, _Color, king) :- minus_one(F_File, T_File). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, king) :- plus_one(F_File, T_File), minus_one(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, king) :- plus_one(F_File, T_File), plus_one(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, king) :- minus_one(F_File, T_File), plus_one(F_Rank, T_Rank). can_move(_Board, F_File-F_Rank, T_File-T_Rank, _Color, king) :- minus_one(F_File, T_File), minus_one(F_Rank, T_Rank). can_move(Board, e-Rank, g-Rank, Color, king) :- % King side not_moved(Board, Color, king), % castle not_moved(Board, Color, king, rook), \+ occupied_by(Board, $f-Rank, _, _). can_move(Board, e-Rank, g-Rank, Color, king) :- % Queen side not_moved(Board, Color, king), % castle not_moved(Board, Color, queen, rook), \+ occupied_by(Board, $d-Rank, _, _), \+ occupied_by(Board, $b-Rank, _, _). can_step(_Board, 1, 1, F_File-F_Rank, T_File-T_Rank) :- % Step moves plus_one(F_File, T_File), plus_one(F_Rank, T_Rank). can_step(Board, 1, 1, F_File-F_Rank, T_File-T_Rank) :- plus_one(F_File, I_File), plus_one(F_Rank, I_Rank), \+ occupied_by(Board, $I_File-I_Rank, _, _), can_step(Board, 1, 1, $I_File-I_Rank, $T_File-T_Rank). can_step(_Board, 1, 0, F_File-Rank, T_File-Rank) :- plus_one(F_File, T_File). can_step(Board, 1, 0, F_File-Rank, T_File-Rank) :- plus_one(F_File, I_File), \+ occupied_by(Board, $I_File-Rank, _, _), can_step(Board, 1, 0, $I_File-Rank, $T_File-Rank). can_step(_Board, 1, -1, F_File-F_Rank, T_File-T_Rank) :- plus_one(F_File, T_File), minus_one(F_Rank, T_Rank). can_step(Board, 1, -1, F_File-F_Rank, T_File-T_Rank) :- plus_one(F_File, I_File), minus_one(F_Rank, I_Rank), \+ occupied_by(Board, $I_File-I_Rank, _, _), can_step(Board, 1, -1, $I_File-I_Rank, $T_File-T_Rank). can_step(_Board, 0, 1, File-F_Rank, File-T_Rank) :- plus_one(F_Rank, T_Rank). can_step(Board, 0, 1, File-F_Rank, File-T_Rank) :- plus_one(F_Rank, I_Rank), \+ occupied_by(Board, $File-I_Rank, _, _), can_step(Board, 0, 1, $File-I_Rank, $File-T_Rank). can_step(_Board, 0, -1, File-F_Rank, File-T_Rank) :- minus_one(F_Rank, T_Rank). can_step(Board, 0, -1, File-F_Rank, File-T_Rank) :- minus_one(F_Rank, I_Rank), \+ occupied_by(Board, $File-I_Rank, _, _), can_step(Board, 0, -1, $File-I_Rank, $File-T_Rank). can_step(_Board, -1, 1, F_File-F_Rank, T_File-T_Rank) :- minus_one(F_File, T_File), plus_one(F_Rank, T_Rank). can_step(Board, -1, 1, F_File-F_Rank, T_File-T_Rank) :- minus_one(F_File, I_File), plus_one(F_Rank, I_Rank), \+ occupied_by(Board, $I_File-I_Rank, _, _), can_step(Board, -1, 1, $I_File-I_Rank, $T_File-T_Rank). can_step(_Board, -1, 0, F_File-Rank, T_File-Rank) :- minus_one(F_File, T_File). can_step(Board, -1, 0, F_File-Rank, T_File-Rank) :- minus_one(F_File, I_File), \+ occupied_by(Board, $I_File-_I_Rank, _, _), can_step(Board, -1, 0, $I_File-Rank, $T_File-Rank). can_step(_Board, -1, -1, F_File-F_Rank, T_File-T_Rank) :- minus_one(F_File, T_File), minus_one(F_Rank, T_Rank). can_step(Board, -1, -1, F_File-F_Rank, T_File-T_Rank) :- minus_one(F_File, I_File), minus_one(F_Rank, I_Rank), \+ occupied_by(Board, $I_File-I_Rank, _, _), can_step(Board, -1, -1, $I_File-I_Rank, $T_File-T_Rank). occupied_by(Board, File-Rank, Color, Piece) :- member($piece(File-Rank, Color, Piece), Board). table plus_one(1,2). plus_one(2,3). plus_one(3,4). plus_one(4,5). plus_one(5,6). plus_one(6,7). plus_one(7,8). plus_one(a,b). plus_one(b,c). plus_one(c,d). plus_one(d,e). plus_one(e,f). plus_one(f,g). plus_one(g,h). minus_one(X,Y) :- plus_one(Y,X). table plus_two(1,3). plus_two(2,4). plus_two(3,5). plus_two(4,6). plus_two(5,7). plus_two(6,8). plus_two(a,c). plus_two(b,d). plus_two(c,e). plus_two(d,f). plus_two(e,g). plus_two(f,h). minus_two(X,Y) :- plus_two(Y,X). % ------------------------------------------------------------------------------ % Book moves book( [ state(white, _WhiteKing, _WhiteKingRook, _WhiteQueenRook), % e2e4 state(black, _BlackKing, _BlackKingRook, _BlackQueenRook), % respond with piece(a-8, black, rook ), piece(b-8, black, night ), % ... e7e5 piece(c-8, black, bishop), piece(d-8, black, queen ), piece(e-8, black, king ), piece(f-8, black, bishop), piece(g-8, black, night ), piece(h-8, black, rook ), piece(a-7, black, pawn ), piece(b-7, black, pawn ), piece(c-7, black, pawn ), piece(d-7, black, pawn ), piece(e-7, black, pawn ), piece(f-7, black, pawn ), piece(g-7, black, pawn ), piece(h-7, black, pawn ), piece(a-1, white, rook ), piece(b-1, white, night ), piece(c-1, white, bishop), piece(d-1, white, queen ), piece(e-1, white, king ), piece(f-1, white, bishop), piece(g-1, white, night ), piece(h-1, white, rook ), piece(a-2, white, pawn ), piece(b-2, white, pawn ), piece(c-2, white, pawn ), piece(d-2, white, pawn ), piece(f-2, white, pawn ), piece(g-2, white, pawn ), piece(h-2, white, pawn ), piece(e-4, white, pawn ) ], e-7, e-5). book( [ state(white, _WhiteKing, _WhiteKingRook, _WhiteQueenRook), % e2e4 e7e5 state(black, _BlackKing, _BlackKingRook, _BlackQueenRook), % g1f3 piece(a-8, black, rook ), piece(b-8, black, night ), % respond with piece(c-8, black, bishop), piece(d-8, black, queen ), % ... b8c6 piece(e-8, black, king ), piece(f-8, black, bishop), piece(g-8, black, night ), piece(h-8, black, rook ), piece(a-7, black, pawn ), piece(b-7, black, pawn ), piece(c-7, black, pawn ), piece(d-7, black, pawn ), piece(f-7, black, pawn ), piece(g-7, black, pawn ), piece(h-7, black, pawn ), piece(a-1, white, rook ), piece(b-1, white, night ), piece(c-1, white, bishop), piece(d-1, white, queen ), piece(e-1, white, king ), piece(f-1, white, bishop), piece(h-1, white, rook ), piece(a-2, white, pawn ), piece(b-2, white, pawn ), piece(c-2, white, pawn ), piece(d-2, white, pawn ), piece(f-2, white, pawn ), piece(g-2, white, pawn ), piece(h-2, white, pawn ), piece(e-4, white, pawn ), piece(e-5, black, pawn ), piece(f-3, white, night ) ], b-8, c-6). book( [ state(white, _WhiteKing, _WhiteKingRook, _WhiteQueenRook), % e2e4 e7e5 state(black, _BlackKing, _BlackKingRook, _BlackQueenRook), % g1f3 b8f6 piece(a-8, black, rook ), piece(c-8, black, bishop), % f1b5 piece(d-8, black, queen ), piece(e-8, black, king ), % respond with piece(f-8, black, bishop), piece(g-8, black, night ), % ... a7a6 piece(h-8, black, rook ), piece(a-7, black, pawn ), piece(b-7, black, pawn ), piece(c-7, black, pawn ), piece(d-7, black, pawn ), piece(f-7, black, pawn ), piece(g-7, black, pawn ), piece(h-7, black, pawn ), piece(a-1, white, rook ), piece(b-1, white, night ), piece(c-1, white, bishop), piece(d-1, white, queen ), piece(e-1, white, king ), piece(h-1, white, rook ), piece(a-2, white, pawn ), piece(b-2, white, pawn ), piece(c-2, white, pawn ), piece(d-2, white, pawn ), piece(f-2, white, pawn ), piece(g-2, white, pawn ), piece(h-2, white, pawn ), piece(e-4, white, pawn ), piece(e-5, black, pawn ), piece(f-3, white, night ), piece(c-6, black, night ), piece(b-5, white, bishop) ], a-7, a-6). % ------------------------------------------------------------------------------ % Utilities opposite(white, black). opposite(black, white).