rewersi1Rewersi lub bardziej po polsku Odwracanka, to bardzo prosta gra rozgrywana na szachownicy, czarnymi i białymi pionami. Uczyłem się na niej programować w kilku różnych językach i na kilku różnych komputerach. Pierwsza wersja na ZX Spectrum – 1985, potem Commodere C64 – 1988 i typowy PeCet – 1991. I jest jeszcze jedna bardzo ciekawa rzecz – ten program udaje że jest inteligentny i przewiduje kilka ruchów do przodu. Ostatnia wersja programu to około 1000 wierszy kodu źródłowego i prawie 30000 znaków.

Moja przygoda z komputerami rozpoczęła się w roku 1984, kiedy to Amerykanie znieśli embargo na sprzęt komputerowy dla krajów tzw. „bloku wschodniego”. Mój kumpel z pokoju w studenckim akademiku przywiózł pewnego dnia małą, czarną skrzyneczkę. Podłączało się do niej byle jaki telewizor (innych wtedy nie było), magnetofon kasetowy i tzw. dżojstiki. Przez 15 minut wczytywało się program, a potem… granie do białego rana. Dzisiaj każdy na komórce ma gierki na wyciągnięcie ręki. Wtedy taki sprzęt był chyba jeden na kilka tysięcy chłopa i jakaż to była nowość! – małym, jednokolorowym kurczakiem, można było sterować, łapać jajka i uciekać przed złym potworem!

Granie zostało mi do dzisiaj, ale pojawiło się typowe inżynierskie pytanie: „Jak to działa?” i od tego momentu zaczęła się moja przygoda z programowaniem. Najpierw rozwiązywaliśmy jakieś laboratoria i skomplikowane obliczenia – o arkuszu kalkulacyjnym nie było jeszcze mowy. Potem wymyśliłem sobie, że sam napiszę gierkę – i wybór padł właśnie na Rewersi. Pierwszy program w Basicu, a gdy okazało się, że mój program zamyśla się nad następnym ruchem zbyt długo, przeniosłem całą „inteligencję” na język maszynowy. Co to język maszynowy? W typowym kodzie źródłowym (Basic, Pascal, itp.) mamy do czynienia ze zrozumiałymi dla człowieka (programisty) wyrazami, które dopiero tłumaczymy na kod zrozumiały dla procesora. Kod maszynowy, to gotowe instrukcje, które rozumie tylko procesor, nie trzeba ich tłumaczyć, i dlatego program działa wiele razy szybciej.

Na piątym roku studiów miałem już swój komputer. Przez półtora miesiąca byłem hutnikiem i grzebałem takim wielkim pogrzebaczem pod stutonowym kociołkiem wypełnionym płynną stalą. Działo się to w austriackim Linzu i najważniejszą rzeczą, którą wtedy przywiozłem był właśnie mój pierwszy komp – Commodore C64 ze stacją dysków. W drugim plecaku miałem ze 20 kilo kawy i tysiąc innych drobiazgów. Dodać należałoby, że działo się to wszystko niecały miesiąc po moim ślubie, a w polskich sklepach królowały głównie puste półki. W trakcie pisania pracy dyplomowej przerobiłem mój program na nową maszynę.

Trzecia i ostatnia wersja Rewersi powstała w 1991 roku pod koniec mojej pracy w Tarnowskich Zakładach Mechanicznych. Tym razem już w Pascalu. Tym razem z wykorzystaniem gotowych bibliotek napisanych przez innych, mądrzejszych ode mnie. Tym razem bez grzebania w „bebechach” procesora. Jak zdążyliście zapewne zauważyć – królował tryb tekstowy, choć już na kolorowym ekranie.

Co w programie ciekawego?

  • Menu zostało wygenerowane za pomocą gotowego oprogramowania.
  • Aby animacje były sprawniejsze niezbędne informacje zapisywane są bezpośrednio w pamięci ekranu – we współczesnych systemach nie wolno i nie można tego już robić.
  • Można wybrać rozgrywki z komputerem lub z innym graczem.
  • Rozgrywkę z komputerem można ustawić na kilku poziomach zaawansowania – analiza kilku ruchów do przodu.
  • Styl programowania dość prymitywny, ale uczyłem się cały czas

W jaki sposób program myśli? Tajemnica zawiera się w odpowiednim przypisaniu punktów do charakterystycznych pól planszy. Przed wykonaniem kolejnego ruchu program analizuje wszystkie możliwe ruchy przeciwnika i sumuje punkty. Tak się dzieje na najprostszym poziomie. Każdy kolejny poziom to kolejne rekurencyjne zapętlenie. Po każdym teoretycznym ruchu przeciwnika zapisanym w pamięci następuje analiza wszystkich możliwych ruchów komputera, znów sumowanie… i tak w koło, w zależności od tego jaki wybraliśmy stopień zaawansowania. Brzmi skomplikowanie i równie skomplikowanie wygląda w programie.

Kod źródłowy dla zainteresowanych a poniżej fragment

procedure nowe_pole_rek(kierunek,x,y,nr_pola,kolor:shortint);
var x1,y1:shortint;
begin
   nowe_pole(kierunek,x,y,nr_pola,x1,y1);
   case tablica[x1,y1] of
           2,0:buf_p[31,3]:=0;
             1:if kolor=1 then buf_p[31,3]:=1
                else begin nr_pola:=nr_pola+1;
                           nowe_pole_rek(kierunek,x,y,nr_pola,kolor);
                           if buf_p[31,3]=1 then rysuj_pole(x1,y1,kolor)
                     end;
            -1:if kolor=-1 then buf_p[31,3]:=1
                else begin nr_pola:=nr_pola+1;
                           nowe_pole_rek(kierunek,x,y,nr_pola,kolor);
                           if buf_p[31,3]=1 then rysuj_pole(x1,y1,kolor)
                     end
   end
end;

procedure rysuj_wokol(x,y,kolor:shortint);
var kierunek,pole:shortint;

begin
  for kierunek:=1 to 8 do
    begin
      buf_p[31,3]:=0;
      pole:=1;
      nowe_pole_rek(kierunek,x,y,pole,kolor)
    end
end;
var ruszaj:boolean;

procedure badaj_wokol(kto_rusza,x,y:shortint;var punkty:integer);
var kierunek,nr_pola,x1,y1:shortint;
    koniec:boolean;

begin
  ruszaj:=false;
  for kierunek:=1 to 8 do
    begin
       koniec:=false;
       nr_pola:=0;
       x1:=0;y1:=0;
       repeat
         nr_pola:=nr_pola+1;
         nowe_pole(kierunek,x,y,nr_pola,x1,y1);
         if (x1<1) or (x1>8) or (y1<1) or (y1>8)
           then nr_pola:=0
           else sprawdz_pole(nr_pola,koniec,x1,y1,kto_rusza)
       until (nr_pola=0) or (koniec=true);
       if nr_pola>1 then begin punkty:=punkty+nr_pola;ruszaj:=true end;
    end;
    if ruszaj=true then punkty:=punkty+punktacja[x,y]
end;

procedure badaj_wokol(kto_rusza,x,y:shortint;var punkty:integer);
  var kierunek,nr_pola,x1,y1:shortint;
    koniec:boolean;

  begin
  for kierunek:=1 to 8 do
    begin
       koniec:=false;
       nr_pola:=0;
       x1:=0;y1:=0;
       repeat
         nr_pola:=nr_pola+1;
         nowe_pole(kierunek,x,y,nr_pola,x1,y1);
         if (x1<1) or (x1>8) or (y1<1) or (y1>8)
           then nr_pola:=0
           else sprawdz_pole(nr_pola,koniec,x1,y1,kto_rusza);
       until (nr_pola=0) or (koniec=true);
       if nr_pola>1 then
          begin
            zapisz:=true;
            punkty:=punkty+(nr_pola-1)*kto_rusza;
            case kierunek of
              6,2:if (y=1) or (y=8)
                     then punkty:=punkty+bb;
              8,4:if (x=1) or (x=8)
                     then punkty:=punkty+bb
            end
          end
    end;
    if zapisz=true then punkty:=punkty+punktacja[x,y]
  end;