Gra w kółko i krzyżyk

0

Witajcie
Po wielu, trudach ukończyłem wcześniej z zaczętą grę kółko i krzyżyk. Kod jest napisany w pascalu, może być kompilowany przez Turbo Pacala jak i Free Pascala. Z góry przepraszam za mój nie profesjonalny angielski, lecz postanowiłem wszelkie komunikaty, które są generowane przez grę napisać właśnie w tym języku, korzystając z google tłumacza. Jak ktoś mógłby jakimś łaskawym okiem zerknąć na nie i dać sugestie jak i co poprawić to byłbym wdzięczny :).
Pozdrawiam

unit Silnik;
interface
type
  tab = array[1..4,1..4] of char;
var
  liczba_pol,nr_pola: byte;
  nr_wiersza,nr_kolumny: byte;
  pola: tab;
  krzyzyk,kolko: boolean;
  z1,z2: char;
function Wyg(tablica: tab; znak_wyg: char): boolean;
procedure Spr_Wyg(var tablica: tab; var i1: byte; var j1: byte; znak: char);
procedure Symulacja_Gry(var tablica: tab; wiersz,kolumna,zajete_pola,poziom: byte; znak: char);
implementation
function Wyg(tablica: tab; znak_wyg: char): boolean;
var
   r,c,z: byte;
begin
     wyg := false; nr_wiersza := 0; nr_kolumny := 0;

     for r := 1 to 3 do
        begin z := 0;
             for c := 1 to 3 do
                if tablica[r,c] = znak_wyg then
                  z := z + 1;
             if z = 3 then begin wyg := true; nr_wiersza := r; break end
        end;

     for c := 1 to 3 do
        begin z := 0;
             for r := 1 to 3 do
                if tablica[r,c] = znak_wyg then
                  z := z + 1;
             if z = 3 then begin wyg := true; nr_kolumny := c; break end
        end;

     z := 0;
     for r := 1 to 3 do
        if tablica[r,r] = znak_wyg then z := z + 1;
     if z = 3 then begin wyg := true; nr_wiersza := r; nr_kolumny := r end;

     z := 0;
     for r := 1 to 3 do
        if tablica[r,4-r] = znak_wyg then z := z + 1;
     if z = 3 then begin wyg := true; nr_wiersza := r; nr_kolumny := 4 - r end
end;
procedure Spr_Wyg(var tablica: tab; var i1: byte; var j1: byte; znak: char);
begin
     if (wyg(tablica,z1) = false) and (wyg(tablica,z2) = false) then
       while i1 < 4 do
            begin
                 j1 := 1;
                 while j1 < 4 do
                      begin
                           if tablica[i1,j1] = ' ' then
                             begin
                                  tablica[i1,j1] := znak;
                                  if wyg(tablica,z1) then
                                    break
                                  else
                                      if wyg(tablica,z2) then
                                        break
                                      else
                                          tablica[i1,j1] := ' '
                             end;
                           inc(j1)
                      end;
                 if wyg(tablica,z1) or wyg(tablica,z2) then break;
                 inc(i1)
            end
end;
procedure Symulacja_Gry(var tablica: tab; wiersz,kolumna,zajete_pola,poziom: byte; znak: char);
var
   w,k,wsp_y,wsp_x,z,x: byte;
begin
     krzyzyk := false; kolko := false;
     w := 1; k := 1;
     Spr_Wyg(tablica,w,k,znak);
     if Wyg(tablica,znak) = true then { gracz }
       begin
            if znak = z1 then
              krzyzyk := true
            else
                kolko := true;
            wiersz := w; kolumna := k
       end
     else { brak wygranej gracza }
         begin
              if znak = z1 then znak := z2 else znak := z1;
              w := 1; k := 1;
              Spr_Wyg(tablica,w,k,znak);
              if Wyg(tablica,znak) then  { Sprawdzenie wygranej przeciwnika }
                begin
                    if znak = z1 then znak := z2 else znak := z1;
                     tablica[w,k] := znak;
                     wiersz := w; kolumna := k
                end
              else
                  begin { Zwykła symulacja rogrywki }
                       if znak = z1 then znak := z2 else znak := z1;
                       if zajete_pola <> 1 then
                         begin
                              if tablica[wiersz,kolumna] = ' ' then
                                begin
                                     tablica[wiersz,kolumna] := znak;
                                     if (zajete_pola > 2) and (zajete_pola < 9) then
                                       begin
                                            if poziom = 0 then
                                              begin
                                                   w := 1; k := 1;
                                                   Spr_Wyg(tablica,w,k,znak)
                                              end;
                                            if (w in [1..3]) and (k in [1..3]) then
                                              begin tablica[w,k] := ' '; w := wiersz; k := kolumna end
                                            else
                                                begin
                                                     w := wiersz; k := kolumna;
                                                     wsp_y := wiersz; wsp_x := kolumna;

                                                     repeat
                                                           if (wsp_y <> wiersz) or (wsp_x <> kolumna) then
                                                             if tablica[wiersz,kolumna] = ' ' then
                                                               begin
                                                                    tablica[wiersz,kolumna] := z2;

                                       Symulacja_Gry(tablica,wiersz,kolumna,zajete_pola+1,poziom+1,z1);

                                                                    if kolko = true then
                                                                      begin
                                                                           tablica[wiersz,kolumna] := ' ';
                                                                           tablica[w,k] := ' ';

                                                                           repeat
                                                                                 if k < 3 then inc(k)
                                                                                 else
                                                                                     if (k = 3) and (w < 3) then
                                                                                       begin k := 1; inc(w) end
                                                                                     else
                                                                                         if (k = 3) and (w = 3) then
                                                                                           begin k := 1; w := 1 end
                                                                           until tablica[w,k] = ' ';
                                                                           tablica[w,k] := z1;
                                                                           break
                                                                      end;
                                                                    tablica[wiersz,kolumna] := ' '
                                                               end;

                                                           if kolumna < 3 then inc(kolumna)
                                                           else
                                                               if (kolumna = 3) and (wiersz < 3) then
                                                                 begin kolumna := 1; inc(wiersz) end
                                                               else
                                                                   if (kolumna = 3) and (wiersz = 3) then
                                                                     begin kolumna := 1; wiersz := 1 end
                                                     until (w = wiersz) and (k = kolumna)
                                                end
                                       end
                                end
                         end
                       else
                           if tablica[2,2] = ' ' then begin w := 2; k := 2; tablica[w,k] := znak end
                           else
                               begin
                                    repeat
                                          w := random(3) + 1;
                                          k := random(3) + 1
                                    until (tablica[w,k] = ' ') and (w <> 2) and (k <> 2);
                                    tablica[w,k] := znak
                               end
                  end

         end;

     inc(zajete_pola); inc(poziom);

     if (zajete_pola < 9) and (Wyg(tablica,z1) = false) and (Wyg(tablica,z2) = false) then
       begin
            if znak = z1 then znak := z2 else znak := z1;
            Symulacja_Gry(tablica,wiersz,kolumna,zajete_pola,poziom,znak)
       end;

     if kolko = true then
       begin
            tablica[w,k] := ' ';
            if poziom = 1 then
              begin
                   repeat
                         if k < 3 then inc(k)
                         else
                             if (k = 3) and (w < 3) then begin k := 1; inc(w) end
                             else
                                 if (k = 3) and (w = 3) then begin k := 1; w := 1 end
                   until tablica[w,k] = ' ';
                   Symulacja_Gry(tablica,w,k,zajete_pola-1,0,z1)
              end
       end
     else
         if poziom > 1 then
           tablica[w,k] := ' '
         else
             begin
                  if k mod 3 = 0 then
                    nr_pola := w * k
                  else
                      nr_pola := (w - 1) * 3 + k;
             end
end;
end.
program Tic_Tac_Toe;
uses Graph,Crt,Silnik; { W Free Pascalu zamiast modułu Crt jest WinCrt. }
var
   sterownik : integer;
   tryb : integer;
   kolor_kolka : byte;
   kolor_krzyzyka: byte;
   licz: integer;
   wspXtekst,wspYtekst: integer;
   liczba_graf: string[56];
   nastepna: char;
procedure Czolowka_Gry;
var
   i: byte;
begin

     OutTextXY(800 div 2 - TextWidth('Game - Tic-Tac-Toe'),20,'Game - Tic-Tac-Toe');
     wspXtekst := 800 div 2 - TextWidth('Press 1 to select the circle character');
     OutTextXY(wspXtekst,35,'Press 1 to select the circle character');
     OutTextXY(wspXtekst,50,'Press 2 to select the cross character');


     repeat
           i := ord(readkey);
           case i of
                49: z2 := '0';
                50: z2 := 'X'
                else OutTextXY(wspXtekst,65,'Press only 1 or 2 !!!')
           end
     until Chr(i) in ['1'..'2'];

     if Chr(i) = '1' then begin z1 := 'X'; z2 := '0' end
     else begin z1 := '0'; z2 := 'X' end;

     if z2 = '0' then
       begin
            OutTextXY(wspXtekst,80,'You have chosen a circle');
            OutTextXY(wspXtekst,95,'The computer sing is: a cross');
       end
     else
         begin
              OutTextXY(wspXtekst,80,'You have chosen a cross');
              OutTextXY(wspXtekst,95,'The computer sing is: a circle');
         end;

     OutTextXY(wspXtekst,110,'To continue press any key !!!');
     readkey
end;
procedure Graficzna_Ilustracja;
var
   i,j: byte;
   wsp_x,wsp_y: integer;
   punkt_x,punkt_y: integer;
   punkt_x1,punkt_x2: integer;
   punkt_y1,punkt_y2: integer;
begin
     wsp_x := 196; wsp_y := 93;
     punkt_x := 122; punkt_y := 81;
     punkt_x1 := 25; punkt_x2 := 221;
     punkt_y1 := 35; punkt_y2 := 128;

     for i := 1 to 3 do
        begin
             for j := 1 to 3 do
                begin
                     setcolor(1);
                     if pola[i,j] = '0' then
                     circle(punkt_x,punkt_y,59);
                     setcolor(2);
                     if pola[i,j] = 'X' then
                       begin
                            line(punkt_x1,punkt_y1,punkt_x2,punkt_y2);
                            line(punkt_x2,punkt_y1,punkt_x1,punkt_y2)
                       end;
                     if Wyg(pola,'X') or Wyg(pola,'0') then
                       begin
                            setcolor(4);
                            if (nr_wiersza = i) and (nr_kolumny = 0) then
                              line(25,punkt_y+1,615,punkt_y+1);
                            if (nr_kolumny = j) and (nr_wiersza = 0) then
                              line(punkt_x+1,35,punkt_x+1,315)
                       end;
                     punkt_x := punkt_x + wsp_x;
                     punkt_x1 := punkt_x1 + wsp_x;
                     punkt_x2 := punkt_x2 + wsp_x
                end;

             punkt_x := 122; punkt_x1 := 25; punkt_x2 := 221;

             if i < 3 then
               begin
                    punkt_y := punkt_y + wsp_y;
                    punkt_y1 := punkt_y1 + wsp_y;
                    punkt_y2 := punkt_y2 + wsp_y
               end;

             setcolor(4);

             if Wyg(pola,'X') or Wyg(pola,'0') then
               if nr_wiersza - nr_kolumny = 0 then
                 line(25,35,615,315)
               else
                   if (nr_wiersza <> 0) and (nr_kolumny <> 0) then
                     line(615,35,25,315)
        end
end;
procedure Runda;
var
  i,j: byte;
begin        i := 0; j := 0;
     repeat

     for i := 1 to 3 do
        for j := 1 to 3 do
           pola[i,j] := ' ';  liczba_pol := 0; randomize;

     ClearDevice;

     SetColor(15); SetTextStyle(DefaultFont,HorizDir,1);

     Czolowka_Gry;

     ClearDevice;

     RecTangle(25,35,615,315);

     Line(221,35,221,315);
     Line(417,35,417,315);
     SetTextStyle(DefaultFont,HorizDir,8);
     wspXtekst := 94; wspYtekst := 55;

     for nr_pola := 1 to 9 do
        begin
             str(nr_pola,liczba_graf);
             OutTextXY(wspXtekst,wspYtekst,liczba_graf);
             wspXtekst := wspXtekst + 205;
             if nr_pola mod 3 = 0 then
               begin
                     wspYtekst := wspYtekst + 93;
                     wspXtekst := 94
               end
        end;

     Line(25,128,615,128);
     Line(25,221,615,221);

     SetTextStyle(SansSerifFont,HorizDir,2);
     OutTextXY(180,1,'Press the keys form 1 to 9');




     repeat
           if (liczba_pol < 9) and (Wyg(pola,z2) = false) and (Wyg(pola,z1) = false) then
           repeat
                 SetColor(15);
                 nr_pola := ord(readkey);
                 nr_pola := nr_pola - 48;


           if nr_pola mod 3 = 0 then
             begin
                  i := nr_pola div 3;
                  j := 3;
             end
           else
               begin
                    i := (nr_pola div 3) + 1;
                    j := nr_pola mod 3;
               end
          until (nr_pola in [1..9]) and (pola[i,j] = ' ');
           pola[i,j] := z2;
           liczba_pol := liczba_pol + 1;

           if (liczba_pol < 9) and (Wyg(pola,z1) = false) then
             begin
                  if liczba_pol > 1 then
                    repeat
                          if j < 3 then inc(j)
                          else
                              if (j = 3) and (i < 3) then begin j := 1; inc(i) end
                              else
                                  if (j = 3) and (i = 3) then begin j := 1; i := 1 end
                    until pola[i,j] = ' ';
                  Symulacja_Gry(pola,i,j,liczba_pol,0,z1);
                  liczba_pol := liczba_pol + 1
             end;

           Graficzna_Ilustracja; SetTextStyle(SansSerifFont,HorizDir,1);
           SetColor(12);
           if (liczba_pol = 9) and (Wyg(pola,z2) = false) and (Wyg(pola,z1) = false) then
             OutTextXY(25,320,'Draw')
           else
               if Wyg(pola,z1) = true then
                 OutTextXY(25,320,'The computer won')
               else
                   if (Wyg(pola,z2) = true) then
                     OutTextXY(25,320,'The player has won');
     until Wyg(pola,z1) or Wyg(pola,z2) or (liczba_pol = 9);
           SetTextStyle(DefaultFont,HorizDir,1); SetColor(15);
           OutTextXY(200,330,'Do you want to play again ? Press Y otherwise any key');
           nastepna := readkey
     until not (nastepna = 'Y')
end;
begin
     sterownik := VGA;
     tryb := VGAMed;
     InitGraph(sterownik,tryb,'D:\Tp\bgi');
     Runda;
     CloseGraph
end.
3

Nie wiem po co się wciąż powtarzam, ale: Kółko i krzyżyk - ciąg dalszy

Naprawdę: całkowicie zmieni to Twoje podejście do problemu, zwłaszcza z tymi wcięciami na 80 spacji.

0

Jest zbyt dużo zmian, żeby było można podpiąć ten post pot tamten. Dlatego założyłem nowy wątek. To trochę tak jak samochód tylko, że po liftingu a w tym przypadku to trochę więcej niż lifting ;).

2

Nie chodzi mi o to, abyś się podpinał pod stary temat, tylko abyś zaimplementował możliwość wyboru rozmiaru planszy :-P

1

@Adept123: no to na początek przenieś blok deklaracji zmiennych globalnych zaraz nad główny blok kodu modułu i zobacz co się stanie. Używanie zmiennych globalnych w taki sposób jaki pokazałeś to zło w czystej postaci. Program powinien działać tak, aby dane były przekazywane do procedur i funkcji w ich parametrach i na taką postać zmień go w pierwszej kolejności.

sterownik := VGA;
tryb := VGAMed;
InitGraph(sterownik,tryb,'D:\Tp\bgi');

Po co te zmienne? Nie dość że zawsze używasz takich samych wartości, to w dodatku z tych zmiennych korzystasz raz, a później już ich nie używasz. Wywal je, podając wartości od razu w parametrach. Poza tym sterownik wrzuć do katalogu z programem, bo używasz ścieżek bezwzględnych, a więc Twojego programu nie uruchomi ktoś, kto nie posiada partycji D: (a tej z reguły nie ma w sklepowych komputerach). Ta instrukcja ma wyglądać tak:

InitGraph(VGA, VGAMed, 'drivers\');

Z innych bolączek to np. procedura Runda ma nazwę z tyłka, bo co „runda”? Procedury i funkcje w założeniu mają wykonywać dane czynności (mniej lub bardziej abstrakcyjne), więc ich nazwy mają pokazywać o jakie czynności chodzi. A skoro mowa o czynnościach, to ich nazwy powinny się rozpoczynać od czasowników, czyli np. StartRound. Poza tym zmieniasz znaczenie nazw funkcji wbudowanych, np. RecTangle – co to kurła jest? Po co Ci RekordPlątaniny?

Kod jest nieczytelny, ma potężne zagnieżdżenia i wcięcia, robi masę rzeczy na raz, operuje na jednoliterowych, co gorsza polskojęzycznych zmiennych, a wiele używanych identyfikatorów nijak nie tłumaczy tego do czego dany element służy.

W obecnej postaci ten kod wygląda bardzo słabo – należy go wywalić i napisać od nowa. Tym razem powoli i z głową, tak aby wyglądał dobrze i aby dało się go analizować bez rwania włosów z głowy.

0

Kilka uwag co do kodu:

  • staraj się nie pisać tak dużych metod/funkcji. Rób mniejsze i z nich składaj większe itd. Kod będzie czytelniejszy i unikniesz copy paste.
  • nie nazywaj zmiennych j i k bo taki kod jest mało czytelny:
    if (j = 3) and (i < 3) then begin j := 1; inc(i) end
    else
    if (j = 3) and (i = 3) then begin j := 1; i := 1 end
  • co do powyższego, jeśli już tobisz warunek typu: (j = 3) and (i = 3) to lepiej wrzucić go do zmiennej typu bool, a potem sprawdzić ja w if'ie. Kod bedzie czytelniejszy i bedzie wiadomo, co sprawdzasz. Tylko nazywaj sensownie zmienne np: allFieldsFull lub noFreeField itp.
  • trzymaj sie jednej konwencji nazewnictwa zmiennych albo pos_x albo pos_X albo posX
0
pawelkO napisał(a):
  • co do powyższego, jeśli już tobisz warunek typu: (j = 3) and (i = 3) to lepiej wrzucić go do zmiennej typu bool, a potem sprawdzić ja w if'ie. […]

Wrzucenie wyniku do pomocniczej zmiennej lokalnej ma sens tylko wtedy, gdy uzyskana wartość wyrażenia ma być używana w kilku miejscach danego bloku kodu, lub gdy wyrażenie zwracające końcową wartość jest zbyt złożone, aby zapisać je w jednej, krótkiej linii.

W pozostałych przypadkach deklarowanie dodatkowych zmiennych jest bez sensu i zaciemnia kod.

  • […] Kod bedzie czytelniejszy i bedzie wiadomo, co sprawdzasz. Tylko nazywaj sensownie zmienne np: allFieldsFull lub noFreeField itp.
  • trzymaj sie jednej konwencji nazewnictwa zmiennych albo pos_x albo pos_X albo posX

Nie, ani jedno, ani drugie, ani żadne.

W Pascalu obowiązuje konwencja PascalCase dla wszelkich identyfikatorów z wyjątkiem stałych, które powinny być zgodne z konwencją UPPER_SNAKE_CASE. Dodatkowo, dla zwiększenia przejrzystości kodu, przewidziane są jednoliterowe prefiksy dla identyfikatorów ”specjalnego przeznaczenia”:

  • T dla typów danych,
  • P dla typów danych wskaźnikowych,
  • I dla interfejsów,
  • A dla argumentów procedur, funkcji i metod,
  • F dla pól klas i obiektów,

Wszelkie odstępstwa od wymienionych wyżej reguł są niemile widziane i niezalecane.


Tak przy okazji:

Adept123 napisał(a):
uses Graph,Crt,Silnik; { W Free Pascalu zamiast modułu Crt jest WinCrt. }

Moduł Crt jak najbardziej jest dostępny we Free Pascalu, a raczej jest dostępny dla FPC.

1
furious programming napisał(a):
pawelkO napisał(a):
  • co do powyższego, jeśli już tobisz warunek typu: (j = 3) and (i = 3) to lepiej wrzucić go do zmiennej typu bool, a potem sprawdzić ja w if'ie. […]

Wrzucenie wyniku do pomocniczej zmiennej lokalnej ma sens tylko wtedy, gdy uzyskana wartość wyrażenia ma być używana w kilku miejscach danego bloku kodu, lub gdy wyrażenie zwracające końcową wartość jest zbyt złożone, aby zapisać je w jednej, krótkiej linii.

W pozostałych przypadkach deklarowanie dodatkowych zmiennych jest bez sensu i zaciemnia kod.

Nie jest to prawda. Często tworzy się dodatkowe zmienne, by poprawić czytelność kodu. Nie tylko dlatego, gdy wyrazenie jest zbyt zlozone i nie miesci sie w jednej linii, ale także, gdy jest zbyt złożone i niezrozumiałe na pierwszy rzut oka.

Tu dobry przykład: https://medium.com/front-end-weekly/readability-and-simplicity-the-new-coding-religion-fe56e43db80
i tu:

1
pawelkO napisał(a):

Tu dobry przykład: https://medium.com/front-end-weekly/readability-and-simplicity-the-new-coding-religion-fe56e43db80

Może najpierw przeczytaj ten artykuł, zanim wykorzystasz go jako argument. Ten materiał traktuje o uproszczeniu złożonej instrukcji warunkowej i wrzucenia jej rezultatu do dodatkowej stałej, a nie o dodaniu lokalnych zmiennych tam gdzie rzekomo ich brakuje.

Zresztą ten przykład i tak jest z d**y, bo instrukcja warunkowa koniec końców i tak jest tak samo złożona jak była wcześniej, więc to raczej składniowa masturbacja, niż jakiekolwiek zwiększenie czytelności.

0

Witajcie
Chociaż nie jestem profesjonalistą w programowaniu, to jednak udało mi się stworzyć zupełnie nowe obliczenia do "silnika" gry kółka i krzyżyka :).
Nowością jest między innymi to, że grę może zacząć zarówno gracz jak i komputer.
Kod mam 888 linii, więc dołączam go w załączniku.
Pozdrawiam

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