Skandináv lottó demóprogram

Skandináv lottó (heteslottó) demóprogramot tervezünk és írunk meg Java nyelven. Lépésenként mutatja meg, hogy mi történik a háttérben: hogyan állítja elő véletlenszerűen a lottószelvényt.

Az emlékezet egy logikai tömb. Ebben 36 elem van. A nulladik elem nem számít, és legyen a többi elem (1-35-ig indexelve) kezdetben mind hamis. A cél: legyen a tömbben pontosan 7 db igaz érték. Másképpen: a logikai tömb a lottószelvényen megjátszható számok kiválasztottságát jelöli, igen vagy nem. A heteslottó-szelvény 7 db 1 és 35 közötti különböző egész számból áll.

Mindig 1 és 35 közötti egész véletlenszámot tippelünk. Kezdetben jóSzámDb=0. Az első tipp biztosan jó és jóSzámDb=1. A többi tipp esetén vizsgálni kell, hogy már kiválasztott-e. Ha igen, akkor nincs teendőnk. Ha nem, akkor meg kell jegyezni (kiválasztottá kell tenni, azaz igazzá kell állítani a logikai tömbben) és a jóSzámDb++ (növelhető). Mindezt ciklusban ismételjük, amíg a jóSzámDb<7 feltétel teljesül (másképpen: amíg nincs elegendő kiválasztott szám a szelvényen). Mindez biztosítja az egyediséget, különbözőséget. Ha jóSzámDb==7, akkor kiírjuk a lottószelvényre kerülő számokat az alapján, hol (melyik indexen) van a logikai tömbben igaz érték.

Tekintsük át az alkalmazott módszer hátrányait és előnyeit. Hátrány, hogy 36 logikai érték szükséges ahhoz, hogy 7 különböző számot előállítsunk. Előny, hogy egyszerű az algoritmus (nem kell keresés és megszámolás programozási tétel) és nincs szükség rendezésre sem, mert a szakterületre jellemző „emelkedő számsorrend” a logikai tömb bejárásával önkéntelenül is adódik. Hangsúlyozzuk, hogy ez csupán egyetlen módszer a nagyon sok izgalmas közül, amikkel generálható egy véletlenszerű lottószelvény.

A megvalósítás, Java forráskód nagy egyszerű. Íme egy függvény, amely visszaadja azt kiválasztottságot jelölő logikai tömböt, amiből megfelelően indexelve kiíratható a véletlenszerűen generált lottószelvény:

Egy demóprogram, szimulációs program, oktatóprogram esetén nem is a konkrét feladat megoldása a cél/probléma. Sokkal inkább a lépésenkénti bemutatás, sok-sok konzolos kiírással vagy grafikus szemléltetéssel. Sokszor időzítővel késleltetjük, lassítjuk, gyorsítjuk a folyamatot, de előfordul az is, hogy rengetegszer megismételjük a tevékenységet és a kapott adatokat elemezzük, következtetünk belőlük. Most például a ciklust ki kell cserélni olyan léptetésre, ami a felhasználó kattintásához kötődik. Ha kéri a következő tippet a lottószelvényre, akkor megkapja. Ha nem kattint, akkor nem kapja meg. Az is egy csalás/lehetőség lenne, hogy a háttérben nem is logikai tömb adatszerkezet van, csupán a vizualizáció miatt tűnik annak.

Az elkészült demóprogram megvalósítja a fenti algoritmust. Az alábbi képernyőképeken végiglapozható a demóprogram működése. Nem is az algoritmus megvalósítása a kihívás és a cél, hanem a folyamat lépésenkénti megjelenítése. Java swing grafikus felület készült el.

 

A demóprogram Start állapottal indul. Olyan a lépésenként tesztesetek sorozata, hogy a lottószelvény nem sikerül rögtön elsőre. Az egyik szám már előfordult korábban. A demóprogram Stop állapottal ér véget. A demóprogram pénztárszalagszerűen időnként jelzi, hol tart éppen. A demóprogram képes egymás után több lottószelvényt is előállítani és az emlékezete egyetlen szelvényre korlátozódik.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A Java SE szoftverfejlesztő tanfolyamunkon, a szakmai modul Objektumorientált programozás témakörét követő 29-36. óra Grafikus felhasználói felület alkalmain már tudunk egyszerűbb szimulációs programot tervezni, kódolni, tesztelni. A Java EE szoftverfejlesztő tanfolyamunkon, a szakmai modul 33-40. óra Java Server Pages alkalmain már a program böngészőben futó változatát is el tudjuk készíteni.

Hóesés szimuláció

Hóesés szimulációt tervezünk és valósítunk meg Java nyelven. A téma igazi örökzöld. Elvileg minden télen aktuális. 😉 A grafikus felülethez és az eseménykezeléshez a swing gyűjteményt használjuk. Adott egy téglalap alakú terület amelyen – méretéhez igazodva – több száz hópehely mocorog. A területet önállóan programoztuk le – azaz ez alkotja a teljes GUI-t –, de lehetne egy nagyobb kép része is. Többféleképpen is beépítünk véletlenszerűséget a szimulációba. Tervezünk is, hiszen az sosem árt. 😉

Többnyire beépített komponenseket, elemeket használunk, de van saját, örökítéssel testre szabott komponensünk is:

  • A szimuláció a Window osztályból példányosított felületen működik, amely JFrame utód. Nem átméretezhető és látható.
  • A területet JPanel típusú pnTransparentWindow alkotja. Mérete 300*200 pixel. Színe a szürke egyik árnyalata. Ezen mozognak a hópelyhek.
  • A hópehely Snowflake típusú JPanel utód. Mérete 2*2 pixel. Színe fehér. Saját swing-es Timer biztosítja az eseménykezelését. A szimulációban 600 hópehely szerepel.

Az elkészült szimuláció

A teljes forráskódból íme a hópehely megvalósítása

A hópehelynek „tudnia kell” hol van, azaz mekkora területen mozoghat, ez a rectangle. A hópehelynek van size mérete. A hópehely saját magát mozgatja a területen a timer segítségével. Az időzítés várakoztatására/késleltetésére vonatkozó delay értéke véletlenszerűen 50, 100, , 250 milliszekundum lehet. Másképpen: a szél által össze-vissza fújt hópelyhek között lehetnek lassabban és gyorsabban mozgók is. Az eseményobjektumhoz lambda kifejezés rendeli hozzá a reakciót jelentő, mozgást megvalósító move() metódus meghívását, amely így adott időközönként bekövetkezik.

A hópelyhet a konstruktora hozza létre. Átveszi azt a pnTransparentWindow területet, amelyre később rákerül a Window példányosítása során. A gyengébb setSize() metódus helyett az erősebb setPreferredSize() metódus állítja be a méretet. Véletlenszerű x és y pozícióba kerül ki/fel a területre. A setBounds() örökölt metódus beállítja a pozícióját és méretét. Erre épít a fogadó oldalon az abszolút helyzet, külön elrendezésmenedzser nélkül. Végül a hópehely átlátszó, fehér és elindítja saját időzítőjét a timer.start() metódushívással.

Az időzítés/várakoztatás véletlenszerűsége után íme a második véletlenszerűség a szimulációban. A hópehely mozgása során a szél által össze-vissza fújva eltérő eséllyel/valószínűséggel mozog 8 lehetséges irányba az alábbiak szerint:

  • 5-5% eséllyel felfelé, azon belül jobbra vagy balra (átlósan),
  • 10-10% eséllyel jobbra vagy balra,
  • 20-20% eséllyel lefelé, azon belül jobbra vagy balra (átlósan),
  • 30% eséllyel lefelé, függőlegesen,
  • felfelé, függőlegesen nem mozog.

Az esélyek összege 100%. Másképpen kulcsszavakban: 1 = biztos esemény (teljes eseménytér, nincs más lehetőség), egymást kizáró események, geometriai valószínűség. A képen középen lévő hópehely a 8 szomszédja közül a 7 szóba jöhető közül valamelyikre adott eséllyel mozog. A geometriai valószínűséget az ábra alapján az óramutató járásával megegyezően leképeztük az 1..100 intervallumra:

A move() metódus megvalósítja a fenti tervnek megfelelően a hópehely mozgatását. Első lépésben tudni kell a jelenlegi/kiinduló location helyét (a bal felső csúcs, elkérjük). Ezután véletlenszerű esély/ tip generálódik. Az első elágazásban a hópehely translate() metódusával eltoljuk az előbb elkért pontot. Az eltolás relatív. Az utolsó elágazásban kompenzálunk, ha a hópehely alul kilépne a területről. Ekkor felül újra belép a területre. Végül beállítjuk a hópelyhet megvalósító komponenst a manipulált location helyre.

Takarékosak vagyunk: ezzel a megoldással „újrahasznosítjuk” a hópelyheket. Csak annyi van belőlük, amennyi szükséges. Nem kell őket folyamatosan megszüntetni és újra létrehozni. Nem mozognak feleslegesen. Nem mozognak olyan területen, ahol nem láthatóak.

Ötletek továbbfejlesztésre

  • A hópelyhek színe lehetne véletlenszerű a fehér és a középszürke között. Ezzel a nézőtől való távolságot, esetleg a kép élességét lehetne modellezni.
  • A szél nem feltétlenül szimmetrikus, vagy a hópelyhek mozgatását meg lehetne oldani jobbra és balra eltérő eséllyel is.
  • A terület lehetne más alakú, például trapéz, íves, kör, ellipszis.
  • Másképpen is vezérelhetnénk a szimulációt. Ahelyett, hogy most minden hópehelynek van saját időzítője, lehetne csak 5 db (lassabbak és gyorsabbak), amelyek közül véletlenszerűen kiválaszthatnánk, hogy melyik hatására mozgatjuk az adott hópelyhet. Fordítva is mehetne: az 5 db időzítőhöz előre hozzárendelhetnénk a hópelyheket. Ez így más-más felelősség, kommunikáció, üzenetküldés, vezérlés lenne az objektumok között. Hasznos tapasztalat lehet megvalósítani bármelyiket.
  • A terület lehetne egy nagyobb kép része. Például meghatározhatnánk egy tetszőleges átlátszóságot (színt vagy arányt) és többrétegű felületet megvalósítani képes JLayeredPane komponens elé vagy mögé is elhelyezhető lehetne a terület a grafikus felületen.
  • Aki kihívást keres: illessze a területet az alábbi hangulatos képre úgy, hogy a középső ablakok téglalap alakúak, a két szélső trapéz alakú vagy perspektivikus nézetű és a kör/ellipszis alakú tükörben pedig tükröződik valahonnan a hóesés látványa.
  • Még bátrabbaknak: a kandallóban lévő tüzet is lehet hasonlóan szimulálni. Itt már többféle fizikai paraméter is figyelembe vehető, például fényerősség, tükröződés. Egy 3D modellezett térben a sugárkövetés (Ray Tracing) algoritmus is megvalósítható. A hópelyheknél lehetne az egyszerű mozgástól eltérő más fizikát is programozni: rugalmas ütközéssel összetapadhatnának vagy rugalmatlan ütközéssel lepattanhatnának egymásról és mindez hathatna a sebességükre is.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A Java SE szoftverfejlesztő tanfolyamunkon, a szakmai modul Objektumorientált programozás témakörét követő 29-36. óra Grafikus felhasználói felület alkalmain már tudunk egyszerűbb szimulációs programot tervezni, kódolni, tesztelni.

Egy matematika érettségi feladat megoldása programozással 2017

érettségi logó

érettségi logóA 2017-es középszintű matematika érettségi feladatsor 12. feladata inspirált egy Java program megírására. Szükséges hozzá néhány programozási tétel: sorozatszámítás, megszámolás, valamint adatszerkezetként ideális egy kétdimenziós tömb. Érdekes belegondolni, hogy mennyire más lehetne a problémamegoldás, ha programozhatnánk a matematika érettségi vizsgán. A teljes feladatsor a megoldásokkal együtt letölthető az oktatas.hu-ról.

12. feladat

Egy kockával kétszer egymás után dobunk. Adja meg annak a valószínűségét, hogy a két dobott szám összege 7 lesz! Válaszát indokolja!

Matematikai megoldás

A feladat nagyon egyszerű. Két megoldást ismertet a javítási-értékelési útmutató:

  • Összesen 6 * 6 = 36-féleképpen dobhatunk. Hat olyan dobáspár van, amelyben 7 az összeg: (1; 6), (2; 5), (3; 4), (4; 3), (5; 2) és (6; 1). A keresett valószínűség 6/36-od, vagyis egyhatod.
  • Bármennyit is dobunk elsőre, ezt a második dobás egyféleképpen egészítheti ki 7-re. Így a második dobásnál a hat lehetséges értékből egy lesz számunkra kedvező. A keresett valószínűség egyhatod.

Közelítő megoldások szimulációval

Egy alkalom két kockadobást jelent egymás után. A dobások sorrendje nem számít (alkalmanként és összességében sem). Minél több alkalommal végezzük el a kockadobásokat, annál jobban megközelítjük a fenti valószínűséget (várható értéket, bővebben: nagy számok törvénye). Az egyhatod közelítő értéke a Java double adattípusával 0.16666666666666666.

1. megoldás

Ha nem akarunk emlékezni a dobásokra, összegükre, csupán megszámolnánk, hogy hány olyan dobáspár van, amelyben 7 az összeg, akkor ehhez mindössze egy számláló ciklus kell, aminek a ciklusmagjában két véletlen kockadobás összegét előállítjuk és növelünk egy számlálót/gyűjtőt, ha az éppen 7. Az eredményt a számláló és a ciklus lépésszámának hányadosa adja meg. Például meghívhatjuk a metódust így: kockadobas1(5000); és kaphatjuk eredményül ezt: 5000 alkalomból 7 összegként 836 alkalommal fordult elő. Valószínűség: 0.1672 . A metódus kivételt dob, ha értelmetlen a paramétere. Íme a metódus Java forráskódja:

2. megoldás

Ha egy 13 elemű egész típusú tömböt használhatunk emlékezetként. Kezdetben 2-től 12-ig indexelve nullázzuk ki, így csoportos gyűjtést tudunk megvalósítani. A nullázás most inicializáló blokkal történt, mert nem sok eleme van a tömbnek (sok elemnél inkább használjunk erre ciklust). A tömb első két elemét nem használjuk semmire. Mi történik a ciklusban? Például dobas1=3 és dobas2=4 esetén a dobasDbTomb[7] elemét növeli (mindegy mi volt ott korábban, de inkrementálódjon). Most több adatot tárolunk, mint amiből megválaszolható a feladatban megfogalmazott konkrét kérdés, de ezt tekinthetjük strukturális tartaléknak.

Hasonló, egydimenziós tömbbel történő belső adattárolást megvalósító elosztott alkalmazásról blogoltunk már: Kockadobás kliens-szerver alkalmazás.

3. megoldás

Ez az igazi szimuláció, swing GUI grafikus környezetben, ahogyan az alábbi képernyőképen látható. A megvalósítás kétdimenziós tömböt használ adatszerkezetként. Álljon 7 sorból és 7 oszlopból és legyen i a sor- és j az oszlopindex. A tömb [0][0]-dik elemét nem használjuk semmire. Az első oszlopába ( j=0 és i>0) bekerülhetnek a dobókockán előforduló számok 1-től 6-ig. Hasonlóan az első sorba ( i=0 és j>0) is. Ezek a dobott számok alapján indexek lesznek és az ábrán zöld hátterű cellákba kerültek. A tömb többi eleme kezdetben 0 (nulla), ezek az ábrán fehér hátterű cellák. A szürke hátterű cellák (mellékátló) esetén a dobott számok összege 7 és jól látszik, hogy ez hatféleképpen fordulhat elő a 36-féle eset közül. Például a 2. sor 5. oszlopában lévő szám mutatja, hogy a 10000 alkalomból 274-szer fordult elő az, hogy a dobáspár a (2; 5) lett. A tömb két indexe felcserélhető lenne, mert ez a mellékátlóban lévő számok összegét nem befolyásolja.

Kockadobás program képernyőkép

A programban kiválasztható néhány alkalomból amit szeretnénk, és a Dob nyomógombra kattintva indul el időzítővel a folyamat. Várakoztatás/menet közben piros színnel kiemelve látszik/megfigyelhető, hogy az éppen aktuális dobás hol növeli az értéket/előfordulást/darabszámot. A képernyőképen befejeződött állapot látható. Az eredményt a szürke cellákban lévő számok összegének és az alkalmak számának hányadosa adja meg. Ezt a háttérbeli kétdimenziós tömbben összesítéssel az alábbi Java forráskód-részlet adja meg:

Most lényegesen több adatot tárolunk, mint ami a konkrét válaszhoz kell, de cserébe jól érzékeltethető a csoportos gyűjtés/megszámolás működése. A program grafikus felhasználói felületének felépítését és az eseménykezelés megvalósítását most nem részletezzük.

Eszünkbe juthatna, hogy a program miért dob kétszer 1 és 6 közötti számot egymás után és ezt összegzi, amikor egyetlen 2 és 12 közötti dobással (véletlenszám generálással) megkaphatnánk a dobáspár összegét. Hiszen két db 1 és 6 közötti szám összege mindig 2 és 12 közötti szám. Jó lenne ez az ötlet/megvalósítás? Igen? Nem? Miért? A hozzászólásokhoz várjuk az indoklást.

Ajánljuk matematika érettségi feladat címkénket, mert a témában évről-évre blogolunk.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A feladat a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 17-28. óra: Objektumorientált programozás alkalmaira épülő 29-36. óra: Grafikus felhasználói felület alkalmaihoz kötődik.