Witam, znalazłem przykładowy kod programu w C++ a staram się go przerobić na Delphi. Niestety w jakimś miejscu popełniłem błąd i moduł inteligencji komputera nie działa tak jak trzeba (ma korzystać z alg. mini-max, a działa tak, jakby z niego nie korzystał). Zresztą zobaczcie sami. Czy jest ktoś w stanie poprawić ten błąd? Siedzę nad tym od dłuższego czasu i już skończyły mi się pomysły.
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
{PLANSZA JEST TABLICĄ TYPU CHAR, GDZIE:
' ' - TO POLE PUSTE
X - TO KRZYŻYK
O - TO KÓŁKO
}
type Tplansza=array [1..9] of char;
var
a:integer;
t:Tplansza;
gracz,wybor:char;
{
Funkcja rysuje planszę gry w kółko i krzyżyk
Plansza przechowywana jest w tablicy t[] w elementach o następujących indeksach:
t[1] t[2] t[3]
t[4] t[5] t[6]
t[7] t[8] t[9]
---------------------------------------------------------------------------------}
procedure plansza(var t:Tplansza);
var i:integer;
begin
for i:= 1 to 9 do begin
write(' ',t[i],' ');
if i mod 3 <> 0 then write('|') { Po elementach 1,2,4,5,7,8 rysujemy |}
else if i mod 3 <> 9 then begin
writeln;
writeln('---+---+---'); { Po elementach 3 i 6 poprzeczka }
end else writeln; { Po elemencie 9 koniec wiersza }
end;
end;
{
Funkcja zwraca true, jeśli nastąpiła
wygrana danego zawodnika
-------------------------------------}
function wygrana(var t:Tplansza; g:char; cisza:boolean):boolean;
var
test: boolean;
i: integer;
begin
test:= false; { Zmienna przyjmuje true, jeśli zawodnik ma trzy figury w wierszu,
kolumnie lub na przekątnych }
{ Sprawdzamy wiersze }
i:= 1;
while i <= 7 do begin
test:=test or ((t[i]=g) and (t[i+1]=g) and (t[i+2]=g));
i:=i+3;
end;
{ Sprawdzamy kolumny }
i:=1;
while i <= 3 do begin
test := test or ((t[i]=g) and (t[i+3]=g) and (t[i+6]=g));
i:=i+1;
end;
{ Sprawdzamy przekątną 1-5-9 }
test := test or ((t[1]=g) and (t[5]=g) and (t[9]=g));
{ Sprawdzamy przekątną 3-5-7 }
test:= test or ((t[3]=g) and (t[5]=g) and (t[7]=g));
if test then
if not cisza then begin
plansza(t); {rysuje plansze }
writeln;
writeln('GRACZ ',g,' WYGRYWA!!!');
writeln;
wygrana:=true;
exit;
end;
wygrana:=false;
end;
{
Funkcja zwraca true, jeśli na planszy nie ma już
żadnego wolnego pola na ruch.
-------------------------------------------------}
function remis(var t:Tplansza; cisza:boolean):boolean;
var i:integer;
begin
{ Jeśli napotkamy spację, to plansza posiada wolne pola - zwracamy false }
for i:= 1 to 9 do if t[i] = ' ' then begin
remis:=false;
exit;
end;
{ Jesli pętla for zakończyła się normalnie, to na żadnym polu planszy nie było spacji.
Mamy do czynienia z remisem - zwracamy true }
if not cisza then begin
plansza(t); {rysuje plansze }
writeln;
writeln('REMIS !!!');
writeln;
end;
remis:=true;
end;
{
Algorytm rekurencyjny MINIMAX
Do algorytmu wchodzimy z planszą, na której ustawione jest pole
bieżącego gracza. Parametr gracz przekazuje literkę gracza, a
parametr mx przekazuje jego wynik w przypadku wygranej
----------------------------------------------------------------}
function minimax(var t:Tplansza; gracz:char):integer;
var
i, m, mmx:integer;
begin
{ Najpierw sprawdzamy, czy bieżący gracz wygrywa na planszy.
Jeśli tak, to zwracamy jego maksymalny wynik }
if wygrana(t,gracz,true) then begin
if gracz='X' then minimax:=1 else minimax:=-1;
exit;
end;
{ Następnie sprawdzamy, czy nie ma remisu. Jeśli jest, zwracamy wynik 0 }
if remis(t,true) then begin
minimax:=0;
exit;
end;
{ Będziemy analizować możliwe posunięcia przeciwnika.
Zmieniamy zatem bieżącego gracza na jego przeciwnika }
if gracz='X' then gracz:='O' else gracz:='X';
{
Algorytm MINIMAX w kolejnych wywołaniach rekurencyjnych naprzemiennie analizuje
grę gracza oraz jego przeciwnika. Dla gracza oblicza maksimum wyniku gry, a dla
przeciwnika oblicza minimum. Wartość mmx ustawiamy w zależności od tego, czyje
ruchy analizujemy:
X - liczymy max, zatem mmx <- -10
O - liczymy min, zatem mmx <- 10
}
if gracz='O' then mmx:=10 else mmx:=-10;
{
Przeglądamy planszę szukając wolnych pół na ruch gracza. Na wolnym polu ustawiamy
literkę gracza i wyznaczamy wartość tego ruchu rekurencyjnym wywołaniem
algorytmu MINIMAX. Planszę przywracamy i w zależności kto gra:
X - wyznaczamy maximum
O - wyznaczamy minimum
}
for i:= 1 to 9 do
if t[i]= ' ' then begin
t[i]:= gracz;
m:= minimax(t,gracz);
t[i]:= ' ';
if (((gracz='O') and (m<mmx)) or ((gracz='X') and (m>mmx)))
then mmx:= m;
end;
minimax:=mmx;
end;
{
Funkcja wyznacza ruch dla komputera.
------------------------------------}
function komputer(var t:Tplansza):integer;
var
ruch, i, m, mmx:integer;
begin
mmx:= -10;
for i:= 1 to 9 do
if t[i]=' ' then begin
t[i]:= 'X';
m:= minimax(t,'X');
t[i]:= ' ';
if (m > mmx) then begin
mmx:= m;
ruch:= i;
end;
end;
komputer:=ruch;
end;
{
Funkcja umożliwia ruch gracza
Po ruchu następuje zamiana gracza
------------------------------------}
procedure ruch(var t:Tplansza; var gracz:char);
var r:integer;
begin
plansza(t);
if gracz='O' then begin
writeln;
write('CZLOWIEK : wybiera ruch : ');
read(r);
end else begin
r:= komputer(t);
writeln;
writeln('KOMPUTER : wybiera ruch : ',r);
end;
writeln('---------------------------');
writeln;
if ((r >= 1) and (r <= 9) and (t[r] = ' ')) then t[r]:= gracz;
if gracz='O' then gracz:='X' else gracz:='O';
end;
begin
repeat
begin
//clrscr;
writeln('Gra w Kolko i Krzyzyk dla gracza i komputera');
writeln;
writeln('============================================');
writeln;
for a:= 1 to 9 do t[a]:= ' ';
gracz:= 'O';
while(not wygrana(t,'X',false) and (not wygrana(t,'O',false)) and (not remis(t,false))) do ruch(t,gracz);
write('Jeszcze raz ? (t = TAK) : ');
readln;
readln(wybor);
end;
until not (upcase(wybor)='T');
end.
Dla porównania, orginalny kod poniżej:
#include <iostream>
using namespace std;
// Funkcja rysuje planszę gry w kółko i krzyżyk
// Plansza przechowywana jest w tablicy t[] w elementach o następujących indeksach:
// t[1] t[2] t[3]
// t[4] t[5] t[6]
// t[7] t[8] t[9]
//---------------------------------------------------------------------------------
void plansza(char t[])
{
for(int i = 1; i <= 9; i++)
{
cout << " " << t[i] << " ";
if(i % 3) cout << "|"; // Po elementach 1,2,4,5,7,8 rysujemy |
else if(i != 9) cout << "\n---+---+---\n"; // Po elementach 3 i 6 poprzeczka
else cout << endl; // Po elemencie 9 koniec wiersza
}
}
// Funkcja zwraca true, jeśli nastąpiła
// wygrana danego zawodnika
//-------------------------------------
bool wygrana(char t[], char g, bool cisza)
{
bool test;
int i;
test = false; // Zmienna przyjmuje true, jeśli zawodnik ma trzy figury
// w wierszu, kolumnie lub na przekątnych
// Sprawdzamy wiersze
for(i = 1; i <= 7; i += 3) test |= ((t[i] == g) && (t[i+1] == g) && (t[i+2] == g));
// Sprawdzamy kolumny
for(i = 1; i <= 3; i++) test |= ((t[i] == g) && (t[i+3] == g) && (t[i+6] == g));
// Sprawdzamy przekątną 1-5-9
test |= ((t[1] == g) && (t[5] == g) && (t[9] == g));
// Sprawdzamy przekątną 3-5-7
test |= ((t[3] == g) && (t[5] == g) && (t[7] == g));
if(test)
{
if(!cisza)
{
plansza(t);
cout << "\nGRACZ " << g << " WYGRYWA!!!\n\n";
}
return true;
}
return false;
}
// Funkcja zwraca true, jeśli na planszy nie ma już
// żadnego wolnego pola na ruch.
//-------------------------------------------------
bool remis(char t[], bool cisza)
{
// Jeśli napotkamy spację, to plansza posiada wolne pola - zwracamy false
for(int i = 1; i <= 9; i++) if(t[i] == ' ') return false;
// Jesli pętla for zakończyła się normalnie, to na żadnym polu planszy nie było
// spacji. Mamy do czynienia z remisem - zwracamy true
if(!cisza)
{
plansza(t); cout << "\nREMIS !!!\n\n";
}
return true;
}
// Algorytm rekurencyjny MINIMAX
// Do algorytmu wchodzimy z planszą, na której ustawione jest pole
// bieżącego gracza. Parametr gracz przekazuje literkę gracza, a
// parametr mx przekazuje jego wynik w przypadku wygranej
//----------------------------------------------------------------
int minimax(char t[], char gracz)
{
int m, mmx;
// Najpierw sprawdzamy, czy bieżący gracz wygrywa na planszy. Jeśli tak, to
// zwracamy jego maksymalny wynik
if(wygrana(t,gracz,true)) return (gracz == 'X') ? 1 : -1;
// Następnie sprawdzamy, czy nie ma remisu. Jeśli jest, zwracamy wynik 0
if(remis(t,true)) return 0;
// Będziemy analizować możliwe posunięcia przeciwnika. Zmieniamy zatem
// bieżącego gracza na jego przeciwnika
gracz = (gracz == 'X') ? 'O' : 'X';
// Algorytm MINIMAX w kolejnych wywołaniach rekurencyjnych naprzemiennie analizuje
// grę gracza oraz jego przeciwnika. Dla gracza oblicza maksimum wyniku gry, a dla
// przeciwnika oblicza minimum. Wartość mmx ustawiamy w zależności od tego, czyje
// ruchy analizujemy:
// X - liczymy max, zatem mmx <- -10
// O - liczymy min, zatem mmx <- 10
mmx = (gracz == 'O') ? 10 : -10;
// Przeglądamy planszę szukając wolnych pół na ruch gracza. Na wolnym polu ustawiamy
// literkę gracza i wyznaczamy wartość tego ruchu rekurencyjnym wywołaniem
// algorytmu MINIMAX. Planszę przywracamy i w zależności kto gra:
// X - wyznaczamy maximum
// O - wyznaczamy minimum
for(int i = 1; i <= 9; i++)
if(t[i] == ' ')
{
t[i] = gracz;
m = minimax(t,gracz);
t[i] = ' ';
if(((gracz == 'O') && (m < mmx)) || ((gracz == 'X') && (m > mmx))) mmx = m;
}
return mmx;
}
// Funkcja wyznacza ruch dla komputera.
//------------------------------------
int komputer(char t[])
{
int ruch, i, m, mmx;
mmx = -10;
for(i = 1; i <= 9; i++)
if(t[i] == ' ')
{
t[i] = 'X';
m = minimax(t,'X');
t[i] = ' ';
if(m > mmx)
{
mmx = m; ruch = i;
}
}
return ruch;
}
// Funkcja umożliwia ruch gracza
// Po ruchu następuje zamiana gracza
//------------------------------------
void ruch(char t[], char &gracz)
{
int r;
plansza(t);
if(gracz == 'O')
{
cout << "\nCZLOWIEK : wybiera ruch : ";
cin >> r;
}
else
{
r = komputer(t);
cout << "\nKOMPUTER : wybiera ruch : " << r << endl;
}
cout << "---------------------------\n\n";
if((r >= 1) && (r <= 9) && (t[r] == ' ')) t[r] = gracz;
gracz = (gracz == 'O') ? 'X' : 'O';
}
int main(int argc, char * argv[])
{
char t[10],gracz,wybor;
do {
cout << "Gra w Kolko i Krzyzyk dla gracza i komputera\n"
"============================================\n\n";
for(int i = 1; i <= 9; i++) t[i] = ' ';
gracz = 'O';
while(!wygrana(t,'X',false) && !wygrana(t,'O',false) && !remis(t,false)) ruch(t,gracz);
cout << "Jeszcze raz ? (T = TAK) : ";
cin >> wybor;
cout << "\n\n\n";
} while((wybor == 'T') || (wybor == 't'));
return 0;
}
Będę wdzięczny za wszelką pomoc :)