/** * Adapted version of Tic-Tac-Toe, found in 'Programming Language Pragmatics' * by M.L. Scott. * * The underlying logic is the same; however, this version is significantly * different as it does not rely on global data. * * Adapted for course work; all rights reserved, copyright 2009, Peter Goodman. */ % utility not(A) :- call(A), !, fail. not(_). same(A,A). different(A,B) :- not(same(A,B)). % define the cells of the game board cell(1). cell(2). cell(3). cell(4). cell(5). cell(6). cell(7). cell(8). cell(9). % all legal winning lines ordered_line(1, 2, 3). ordered_line(4, 5, 6). ordered_line(7, 8, 9). ordered_line(1, 4, 7). ordered_line(2, 5, 8). ordered_line(3, 6, 9). ordered_line(1, 5, 9). ordered_line(7, 5, 3). % all permutations of A, B, C line(A, B, C) :- ordered_line(C, B, A). line(A, B, C) :- ordered_line(A, B, C). line(A, B, C) :- ordered_line(A, C, B). line(A, B, C) :- ordered_line(B, C, A). line(A, B, C) :- ordered_line(B, A, C). line(A, B, C) :- ordered_line(C, A, B). % check if the nth element of a list is X nth_state(X,[X|_],1). nth_state(X,[_|L],N) :- N1 is N - 1, nth_state(X,L,N1). % set the nth element of a list to X set_nth_state(1, [_|T], X, [X|T]). set_nth_state(N, [H|T], X, [H|Ts]) :- N1 is N - 1, set_nth_state(N1, T, X, Ts). % game state empty(N, State) :- cell(N), nth_state(0, State, N). x(N, State) :- cell(N), nth_state(x,State,N). o(N, State) :- cell(N), nth_state(o,State,N). all_full([]). all_full([x|T]) :- all_full(T). all_full([o|T]) :- all_full(T). % print game board print_cell(0) :- write(' '). print_cell(x) :- write(' x '). print_cell(o) :- write(' o '). sep :- write('|'). sei :- write('---+---+---'). print_board([A,B,C,D,E,F,G,H,I]) :- print_cell(A), sep, print_cell(B), sep, print_cell(C), nl, sei, nl, print_cell(D), sep, print_cell(E), sep, print_cell(F), nl, sei, nl, print_cell(G), sep, print_cell(H), sep, print_cell(I), nl, !. % strategy good(A, S) :- win(A, S). good(A, S) :- block_win(A, S). good(A, S) :- split(A, S). good(A, S) :- block_split(A, S). good(A, S) :- build(A, S). good(A, _) :- bad(A). bad(5). bad(1). bad(3). bad(7). bad(9). bad(2). bad(4). bad(6). bad(8). win(A, S) :- x(B, S), x(C, S), line(A,B,C). block_win(A, S) :- o(B, S), o(C, S), line(A,B,C). split(A, S) :- x(B, S), x(C, S), different(B,C), line(A,B,D), line(A,C,E), empty(D, S), empty(E, S). block_split(A, S) :- o(B, S), o(C, S), different(B,C), line(A,B,D), line(A,C,E), empty(D, S), empty(E, S). build(A, S) :- x(B, S), line(A,B,C), empty(C, S). % game over? game_over(S) :- ordered_line(A,B,C), x(A,S), x(B,S), x(C,S), nl, write('x wins!'), nl. game_over(S) :- ordered_line(A,B,C), o(A,S), o(B,S), o(C,S), nl, write('o wins!'), nl. game_over(S) :- all_full(S), nl, write('draw!'), nl. % moves user_move(State, NewState) :- repeat, write('Please enter a move: '), read(N), empty(N, State), !, set_nth_state(N, State, o, NewState). comp_move(State, NewState) :- write('o is making a move...'), nl, good(N, State), empty(N, State), !, set_nth_state(N, State, x, NewState). % run the game play :- user_loop([0,0,0,0,0,0,0,0,0]). continue_playing(State) :- print_board(State), !, not(game_over(State)). user_loop(State) :- continue_playing(State), !, user_move(State, NewState), comp_loop(NewState). user_loop(_). comp_loop(State) :- continue_playing(State), !, comp_move(State, NewState), user_loop(NewState). game_loop(_).