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.

Letöltés szimuláció

letöltés logó

letöltés logóLetöltési folyamatot szimulálunk. A paraméterek rugalmasan beállíthatóak. Előre beállított mennyiségű adatot, párhuzamos szálakon/folyamatokon keresztül töltünk le, miközben mérjük az eltelt időt. A folyamatok állapota lehet inaktív, aktív és befejezett. Az aktív folyamatok esetében megjelenő százalék fejezi ki, hogy a folyamat hol tart a rá jutó részfeladat végrehajtásával. Összesített formában követhetjük a hiányzó és a letöltött adat mennyiségét MB-onként és százalékosan is. A folyamat szimulációjához grafikus felületű Java kliensprogram készült, egyszerű GUI komponensekkel (nyomógomb, címke, folyamatindikátor, másképpen JButton, JLabel, JProgressBar swing komponensek).

Az alábbi animáció bemutatja a letöltés szimulációját:

letölés szimuláció

A konkrét paraméterek: 128 MB-nyi adatot töltünk le 256 párhuzamos szálon/folyamaton keresztül, így egy-egy részfeladat 0,5 MB-nyi adat letöltését jelenti. Minden értéket/mérőszámot egész számként ábrázolunk, akár százalékhoz tartozik, akár mértékegységként MB vagy s. A változások – és egyben a frissítés is – 5 ezredmásodpercként történnek a GUI-n.

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 5-8. óra Szálkezelés, párhuzamosság alkalommal többféle elosztott stratégiát ismertetünk, és a 17-24. óra Socket és RMI alapú kommunikáció alkalommal pedig megvalósíthatjuk többféle protokoll szerint a hálózati kapcsolatot, letöltést/feltöltést.

Elosztott alkalmazások esetén többféleképpen is modellezhető és kialakítható a rendszer architektúrája. Elosztott lehet maga a hálózat, a számítási folyamat, az algoritmus. Elosztott objektumok kommunikálhatnak egyenrangúnak tekinthető P2P szerepkörben vagy szerver/kliens oldalon, és több dolog/elem/hardver/szoftver/komponens együttműködéseként is megvalósulhat elosztott alkalmazás. A hálózati kommunikáció folyamatát valamilyen protokoll határozza meg, amit minden komponens ismer és így meghatározott szabályrendszer szerint működik.

Hardver szinten elosztottak a többprocesszoros rendszerek. Szoftveresen elosztott például egy moduláris vállalatirányítási rendszer, illetve a mobilalkalmazások többsége. Tipikus háromrétegű webalkalmazás esetén külön szerver nyújtja az adatbázishoz kapcsolódó szolgáltatásokat, a felhasználó számítógépén található a böngészőben futó/megjelenő kliensprogram/weboldal és a kettő között a felhő rétegben lehet a funkcionálisan elosztott alkalmazáslogika (például validálás, titkosítás, tömörítés, autentikáció, autorizáció).

A feladat könnyen általánosítható, például:

  • Egy keresési feladatot oldjunk meg az állományrendszerben! Kereshetünk egy konkrét nevű fájlt, adott kiterjesztésű fájlt, joker karakterekkel paraméterezett nevű fájlt/mappát, adott méretű állományt, adott dátum előtt létrehozott fájlt… Az állományrendszer bejárása rekurzív módon történik. A gyökérben lévő mappánként külön, esetleg második szinten lévő mappánként külön indíthatók szálak, párhuzamos folyamatok. Ha egyetlen találat elegendő, akkor bármelyik szál pozitív visszajelzésére minden szál leállítható. A feladatnál nagy eséllyel nagyon különböző méretű mappákon és eltérő mélységű mappaszerkezeteken kell végighaladni, így erre érdemes lehet optimalizálni, de ez már nagyon más szintje ennek a problémának.
  • Active Directory szerkezetben keressünk elérhető nyomtatókat a hálózaton!
  • Elosztott számítási hálózatként működik/működött a SETI@home. Koncepciójának lényege, hogy egy hatalmas feladatot nem nagyon drága szuperszámítógépeken, hanem olcsó gépek ezrein, százezrein, vagy akár millióin végeztetjük el, amelyek jelentős szabad kapacitással (pl. processzoridővel, átmeneti tárhellyel) rendelkeznek és egyébként is csatlakoznak a világhálóra.
  • Hasonlóan elosztott működésű a torrent protokoll. A kliensek/szálak az állományokat több kisebb darabban/szeletben töltik le, természetesen párhuzamosítva. Minden csomópont megkeresi a hiányzó részhez a lehető leggyorsabb kapcsolatot, miközben saját maga is letöltésre kínálja fel a már letöltött fájldarabokat. A módszer nagyon jól beválik nagyméretű fájloknál, például videók esetében. Minél népszerűbb/keresettebb egy fájl, annál többen vesznek részt az elosztásában, ezáltal a letöltési folyamat gyorsabb, mintha mindenki egy központi szerverről töltené le ugyanazt (hiszen az informatikában minden korlátos, a sávszélesség is).
  • A képtömörítést végző algoritmusok is lehetnek elosztottak, ezáltal párhuzamosíthatóak. Például ha felosztjuk a képet 16*16-os méretű egymást nem átfedő részekre, akkor ezek egymástól függetlenül tömöríthetők.
  • A merevlemezek esetén korábban használatos defragmentáló szoftverek felhasználói felülete emlékeztet a mintafeladat ablakára.

Fontos szem előtt tartani, hogy a grafikus megjelenítés csupán a szimulációhoz tartozó – annak megértéséhez szükséges – reprezentáció, így teljesen független lehet a folyamatok valós működésétől.

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

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.