%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Prolog TicTacToe alpha-beta expert %% Design to play against human (Java GUI) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% The empty Tac Tac Toe board %% Z1 Z2 Z3 %% Z4 Z5 Z6 ~ [Z1,Z2,Z3,Z4,Z5,Z6,Z7,Z8,Z9] %% Z7 Z8 Z9 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% :- dynamic board/1. init:- retractall(board(_)), assert(board([_Z1,_Z2,_Z3,_Z4,_Z5,_Z6,_Z7,_Z8,_Z9])). :- init. %%%%% %% Generate possible marks on a free spot on the board. %% Use mark(+,+,-X,-Y) to query/generate possible moves (X,Y). %%%%% mark(Player, [X|_],1,1) :- var(X), X=Player. mark(Player, [_,X|_],2,1) :- var(X), X=Player. mark(Player, [_,_,X|_],3,1) :- var(X), X=Player. mark(Player, [_,_,_,X|_],1,2) :- var(X), X=Player. mark(Player, [_,_,_,_,X|_],2,2) :- var(X), X=Player. mark(Player, [_,_,_,_,_,X|_],3,2) :- var(X), X=Player. mark(Player, [_,_,_,_,_,_,X|_],1,3) :- var(X), X=Player. mark(Player, [_,_,_,_,_,_,_,X|_],2,3) :- var(X), X=Player. mark(Player, [_,_,_,_,_,_,_,_,X|_],3,3) :- var(X), X=Player. %%%%% %% Move %%%%% move(P,(1,1),[X1|R],[P|R]) :- var(X1). move(P,(2,1),[X1,X2|R],[X1,P|R]) :- var(X2). move(P,(3,1),[X1,X2,X3|R],[X1,X2,P|R]) :- var(X3). move(P,(1,2),[X1,X2,X3,X4|R],[X1,X2,X3,P|R]) :- var(X4). move(P,(2,2),[X1,X2,X3,X4,X5|R],[X1,X2,X3,X4,P|R]) :- var(X5). move(P,(3,2),[X1,X2,X3,X4,X5,X6|R],[X1,X2,X3,X4,X5,P|R]) :- var(X6). move(P,(1,3),[X1,X2,X3,X4,X5,X6,X7|R],[X1,X2,X3,X4,X5,X6,P|R]) :- var(X7). move(P,(2,3),[X1,X2,X3,X4,X5,X6,X7,X8|R],[X1,X2,X3,X4,X5,X6,X7,P|R]) :- var(X8). move(P,(3,3),[X1,X2,X3,X4,X5,X6,X7,X8,X9|R],[X1,X2,X3,X4,X5,X6,X7,X8,P|R]) :- var(X9). %%%%% %% Record a move: record(+,+,+). %%%%% record(Player,X,Y) :- retract(board(B)), mark(Player,B,X,Y), assert(board(B)). %%%%% %% A winning line is ALREADY bound to Player. %% win(+Board,+Player) is true or fail. %% e.g., win([P,P,P|_],P). is NOT correct, because could bind %%%%% win([Z1,Z2,Z3|_],P) :- Z1==P, Z2==P, Z3==P. win([_,_,_,Z1,Z2,Z3|_],P) :- Z1==P, Z2==P, Z3==P. win([_,_,_,_,_,_,Z1,Z2,Z3],P) :- Z1==P, Z2==P, Z3==P. win([Z1,_,_,Z2,_,_,Z3,_,_],P) :- Z1==P, Z2==P, Z3==P. win([_,Z1,_,_,Z2,_,_,Z3,_],P) :- Z1==P, Z2==P, Z3==P. win([_,_,Z1,_,_,Z2,_,_,Z3],P) :- Z1==P, Z2==P, Z3==P. win([Z1,_,_,_,Z2,_,_,_,Z3],P) :- Z1==P, Z2==P, Z3==P. win([_,_,Z1,_,Z2,_,Z3,_,_],P) :- Z1==P, Z2==P, Z3==P. %%%%% %% A line is open if each position is either free or equals the Player %%%%% open([Z1,Z2,Z3|_],Player) :- (var(Z1) | Z1 == Player),(var(Z2) | Z2 == Player), (var(Z3) | Z3 == Player). open([_,_,_,Z1,Z2,Z3|_],Player) :- (var(Z1) | Z1 == Player),(var(Z2) | Z2 == Player), (var(Z3) | Z3 == Player). open([_,_,_,_,_,_,Z1,Z2,Z3],Player) :- (var(Z1) | Z1 == Player),(var(Z2) | Z2 == Player), (var(Z3) | Z3 == Player). open([Z1,_,_,Z2,_,_,Z3,_,_],Player) :- (var(Z1) | Z1 == Player),(var(Z2) | Z2 == Player), (var(Z3) | Z3 == Player). open([_,Z1,_,_,Z2,_,_,Z3,_],Player) :- (var(Z1) | Z1 == Player),(var(Z2) | Z2 == Player), (var(Z3) | Z3 == Player). open([_,_,Z1,_,_,Z2,_,_,Z3],Player) :- (var(Z1) | Z1 == Player),(var(Z2) | Z2 == Player), (var(Z3) | Z3 == Player). open([Z1,_,_,_,Z2,_,_,_,Z3],Player) :- (var(Z1) | Z1 == Player),(var(Z2) | Z2 == Player), (var(Z3) | Z3 == Player). open([_,_,Z1,_,Z2,_,Z3,_,_],Player) :- (var(Z1) | Z1 == Player),(var(Z2) | Z2 == Player), (var(Z3) | Z3 == Player). %%%%% %% Calculate the value of a position, o maximizes, x minimizes. %%%%% value(Board,100) :- win(Board,o), !. value(Board,-100) :- win(Board,x), !. value(Board,E) :- findall(o,open(Board,o),MAX), length(MAX,Emax), % # lines open to o findall(x,open(Board,x),MIN), length(MIN,Emin), % # lines open to x E is Emax - Emin. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % using minimax procedure with alpha-beta cutoff. % Computer (o) searches for best tic tac toe move, % Human player is x. % Adapted from L. Sterling and E. Shapiro, The Art of Prolog, MIT Press, 1986. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% :- assert(lookahead(2)). :- dynamic spy/0. % debug calls to alpha_beta :- assert(spy). % Comment out stop spy. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% search(Position,Depth,(Move,Value)) :- alpha_beta(o,Depth,Position,-100,100,Move,Value). alpha_beta(Player,0,Position,_Alpha,_Beta,_NoMove,Value) :- value(Position,Value), spy(Player,Position,Value). alpha_beta(Player,D,Position,Alpha,Beta,Move,Value) :- D > 0, findall((X,Y),mark(Player,Position,X,Y),Moves), Alpha1 is -Beta, % max/min Beta1 is -Alpha, D1 is D-1, evaluate_and_choose(Player,Moves,Position,D1,Alpha1,Beta1,nil,(Move,Value)). evaluate_and_choose(Player,[Move|Moves],Position,D,Alpha,Beta,Record,BestMove) :- move(Player,Move,Position,Position1), other_player(Player,OtherPlayer), alpha_beta(OtherPlayer,D,Position1,Alpha,Beta,_OtherMove,Value), Value1 is -Value, cutoff(Player,Move,Value1,D,Alpha,Beta,Moves,Position,Record,BestMove). evaluate_and_choose(_Player,[],_Position,_D,Alpha,_Beta,Move,(Move,Alpha)). cutoff(_Player,Move,Value,_D,_Alpha,Beta,_Moves,_Position,_Record,(Move,Value)) :- Value >= Beta, !. cutoff(Player,Move,Value,D,Alpha,Beta,Moves,Position,_Record,BestMove) :- Alpha < Value, Value < Beta, !, evaluate_and_choose(Player,Moves,Position,D,Value,Beta,Move,BestMove). cutoff(Player,_Move,Value,D,Alpha,Beta,Moves,Position,Record,BestMove) :- Value =< Alpha, !, evaluate_and_choose(Player,Moves,Position,D,Alpha,Beta,Record,BestMove). other_player(o,x). other_player(x,o). spy(Player,Position,Value) :- spy, !, write(Player), write(' '), write(Position), write(' '), writeln(Value). spy(_,_,_). % do nothing %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% For testing, use h(+,+) to record human move, %%% supply coordinates. Then call c (computer plays). %%% Use s to show board. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% h(X,Y) :- record(x,X,Y), showBoard. c :- board(B), alpha_beta(o,2,B,-200,200,(X,Y),_Value), record(o,X,Y), showBoard. showBoard :- board([Z1,Z2,Z3,Z4,Z5,Z6,Z7,Z8,Z9]), write(' '),mark(Z1),write(' '),mark(Z2),write(' '),mark(Z3),nl, write(' '),mark(Z4),write(' '),mark(Z5),write(' '),mark(Z6),nl, write(' '),mark(Z7),write(' '),mark(Z8),write(' '),mark(Z9),nl. s :- showBoard. mark(X) :- var(X), write('#'). mark(X) :- \+var(X), write(X). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Play tic tac toe with the Java GUI %%% using port 54321. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% connect(Port) :- tcp_socket(Socket), gethostname(Host), % local host tcp_connect(Socket,Host:Port), tcp_open_socket(Socket,INs,OUTs), assert(connectedReadStream(INs)), assert(connectedWriteStream(OUTs)). :- connect(54321). % Comment out for testing ttt :- connectedReadStream(IStream), read(IStream,(X,Y)), record(x,X,Y), board(B), alpha_beta(o,2,B,-200,200,(U,V),_Value), record(o,U,V), connectedWriteStream(OStream), write(OStream,(U,V)), nl(OStream), flush_output(OStream), ttt. :- ttt. % Comment out for testing