Pocecemo od vrlo jednostavne igre - X-O u konzoli. Nema kreiranja prozora, inicijalizacije za crtanje 3D objekata, pustanja zvuka i slicnih stvari. Pozabavicemo se osnovnim operacijama koje uglavnom svaka igra ima.
Za pocetak cemo sve da uprostimo i prikazemo kako ce program izgledati:
Code:
program helloxo;
begin
Inicijalizacija promenljivih
Izvrsavanje glavne petlje
Oslobadjanje resursa
end.
Posto je glavna petlja cesto velika i komplikovana, praksa je da se ona i pomocne funkcije nalaze u drugom unit-u, a da se u programu sve inicijalizuje i samo pozove funkcija koja pokrece glavnu petlju. Tako cemo i mi uraditi bez obzira sto je XO vrlo jednostavno napraviti.
Napravicemo nov unit u kojem cemo postaviti promenljive i sve potrebne funkcije. Pocecemo od promenljivih... tabela u XO je velicine 3x3 i svako polje moze imati 3 moguce verdnosti: X, O ili prazno. Za takav podatak nam dvodimenzionalni niz (3x3) sasvim odgovara. Posto svako polje moze da ima 3 razlicite vrednosti, tip podatka za niz takodje mora da bude u stanju da ima bar 3 vrednosti. Integer moze da mnogo razlicitih vrednosti i operacije nad njim se vrlo brzo izvrsavaju pacemo napraviti dvodimenzionalni niz celobrojnih vrednosti.
Code:
Table: array[1..3, 1..3] of Integer;
Da nam se u kodu ne bi desilo da zaboravimo da li X predstavlja broj 1 ili broj 2 ili neki treci, nije lose da napravimo konstante koje ce nam pomoci i da se lakse snadjemo u kodu i da ne moramo da pamtimo sta koji broj znaci:
Code:
CX = 1;
CO = 2;
Dobro... imamo tabelu... bilo bi lepo da mozemo da zapamtimo imena igraca koji igraju i da mozemo kasnije da kazemo
na redu je Pera umesto
na redu je igrac koji igra sa znakom X. Niz od dva clana (jedan za X jedan za O) nam je sasvim dovoljan za to:
Code:
Players: array[CX..CO] of String;
Sta nam je jos potrebno... potrebno nam je da znamo koji igrac trenutno igra. Posto postoje samo X i O igrac bilo bi nam dovoljno da uzmemo Boolean tip i da True predstavlja igraca X, a False igraca O, ali da bi kod bio citljiviji i laksi za trazenje greske, bolje je da ovaj podatak cuvamo u tipu Integer i da ga postavimo na konstantu CX kada igra igrac X ili na CO kada igra igrac O:
Code:
CurrentPlayer: Integer;
Za kraj nam jos trebaju 2 promenljive u koje ce igrac upisati na koje polje zeli da igra (X i Y koordinatu polja):
Code:
CurrentX, CurrentY: Integer;
Imamo sve potrebne promenljive, sada krecemo na proceduru koja ce da predstavlja glavnu petlju u igri i na pomocne procedure i funkcije. U nasem slucaju bi glavna petlja trebala da radi sledece:
Code:
procedure Run;
begin
Nacrtaj trenutno stanje na tabeli
Uzmi od igraca polje na koje zeli da igra i postavi ga na
vrednost koja zavisi od igraca koji je na potezu (X ili O)
Promeni igraca
Ako nije kraj igre, ponovi sve
end;
Kod koji uzima od igraca koordinatu polja i postavlja znak bi mogao da izgleda ovako:
Code:
Write('Postavi znak na (X Y): ');
ReadLn(CurrentX, CurrentY);
Table[CurrentX, CurrentY] := CurrentPlayer;
Sve deluje lepo, ali sta ako igrac pokusa da odigra na vec zauzeto polje ili da odigra na polje 10, 10 koje ne postoji? Treba nam neka provera. Da ne bi bez potrebe komplikovali glavnu petlju, tu proveru cemo napraviti u pomocnoj funkciji:
Code:
function GetField(aX, aY: Integer): Integer;
begin
if (aX in [1..3]) and (aY in [1..3]) then
Result := Table[aX, aY]
else
Result := -1;
end;
Ova funkcija ce nam vratiti -1 ako igrac bira nepostojece polje ili vrednost iz polja koja se trenutno tamo nalazi. Dakle, prolje je prazno ako nije -1, CX ni CO. Da ne bi morali da proveravamo sva tri uslova, prilikom inicijalizacije promenljivih cemo celu tabelu popuniti nulama i ona ce nam predstavljati prazno polje (nula i nil uglavnom uvek znace da je nesto prazno pa necemo definisati konstantu za prazno polje).
Sada kod za postavljanje znaka izgleda ovako:
Code:
repeat
Write('Postavi znak na (X Y): ');
ReadLn(CurrentX, CurrentY);
until GetField(CurrentX, CurrentY) = 0;
Table[CurrentX, CurrentY] := CurrentPlayer;
Imamo deo glavne petlje... idemo dalje... kod za promenu igraca je prilicno jednostavan i ne treba ga objasnjavati... ako nekom nije jasan neka uzme knjigu i prvo nauci Pascal pa neka nastavi sa citanjem ovog tutoriala:
Code:
Inc(CurrentPlayer);
if CurrentPlayer > CO then
CurrentPlayer := CX;
Kod za proveru da li je igra zavrsena je takodje velik da bi ga ostavili u proceduri za glavnu petlju pa cemo i njega izvuci u pomocnu funkciju. Funkcija bi mogla da vracam samo True ili False, ali onda ne bi znali da li je igra gotova zato sto je neko pobedio ili je nereseno. Zato mozemo da uradimo funkciju tako da vrati -1 ako jos moze da se igra, 0 ako je nereseno, CX ako je pobedio igrac X ili CO ako je pobedio igrac O. Kako bi trebalo da izgleda ta funkcija... to je na vama da odlucite. Dacu vam samo malu pomoc. Imate polje na kojem je poslednji znak postavljen, dovoljno je da pogledate gore, dole i ukoso od tog polja i vidite da li imate 3 spojena znaka, ako nema 3 znaka ostaje samo jos da se proveri da li je tabela puna. Resenje koja ja trenutno imam je da svaki put prodjem kroz celu tabelu i vidim da li su sva polja puna, ali to moze da se resi na mnogo bolji i jednostavniji nacin... ako ima samo 9 polja koliko puta moze da se postavi znak do se tabla ne popuni
Jos jedna funkcija koju vam prepustam je funkcija za crtanje tabele. Ova funkcija je prilicno jednostavna... ja sam je uradio tako da ona ispisuje znak iz tabele i pravi razmak posle njega i, poels svakog reda ubacuje jedan prazan, a vi mozete da se igrate i da probate da nacrtate okvir i linije izmedju.
Kada imamo sve ovo, program je jednostavno napisati... prvo inicijalizujemo promenljive:
Code:
FillChar(Table, SizeOf(Table), 0);
Write('Unesite ime prvog igraca: ');
ReadLn(Players[CX]);
Write('Unesite ime drugog igraca: ');
ReadLn(Players[CO]);
Posle toga pozivamo glavnu petlju:
Code:
Run;
To je dovoljno da bi igra radila... ali, igraci bi voleli da vide ko je pobedio. Jedno od resenja je da u programu ponovo pozovemo funkciju koja nam je rekla zbog cega je doslo do kraja igre i na osnovu toga ispisemo poruku (tako sam uradio u kodu koji cu kasnije postovati)... ali zasto pozivati istu funkciju 2 puta kad mozemo da uradimo nesto drugo

Ko se seti neka kaze.
Jos jedna stvar koja nervira igrace... zavrse igru i ona se zatvori bez pitanja da li zelis da igras ponovo. Funckija koja pita igraca bi mogla da izgleda ovako:
Code:
function PlayAgain: Boolean;
var
YesNo: Char;
begin
Write('Da li zelite da igrate ponovo (D/N): ');
ReadLn(YesNo);
Result := upCase(YesNo) = 'D';
end;
Kod glavnog programa bi onda ovako izgledao:
Code:
repeat
FillChar(Table, SizeOf(Table), 0);
Write('Unesite ime prvog igraca: ');
ReadLn(Players[CX]);
Write('Unesite ime drugog igraca: ');
ReadLn(Players[CO]);
Run;
until not PlayAgain;
E, sad... na nekom od vas je da napise ceo kod i da ga postuje. Cim dobijemo funkcionalnu igru, postovacu svoj kod i onda cemo na kraju zajedno da doteramo kod tako da bude lak za pregled, jednostavan, da ima sve sto treba da ima od funckionalnosti (bio bi lepo da i u sred igre da se izadje iz programa, zar ne) i da korisniku izgleda sto je lepse moguce
