Skip to content

Instantly share code, notes, and snippets.

@andy-williams
Created June 23, 2015 17:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andy-williams/f0fc7357d4433276c47a to your computer and use it in GitHub Desktop.
Save andy-williams/f0fc7357d4433276c47a to your computer and use it in GitHub Desktop.
Some old code I've written during my time in University. This is a tic-tact-toe game written entirely in prolog. Includes board generator and support for 2 players.
/*************************************************
* CHA 2555 - ARTIFICIAL INTELLIGENCE (2012-2013)
* Andrew Williams
* u0857629@unimail.hud.ac.uk
* BSc (Hons) Software Development
************************************************/
/********
* XOXO
********
XOXO is a game that is a modified version of the classic tic-tac-toe game.
AI player uses a minimax implementation for making decisions.
********
* Rules
********
as per the classic tic-tac-toe game, the symbols for each player are 'x' and 'o' where 'x' always starts first.
In order to win, a player needs to have four of their own symbol in a line
for example:
| x | x | x | x |
or
|x|
|x|
|x|
|x|
or
|x||0||0||0|
|0||x||0||0|
|0||0||x||0|
|0||0||0||x|
*************
* Variables
**************
B - Board
P - Player (human or computer)
PS - Player Symbol (x or o)
D - Depth of minimax search tree
***************
* Facts
**************/
% the number of the next player
next_player(x, o).
next_player(o, x).
% human and computer players declaration
player(x, human).
player(o, computer).
% empty symbol
empty_symbol(e).
/*********
* GAME
*********/
default_game :-
make_board(4,4,B), !,
game(B).
game(B) :-
game(B, x).
game(B, PS) :-
pretty_print(B),
next_player(PS, PS1),
write('Checking if '),
write(PS1), write(' has won...'), nl,
fail.
% Win through horizontal matching
game(B, PS) :-
next_player(PS, PS1),
horizontal(PS1, B),
write('Player '), write(PS1),
write(' has won the game.'), nl.
% Win through vertical matching
game(B, PS) :-
next_player(PS, PS1),
vertical(PS1, B),
write('Player '), write(PS1),
write(' has won the game.'), nl.
% Win through diagonal matching
game(B, PS) :-
next_player(PS, PS1),
diagonal(PS1, B),
write('Player '), write(PS1),
write(' has won the game.'), nl.
game(B, PS) :-
player(PS, P),
make_move(PS, P, B, B_out),
next_player(PS, NPS),
game(B_out, NPS), !.
% Human's turn
make_move(PS, human, B_in, B_out) :-
write('Player '), write(PS), write(':'), nl,
write('Type in where you want to place a disc mark(X,Y).'),
nl,
read(mark(X,Y)),nl,
mark(x(X, Y, PS), B_in, B_out).
% Computer's turn
make_move(PS, computer, B_in, B_out) :-
write('Computer is thinking for a move...'),nl,
write('Type in where you want to place a disc mark(X,Y).'),
nl,
read(mark(X,Y)),nl,
mark(x(X, Y, PS), B_in, B_out).
% Mark a cell in the board
mark(x(X, Y, PS), B_in, B_out) :-
valid_mark_placement(X,Y,B_in),
empty_symbol(E),
remove(x(X,Y,E), B_in, B_new),
append([x(X,Y,PS)], B_new, B_out).
% Valid if it's an empty symbol
valid_mark_placement(X,Y,B) :-
empty_symbol(E),
member(x(X,Y,E), B).
/**********
* TESTS
*********/
game_win_vertical :-
make_board(6,6,B),!,
mark(x(1,1,x), B, B1),
mark(x(2,1,x), B1, B2),
mark(x(3,1,x), B2, B3),
mark(x(4,1,x), B3, B4),
game(B4, o).
game_win_vertical_2 :-
make_board(6,6,B),!,
mark(x(1,2,x), B, B1),
mark(x(2,2,x), B1, B2),
mark(x(3,2,x), B2, B3),
mark(x(4,2,x), B3, B4),
game(B4, o).
game_win_horizontal :-
make_board(4,4,B),!,
mark(x(1,1,x), B, B1),
mark(x(1,2,x), B1, B2),
mark(x(1,3,x), B2, B3),
mark(x(1,4,x), B3, B4),
game(B4, o).
game_win_horizontal_2 :-
make_board(4,4,B),!,
mark(x(2,1,x), B, B1),
mark(x(2,2,x), B1, B2),
mark(x(2,3,x), B2, B3),
mark(x(2,4,x), B3, B4),
game(B4, o).
game_win_diagonal :-
make_board(6,6,B),!,
mark(x(1,1,x), B, B1),
mark(x(2,2,x), B1, B2),
mark(x(3,3,x), B2, B3),
mark(x(4,4,x), B3, B4),
game(B4, o).
game_win_diagonal_2 :-
make_board(6,6,B),!,
mark(x(1,4,x), B, B1),
mark(x(2,3,x), B1, B2),
mark(x(3,2,x), B2, B3),
mark(x(4,1,x), B3, B4),
pretty_print(B4),
game(B4, o).
/*********
END GAME
*********/
/***********************
* LINE MATCHER:
***********************
Used for finding Symbols
that create Horizontal,
Vertical and Diagonal
lines
*/
% Check if Player Symbol makes a horizontal line
horizontal(PS, B) :-
write('Checking horizontally...'), nl,
member(x(X, Y, PS), B),
Y1 is Y+1, Y2 is Y+2, Y3 is Y+3,
member(x(X, Y1, PS), B),
member(x(X, Y2, PS), B),
member(x(X, Y3, PS), B).
% Check if Player Symbol makes a vertical line
vertical(PS, B) :-
write('Checking vertically...'), nl,
member(x(X, Y, PS), B),
X1 is X+1, X2 is X+2, X3 is X+3,
member(x(X1, Y, PS), B),
member(x(X2, Y, PS), B),
member(x(X3, Y, PS), B).
% Check if Player Symbol makes a diagonal line
diagonal(PS, B) :-
write('Checking diagonally...'), nl,
member(x(X, Y, PS), B),
X1 is X+1, X2 is X+2, X3 is X+3,
Y1 is Y+1, Y2 is Y+2, Y3 is Y+3,
member(x(X1, Y1, PS), B),
member(x(X2, Y2, PS), B),
member(x(X3, Y3, PS), B).
diagonal(PS, B) :-
write('Checking diagonally...'), nl,
member(x(X, Y, PS), B),
X1 is X+1, X2 is X+2, X3 is X+3,
Y1 is Y-1, Y2 is Y-2, Y3 is Y-3,
member(x(X1, Y1, PS), B),
member(x(X2, Y2, PS), B),
member(x(X3, Y3, PS), B).
/*********
* TESTS
********/
test_vertical :-
make_board(6,6,B),!,
mark(x(1,1,x), B, B1),
mark(x(2,1,x), B1, B2),
mark(x(3,1,x), B2, B3),
mark(x(4,1,x), B3, B4),
vertical(x, B4).
test_vertical_2 :-
make_board(6,6,B),!,
mark(x(1,2,x), B, B1),
mark(x(2,2,x), B1, B2),
mark(x(3,2,x), B2, B3),
mark(x(4,2,x), B3, B4),
vertical(x, B4).
test_horizontal :-
make_board(4,4,B),!,
mark(x(1,1,x), B, B1),
mark(x(1,2,x), B1, B2),
mark(x(1,3,x), B2, B3),
mark(x(1,4,x), B3, B4),
horizontal(x, B4).
test_horizontal_2 :-
make_board(4,4,B),!,
mark(x(2,1,x), B, B1),
mark(x(2,2,x), B1, B2),
mark(x(2,3,x), B2, B3),
mark(x(2,4,x), B3, B4),
horizontal(x, B4).
test_diagonal :-
make_board(6,6,B),!,
mark(x(1,1,x), B, B1),
mark(x(2,2,x), B1, B2),
mark(x(3,3,x), B2, B3),
mark(x(4,4,x), B3, B4),
pretty_print(B4),
diagonal(x, B4).
test_diagonal_2 :-
make_board(6,6,B),!,
mark(x(1,4,x), B, B1),
mark(x(2,3,x), B1, B2),
mark(x(3,2,x), B2, B3),
mark(x(4,1,x), B3, B4),
pretty_print(B4),
diagonal(x, B4).
/*******************
* END LINE MATCHER
*******************/
/*******************
* BOARD GENERATOR
********************
Used for generating boards automatically.
*************
* Variables
**************
W - Width
H - Height
I - used for controlling row recursions
J - used for controlling col recursions
B_out - board output
B_in - board input
*/
%Generate a board
make_board(W, H, B_out) :-
nl,
write('Generating board...'),
make_board(W, H, 1, [], B_out).
% End if J == H + 1.
make_board(W, H, I, B_in, B_out) :-
write(I), write(' is the value of I'), nl,
H1 is H+1,
I == H1,
% Assign the last board modication as our board output
B_out = B_in.
% Recursive - make_board until J == H + 1
make_board(W, H, I, B_in, B_out) :-
add_row(W, I, 1, B_in, B_new),
I1 is I+1,
make_board(W, H, I1, B_new, B_out).
% End if J == W+1
add_row(W, I, J, B_in, B_out) :-
write(J), write(' is the value of J'), nl,
W1 is W+1,
J == W1,
% Assign the last board modication as our board output
B_out = B_in.
% Recursive - add_row until J == W+1.
add_row(W, I, J, B_in, B_out) :-
empty_symbol(E),
append([x(I,J,E)], B_in, B_new),
J1 is J+1,
add_row(W, I, J1, B_new, B_out).
/*********
* TESTS
********/
test_board_gen :-
test_board_gen(4, 4).
test_board_gen_2 :-
test_board_gen(6, 6).
test_board_gen(W, H) :-
make_board(W, H, B), pretty_print(B).
/**********************
* END BOARD GENERATOR
**********************/
% GENERAL UTILITIES
% remove(a,l,m) - a is a member of l, m is l without a
remove(X, [X|Y], Y) :-!.
remove(X, [X1|Y], [X1|Z]) :- remove(X,Y,Z),!.
member(X,[X|_]).
member(X,[_|L]) :- member(X,L).
pretty_print(B):-
nl,
print_each_row(1, B),
nl.
% finished if no elements in row "I" in board:
print_each_row(I,B) :-
\+ member(x(I,_,_),B),!.
print_each_row(I,B) :-
print_out_row(I,1,B),
J is I+1,
print_each_row(J,B),!.
print_out_row(I,J,B) :-
member(x(I,J,Piece),B),
write(Piece),write(' '),
J1 is J+1,
print_out_row(I,J1,B).
% to get here means we have got to the end ..
print_out_row(_,_,_) :-
nl.
testp :- get_board(medium,B), pretty_print(B).
/*******
* END
*******/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment