Rewersi 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;