:- dynamic board/1 . board(no). player(x). player(o). turn(B,x) :- count(B,x,C), count(B,o,C). turn(B,o) :- count(B,x,Cx), Co is Cx - 1, count(B,o,Co). win(B,P) :- player(P), row(B,R), tuple_count(R,P,3). subscript((Item,X,Y),0,Item,(X,Y)). subscript((Y,Item,X),1,Item,(X,Y)). subscript((X,Y,Item),2,Item,(X,Y)). count((R1,R2,R3),P,C) :- tuple_count(R1, P, C1) , tuple_count(R2, P, C2) , tuple_count(R3, P, C3) , C is C1 + C2 + C3 , ! . print_winner(B) :- win(B, P), write(P), write(' wins!'),!. print_winner(_). print_row((X,Y,Z)) :- write(X), write('|'), write(Y), write('|'), write(Z), nl. print_board((X,Y,Z)) :- print_row(X) , write('-+-+-') , nl , print_row(Y) , write('-+-+-') , nl , print_row(Z) , print_winner((X,Y,Z)) . tuple_count((P,P,P), P, 3). tuple_count((P,P,_), P, 2). tuple_count((P,_,P), P, 2). tuple_count((_,P,P), P, 2). tuple_count((P,_,_), P, 1). tuple_count((_,P,_), P, 1). tuple_count((_,_,P), P, 1). tuple_count(_,_,0). row((Fst,_,_),Fst). row((_,Snd,_),Snd). row((_,_,Thd),Thd). row(((X,_,_),(Y,_,_),(Z,_,_)),(X,Y,Z)). row(((_,X,_),(_,Y,_),(_,Z,_)),(X,Y,Z)). row(((_,_,X),(_,_,Y),(_,_,Z)),(X,Y,Z)). row(((X,_,_),(_,Y,_),(_,_,Z)),(X,Y,Z)). row(((_,_,X),(_,Y,_),(Z,_,_)),(X,Y,Z)). can_move(B,(X,Y)) :- \+ win(B,_), subscript(B,Y,R,_), subscript(R,X,' ',_). do_move(B1,(X,Y),B2) :- turn(B1,P) , subscript(B1,Y,R1,Rows) , subscript(R1,X,' ',Items) , subscript(R2,X,P,Items) , subscript(B2,Y,R2,Rows) . move(B1,(X,Y),'',B2) :- can_move(B1, (X,Y)), do_move(B1,(X,Y),B2),!. move(B,_,'cannot move there',B). start_game :- B = ((' ', ' ', ' '),(' ', ' ', ' '),(' ', ' ', ' ')) , retract(board(_)) , asserta(board(B)) , print_board(B) . move(X,Y) :- board(B1) , move(B1,(X,Y),M,B2) , write(M) , nl , retract(board(_)) , asserta(board(B2)) , print_board(B2) .