Izdelaj kompletno aplikacijo za preprosto potezno igro POTAPLJANJE LADJIC med dvema igralcema (en igralec je računalnik).
NAVODILO NALOGE
Izdelaj kompletno aplikacijo za preprosto potezno igro POTAPLJANJE LADJIC med dvema igralcema (en igralec je računalnik).
PRAVILA IGRE
Igro igrata dva igralca. V našem primeru je eden izmed igralcev računalnik.
Vsak igralec ima igralno mrežo 10x10 kvadratkov. Hkrati ima na voljo 7 ladjic:
Vsak igralec postavi na svojo mrežo poljubno vse ladjice.
Ko imata oba igralca postavljene vse ladjice, se igra začne.
Igralca izmenično "streljata" nasprotnikova polja. Ko napadalec "strelja" mora nasprotnik (v našem primeru računalnik) preveriti, ali je polje zadeto ali ne in to sporoči nasprotniku. Če je napadalec s potezo hkrati tudi potopil ladjo, mu mora to nasprotnik tudi sporočiti.
Zmagovalec igre je tisti, ki prvi potopi vse nasprotnikove ladje.
ZAČETEK in RAZMISLEK
Najprej bomo ustvarili nov projekt v programu Visual Studio 2010. Poimenujemo ga npr. PotapljanjeLadjic.
Omenjeno igrico lahko igramo na več spletnih straneh.
Primer: klik
Ogled simulacije igranja igre v našem programu.
RAZMISLEK O VIDEZU PROGRAMA
GLAVNI DEL programa predstavljata dve mreži s kvadratki (velikosti 10x10). Vprašamo se, kako bi bilo mreže najlažje prikazati v programu:
Boljša ideja je, da izrisujemo mreži na platno (Panel):
Glavni del programa tako predstavljata dve platni (Panel-a). Da bo bolj pregledno, lahko vsakega postavimo v svoj GroupBox in le-tega ustrezno poimenujemo (spremenimo lastnost Text.)
Poleg dveh platnov bomo na formi prikazovali tudi različna sporočila (koliko ladij je potopljenih, kdaj je bila potopljena ladja itd.). Zato bodo poskrbele tri oznake (Label). Vsaka oznaka bo prikazovala svojo informacijo:
Potrebujemo samo še nek gumb, ki bo sprožil novo igro:
RAZMISLEK - HRANJENJE PODATKOV
Ko smo zadovoljni z videzom programa razmislimo, kako bomo hranili podatke v mreži oz. podatke o posameznih poljih.
Najprej premislimo, kaj moramo vedeti o posameznem polju:
Kasneje se bo izkazalo, da moramo hraniti tudi podatke o tem, ali je polje sosed ladje.
Za vsako polje, ki je del ladje, moramo vedeti kateri ladji pripada.
Kot opazimo, moramo za vsako polje vedeti kar nekaj podatkov. Lahko bi sicer imeli več kot dvodimenzionalno tabelo, a bi bilo to skrajno nepregledno.
Odločimo se, da bomo naredili dva nova razreda:
razred Polje,
Vsak objekt tega razreda bo vseboval naslednje podatke:
razred Ladja.
Vsak objekt tega razreda bo vseboval naslednje podatke:
S pomočjo razreda Polje tako mrežo polj hranimo kot dvodimenzionalno tabelo Polj.
Tabela je velika 10x10, ker je ravno toliko polj na mreži.
Polja [,] mrezaRacunalnik
Polja [,] mrezaIgralec
ZAČETEK
Kot smo že prej omenili, najprej naredimo nov projekt Windows Forms Application z imenom "PotapljanjeLadjic".
Odpremo program Visual Studio.
|
V spodnjem delu preimenujemo projekt v"PotapljanjeLadjic" (Name).
VIDEZ ("DESIGN") PROGRAMA
Potem, ko smo ustvarili nov projekt, se nam odpre projekt in se nahajamo v zavihku "Form1.cs [Design]". V tem zavihku bomo poskrbeli za videz programa.
Preden se lotimo "grajenja" forme oz. videza programa pa poskrbimo še za nekatere malenkosti.
Najprej naši formi spremenimo lastnost Text. To storimo tako, da desno v oknu "Properties" poiščemo lastnost Text in vpišemo poljuben niz. V našem primeru "Potapljanje ladjic". S tem poskrbimo, da bo prikazan naslov našega programa ravno "Potapljanje ladjic" in ne "Form1".
Poskrbimo, da je v programu Visual Studio prikazan razdelek/podokno Toolbox, ker ga bomo potrebovali v prihodnjih korakih.
Če v programu Visual Studio nimamo prikazanega podokna/razdelka "Properties" ga prikažemo tako, da v zavihku View izberemo možnost Properties Window.
Podobno prikažemo tudi podokno/razdelek "Toolbox" (View/Toolbox).
VIDEZ ("DESIGN") PROGRAMA
Naša verzija programa Potapljanje ladjic ne bo omogočala povečevanja okna programa, ker ni smiselno, da je večji oz. manjši.
Na začetku v [Design]-zavihku našo formo raztegnemo na velikost 604x408 oz. v podoknu Properties spremenimo lastnost Size (za frmPotapljanjeLadjic) na 604;408.
Sedaj iz podokna Toolbox posamično in ustrezno povlečemo na formo vse želene kontrole/komponente:
|
Ustrezno poimenovanje kontrol.
Prav tako moramo paziti, da sta obe platni (Panel-a) kvadratne oblike, ker je naša mreža polje velika 10x10.
V podoknu Properties spremenimo velikost platnoma (lastnost Size):
pnlIgralec --> Size --> 150; 150
Oznaki lblStatus spremenimo velikost pisave na 9, ker želimo, da to oznako igralec nekoliko bolj opazi.
Program bo spisan tako, da načeloma (razen začetnih nastavitev) ne bo odvisen od velikosti komponent. Če se bo programer kasneje odločil za razteg/pomanjšanje forme, tako ne bo imel večjih težav s spreminjanjem kode.
Že na začetku projekta se dogovorimo za enotno poimenovanje kontrol oz. za oznake v imenih kontrol:
PROGRAMIRANJE KODE IGRICE
Ko smo enkrat zadovoljnji s tem, kako je videti naša forma, nas čaka še najtežje delo, kaj se zgodi v ozadju. Pisanja kode se lotimo postopoma.
Razmislimo: Najprej potrebujemo narediti dve 2D tabeli polj in ju napolniti. Tukaj takoj naletimo na problem, nimamo še razreda Polje in razreda Ladja.
To naredimo tako, da v podoknu "Solution Explorer" z desnim klikom kliknemo na naš projekt "PotapljanjeLadjic", nato izberemo "Add" in zatem "Class".
|
Nato se nam odpre okno, kjer v spodnjem delu preimenujemo objekt in potrdimo s klikom na gumb Add.
V našem primeru naredimo dva razreda:
RAZRED Polje
Spomnimo se, kaj potrebujemo vedeti o polju:
Razred polje bo imel tako štiri privatne razredne spremenljivke:
bool odkrit:
Ladja ladja:
bool sosed:
bool potopljen:
Naredili bomo konstruktor čisto po meri glede na naš projekt Potapljanje ladjic, ki na začetku napolni mrežo 10x10 s samimi neodkritimi polji, ki predstavljajo vodo. Šele kasneje pa spreminjamo dana polja, glede na potek igre.
Torej so na začetku vsa bool polja false, spremenljivka ladja pa null (ker polje predstavlja vodo).
RAZRED Polje - METODE
Razred Polje bo vseboval naslednje metode:
METODI jeOdkrit() in odkrijPolje() - RAZRED Polje
Metoda vrne true, če je polje že odkrito oz. false, če še ni.
Metoda nastavi spremenljivko Polja odkrit na true in vrne true, če smo s to potezo potopili celotno ladjo oz. false če je nismo.
Če smo s to potezo potopili ladjo, pokličemo metodo zadeniLadjo(), ki jo kličemo na objektu razreda Ladja, ki ga hranimo v razredni spremenljivki ladja. Vrednost te spremenljivke dobimo z metodo vrniLadjo().
METODE jeVoda(), jeSosed() in nastaviSosed() - RAZRED Polje
Metoda vrne true, če je polje voda, torej kadar je spremenljivka ladja enaka null. Metoda vrne false, če je polje del ladje (ladja ni null).
Metoda vrne true, če je polje sosed kakšne ladje. Torej vrne kar vrednost razredne spremenljivke sosed.
Metoda spremenljivko sosed nastavi na podano vrednost jeSosed.
METODI vrniLadjo() in nastaviLadjo() - RAZRED Polje
Metoda vrne vrednost, ki jo ima razredna spremenljivka ladja.
Metoda polju priredi podano ladjo.
METODI jePotopljen() in potopiPolje() - RAZRED Polje
Metoda vrne true, če je polje že potopljeno, kar pomeni, da je polje del že v celoti potopljene ladje. Če spremenljivka vrne false pomeni, da je polje voda ali pa del še ne potopljene ladje.
Metoda razredni spremenljivki potopljen nastavi na true.
RAZRED Ladja
Spomnimo se, kaj potrebujemo vedeti o ladji:
Poznati moramo vsa polja, ki so del ladje.
Število zadetih polj
Konstruktor sprejme tabelo Polj.
Število zadetih polj je na začetku nič.
Znotraj konstruktorja se sprehodimo čez tabelo polj in vsakemu polju priredimo ladjo.
RAZRED Ladja - METODI
Razred Ladja bo vseboval naslednji metodi:
METODA zadeniLadjo() - RAZRED Ladja
Metoda poveča število zadetih polj ladje za ena in hkrati preveri, če smo s to potezo ladjo potopili.
Metoda vrne true, če smo s to potezo v celoti potopili ladjo. Torej je število zadetih polj enako dolžini tabele Polj ladje (polja).
METODA tipLadje() - RAZRED Ladja
Metoda vrne tip ladje, kot niz.
Tip ladje določimo glede na število polj, ki jih ladja zasede:
Nazaj v naš glavni program - DEKLARACIJA RAZREDNIH SPREMENLJIVK
Sedaj imamo pripravljena oba potrebovana razreda.
Kodo v ozadju programa bomo pisali v zavihku "frmPotapljanjeLadjic.cs".
Vse spremenljivke na nivoju forme bodo privatne (private).
Na nivoju forme bomo hranili naslednje spremenljivke:
Obe mreži oz. dvodimenzionalni tabeli Polj.
Število potopljenih ladij na posamezni mreži/plošči.
int stPotopljenihIgr;
int stPotopljenihRac;
Enota velikosti kvadratka plošče pnlRacunalnik.
Generator naključnih števil, ki ga bomo uporabili pri naključnem postavljanju ladij in pri potezah računalnika.
Seznam zadnjih zadetih polj ladje, ki še ni potopljena.
List<Point> zadnjePoteze;
DOGODEK/METODA Load - frmPotapljanjeLadjic_Load(object sender, EventArgs e)
KAJ SE ZGODI, KO SE FORMA NALOŽI OZ. ODPREMO PROGRAM?
Vrednost, ki se ne bo spreminjala čez celotni projekt, je enota velikosti kvadratka za ploščo pnlRacunalnik. Zato jo lahko izračunamo na začetku.
Poleg enote, lahko na začetku naredimo še generator naključnih števil.
Vse ostale spremenljivke in lastnosti se bodo spreminjale glede na potek igre oz. začetek igre.
Pripravimo si neko novo metodo, ki ne vrača ničesar(void), npr. metodo novaIgra(). Ta metoda bo poskrbela za pripravo vseh spremenljivk in kontrol ter njihovih lastnosti za začetek igre.
V zavihku, kjer se nahaja koda, Load metodo dobimo tako, da v [Design]zavihku dvakrat kliknemo na formo. Ob dvojnem kliku se nam odpre zavihek "frmPotapljanjeLadjic.cs", fokusirana je želena metoda.
METODA novaIgra()
Metodo novaIgra() bomo poklicali vsakič, ko bomo začeli novo igro.
Znotraj metode bomo najprej na novo naredili obe dvodimenzionalni tabeli Polj velikosti 10x10. Omenjeni tabeli bosta predstavljali mreži obeh igralcev.
Nato bomo mreži napolnili s samimi neodkritimi polji, ki bodo za enkrat predstavljali samo vodo.
Za to spišemo novo funkcijo napolniMrezo(Polje [,] mreza).
Za tem bomo naključno na vsako mrežo postavili vseh možnih 7 ladjic. Ladjice bomo postavljali posamično.
Na začetku igre je število potopljenih ladij igralca enako nič, prav tako je število potopljenih ladij računalnika enako nič.
Ustrezno oznakama lblStIgr in lblStRac spremenimo prikazano besedilo oz. lastnost Text.
Oznaka lblStatus na začetku ne prikazuje nobenega besedila. Njena lastnost Text je prazen niz.
Nato naredimo še nov seznam točk zadnjePoteze. Na začetku le-ta nima nobenega elementa, saj računalnik nima odkrite na začetku nobene ladje.
Za konec samo še sprožimo dogodka Paint za obe platni. Omenjen dogodek poskrbi za ponoven izris platna.
Dogodek Paint sprožimo s klicem Invalidate() na platnu.
METODA napolniMrezo(Polje[,] mreza) - frmPotapljanjeLadjic
Metoda podano mrežo oz. tabelo polj napolni s samimi neodkritimi polji, ki predstavljajo vodo.
Sprehodimo se torej čez vse elemente podane tabele in vsakemu polju priredimo nov objekt razreda Polje.
METODA dodajLadjo(int steviloPolj, Polje[,] mreza) - frmPotapljanjeLadjic
Metoda doda ladjo na mrežo. Pozicijo izbere naključno. Metoda sprejme dva parametra:
int steviloPolj
Polje[,] mreza
Metoda ne vrača ničesar, zato je void.
Znotraj metode si najprej pripravimo 4 spremenljivke
int rotacija nam bo povedala ali je ladja postavljena navpično ali vodoravno na mreži.
bool ok = false. Spremenljivka ok bo držala informacijo, če je ladjo z danim začetnim poljem (x,y) in izbrano rotacijo možno postaviti. Vemo namreč, da imamo več pogojev:
Dokler je spremenljivka ok enaka false, iščemo novo pozicijo ladje. Pomagamo si z while zanko.
Znotraj while zanke spremenljivko ok nastavimo na true in poiščemo naključno rotacijo. Torej s pomočjo generatorja števila gen, poiščemo naključno število, bodisi 0 bodisi 1. Nato glede na rotacijo ločimo dva primera.
Če je rotacija enaka 0, bomo poizkusili ladjo postaviti vodoravno.
Določimo neko naključno začetno pozicijo/polje (x,y) s pomočjo generatorja naključnih števil gen:
x je naključno celo število med 0 in 10-steviloPolj.
y je naključno število med 0 in 10.
Glede na velikost se sprehodimo čez polja, kamor želimo postaviti ladjo. Pomagamo si s for zanko, kjer i teče od x-a do vključno x+steviloPolj-1. Za vsako polje (i, y) preverimo, če je prosto oz. (i,y) polje ni sosed. Če je polje že sosed kateri ladji, ok nastavimo na false in gremo z ukazom break ven iz zanke, ker vemo, da ta postavitev ni v redu. Ker bo ok false, se bo zanka izvedla ponovno oz. tolikokrat, dokler ne bomo našli ustrezne pozicije.
V kolikor se for zanka izteče in je ok enak true vemo, da smo našli ustrezno pozicijo za ladjo. Takrat naredimo tabelo Polj dolžine vrednosti spremenljivke steviloPolj.
Spet se s pomočjo for zanke sprehodimo čez polja ladje v mreži in jih hkrati dodajamo v našo novo tabelo polja.
Ko se for zanka izteče, naredimo novo ladjo s tabelo polja.
Če je rotacija enaka 1, bomo poizkusili ladjo postaviti navpično.
Podobno kot prej določimo naključno začetno polje ladje (x,y). Tokrat pazimo, da je x enak za vsa polja in se y spreminja.
Princip je podoben kot pri ladji, ki je postavljena vodoravno, le da, kot smo omenili, se spreminja y in ne x.
Torej, sprehodimo se čez polja in preverimo, če so vsa polja prosta oz. nobeno polje še ni sosed.
Če so vsa polja prosta, naredimo novo ladjo in vsa polja ladja označimo za sosede.
METODA oznaciSosede(int x, int y, Polje[,] mreza)
Na spodnji sliki imamo označene sosede polja, ki ima vse sosede. Upoštevati moramo dejstvo, da polje na robu mreže nima vseh sosedov!
|
Iz slike razberemo, da označimo polja od x-1 dox+1 po x-osi in od y-1 do y+1 po y-osi(če nismo na robu).
Torej, potrebovali bomo dvojno for zanko. V zunanji for zanki bo i tekel po indeksih stolpcev tabele od vključno x-1 do vključno x+1. V notranji for zanki pa bo j tekel po indeksih vrstic od y-1 do y+1.
Znotraj obeh for zank preverimo, če je polje (i,j) res v tabeli/mreži, torej velja:
Če je polje (i,j) znotraj mreže, temu polju s pomočjo objektne metode nastaviSosed(true) nastavimo lastnost sosed na true.
RISANJE
Sedaj se moramo lotiti izrisovanja mreže na platno.
Velikost stranice kvadratka bomo dobili tako, da bomo širino ali višino celotnega platna delili z 10, torej s številom kvadratkov.
Za izrisovanje bomo spisali svojo metodo, ki bo sprejela 4 argumente:
Razločili bomo pet vrst Polj in le-te bomo ločili glede na barvo:
Znotraj metode najprej izračunamo enoto kvadratka za podano platno.
Širino platna dobimo tako, da uporabimo kar lastnost platna Width. Lahko bi uporabili to višino platna Height.
Kot smo omenili, bomo izrisovali na platno kvadratek po kvadratek. Z dvojno for zanko se tako sprehodimo čez vse elemente mreže.
Znotraj notranje for zanke najprej naredimo kvadrat z ustrezno pozicijo in velikostjo. Za to poskrbi funkcija Rectangle, ki jo kličemo na podanem objektu g. Omenjena funkcija sprejme štiri argumente.
Prva dva argumenta povesta pozicijo (x, y).
3. in 4. argument pa povesta širino in višino pravokotnika. V našem primeru gre za kvadrat, zato sta širina in višina enaki.
Naredimo torej nov kvadrat:
Kvadrat bomo narisali z naslednjim klicem:
g.FillRectangle(copic, kvadrat)
Kvadratke bomo ločili glede na barvo:
ZADETA VODA:
POTOPLJENA LADJA
ZADETA LADJA
NEZADETA LADJA
NEODKRITO POLJE
Vse naštete primere seveda ločimo z if/else if/…/else stavki. Ko se le-ti izvedejo, imamo pripravljen čopič in samo še ustrezno izrišemo kvadratek:
Koda metode narisiPolja(Graphics g, Panel platno, Polje[,] mreza, bool rac)
RISANJE - DOGODKA Paint
Na prejšnji prosojnici smo si pripravili splošno metodo narisiPolja(), ki nam na podano platno izriše trenutno mrežo.
Omenjeno funkcijo kličemo takrat, ko se sproži ponovni izris platna. Za to poskrbi dogodek Paint, ki je vezan na platno.
Dogodek Paint vsebuje dva parametra:
PaintEventArgs e --> S pomočjo e-ja bomo dobili objekt Graphics:
e.Graphics
Znotraj te metode pokličemo metodo narisiPolja(), kateri podamo:
Koda dogodka pnlRacunalnik_Paint(object sender, PaintEventArgs e)
Znotraj te metode pokličemo metodo narisiPolja(), kateri podamo:
Koda dogodka pnlIgralec_Paint(object sender, PaintEventArgs e)
METODA konecIgre()
Metoda konecIgre() vrne true, če je konec igre oz. false, če ni.
Igre je konec, ko eden od igralcev potopi vseh 7 ladij nasprotnika. Torej kadar ima ena od spremenljivk stPotopljenihIgr ali stPotopljenihRac vrednost 7.
V kolikor je omenjen pogoj uresničen:
Uporabniku izpišemo sporočilo glede na to, kdo je zmagal.
Sporočilo prikažemo na zaslon s pomočjo naslednjega ukaza:
Ko se izvede zgornji ukaz, se uporabniku prikaže naslednje okno. Spodnja slika prikazuje primer, ko zmaga igralec:
Igralec se odloči, ali želi ponovno igro oz. ali želi zaključiti igro.
Rezultat njegove odločitve se shrani v spremenljivko result.
V kolikor ni konec igre, torej prvi pogoj, da je eden od igralcev potopil vseh 7 ladij, ni resničen, pa metoda vrne false.
POTEZA IGRALCA in dogodek pnlRacunalnik_Click
Igralec bo naredil svojo potezo tako, da bo kliknil na izbrano polje na računalnikovi mreži/platnu.
Glede na to, kam bo kliknil, se bo polje odkrilo. Če je polje že odkrito, se ne zgodi nič.
Ko uporabnik klikne nekam na platno, se sproži dogodek pnlRacunalnik_MouseClick.
int y = e.Location.Y / enota;
Če je polje znotraj tabele, potem odkrijemo polje oz. (x,y)-ti element tabele mrezaRacunalnik. To naredimo tako, da pokličemo metodo mrezaRacunalnik[x, y].odkrijPolje(). Njen rezultat shranimo v neko bool spremenljivko, npr. potopljena. Če je potopljena true, to pomeni, da smo s to potezo potopili ladjo.
Spremenimo še lastnost Text oznake lblStRac, izpišemo novo število potopljenih:
Na zaslon s pomočjo lblStatus sporočimo, da smo potopili določeno ladjo (tip ladje dobimo s pomočjo objektne metode tipLadje() razreda Ladja).
Ustrezno moramo seveda spremeniti tudi lblStatus.Text.
Za tem preverimo, če je slučajno konec igre. To naredimo tako, da pokličemo funkcijo konecIgre().
Če še ni konec igre, računalnik naredi naslednjo potezo.
Koda dogodka pnlRacunalnik_MouseClick(object sender, MouseEventArgs e)
Opomba 1 - Kako do dogodka MouseClick?:
V [Design]-zavihku se postavimo na platno pnlRacunalnik, nato pa v Properties pod Events(strela) poiščemo dogodek MouseClick in nanj dvakrat kliknemo.
Opomba 2:
Kasneje bomo program izboljšali tako, da bo s pomočjo miškinega kazalca znano, ali je polje že odkrito ali ne.
METODA naslednjaPoteza()
Metoda naslednjaPoteza() poskrbi za naslednjo potezo računalnika. Torej izbere in cilja naključno polje.
Lahko bi to metodo naredili zelo enostavno. Torej, generirali bi naključna polja toliko časa, dokler ne bi zgenerirali nekega polja, ki do sedaj še ni bilo odkrito.
Lahko pa malo bolj "zakompliciramo" zadevo in naredimo nekoliko bolj pameten računalnik.
Imamo 3 možnosti:
Trenutno nimamo odkrite (še ne v celoti potopljene) nobene ladje.
Trenutno imamo odkrito eno ladjo (še ne v celoti potopljeno), a le eno polje te ladje
Trenutno imamo odkrito eno ladjo (še ne v celoti potopljeno) in ta ladja ima odkrito več kot eno polje.
METODA naslednjaPoteza() - PODROBNA RAZLAGA
Na začetku metode si pripravimo nekaj spremenljivk:
int x=0 in int y = 0 --> Ti dve spremenljivki bosta predstavljali trenutno polje (x,y).
int ind = 0 --> Spremenljivka bo hranila število odkritih polj trenutno delno odkrite ladje.
Če trenutno nimamo odkrite nobene ladje, bo to število enako 0.
Sedaj imamo definirane vse spremenljivke, ki ji potrebujemo znotraj te metode.
Kot smo že omenili, dokler bo spremenljivka odkrit enaka true, iščemo novo polje (x,y). Pomagamo si z while zanko. Znotraj le-te ločimo na grobo 2 primera:
V tem primeru generiramo naključna x in y med vključno 0 in vključno 9.
V tem primeru najprej določimo smer.
Ločimo 2 primera:
Če je število elementov seznama 1, imamo odkrito samo eno polje in imamo na voljo 4 smeri.
Če je število elementov seznama večje kot 1, pa priredimo smer glede na rotacijo ladje.
Sedaj imamo določeno smer. Glede na smer pa sedaj določimo polje.
Spet imamo 4 možnosti (toliko kolikor imamo možnih smeri):
Če je smer = 0 - pogledamo gor:
Koordinata x ostane enaka kot že pri odkritem polju ladje.
Koordinato y pa določimo s pomočjo točke na ničtem mestu seznama in njene lastnosti Y, kateri odštejemo 1.
Če je smer = 1 - pogledamo dol:
Koordinata x ostane enaka kot že pri odkritem polju ladje.
Koordinato y pa določimo s pomočjo točke na zadnjem mestu seznama in njene lastnosti Y, kateri prištejemo 1.
Točka na zadnjem mestu v seznamu zadnjePoteze bo imela največji možni y od odkritih polj ladje.
Če je smer = 2 - pogledamo levo:
Koordinato x določimo s pomočjo točke na ničtem mestu seznama in njene lastnosti X, kateri odštejemo 1.
Če je smer = 3 - pogledamo desno:
Koordinato x določimo s pomočjo točke na zadnjem mestu seznama in njene lastnosti X, kateri prištejemo 1.
Glede na smer smo sedaj določili neko polje (x,y). Če omenjeno polje leži znotraj mreže, preverimo s pomočjo polja (x,y) v mreži mrezaIgralec na (x,y)-tem nad katerim kličemo metodo jeOdkrit(). Kar omenjena metoda vrne, si shranimo v spremenljivko odkrit.
V koliko ima spremenljivka odkrit vrednost false, smo našli polje, ki še ni odkrito in ga odkrijemo s pomočjo metode odkrijPolje(). Kar slednja metoda vrne, si zapolnemo v spremenljivko potopljena.
Naša metoda se glede na to, ali smo s to potezo potopili ladjo ali ne, razdeli na dva dela:
Če smo s to potezo potopili celotno ladjo, torej če ima spremenljivka potopljena vrednost true, izvedemo naslednje korake:
seznam zadnjePoteze s pomočjo metode Clear() izpraznimo.
Z rdečo barvo izpišemo na zaslon sporočilo, da je računalnik potopil določeno ladjo.
Preverimo, če je konec igre - klic metode konecIgre().
Če s to potezo še nismo potopili celotne ladje, seznamu zadnjePoteze dodamo točko s koordinatami (x,y) in nato seznam uredimo.
SeznamzadnjePotezeželimo sortirati najprej po koordinatix, nato pa še po koordinatiy.
Najbolj naravno se nam zdi, da pokličemo metodo Sort(). Na žalost tukaj naletimo na problem, da metoda ne zna primerjati dveh točk.
Problem rešimo z naslednjim klicem:
DOGODKA pnlRacunalnik_MouseMove IN pnlRacunalnik_MouseLeave
Sedaj, ko se z miško postavimo na določeno polje, se miškin kazalec ne spremeni oz. je za vsa polja enak.
Program spremenimo tako, da se kazalec spreminja glede na to, kje je miška.
Pozicijo miške dobimo s pomočjo dogodka pnlRacunalnik_MouseMove. Omenjeni dogodek se sproži vsakič, ko se z miško premaknemo kjerkoli na platnu pnlRacunalnik.
Pozicijo miške dobimo podobno kot pri dogodku pnlRacunalnik_Click (s pomočjo parametra e).
Če je polje (x,y) že odkrito, kazalec miške spremenimo z naslednjim ukazom:
Če je polje še neodkrito, torej ga uporabnik s klikom lahko odkrije, pa kazalec miške spremenimo v roko z naslednjim ukazom:
To pa še ni vse, ko uporabnik z miško zapusti naše platno pnlRacunalnik, se more naš kazalec miške spremeniti nazaj v puščico.
Koda dogodka pnlRacunalnik_MouseMove(object sender, MouseEventArgs e)
Ko uporabnik z miško zapusti ploščo pnlRacunalnik, se sproži dogodek MouseLeave.
Ko se sproži omenjeni dogodek, kazalec miške nastavimo nazaj na puščico. To naredimo z ukazom:
Koda dogodka pnlRacunalnik_MouseLeave(object sender, EventArgs e)
ZAKLJUČEK
S tem smo "zgradili" preprosto aplikacijo za potezno igro Potapljanje ladjic.
PONOVILI:
SE NAUČILI:
PREDNOSTI IN SLABOSTI PROGRAMA
SIMULACIJA IGRE
VIRI
Pravila igre:
Ideja za sortiranje seznama točk:
Primer in ideja: