112 lines
3 KiB
Text
112 lines
3 KiB
Text
# Play TicTacToe
|
|
|
|
$define E " " # empty square
|
|
$define X "X" # X piece
|
|
$define O "O" # O piece
|
|
|
|
# -- define a board
|
|
record Board(a, b, c, d, e, f, g, h, i)
|
|
|
|
procedure display_board (board, player)
|
|
write ("\n===============")
|
|
write (board.a || " | " || board.b || " | " || board.c)
|
|
write ("---------")
|
|
write (board.d || " | " || board.e || " | " || board.f)
|
|
write ("---------")
|
|
write (board.g || " | " || board.h || " | " || board.i)
|
|
end
|
|
|
|
# return a set of valid moves (empty positions) in given board
|
|
procedure empty_fields (board)
|
|
fields := set()
|
|
every i := !fieldnames(board) do
|
|
if (board[i] == E) then insert (fields, i)
|
|
return fields
|
|
end
|
|
|
|
procedure game_start ()
|
|
return Board (E, E, E, E, E, E, E, E, E)
|
|
end
|
|
|
|
procedure game_is_drawn (board)
|
|
return *empty_fields(board) = 0
|
|
end
|
|
|
|
procedure game_won_by (board, player)
|
|
return (board.a == board.b == board.c == player) |
|
|
(board.d == board.e == board.f == player) |
|
|
(board.g == board.h == board.i == player) |
|
|
(board.a == board.d == board.g == player) |
|
|
(board.b == board.e == board.h == player) |
|
|
(board.c == board.f == board.i == player) |
|
|
(board.a == board.e == board.i == player) |
|
|
(board.g == board.e == board.c == player)
|
|
end
|
|
|
|
procedure game_over (board)
|
|
return game_is_drawn (board) | game_won_by (board, O) | game_won_by (board, X)
|
|
end
|
|
|
|
# -- players make their move on the board
|
|
# assume there is at least one empty square
|
|
|
|
procedure human_move (board, player)
|
|
choice := "z"
|
|
options := empty_fields (board)
|
|
# keep prompting until player selects a valid square
|
|
until member (options, choice) do {
|
|
writes ("Choose one of: ")
|
|
every writes (!options || " ")
|
|
writes ("\n> ")
|
|
choice := read ()
|
|
}
|
|
board[choice] := player
|
|
end
|
|
|
|
# pick and make a move at random from empty positions
|
|
procedure random_move (board, player)
|
|
board[?empty_fields(board)] := player
|
|
end
|
|
|
|
# -- manage the game play
|
|
procedure play_game ()
|
|
# hold procedures for players' move in variables
|
|
player_O := random_move
|
|
player_X := human_move
|
|
|
|
# randomly determine if human or computer moves first
|
|
if (?2 = 0)
|
|
then {
|
|
write ("Human plays first as O")
|
|
player_O := human_move
|
|
player_X := random_move
|
|
}
|
|
else write ("Computer plays first, human is X")
|
|
|
|
# set up the game to start
|
|
board := game_start ()
|
|
player := O
|
|
display_board (board, player)
|
|
# loop until the game is over, getting each player to move in turn
|
|
until game_over (board) do {
|
|
write (player || " to play next")
|
|
# based on player, prompt for the next move
|
|
if (player == O)
|
|
then (player_O (board, player))
|
|
else (player_X (board, player))
|
|
# change player to move
|
|
player := if (player == O) then X else O
|
|
display_board (board, player)
|
|
}
|
|
# finish by writing out result
|
|
if game_won_by (board, O)
|
|
then write ("O won")
|
|
else if game_won_by (board, X)
|
|
then write ("X won")
|
|
else write ("draw") # neither player won, so must be a draw
|
|
end
|
|
|
|
# -- get things started
|
|
procedure main ()
|
|
play_game ()
|
|
end
|