algorithm for tic-tac-toe
ZXNet echo conference «code.zx»
From Kirill Frolov → To All 22 August 2000
Press RESET immediately, All!
Someone on CC told me that there are difficulties with the subject...
This program doesn't play too badly, but not too well either,
I don’t know how to do it better.
You can try to run it on the Spectrum in hi-soft pascal, if not
it will work out
then CP/M has Borland Pascal. In hi-soft you can convert in the shell
zxword 2.5.
I tried to rewrite this on ASMA, but gave up... In the next letter there will be
asm.
> --------- begin of gomoku.pas -----------------------------------------
uses crt;
const edge = 0; us = 1; them = 2; none = 3;
gridsize = 15;
maxmoves = 200;
alphabet = 96;
null = ';
type squares = edge..none;
smallint = byte;{0..gridsize}
line = array[0..9] of squares;
var
grid : array [1..gridsize,1..gridsize] of squares;
name : array [squares] of char;
icol, irow : array [1..4] of -1..1;
play : array [1..maxmoves] of record
rowfield,colfield : smallint;
end;
v, vals : array [1..4] of integer;
i, j, r, c : byte; {x- and y-coord}
onboard : set of smallint;
move : word;
endgame: squares;
yourturn : boolean;
topvalue: integer;
response: char;
procedure tell;
var y : char;
begin
writeln('Welcome to Go-Moku!');
writeln;
end;procedure init;
var m : real;
begin
name[none] := '·';
name[us] := 'O';
name[them] := '*';
name[edge] := '-';
irow[1] := 0; icol[1] := -1; {left}
irow[2] := -1; icol[2] := -1; {up-left}
irow[3] := -1; icol[3] := 0; {up}
irow[4] := -1; icol[4] := 1; {up-right}
onboard := [1..gridsize];
end;
procedure whofirst(var youfirst : boolean);
var no : char;
begin
writeln;
write('do you want to move first (n=no) ?');
readln(no);
youfirst := upcase(no) <> 'N';
end;
procedure slab(r,c,compass: smallint; var l : line);
{forming a line of 10 cells with a center at R, C and a guide
vector COMPASS}
var i, j : integer;
k : smallint;
begin
i := r; j := c;
for k := 4 downto 0 do {top left of ruler}
begin
inc(i, irow[compass]);
inc(j, icol[compass]);
if (i in onboard) and (j in onboard) then
l[k] := grid[i,j] {end of the ruler within the board}
else
l[k] := edge; {end of the ruler outside the board}
end;
i := r; j := c;
for k := 5 to 9 do {bottom right of ruler}
begin
dec(i, irow[compass]);
dec(j, icol[compass]);
if (i in onboard) and (j in onboard) then l[k] := grid[i,j]
else l[k] := edge;
end;
end;
procedure remember(i, j : smallint);
beginplay[move].rowfield := i;
play[move].colfield := j;
end;
procedure dumpgame(m : word);
var n : word;
begin
for n := 1 to m do with play[n] do
begin
write(chr(colfield+alphabet),rowfield:2);
if odd(n) then write(' ')
else writeln;
end;
end;
function foursome (var span : line; self : squares) : integer;
{calculation of weight function}
var best : integer;
near : boolean;
i, s, firstone, last, gaps : word;
friendly : set of squares;
begin
best := 0; friendly := [none, self];
for i := 1 to 5 do {five potential fours}
begin
firstone := 0; last := 0; {final positions}
gaps := 0; near := false;
s := i; {starting position}
while (gaps < 4) and (s < i+4) do
begin
if span[s] = none then inc(gaps) {counting gaps in the ruler}
else if span[s] = self then
begin
last := s;
if firstone = 0 then firstone := s;
near := near or (s in [4,5]);
{neighboring chip is its own}
end
else {the line is blocked by an opponent's piece}
gaps := 4;
inc(s);
end;
{summation of weights}
s := sqr(4-gaps); {value range from 0 to 16}if (last - firstone) < (4 - gaps) then
inc(s); {plus 1 if there is no break in the line}
if near then inc(s); {plus 1 if there is a chip in the adjacent cell}
if [span[i-1], span[i+4]] <= friendly then
inc(s); {plus 1 if the ruler is not locked}
if s > best then best := s; {new max}
end;
foursome := best;
end;
function evaluate(r, c : smallint) : integer;
{calculation of the total score of the move to position R, C}
var thoughts, crosses, x : integer;
i, j, thisway : smallint;
span: line;
function max(a,b:integer):integer;
begin
if a > b then max := a
else max := b;
end;
begin
for thisway := 1 to 4 do {4th possible directions}
begin
slab(r,c,thisway,span);
thoughts := foursome(span,us) + 2; {preference to zeros}
crosses := foursome(span,them);
v[thisway] := max(noughts,crosses)-2;
end;
for i := 1 to 3 do {sorting >=}
for j := 1 to 4 - i do if v[j] < v[j+1] then
begin
x := v[j];
v[j] := v[j+1];
v[j+1] := x;
end;
{final score}
evaluate := v[1]*64 + v[2]*16 + v[3]*4 + v[4];
end;
procedure makemove(var r,c : smallint);
{search for the best move}
var bestcol, bestrow : smallint;
q,w : smallint;
e: integer;
begin
q := r; w := c;
topvalue := 0;
bestcol := 0; bestrow := 0;
if move = 1 then {first move - to the central cell}
begin bestrow := gridsize div 2 + 1;
bestcol := bestrow;
end
else
for q := 1 to gridsize do
for w := 1 to gridsize do
if grid[q,w] = none then
begin
e := evaluate(q,w);
if (e > topvalue) or (bestrow = 0) then
begin
topvalue := e;
bestcol := w;
bestrow := q;
vals := v;
end;
end;
c := bestcol;
r := bestrow;
end;
procedure getmove(var i,j : smallint);
var c : char;
ok : boolean;
cols : integer;
begin
writeln;
repeat
write('where do you move ?');
read(c);
readln(i);
cols := ord(c) - alphabet;
ok := (i in onboard) and (cols in onboard);
if not ok then writeln('no such position as