Algorytm minimax w grze kółko i krzyżyk

0

Czesc, mam problem z implementacja algorytmu minimax w grze kolko i krzyzyk. Przegladajac kilka zrodel probowalam odtworzyc go w moim programie, jednak mimo bezproblemowej kompilacji program nie dziala jak nalezy. To znaczy komputer wstawia krzyzyki w roznych grach ciagle w to samo miejsce (mimo roznych ruchow gracza). Moglby ktos zerknac i powiedziec gdzie moze lezec blad? Zalaczam kod pomijajac pewne procedury,warunki, ktore nie sa przydatne do wersji 3x3 (w rzeczywistosci program jest bardziej rozbudowany).

 
program minimax;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this };
type polegry= array of array of char;
var plansza: polegry;
  n,rozmiar:integer;
  a:char;


procedure wczytaj(var plansza:polegry);
var i,j:integer;
begin
   for i:=0 to rozmiar-1 do
   begin
     for j:=0 to rozmiar-1 do
       plansza[i,j]:=' ';
   end;
end;

procedure wyswietl(plansza:polegry);
var i,j:integer;
begin
   for i:=0 to rozmiar-1 do
   begin
     for j:=0 to rozmiar-1 do
       write('|',plansza[i,j]);
     write('|');
     writeln();
   end;
end;

function remis(plansza:polegry;sprawdzenie:boolean):boolean;
var i,j,k:integer;
begin
   k:=0;
   for i:=0 to rozmiar-1 do
   begin
     for j:=0 to rozmiar-1 do
     begin
       if (plansza[i,j]<>' ') then inc(k);
     end;
   end;
   if (k=rozmiar*rozmiar) then
   begin
     remis:=true;
     if sprawdzenie then writeln('Remis');
   end
   else remis:=false;
end;

function sprawdzgre(plansza:polegry;znak:char;sprawdzenie:boolean):boolean;
var test: boolean;
  i,j:integer;
begin
   test:= false;
   for i:=0 to rozmiar-1 do
   begin
       if (plansza[i,0]=znak) and (plansza[i,1]=znak) and (plansza[i,2]=znak) then test:=true;
       if (plansza[0,i]=znak) and (plansza[1,i]=znak) and (plansza[2,i]=znak) then test:=true;
   end;
   if (plansza[0,0]=znak) and (plansza[1,1]=znak) and (plansza[2,2]=znak) then test:=true;
   if (plansza[0,2]=znak) and (plansza[1,1]=znak) and (plansza[2,0]=znak) then test:=true;
   if sprawdzenie then
   begin
        if test then
        begin
             writeln('Wygral gracz poslugujacy sie znakiem ',znak);
             sprawdzgre:=true;
        end
        else if (remis(plansza,sprawdzenie)) then sprawdzgre:=true
        else sprawdzgre:=false;
   end;
end;

function minmax({plansza:polegry;}znak:char):integer;
var i,j,m,mmx:integer;
begin
  if (sprawdzgre(plansza,znak,false)) then
  begin
       if (not remis(plansza,false)) then
       begin
            if znak='O' then minmax:=-1
            else minmax:=1;
       end;
  end
  else if remis(plansza,false) then minmax:=0
  else
  begin
    if znak='O' then znak:='X'
    else if znak='X' then znak:='O';
    if znak='O' then mmx:=10
    else if znak='X' then mmx:=-10;
    for i:=0 to rozmiar-1 do
    begin
         for j:=0 to rozmiar-1 do
         begin
              if plansza[i,j]=' ' then
              begin
                   plansza[i,j]:=znak;
                   m:=minmax(znak);
                   plansza[i,j]:=' ';
                   if (((znak='O') and (m<mmx)) or ((znak='X') and (m>mmx))) then mmx:=m;
              end;
         end;
    end;
    minmax:=mmx;
    end;
end;



procedure ruchgracza(znak:char;var plansza:polegry);
var wiersz,kolumna: integer;
begin
   writeln('Podaj wiersz, w ktorym chcesz postawic znak');
   readln(wiersz);
   writeln('Podaj kolumne, w ktorej chcesz postawic znak');
   readln(kolumna);
   if ((wiersz>=1) and (wiersz<=rozmiar) and (kolumna>=1) and (kolumna<=rozmiar) and (plansza[wiersz-1,kolumna-1]=' '))then plansza[wiersz-1,kolumna-1]:=znak
   else writeln('Nie mozna postawic znaku w tym miejscu, tracisz ruch');
end;

procedure ruchkomputera(znak:char;var plansza:polegry);
var wiersz,kolumna,mmx,m,i,j,pom: integer;
begin
   mmx:=-10;
   for i:=0 to rozmiar-1 do
   begin
     for j:=0 to rozmiar-1 do
     begin
       if plansza[i,j]=' ' then
       begin
         plansza[i,j]:=znak;
         m:=minmax(znak);
         plansza[i,j]:=' ';
         if m>mmx then
         begin
           mmx:=m;
           plansza[i,j]:=znak;
         end;
       end;
     end;
   end;

end;


begin
  n:=1;
  writeln('GRA KOLKO I KRZYZYK');
  while (n>0) do
  begin
    writeln('1 - plansza 3x3');
    writeln('2 - plansza 4x4');
    writeln('3 - plansza 5x5');
    write('Twoj wybor: ');
    readln(n);
    if n=1 then
    begin
      rozmiar:=3;
      SetLength(plansza,rozmiar,rozmiar);
        writeln('Gracz posluguje sie O, komputer X');
        wczytaj(plansza);
        wyswietl(plansza);
        while (not sprawdzgre(plansza,'X',true)) do
        begin
          ruchgracza('O',plansza);
          writeln('Twoj ruch:');
          wyswietl(plansza);
          if (not sprawdzgre(plansza,'O',true))  then
          begin
            writeln('Ruch komputera:');
            ruchkomputera('X',plansza);
            wyswietl(plansza);
          end
          else break;
        end;
      end;
    end;
  end;
end.

0

Algorytm MINIMAX w kółko i krzyżyk
Problemy dokładnie te same.

0

@_13th_Dragon widzialam juz ten post,jednak nie zrozumialam fragmentu:

Problemem jest to że twoja funkcja minmax nie sumuje całej ścieżki ruchu mmx należy podzielić na dwie różne zmienne.

Tak samo jak autor tamtego posta (a dopiero teraz zauwazylam ze ten post jest aktualny a nie sprzed kilku lat jak mi sie wydawalo). Mozna prosic o jakies wyjasnienie pod tamtym postem,abym mogla usunac ten post i nie zasmiecac forum tymi samymi tematami? Bede bardzo wdzieczna :)

0
4n napisał(a):
    if znak='O' then mmx:=10 // tu masz jeden mmx - z tego poziomu
    else if znak='X' then mmx:=-10; // to ten sam mmx co wyżej

                   if (((znak='O') and (m<mmx)) or ((znak='X') and (m>mmx))) then mmx:=m; // a tu masz zupełnie inny mmx z kolejnego poziomu, który ma się zsumować z tym pierwszym
0

dokonalam nastepujacych zmian w podanych fragmentach

 
if znak='O' then mmx1:=10
    else if znak='X' then mmx1:=-10;  


if (((znak='O') and (m<mmx1)) or ((znak='X') and (m>mmx1))) then mmx:=m+mmx1;

jednak wciaz komputer stawia krzyzyki w tych samych miejscach w kazdej grze. jezeli cos zle zrozumialam prosze o wyrozumialasc,bo to dopiero moje poczatki z ta przygoda

0
4n napisał(a):

dokonalam nastepujacych zmian w podanych fragmentach ...
Programowanie metodą na chybił trafił z góry skazana na porażkę.
Najpierw zastosuj pozostałe wskazówki z tamtego tematu, w wyniku czego program znacznie się uprości i może będziesz wiedział co robisz.

0
_13th_Dragon napisał(a):

Programowanie metodą na chybił trafił z góry skazana na porażkę.

Dokonalam tych zmian wnioskujac z tych wskazowek,jakie otrzymalam. Rozumiem ze sie pomylilam,ale mimo przeszukania wielu stron poswieconych temu algorytmowi nie moge sobie poradzic sama.Czy moge dostac jeszcze jakas wskazowke? Bardzo zalezy mi na ukonczeniu tej procedury, poprawkami "kosmetycznymi" wolalabym sie zajac po zamknieciu najwazniejszej sprawy,gdyz goni mnie czas.

0

To nie są poprawki kosmetyczne, to strukturalne naprawienie programu. W tej postaci nie rozumiesz nic a nic z tego co tam się dzieje, więc musisz to uprościć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1