%% CHAI, the Uncommon Chess Agent %% Shepherd McIlroy %% 12/13/00 :- dynamic(board/3). % the current board representation :- dynamic(in_check/1). % the color that is currently in check :- dynamic(chai_color/1). % chai's color :- dynamic(state/1). % current game state: opening, mid_game, or end_game :- dynamic(history/1). % history (list) of played moves %% %% new_game(Color) %% start a new game with Color as your color new_game(_) :- board(_,_,init), write('Game in progress, use end_game first.'), nl. new_game(C) :- inv_color(C,I), asserta(chai_color(I)), asserta(state(opening)), asserta(history([])), asserta(in_check(none)), asserta(state(opening)), asserta( board( [ [-5,-3,-4,-8,-9,-4,-3,-5], [-1,-1,-1,-1,-1,-1,-1,-1], [ 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0], [ 1, 1, 1, 1, 1, 1, 1, 1], [ 5, 3, 4, 8, 9, 4, 3, 5] ], white, init) ), board(B,white,init), nl, draw_board(B), write_move, chai(opening). new_game(C) :- \+is_color(C), write(C), write(' is not a useable color. Pick black or white.'), nl. is_color(white). is_color(black). %% %% offer_draw %% offer a draw to CHAI offer_draw :- chai_color(C), inv_color(C,IC), board(B,_,init), rating(B,C,R1), rating(B,IC,R2), R1 >= R2, write('Draw offer declined.'), nl. offer_draw :- write('CHAI accepts a draw.'), nl, end_game. %% %% end_game %% delete dynamic atoms so a new game can be initiated end_game :- retract(board(_,_,init)), retract(in_check(_)), retract(history(_)), retract(state(_)), retract(chai_color(_)), write('Thanks for playing.'). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% move([Row_From,Col_From],[Row_To,Col_To]). %% %% human player makes his move; %% [0,0] is top left, [0,7] is top right, %% where top belongs to black %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% move(_,_) :- % no game has been started \+board(_,_,init), write('Use new_game(Color) to start a new game.'), nl. move(From,_) :- % no piece exists at From board(B,_,init), piece_at(B,From,0), write('No piece at '), write(From), write('.'), nl. move(From,_) :- % piece at From doesn't belong to turn owner board(B,C,init), piece_at(B,From,P), \+color_of(P,C), write(From), write(' is not your piece.'), nl. move(_,To) :- % piece at To doesn't belong to turn owner board(B,C,init), piece_at(B,To,Piece), color_of(Piece,C), write('Cannot take your own piece.'), nl. move(From,To) :- % move isn't possible board(B,_,init), \+poss_move(From,To,B), write('Impossible move!'), nl. move(From,To) :- % someone has won the game board(B,C,init), poss_move(From,To,B,Spec), next_board(From,To,B,N,Spec), inv_color(C,IC), mated(N,IC), end_game, write(IC), write(' is checkmated. Good game.'). move(From,To) :- % move is possible, and move is made board(B,C,init), poss_move(From,To,B,Spec), next_board(From,To,B,N,Spec), \+checked(N,C), % unless the mover is in check inv_color(C,IC), retract(board(B,C,init)), asserta(board(N,IC,init)), retract(history(H)), append(H,[move(From,To,C)],Hn), asserta(history(Hn)), nl, draw_board(N), reveal_check(N,C), write_move, state(S), chai(S). move(_,_) :- % probably didn't notice he was in check board(_,C,init), in_check(C), write('Better move out of check instead.'), nl. move(_,_) :- % moved into / discovered check write('That would put you in check.'), nl. write_move :- board(_,C,init), chai_color(C), write('CHAI`s move ...'), nl. write_move :- board(_,C,init), \+chai_color(C), write('Your move.'), nl. %% %% draw_board(Board) %% draws a frugal representation of Board draw_board(B) :- draw_board(B,0). draw_board([],_) :- nl, write(' 0 1 2 3 4 5 6 7'), nl. draw_board([R|L],C) :- write('|'), draw_row(R), write(' '), write(C), nl, Cn is C+1, draw_board(L,Cn). draw_row([]). draw_row([E|L]) :- E > 0, write('+'), write(E), write('|'), draw_row(L). draw_row([0|L]) :- write(' 0|'), draw_row(L). draw_row([E|L]) :- E < 0, write(E), write('|'), draw_row(L). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% poss_move(From,To,Board) %% true if moving piece at From to To on Board is a valid move %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% poss_move(From,To,B) :- piece_at(B,From,P), P \== 0, piece_at(B,To,T), color_of(P,C), \+color_of(T,C), abs(P,Pa), poss_move(From,To,B,Pa,_). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% poss_move(From,To,Board,Special) %% valid move of type Special (castle, queen promotion or none) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% poss_move(From,To,B,Spec) :- piece_at(B,From,P), P \== 0, piece_at(B,To,T), color_of(P,C), \+color_of(T,C), abs(P,Pa), poss_move(From,To,B,Pa,Spec). %% %% poss_move_x(From,To,C,B) %% valid move for player of color C regardless of what piece is there poss_move_x(From,To,C,B,Spec) :- piece_at(B,From,P), P \== 0, color_of(P,C), abs(P,Pa), poss_move(From,To,B,Pa,Spec). %% %% valid move for pawns poss_move(From,To,B,1,Spec) :- piece_at(B,From,Piece), color_of(Piece,Color), ok_pawn(From,To,B,Color), queening(To,Color,Spec). queening([0,_],white,white_queen). % promote to queen if piece has reached opposing flank queening([7,_],black,black_queen). queening(_,_,none). ok_pawn([1,C],[3,C],B,black) :- % allow black pawns to move 2 first time piece_at(B,[2,C],0), piece_at(B,[3,C],0). ok_pawn([6,C],[4,C],B,white) :- % allow white pawns to move 2 first time piece_at(B,[5,C],0), piece_at(B,[4,C],0). ok_pawn([R1,C],[R2,C],B,black) :- % allow normal black pawn advance R2 is R1 + 1, piece_at(B,[R2,C],0). ok_pawn([R1,C],[R2,C],B,white) :- % allow normal white pawn advance R2 is R1 - 1, piece_at(B,[R2,C],0). ok_pawn([R1,C1],[R2,C2],B,black) :- % allow black pawns to capture R2 is R1 + 1, C is C1 - C2, abs(C,1), \+piece_at(B,[R2,C2],0). ok_pawn([R1,C1],[R2,C2],B,white) :- % allow white pawns to capture R2 is R1 - 1, C is C1 - C2, abs(C,1), \+piece_at(B,[R2,C2],0). %% %% valid move for knight poss_move([C1,R1],[C2,R2],_,3,none) :- C is C1 - C2, R is R1 - R2, C \== 0, R \== 0, abs(C,AC), abs(R,AR), Z is AC + AR, Z is 3. %% %% valid move for bishop poss_move([R1,C1],[R2,C2],B,4,none) :- C is C1 - C2, R is R1 - R2, abs(C,X), abs(R,X), move_dir(R1,R2,D1), move_dir(C1,C2,D2), Rn is R1 + D1, Cn is C1 + D2, ok_bishop([Rn,Cn],[R2,C2],B,D1,D2). ok_bishop(F,F,_,_,_). ok_bishop([R1,C1],Final,B,D1,D2) :- piece_at(B,[R1,C1],0), R is R1+D1, C is C1+D2, ok_bishop([R,C],Final,B,D1,D2). %% %% valid move for rook poss_move([R1,C],[R2,C],B,5,none) :- move_dir(R1,R2,D), Rn is R1+D, ok_rook([Rn,C],[R2,C],B,D,0). poss_move([R,C1],[R,C2],B,5,none) :- move_dir(C1,C2,D), Cn is C1+D, ok_rook([R,Cn],[R,C2],B,0,D). ok_rook(F,F,_,_,_). ok_rook([R1,C1],Final,B,D1,D2) :- piece_at(B,[R1,C1],0), Rn is R1+D1, Cn is C1+D2, ok_rook([Rn,Cn],Final,B,D1,D2). %% %% valid move for queen poss_move(P1,P2,B,8,none) :- poss_move(P1,P2,B,5,none). % valid rook move or poss_move(P1,P2,B,8,none) :- poss_move(P1,P2,B,4,none). % valid bishop move %% %% valid move for king poss_move([R1,C1],[R2,C2],_,9,none) :- C is C1 - C2, R is R1 - R2, abs(R,Ra), abs(C,Ca), ok_king(Ra,Ca). ok_king(1,1). ok_king(1,0). ok_king(0,1). poss_move([0,4],[0,6],B,9,castle_ur) :- % black side castle piece_at(B,[0,5],0), piece_at(B,[0,6],0), piece_at(B,[0,7],-5). poss_move([0,4],[0,2],B,9,castle_ul) :- piece_at(B,[0,3],0), piece_at(B,[0,2],0), piece_at(B,[0,1],0), piece_at(B,[0,0],-5). poss_move([7,4],[7,6],B,9,castle_lr) :- % white side castle piece_at(B,[7,5],0), piece_at(B,[7,6],0), piece_at(B,[7,7],5). poss_move([7,4],[7,2],B,9,castle_ll) :- piece_at(B,[7,3],0), piece_at(B,[7,2],0), piece_at(B,[7,1],0), piece_at(B,[7,0],5). % returns a move's direction % +1 for left-right, up-down; -1 for right-left, down-up move_dir(P1,P2,D) :- P1 < P2, D is 1. move_dir(P1,P2,D) :- P1 > P2, D is -1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% checked(Board,Color) %% Color is in check on Board checked(B,C) :- king_pos(B,C,Pos), king_in_check(B,C,Pos). king_pos(B,C,Pos) :- king_pos(B,C,[0,0],Pos). king_pos(B,C,Pos,Pos) :- piece_at(B,Pos,Piece), color_of(Piece,C), abs(Piece,9). king_pos(B,C,Sx,Pos) :- next_boff(Sx,Sn), legal_pos(Sn), king_pos(B,C,Sn,Pos). king_in_check(B,C,Pos) :- king_in_check(B,C,[0,0],Pos). king_in_check(B,C,Sx,Pos) :- piece_at(B,Sx,Piece), color_of(Piece,Cx), inv_color(Cx,C), poss_move(Sx,Pos,B). king_in_check(B,C,Sx,Pos) :- next_boff(Sx,Sn), legal_pos(Sn), king_in_check(B,C,Sn,Pos). reveal_check(B,C) :- inv_color(C,I), checked(B,I), write(I), write(' is in check.'), nl, retract(in_check(_)), asserta(in_check(I)). reveal_check(_,_). %% %% mated(Board,Color) %% Color is checkmated on Board mated(B,C) :- checked(B,C), mated(B,C,[0,0]). mated(_,_,[0,8]). mated(B,C,Sx) :- piece_at(B,Sx,Piece), color_of(Piece,C), poss_moves(Sx,Pml,B), checked(B,C,Sx,Pml), next_boff(Sx,Next), mated(B,C,Next). checked(_,_,_,[]). checked(Bi,C,From,[To|Tos]) :- next_board(From,To,Bi,Bn), checked(Bn,C), checked(Bi,C,From,Tos). %% %% poss_moves(From,ToList,Board) %% ToList is the possible moves for piece at From on Board poss_moves(From,L,B) :- poss_moves(From,L,[0,0],B). poss_moves(_,[],[0,8],_). poss_moves(From,L,Sx,B) :- poss_move(From,Sx,B), append([Sx],Ln,L), next_boff(Sx,Next), poss_moves(From,Ln,Next,B). poss_moves(From,L,Sx,B) :- legal_pos(Sx), \+poss_move(From,Sx,B), next_boff(Sx,Next), poss_moves(From,L,Next,B). %% %% poss_moves_for(Board,From,ToList) %% same as poss_moves but with special move parameter included in ToList poss_moves_for(B,From,L) :- poss_moves_for(B,From,L,[0,0]). poss_moves_for(_,_,[],[0,8]). poss_moves_for(B,From,L,Sx) :- poss_move(From,Sx,B,Spec), next_boff(Sx,Next), poss_moves_for(B,From,Ln,Next), append([[From,Sx,Spec]],Ln,L). poss_moves_for(B,From,L,Sx) :- legal_pos(Sx), \+poss_move(From,Sx,B,_), next_boff(Sx,Next), poss_moves_for(B,From,L,Next). %% %% poss_moves_to(FromList,To,Color,Board) %% all possible moves to To for Color on Board poss_moves_to(L,To,C,B) :- poss_moves_to(L,To,[0,0],C,B). poss_moves_to([],_,[0,8],_,_). poss_moves_to(L,To,Sx,C,B) :- poss_move_x(Sx,To,C,B,_), append([Sx],Ln,L), next_boff(Sx,Next), poss_moves_to(Ln,To,Next,C,B). poss_moves_to(L,To,Sx,C,B) :- legal_pos(Sx), \+poss_move_x(Sx,To,C,B,_), next_boff(Sx,Next), poss_moves_to(L,To,Next,C,B). %% %% next_board(From,To,Bi,Bn,Spec) %% Bn is the board after move From -> To in Bi next_board(From,To,Bi,Bn,none) :- % next board after normal move piece_at(Bi,From,P), boff(From,To,[0,0],P,Bi,Bn). next_board(From,To,Bi,Bn,white_queen) :- % next board after queen promotion boff(From,To,[0,0],8,Bi,Bn). next_board(From,To,Bi,Bn,black_queen) :- boff(From,To,[0,0],-8,Bi,Bn). next_board(From,To,Bi,Bn,S) :- % next board after castle piece_at(Bi,From,King), boff(From,To,[0,0],King,Bi,Bm), next_rook(S,Fr,Tr), piece_at(Bi,Fr,Rook), boff(Fr,Tr,[0,0],Rook,Bm,Bn). next_rook(castle_ur,[0,7],[0,5]). next_rook(castle_ul,[0,0],[0,3]). next_rook(castle_lr,[7,7],[7,5]). next_rook(castle_ll,[7,0],[7,3]). next_board(From,To,Bi,Bn) :- % next board without special move piece_at(Bi,From,P), boff(From,To,[0,0],P,Bi,Bn). boff(_,_,[0,8],_,_,_). boff(From,To,From,P,Bi,Bn) :- % if at square From piece_at(Bn,From,0), % pick up Piece next_boff(From,Next), boff(From,To,Next,P,Bi,Bn). boff(From,To,To,P,Bi,Bn) :- % if at square To piece_at(Bn,To,P), % drop Piece next_boff(To,Next), boff(From,To,Next,P,Bi,Bn). boff(From,To,Sx,P,Bi,Bn) :- Sx \== From, Sx \== To, piece_at(Bi,Sx,Piece), % otherwise just copy piece piece_at(Bn,Sx,Piece), next_boff(Sx,Sn), boff(From,To,Sn,P,Bi,Bn). next_boff([7,Y],[0,Yn]) :- Yn is Y+1. next_boff([X,Y],[Xn,Y]) :- X < 7, Xn is X+1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% piece_at(B,[Row,Col],P) :- legal_pos([Row,Col]), elem_at(B,Row,E), elem_at(E,Col,P). elem_at([E,_,_,_,_,_,_,_],0,E). elem_at([_,E,_,_,_,_,_,_],1,E). elem_at([_,_,E,_,_,_,_,_],2,E). elem_at([_,_,_,E,_,_,_,_],3,E). elem_at([_,_,_,_,E,_,_,_],4,E). elem_at([_,_,_,_,_,E,_,_],5,E). elem_at([_,_,_,_,_,_,E,_],6,E). elem_at([_,_,_,_,_,_,_,E],7,E). color_of(P,white) :- P > 0. color_of(P,black) :- P < 0. color_of(0,none). inv_color(white,black). inv_color(black,white). abs(A,A) :- A >= 0. abs(A,B) :- A < 0, B is -A. append([],L,L). append([H|L1],L2,[H|L3]) :- append(L1,L2,L3). size_of([],0). size_of([_|L],S) :- size_of(L,N), S is N+1. legal_pos([R,C]) :- legal(R), legal(C). legal(0). legal(1). legal(2). legal(3). legal(4). legal(5). legal(6). legal(7). %legal(N) :- % N >= 0, % N =< 7. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% chai(_) :- % do nothing, it's not chai's turn board(_,C,init), \+chai_color(C). rating(_,_,0) :- state(opening). rating(B,C,R) :- state(mid_game), mid_rating(B,C,R). rating(B,C,R) :- state(end_game), end_rating(B,C,R). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% CHAI's opening implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% chai(opening) :- chai_color(C), history(H), opening(O), opening(O,H,move(From,To,C)), move(From,To). opening([M|_],[],M). opening([Z|O],[Z|H],M) :- opening(O,H,M). chai(opening) :- chai_color(C), board(_,C,init), retract(state(opening)), asserta(state(mid_game)), % advance to mid game chai(mid_game). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% CHAI's mid game implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% chai(mid_game) :- still_mid_game, board(B,C,init), all_moves(B,C,Moves), best_mid(B,C,Moves,[From,To,_],_), % pick best move from Moves move(From,To). chai(mid_game) :- \+still_mid_game, retract(state(mid_game)), asserta(state(end_game)), % advance to end game chai(end_game). still_mid_game :- % remain in mid game until number of pieces =< 12 board(B,_,init), pieces(B,Num), Num > 12. %% %% all_moves(B,C,Moves) %% list Moves contains all the possible moves for C on B all_moves(B,C,Moves) :- all_moves(B,C,Moves,[0,0]). all_moves(_,_,[],[0,8]). all_moves(B,C,L,Sx) :- piece_at(B,Sx,P), color_of(P,C), poss_moves_for(B,Sx,M), next_boff(Sx,Next), all_moves(B,C,Ln,Next), append(M,Ln,L). all_moves(B,C,L,Sx) :- piece_at(B,Sx,P), \+color_of(P,C), next_boff(Sx,Next), all_moves(B,C,L,Next). %% %% best_mid1(B,C,Moves,Move,Rating) %% best Move from list Moves for C on B given mid game strategy %% thinks 1 full move ahead best_mid1(B,C,[[From,To,Spec]|Moves],Move,Rating) :- best_mid1(B,C,Moves,BestMove,BestRating), next_board(From,To,B,N,Spec), inv_color(C,IC), all_moves(N,IC,MovesIC), best_mid(N,IC,MovesIC,[FIC,TIC,SIC],RatingIC), next_board(FIC,TIC,N,N1,SIC), mid_rating(N1,C,R1), R is R1 - RatingIC, better_mid([From,To,Spec],R,BestMove,BestRating,Move,Rating). %% %% best_mid(B,C,Moves,Move,Rating) %% best move Move from list Moves for C on B given a mid game strategy %% thinks half a move ahead best_mid(_,_,[],_,0). best_mid(B,C,[[From,To,Spec]|Moves],Move,Rating) :- next_board(From,To,B,N,Spec), mid_rating(N,C,R), best_mid(B,C,Moves,BestMove,BestRating), better_mid([From,To,Spec],R,BestMove,BestRating,Move,Rating). better_mid(BetterMove,BetterRating,_,Rating,BetterMove,BetterRating) :- BetterRating > Rating. better_mid(_,Rating,BetterMove,BetterRating,BetterMove,BetterRating) :- BetterRating >= Rating. %% %% pieces(B,Num) %% Num is number of pieces on board B pieces(B,Num) :- pieces(B,[0,0],Num). pieces(_,[0,8],0). pieces(B,Sx,Num) :- piece_at(B,Sx,0), next_boff(Sx,Next), pieces(B,Next,Num). pieces(B,Sx,Num) :- \+piece_at(B,Sx,0), next_boff(Sx,Next), pieces(B,Next,N), Num is N+1. %% %% mid_rating(B,C,R) %% R is the rating of C on B given a mid game strategy mid_rating(B,C,Rating) :- developed_major_pieces(B,C,R1), castle(B,C,R2), pawn_structure(B,C,R3), piece_values(B,C,R4), center_control(B,C,R5), checked_rating(B,C,R6), Rating is R1+R2+R3+R4+R5+R6. %% %% developed_major_pieces(B,C,R) %% R is the rating of C's major piece development developed_major_pieces(B,black,R) :- developed(B,[0,0],R1), developed(B,[0,1],R2), developed(B,[0,2],R3), developed(B,[0,3],R4), developed(B,[0,4],R5), developed(B,[0,5],R6), developed(B,[0,6],R7), developed(B,[0,7],R8), R is R1+R2+R3+R4+R5+R6+R7+R8. developed_major_pieces(B,white,R) :- developed(B,[7,0],R1), developed(B,[7,1],R2), developed(B,[7,2],R3), developed(B,[7,3],R4), developed(B,[7,4],R5), developed(B,[7,5],R6), developed(B,[7,6],R7), developed(B,[7,7],R8), R is R1+R2+R3+R4+R5+R6+R7+R8. developed(B,Pos,1) :- piece_at(B,Pos,P), abs(P,Pa), ok_developed(Pa). developed(B,Pos,0) :- piece_at(B,Pos,P), abs(P,Pa), \+ok_developed(Pa). ok_developed(0). ok_developed(5). ok_developed(9). %% %% castle(B,C,R) %% R is the rating of C's ability to castle on B castle(B,C,0) :- \+can_castle(B,C). can_castle(B,black) :- % can castle if a rook and king are in place piece_at(B,[0,4],-9), piece_at(B,[0,0],-5). can_castle(B,black) :- \+piece_at(B,[0,0],-5), piece_at(B,[0,4],-9), piece_at(B,[0,7],-5). can_castle(B,white) :- piece_at(B,[7,4],9), piece_at(B,[7,0],5). can_castle(B,white) :- \+piece_at(B,[7,0],5), piece_at(B,[7,4],9), piece_at(B,[7,7],5). castle(B,black,R) :- can_castle(B,black), castle_t(B,[0,1],R1), castle_t(B,[0,2],R2), castle_t(B,[0,3],R3), castle_t(B,[0,5],R4), castle_t(B,[0,6],R5), R is R1+R2+R3+R4+R5. castle(B,white,R) :- can_castle(B,white), castle_t(B,[7,1],R1), castle_t(B,[7,2],R2), castle_t(B,[7,3],R3), castle_t(B,[7,5],R4), castle_t(B,[7,6],R5), R is R1+R2+R3+R4+R5. castle_t(B,Pos,1) :- piece_at(B,Pos,0). castle_t(B,Pos,0) :- \+piece_at(B,Pos,0). %% %% pawn_structure(B,C,R) %% R is the rating of C's pawn structure on B pawn_structure(B,C,R) :- pawn_structure(B,C,R,[-1,0]). pawn_structure(B,C,R,Sx) :- next_pawn(B,C,Sx,Next), eval_pawn(B,Next,C,Rp), pawn_structure(B,C,Rn,Next), R is Rp+Rn. pawn_structure(B,C,0,Sx) :- \+next_pawn(B,C,Sx,_). next_pawn(B,white,Sx,Next) :- next_boff(Sx,Next), piece_at(B,Next,1). next_pawn(B,white,Sx,Next) :- next_boff(Sx,N), legal_pos(N), \+piece_at(B,N,1), next_pawn(B,white,N,Next). next_pawn(B,black,Sx,Next) :- next_boff(Sx,Next), piece_at(B,Next,-1). next_pawn(B,black,Sx,Next) :- next_boff(Sx,N), legal_pos(N), \+piece_at(B,N,-1), next_pawn(B,black,N,Next). eval_pawn(B,At,C,R) :- eval_pawn_l(B,At,C,R1), eval_pawn_r(B,At,C,R2), R is R1+R2. eval_pawn_l(B,[R,C],black,1) :- % +1 if if pawn has pawn to the left protecting it Rx is R-1, Cx is C-1, piece_at(B,[Rx,Cx],-1). eval_pawn_l(B,[R,C],white,1) :- Rx is R+1, Cx is C-1, piece_at(B,[Rx,Cx],1). eval_pawn_l(B,At,C,0) :- \+eval_pawn_l(B,At,C,1). eval_pawn_r(B,[R,C],black,1) :- % +1 if if pawn has pawn to the right protecting it Rx is R-1, Cx is C+1, piece_at(B,[Rx,Cx],-1). eval_pawn_r(B,[R,C],white,1) :- Rx is R+1, Cx is C+1, piece_at(B,[Rx,Cx],1). eval_pawn_r(B,At,C,0) :- \+eval_pawn_r(B,At,C,1). %% %% piece_values(B,C,R) %% R is the rating of C's piece values on B piece_values(B,C,R) :- piece_values(B,C,R,[0,0]). piece_values(_,_,0,[0,8]). piece_values(B,C,R,Sx) :- piece_at(B,Sx,P), color_of(P,C), abs(P,Pa), next_boff(Sx,Next), piece_values(B,C,N,Next), R is Pa + N. piece_values(B,C,R,Sx) :- piece_at(B,Sx,P), \+color_of(P,C), next_boff(Sx,Next), piece_values(B,C,R,Next). %% %% center_control(B,C,R) %% R is the rating of C's control of the center on B center_control(B,C,R) :- poss_moves_to(L1,[3,3],C,B), poss_moves_to(L2,[3,4],C,B), poss_moves_to(L3,[4,3],C,B), poss_moves_to(L4,[4,4],C,B), size_of(L1,R1), size_of(L2,R2), size_of(L3,R3), size_of(L4,R4), R is R1+R2+R3+R4. %% %% checked_rating(B,C,R) %% R is the rating of C's checkedness checked_rating(B,C,0) :- checked(B,C). checked_rating(B,C,100) :- \+checked(B,C). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% CHAI's end game implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% chai(end_game) :- % chai's not really smart enough to write('no implementation'), nl. % get this far anyway .. end_rating(_,_,0). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% book of openings %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% open ruy lopez opening([move([6,4],[4,4],white),move([1,4],[3,4],black),move([7,6],[5,5],white), move([0,1],[2,2],black),move([7,5],[3,1],white),move([1,0],[2,0],black), move([3,1],[4,0],white),move([0,6],[2,5],white),move([7,4],[7,6],white), move([2,6],[4,4],black)]). %% closed ruy lopez opening([move([6,4],[4,4],white),move([1,4],[3,4],black),move([7,6],[5,5],white), move([0,1],[2,2],black),move([7,5],[3,1],white),move([1,0],[2,0],black), move([3,1],[4,0],white),move([0,6],[2,5],white),move([7,4],[7,6],white), move([0,5],[1,4],black)]). %% open giuoco piano opening([move([6,4],[4,4],white),move([1,4],[3,4],black),move([7,6],[5,5],white), move([0,1],[2,2],black),move([7,5],[4,2],white),move([0,5],[3,2],black), move([6,2],[5,2],white),move([0,6],[5,5],black),move([6,3],[4,3],white), move([3,4],[4,3],black)]). %% closed giuoco piano opening([move([6,4],[4,4],white),move([1,4],[3,4],black),move([7,6],[5,5],white), move([0,1],[2,2],black),move([7,5],[4,2],white),move([0,5],[3,2],black), move([6,2],[5,2],white),move([0,3],[1,4],black),move([6,3],[4,3],white), move([3,2],[2,1],black)]). %% evan's gambit opening([move([6,4],[4,4],white),move([1,4],[3,4],black),move([7,6],[5,5],white), move([0,1],[2,2],black),move([7,5],[4,2],white),move([0,5],[3,2],black), move([6,1],[4,1],white)]). %% dragon sicilian opening([move([6,4],[4,4],white),move([1,2],[3,2],black),move([7,6],[5,5],white), move([1,3],[2,3],black),move([6,3],[4,3],white),move([3,2],[4,3],black), move([5,5],[4,3],white),move([0,6],[2,5],black),move([7,1],[5,2],white), move([1,6],[2,6],black),move([7,2],[5,4],white),move([0,5],[1,6],black), move([7,3],[6,3],white),move([0,4],[0,6],black),move([7,4],[7,2],white)]). %% najdorf sicilian opening([move([6,4],[4,4],white),move([1,2],[3,2],black),move([7,6],[5,5],white), move([1,3],[2,3],black),move([6,3],[4,3],white),move([3,2],[4,3],black), move([5,5],[4,3],white),move([0,6],[2,5],black),move([7,1],[5,2],white), move([1,0],[2,0],black),move([7,5],[6,4],white),move([0,5],[1,4],black), move([7,2],[5,4],white)]). %% queen's gambit declined opening([move([6,3],[4,3],white),move([1,3],[3,3],black),move([6,2],[4,2],white), move([1,4],[3,4],black),move([7,1],[5,2],white),move([0,6],[2,5],black), move([7,2],[3,6],white),move([0,5],[1,4],black),move([6,4],[5,4],white)]). %% queen's gambit opening([move([6,3],[4,3],white),move([1,3],[3,3],black),move([6,2],[4,2],white), move([3,3],[4,2],black),move([7,6],[5,5],white),move([0,6],[2,5],black), move([6,4],[5,4],white)]).