180 lines
6.9 KiB
Text
180 lines
6.9 KiB
Text
begin
|
|
|
|
string(10) board;
|
|
|
|
% initialise the board %
|
|
procedure initBoard ; board := " 123456789";
|
|
|
|
% display the board %
|
|
procedure showBoard ;
|
|
begin
|
|
s_w := 0;
|
|
write( board(1//1), "|", board(2//1), "|", board(3//1) );
|
|
write( "-+-+-" );
|
|
write( board(4//1), "|", board(5//1), "|", board(6//1) );
|
|
write( "-+-+-" );
|
|
write( board(7//1), "|", board(8//1), "|", board(9//1) )
|
|
end showBoard ;
|
|
|
|
% returns true if board pos is free, false otherwise %
|
|
logical procedure freeSpace( integer value pos ) ;
|
|
( board(pos//1) >= "1" and board(pos//1) <= "9" );
|
|
|
|
% check for game over %
|
|
logical procedure gameOver ;
|
|
begin
|
|
logical noMoves;
|
|
noMoves := true;
|
|
for i := 1 until 9 do if noMoves then noMoves := not freeSpace( i );
|
|
noMoves
|
|
end gameOver ;
|
|
|
|
% makes the specified winning move or blocks it, if it will win %
|
|
logical procedure winOrBlock( integer value pos1, pos2, pos3
|
|
; string(1) value searchCharacter
|
|
; string(1) value playerCharacter
|
|
) ;
|
|
if board(pos1//1) = searchCharacter
|
|
and board(pos2//1) = searchCharacter
|
|
and freeSpace( pos3 )
|
|
then begin
|
|
board(pos3//1) := playerCharacter;
|
|
true
|
|
end
|
|
else if board(pos1//1) = searchCharacter
|
|
and freeSpace( pos2 )
|
|
and board(pos3//1) = searchCharacter
|
|
then begin
|
|
board(pos2//1) := playerCharacter;
|
|
true
|
|
end
|
|
else if freeSpace( pos1 )
|
|
and board(pos2//1) = searchCharacter
|
|
and board(pos3//1) = searchCharacter
|
|
then begin
|
|
board(pos1//1) := playerCharacter;
|
|
true
|
|
end
|
|
else begin
|
|
false
|
|
end winOrBlock ;
|
|
|
|
% makes a winning move or blocks a winning move, if there is one %
|
|
logical procedure makeOrBlockWinningMove( string(1) value searchCharacter
|
|
; string(1) value playerCharacter
|
|
) ;
|
|
( winOrBlock( 1, 2, 3, searchCharacter, playerCharacter )
|
|
or winOrBlock( 4, 5, 6, searchCharacter, playerCharacter )
|
|
or winOrBlock( 7, 8, 9, searchCharacter, playerCharacter )
|
|
or winOrBlock( 1, 4, 7, searchCharacter, playerCharacter )
|
|
or winOrBlock( 2, 5, 8, searchCharacter, playerCharacter )
|
|
or winOrBlock( 3, 6, 9, searchCharacter, playerCharacter )
|
|
or winOrBlock( 1, 5, 9, searchCharacter, playerCharacter )
|
|
or winOrBlock( 3, 5, 7, searchCharacter, playerCharacter )
|
|
) ;
|
|
|
|
% makes a move when there isn't an obvious winning/blocking move %
|
|
procedure move ( string(1) value playerCharacter ) ;
|
|
begin
|
|
logical moved;
|
|
moved := false;
|
|
% try for the centre, a corner or the midle of a line %
|
|
for pos := 5, 1, 3, 7, 9, 2, 4, 6, 8 do begin
|
|
if not moved and freeSpace( pos ) then begin
|
|
moved := true;
|
|
board(pos//1) := playerCharacter
|
|
end
|
|
end
|
|
end move ;
|
|
|
|
% gets a move from the user %
|
|
procedure userMove( string(1) value playerCharacter ) ;
|
|
begin
|
|
integer move;
|
|
while
|
|
begin
|
|
write( "Please enter the move for ", playerCharacter, " " );
|
|
read( move );
|
|
( move < 1 or move > 9 or not freeSpace( move ) )
|
|
end
|
|
do begin
|
|
write( "Invalid move" )
|
|
end;
|
|
board(move//1) := playerCharacter
|
|
end userMove ;
|
|
|
|
% returns true if the three board positions have the player character, %
|
|
% false otherwise %
|
|
logical procedure same( integer value pos1, pos2, pos3
|
|
; string(1) value playerCharacter
|
|
) ;
|
|
( board(pos1//1) = playerCharacter
|
|
and board(pos2//1) = playerCharacter
|
|
and board(pos3//1) = playerCharacter
|
|
);
|
|
|
|
% returns true if the player has made a winning move, false otherwise %
|
|
logical procedure playerHasWon( string(1) value playerCharacter ) ;
|
|
( same( 1, 2, 3, playerCharacter )
|
|
or same( 4, 5, 6, playerCharacter )
|
|
or same( 7, 8, 9, playerCharacter )
|
|
or same( 1, 4, 7, playerCharacter )
|
|
or same( 2, 5, 8, playerCharacter )
|
|
or same( 3, 6, 9, playerCharacter )
|
|
or same( 1, 5, 9, playerCharacter )
|
|
or same( 3, 5, 7, playerCharacter )
|
|
) ;
|
|
|
|
% takes a players turn - either automated or user input %
|
|
procedure turn ( string(1) value playerCharacter, otherCharacter
|
|
; logical value playerIsUser
|
|
) ;
|
|
begin
|
|
if playerIsUser then userMove( playerCharacter )
|
|
else begin
|
|
write( playerCharacter, " moves..." );
|
|
if not makeOrBlockWinningMove( playerCharacter, playerCharacter )
|
|
and not makeOrBlockWinningMove( otherCharacter, playerCharacter )
|
|
then move( playerCharacter )
|
|
end;
|
|
showBoard
|
|
end turn ;
|
|
|
|
% asks a question and returns true if the user inputs y/Y, %
|
|
% false otherwise %
|
|
logical procedure yes( string(32) value question ) ;
|
|
begin
|
|
string(1) answer;
|
|
write( question );
|
|
read( answer );
|
|
answer = "y" or answer = "Y"
|
|
end yes ;
|
|
|
|
% play the game %
|
|
while
|
|
begin
|
|
string(1) again;
|
|
string(32) gameResult;
|
|
logical oIsUser, xIsUser;
|
|
|
|
oIsUser := yes( "Do you want to play O? " );
|
|
xIsUser := yes( "Do you want to play X? " );
|
|
|
|
gameResult := "it's a draw";
|
|
initBoard;
|
|
showBoard;
|
|
while not gameOver and not playerHasWon( "O" ) and not playerHasWon( "X" ) do begin
|
|
turn( "O", "X", oIsUser );
|
|
if playerHasWon( "O" ) then gameResult := "O wins"
|
|
else if not gameOver then begin
|
|
turn( "X", "O", xIsUser );
|
|
if playerHasWon( "X" ) then gameResult := "X wins"
|
|
end
|
|
end ;
|
|
write( gameResult );
|
|
|
|
yes( "Play again? " )
|
|
end
|
|
do begin end
|
|
|
|
end.
|