RosettaCodeData/Task/Tic-tac-toe/XPL0/tic-tac-toe.xpl0
Ingy döt Net 68f8f3e56b all tasks
2013-04-11 01:07:29 -07:00

145 lines
4.6 KiB
Text

\The computer marks its moves with an "O" and the player uses an "X". The
\ numeric keypad is used to make the player's move.
\
\ 7 | 8 | 9
\ ---+---+---
\ 4 | 5 | 6
\ ---+---+---
\ 1 | 2 | 3
\
\The player always goes first, but the 0 key is used to skip a move. Thus
\ it can be used to let the computer play first. Esc terminates program.
inc c:\cxpl\codes; \intrinsic routine declarations
def X0=16, Y0=10; \coordinates of character in upper-left square
int I0,
PMove, \player's move (^0..^9)
Key; \keystroke
int X, O; \bit arrays for player and computer
\ bit 0 corresponds to playing square 1, etc.
proc HLine(X, Y); \Draw a horizontal line
int X, Y;
int I;
[Cursor(X, Y);
for I:= 0 to 10 do ChOut(0, ^Ä);
]; \HLine
proc VLine(X, Y); \Draw a vertical line over the above horizontal line
int X, Y;
int I;
[for I:= 0 to 4 do
[Cursor(X, Y+I);
ChOut(0, if I&1 then ^Å else ^³);
];
]; \VLine
func Won(p); \Return 'true' if player P has won
int P;
int T, I;
[T:= [$007, $038, $1C0, $049, $092, $124, $111, $054];
for I:= 0 to 7 do \check if player matches a bit pattern for 3 in a row
if (P & T(I)) = T(I) then return true;
return false;
]; \Won
func Cats; \Return 'true' if no more moves available (Cat's game)
[if (X ! O) = $1FF then \all bit positions played
[Cursor(17, 20);
Text(0, "A draw!");
return true;
];
return false;
]; \Cats
proc DoMove(P, M, Ch); \Make move in player's bit array and display it
int P, \address of player's bit array
M, \index 0..8 where bit is placed
Ch;
int I, X, Y;
[P(0):= P(0) ! 1<<M; \make move
I:= M / 3; \display move
X:= Rem(0) * 4;
Y:= (2-I) * 2;
Cursor(X+X0, Y+Y0);
ChOut(0, Ch);
]; \DoMove
func Try(P); \Return the value of the best node for player P
int P; \address of player's bit array
int P1, I, I0, V, V0;
[P1:= if P = addr X then addr O else addr X;
if Won(P1(0)) then return -1;
if (X ! O) = $1FF then return 0;
V0:= -1; \assume the worst
for I:= 0 to 8 do \for all of the squares...
if ((O!X) & 1<<I) = 0 then \if square is unused
[P(0):= P(0) ! 1<<I; \make tenative move
V:= -(extend(Try(P1))); \get value
if V > V0 then \save best value
[V0:= V; I0:= I];
P(0):= P(0) & ~(1<<I); \undo tenative move
];
return V0 & $FF ! I0<<8;
]; \Try
proc PlayGame; \Play one game
[ChOut(0, $0C\FF\); \clear screen with a form feed
HLine(X0-1, Y0+1); \draw grid (#)
HLine(X0-1, Y0+3);
VLine(X0+2, Y0);
VLine(X0+6, Y0);
X:= 0; O:= 0; \initialize player's bit arrays to empty
loop [loop [PMove:= ChIn(1); \GET PLAYER'S MOVE (X)
if PMove = $1B\Esc\ then
[SetVid(3); exit]; \restore display and end program
if PMove = ^0 then quit;
if PMove>=^1 & PMove<=^9 & \check for legal move
((X!O) & 1<<(PMove-^1)) = 0 then quit;
ChOut(0, 7\Bel\); \beep the dude
];
if PMove # ^0 then
[DoMove(addr X, PMove-^1, ^X);
if Won(X) then
[Cursor(17, 20);
Text(0, "X wins!");
quit;
];
];
if Cats then quit;
I0:= Try(addr O) >>8; \GET COMPUTER'S MOVE (O)
DoMove(addr O, I0, ^O); \do best move
if Won(O) then
[Cursor(17, 20);
Text(0, "O wins!");
quit;
];
if Cats then quit;
];
]; \PlayGame
int CpuReg;
[SetVid(1); \set 40x25 text mode
CpuReg:= GetReg; \turn off annoying flashing cursor
CpuReg(0):= $0100; \ with BIOS interrupt 10h, function 01h
CpuReg(2):= $2000; \set cursor type to disappear
SoftInt($10);
loop [PlayGame;
Key:= ChIn(1); \keep playing games until Esc key is hit
if Key = $1B\Esc\ then
[SetVid(3); exit]; \clear screen & restore normal text mode
];
]