Tikumängu ülesanne
Allikas: Lambda
Praktikumitöö tuleb teha vastavalt siin failis antud täpsustustele. Kõigepealt seletan, kuidas tikumäng käib, siis seda, kuidas seal võita, ning seejärel annan juhendid ja soovitused programmeerimiseks. Kuidas tikumängu mängitakse --------------------------- Vaatame kõigepealt hästi lihtsat varianti, siis kirjeldame selle väikest üldistust, st natuke keerulisemat varianti. Lihtsas variandis on algseisus laual kümme tikku: | | | | | | | | | | Kaks mängijat võtavad vaheldumisi laualt tikke ära. Kumbki võib võtta kas ühe, kaks või kolm tikku. Võtmata jätta ei tohi ja üle kolme võtta ei või. Kes võtab viimase tiku, on võitnud. Näiteks võib mäng käia nii: Mängija A võtab kaks tikku. Lauale jääb kaheksa: | | | | | | | | Mängija B võtab kolm tikku. Lauale jääb viis: | | | | | Mängija A võtab ühe tiku. Lauale jääb neli: | | | | Mängija B võtab ühe tiku. Lauale jääb kolm: | | | Mängija A võtab kõik kolm tikku, lauale ei jää enam ühtegi ja mängija A on võitnud. Keerukamas variandis on põhimõte sama, kuid: - Laual võib algseisus olla suvaline arv tikke (st päris palju, kasvõi sada) - Maksimaalne võetav tikkude arv ei pruugi olla kolm, vaid võib olla suvaline number kahest alates. Keerukamas mänguvariandis on seega vaja enne mängu algust kokku leppida: - Algseisus olevate tikkude arv N - Maksimaalne võetavate tikkud arv M. Näiteks, M võib olla kaks - siis tohib võtta kas ühe või kaks tikku. Kui M on viis, tohib võtta kas 1,2,3,4 või 5 tikku. Mängu käigus loomulikult M-i ei muudeta, M lepitakse kokku enne mängu algust. Kuidas tikumängus võita ----------------------- Üks viis tikumängus võitmiseks oleks mõelda ette oma võimalikud käiguvariandid, vastase võimalikud käiguvariandid, seejärel tekkivad oma käiguvariandid jne jne, justnagu males või kabes. Õnneks on tikumängu võimalik võita ka palju lihtsamini: nii, et üldse pole vaja midagi ette mõelda! Vaatame näiteks lihtsat tikumängu: 10 tikku algseisus (N=10) ja maksimaalselt kolm võetavat tikku (M=3). Selge, et kui vastasel on tema käigukorra ajal ees neli tikku: | | | | siis on vastane kindlas kaotusseisus: mina saan igal juhul viimase tiku. Kuidas teha nii, et vastasele jääks ette neli tikku? Kui vastasel on ees kaheksa tikku: | | | | | | | | siis saan ma igal juhul tekidada olukorra, kus peale tema käiku ja seejärel minu käiku on temal ees neli tikku, ning seega saan lõpuks võita. Üldpõhimõte on järgmine: - mängija on kaotusseisus, kui jääk(N/(M+1))=0 see tähendab: kui jagan laual olevate tikkude arvu arvuga M+1 ja võtan jäägi (näiteks, 5/3 annab jäägi 2), siis seis on kaotusseis, kui jääk on 0. - igal muul juhul on mängija võiduseisus ning võidukäigu saab ta arvutada sama põhimõtte järgi: võidukäik=jääk(N/(M+1)) Kuidas tikumängu praktikumis programmeerida =========================================== Kõigepealt, sinu programm peab vastama järgmistele nõuetele: - Programm läheb käima käsurealt ja trükkimine ning käikude lugemine toimub samuti lihtsalt käsurea viisil, st mingeid eraldi aknaid programm ei tee. - Programm suudab võiduseisust alati võita. - Kaotusseisus teeb programm juhusliku reeglitega lubatud käigu (näiteks, lihtsas tikumängus valib programm nelja tikuga seisus käiguks juhuslikult kas 1, 2 või 3). - Enne mängu algust peab programm kasutajalt küsima ja endale meelde jätma: - algseisus olevate tikkude arvu N - maksimaalse võetavate tikkude arvu M - mängu alustaja (masin või inimene) - Programm peab ise mängima vastavalt reeglitele ja ei tohi lubada vastasel teha keelatud käike (vastane ei tohi saada võtta 0 tikku või rohkem tikke, kui M). Kui vastane proovib teha keelatud käiku, siis programm teatab, et see pole lubatud käik ja küsib käiku uuesti. - Programm peab inimmängijale arusaadavalt iga oma käigu juures trükkima välja - kõigepealt, laual olevate tikkude arvu - seejärel oma käigu - seejärel lauale jäävate tikkude arv - seejärel küsima kas inimmängija käiku või teatama oma võidust. - Programm peab aru saama, kui programm või inimmängija on võitnud ning selle info ilusti välja trükkima. - Kui mäng saab läbi, siis peab programm küsima inimmängijalt, et kas too tahab veel mängida või ei. Kui mängija ei taha rohkem mängida, siis programm lõpetab töö. - Programmi java koodis peab taande kasutamine olema mõistlik ja ilus, samuti peab seal olema mõistlikus koguses mõistlikke kommentaare! Ilma kommentaarideta ja/või nõmeda taandega programmi ei pruugi praktikumijuhendaja vastu võtta. Järgnevalt mõned soovitused programmeerimiseks ============================================== Alusta programmeerimist sellest, et kirjuta ise või kopeeri endale HelloWorld programm, kompileeri ja lase käima: public class HelloWorld { // A program to display the message // "Hello World!" on standard output public static void main(String[] args) { System.out.println("Hello World!"); } } // end of class HelloWorld Seejärel kopeeri see fail "päris" tikumängu failiks nimega Tikumang.java ja asenda tema sees klassi nimi "HelloWorld" nimega "Tikumang". NB! Jutumärke ära muidugi pane, täpitähti ära kasuta, ning arvesta, et faili nimi ja klassi nimi peavad olema samad (välja arvatud .java lõpp) ja suured/väikesed tähed on erinevad. Kompileeri see uus fail ka ära ja pane käima. Nüüd hakka programmi kirjutama "main" funktsiooni sisse, kus esialgu on ainult rida System.out.println("Hello World!"); (selle rea võid ära ka kustutada). Mingeid muid funktsioone pole vaja teha. Programmi saab kokku panna lihtsalt if-dest, tsüklitest, arvutustest, lugemisest ja trükkimisest. Kuidas trükkida: ---------------- Kasuta lihtsalt System.out.println funktsiooni. Sellega saad trükkida nii stringe kui arve. Kui tahad, et trükitava lõpuks poleks reavahet, kasuta hoopis System.out.print funktsiooni (nime lõpus puudub ln). Kuidas lugeda inimmängija käike ja algseisu jne ----------------------------------------------- Loe kõigepealt Ecki õpikust peatükk 2.4 (URL: http://math.hws.edu/javanotes/c2/s4.html) Seal on õpetus, kuidas seda mugavalt teha. Sinul läheb vaja funktsiooni TextIO.getInt(), muid polegi otseselt vaja. NB! Selleks, et kasutada TextIO.getInt() funktsiooni, peab sinu arvutis sellesamas kataloogis, kus on tikumängu programmi fail, asuma Ecki kirjutatud programmifail TextIO.java. Selle faili saad võrgust tõmmata URL-ilt http://math.hws.edu/javanotes/source/TextIO.java ning ta oma kataloogi kirjutada. Proovi ta ära ka kompileerida. Käima see TextIO programm ise ei lähe, sest tal pole main funktsiooni sees. Idee selles, et kui Java kompilaator/mootor näeb funktsiooni TextIO.getInt(), siis ta asub otsima faili TextIO, kust seda funktsiooni leida võiks. Otsib ta faili kõigepealt sealtsamast kataloogist, kus sinu programmifail asub. NB! AK arvutiklassides kasuta nii kompilaatori javac kui interpretaatori java jaoks lisaparameetrit -cp . (javac -cp . minuprogramm.java), muidu ei leita .class faile sinu hetkekataloogist üles. Kuidas hoida hetkeseisu, vastase tehtud käiku jne? -------------------------------------------------- See on väga lihtne: iga selline info on lihtsalt üks täisarv ja teda saab hoida ühes täisarvu tüüpi muutujas. Näiteks, mänguseisu saabki hoida muutujas nimega n. Deklareeri programmi algul: int n; ja hiljem muuda seda n-i. Las n sisaldab alati laual olevate tikkude arvu. NB! Muutujate nimedes (nagu ka mujal) on väikesed ja suured tähed erinevad asjad. Mulle endale meeldib aga kasutada pikemaid muutujate nimesid, sest siis saan muutujat nähes alati aru, mis seal sees peaks olema. Mina kasutaksin mänguseisu hoidmiseks pigem näiteks muutujat nimega table. Näiteks nii: int table; table=10; Muuseas, soovitan kirjutada programmi sees muutujate nimed, kommentaarid jms alati inglise keeles! See on hea edaspidises päris-töös, kus väga tihti on vaja teha koostööd inimestega, kes eesti keelt ei mõista. Programmi koodi loetavus on programmeerimise-alase koostöö jaoks hädavajalik. Kuidas jäägiga jagada ---------------------- Nagu C keeles, nii ka javas on olemas täisarvude jäägiga jagamise tehe % (protsendimärk). Näiteks, 8 % 3 annab tulemuseks kahe: kaheksa jäägi kolmega jagamisel. Kuidas arvutada juhuslikku arvu ------------------------------- Juhusliku arvu leidmiseks on Java teegis spetsiaalne funktsioon juba olemas: Math.random() See funktsioon annab juhusliku suurusega, komaga arvu 0-i ja 1-e vahel. (0 võib tulla, 1 ei tule). Kuidas saada juhuslik täisarv 1-e ja X-i vahel (st lubatud väärtused oleks 1,2,...,X): korruta Math.random() tulemus arvuga X (siis saad arvu vahemikus 0,...,X kus X ei saa siiski tulla) liida tulemusele 1 (et ei tuleks 0 ja saaks tulla X) ja võta saadud arvust täisosa tüübiteisendust tegeva nn "cast"-i (int) abil: tulemus = (int)((Math.random()*X)+1) Kuidas programmi kirjutamisega hakkama saada -------------------------------------------- Kui asi tundub veidi keeruline, siis järgi neid põhimõtteid, mis on programmeerimise juures alati abiks (eriti veel suuremate ja tõsisemate programmide puhul, kus nende põhimõtete eiramine viib üldiselt fiaskoni): - Ära proovi kõike kohe valmis kirjutada. Selle asemel kirjuta algul hoopis lihtne variant programmist, näiteks lihtne tikumäng, kus alati N on algul 10, M on alati 3, inimmängija käike ei kontrollita, mäng toimub ainult ühe korra (uuesti ei alustata). Proovi see lihtsam programm korralikult käima saada. Kui selle lihtsama programmi kirjutamine läheb kah aeglaselt, siis tee hakatuseks veel lihtsam: Tee algul näiteks programm, kus arvuti võtab alati ühe tiku ja vastane üldse ei käi. Selge, et kümne käiguga on siis masin võitnud. Las programm trükib iga sammu järel oma käigu ja seisu ka. Kui see programm töötab, alles siis asu lisama vastase käigu lugemist. Ära kontrolle esialgu kohe peale pane ja ära esialgu pane arvutit juhuslikku käiku arvutama (las võtab alati ühe tiku). Enne, kui programmiga edasi lähed, kompileeri ja pane käima ja testi, et lisandusega lihtne variant käib OK. - Kui see lihtsam programm käib OK, alles siis asu lisandusi tegema: - juhusliku käigu leidmine - M ja N valik, - inimmängija käikude kontroll, - inimmängija võidu / kaotuse tuvastamine ja väljatrükk - mängu uuesti alustamine - jne ning iga lisanduse järel kompileeri ja paranda ja testi, kuni see lisandus töötab OK. Alles seejärel asu programmeerima uut lisandust! - Küsimus inimmängija käigu kontrollimisest. Kuna inimmängija võib püüda vale käiku teha mitte ainult ühe korra, vaid näiteks sada korda järjest, siis kuidas seda kontrollida? Vastus: inimmängija käigu lugemine tuleb panna omaette väikesesse tsüklisse, mis lõpeb siis, kui anti OK, reeglipärane käik. - Küsimus mängu uuesti alustamisest: kuidas päris algusse tagasi minna? Mängu enda tsükli ümber tuleb teha veel üks tsükkel, kus iga tsükli kord tähendab ühte täismängu. Tsükkel lõpeb siis, kui inimmängija enam uut mängu mängida ei taha. NB! Kui olemasoleva tsükli ümber uue paned, siis ära unusta sisemise programmiteksti taanet igal pool kenasti paremale nihutamast! Disclaimer ========== Kui mõni soovitus või nõuanne siin tekstis tundub mitte aitavat või tundub otseselt vale, siis seda nõuannet ei pea arvestama! Lõppkokkuvõttes loeb ainult see, et programm oleks tehtud vastavalt alguses toodud nõuetele ja töötaks OK. Vajadusel eksperimenteeri ja katseta ise, loe õpikut ja juhendeid, vaata näiteid jne.