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.

Keresztrejtvény készítése

Támogatjuk a keresztrejtvények készítését Java programmal. A program grafikus felülete eszköztárból és a keresztrejtvényből áll. Az elkészült programban 10×10-től 15×15-ig beállítható négyzetrács készíthető elő. A tiltott négyzetek száma 15-től 30-ig beállítható. Mivel a tiltott négyzetek helyzete véletlenszerű, így nem biztos, hogy az elsőre jó/szerencsés lesz, ezért újragenerálható a négyzetrács. A program a tipikus követelményeknek megfelelően sorfolytonosan sorszámozza a négyzetrács elemeit, ami alapján megadhatók hozzá a vízszintes és függőleges feladványok. A program az elfogadott négyzetrácsot többféle képformátumban is el tudja menteni.

Az elkészült Java program grafikus felülete

Objektumorientált tervezés

A keresztrejtvény ábrája egy négyzetrácsból áll, amelyben rejtvénymezők helyezkednek el. A rejtvénymezőnek megfelel egy örökítéssel felüldefiniált címkekomponens. A rejtvénymezőt körülveszi egy szegély/keret, tiltott vagy sem állapotától függően fekete vagy fehér a háttérszíne, valamint van a bal felső sarkához igazított kis méretű betűvel nem kötelezően megjeleníthető sorszáma. A tiltott és sorszám tulajdonságait kell tudni beállítani és megkérdezni. Ez a feladatban a RejtvenyMezo POJO. A négyzetrács sorai és oszlopai azonos méretűek (pixelre és darabszámra egyaránt).

Algoritmus a keresztrejtvény sorszámozására

A rejtvénymezők kétdimenziós négyzetes mátrixban/tömbben helyezkednek el. A sorszámozáshoz hasznos, ha a négyzetrácsot körbeveszi egy tiltott rejtvénymezőkből álló keret. Először a rács sorain és oszlopain végighaladó egymásba ágyazott ciklusok létrehozzák a POJO-kat úgy, hogy a négyzetrács keretén lévő rejtvénymezők tiltottak, a többi nem tiltott. Ezután véletlenszerűen ki kell választani – a még nem tiltottak közül – a szükséges mennyiségű tiltott rejtvénymezőt. Ezután sorfolytonosan sorszámozni kell azokat a rejtvénymezőket, ahol vízszintes vagy függőleges feladvány kezdődik. Ehhez is két egymásba ágyazott ciklus kell, amelyben minden még nem tiltott rejtvénymező egyre növekvő sorszámot kap, ha tőle balra tiltott és tőle jobbra nem tiltott rejtvénymező helyezkedik el, de akkor is, ha felette tiltott és alatta nem tiltott rejtvénymező található.

A keresztrejtvényt sorszámozó algoritmus Java megvalósítása

Továbbfejlesztési lehetőségek

  • A feladványok listázhatók és kideríthető a hosszuk.
  • A tiltott rejtvénymezők véletlenszerű elhelyezése helyett lehetne valamilyen szabály, stratégia az egymáshoz való helyzetükre, távolságukra, közvetlen szomszédságukra vonatkozóan. Figyelembe vehetnénk valamilyen szimmetriát is, mintákat, alakzatokat is. Véletlenszerű elhelyezésük nem biztos, hogy mindig jó/szerencsés: például a tiltott rejtvénymezők körbezárhatnak egy nem tiltottat, hosszabb feladványokat nehezebb találni…
  • A Java SE szoftverfejlesztő tanfolyam tematikájához kötődően többféle szótárból, fájlformátumból betölthetünk a feladványokhoz használható, például 7 betűs országnevek, 2 betűs kémiai elemek, női/férfi keresztnevek, autójelek, pénznemek, szinonimák…
  • A Java EE szoftverfejlesztő tanfolyam tematikához kötődően többféle webes adatforrásból, Wikipédiából, szótárból, API hívásokkal letölthetünk a feladványokhoz használható listákat, meghatározásokat, kulcs-érték párokat. A swing-es felületet lecserélhetjük böngészőben futó webes GUI-ra is.
  • A Java adatbázis-kezelő tanfolyam tematikájához kötődően a fentiek kiegészítéseként tervezhetünk és építhetünk helyben tárolt tudástárat, adatbázist, amiből hatékonyan lekérdezve adhatunk feladványokat a keresztrejtvényhez.
  • Miután a fentiek szerint valahogyan – tipikusan visszalépéses algoritmussal – meghatároztuk a feladványokat, a keresztrejtvényből menthetünk kitöltött változatot 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.

Barátságos számpárok

számok

Azokat a számpárokat, amelyekre igaz, hogy az egyik szám önmagánál kisebb osztóinak összege megegyezik a másik számmal és fordítva, külön-külön barátságos számoknak, együtt barátságos számpárnak hívjuk.

Másképpen: legyen d(n) az n természetes szám önmagánál kisebb osztóinak összege. Ha d(a)=b és d(b)=a, ahol ab, akkor a és b barátságos számpár.

Például: (220; 284), hiszen a 220 önmagánál kisebb osztói: 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110 és ezek összege 284, illetve 284 önmagánál kisebb osztói: 1, 2, 4, 71, 142 és ezek összege 220.

Írjunk Java programot, amely kiírja az 1-10000 zárt intervallumban található barátságos számpárokat!

1. megoldás

A baratsagosSzamparok1() eljárás ciklusai a brute force módszer szerint behelyesítik az összes lehetséges számot. Minimális lépésszám csökkentésre adódik lehetőség, hiszen a belső ciklus j változója i+1-ről indítható (így a megtalált számpárok nem íródnak ki fordítva is, mert teljesül, hogy i<j).

Az osztokOsszege1(n) függvény is minden lehetséges osztót figyelembe vesz 1-től n-1-ig.

2. megoldás

Kisebb módosításokkal a lépésszám csökkenthető. A baratsagosSzamparok2() eljárás külső ciklusánál figyelembe vettem, hogy a legkisebb barátságos számpár kisebb tagja nagyobb 200-nál. Mivel a barátságos számpárok tagjainak paritása mindig megegyezik (azaz mindkettő páros vagy mindkettő páratlan), így a belső ciklus j változója indítható i+2-ről és léptethető kettesével ( j+=2), és továbbra is teljesül, hogy i<j.

Az osztokOsszege2(n) függvényt is módosítottam. Mivel az 1 minden számnak osztója, illetve a 2 minden páros számnak osztója, így s lehet 3 vagy 1 és a ciklus indítható 3-ról. A páros számok esetén a számnál kisebb legnagyobb osztó maximum n/2 lehet, illetve ugyanez páratlan számok esetén n/3 lehet. Ezekre figyelve a max változó adja a ciklus léptetésének felső határát. Az i változó léptetésénél figyelembe vettem, hogy páratlan számnak csak páratlan osztói lehetnek ( i=3-mal szinkronban).

3. megoldás

Az eddigi két egymásba ágyazott ciklus helyett átszervezhető a baratsagosSzamparok3() eljárás. A j>i && osztokOsszege2(j)==i feltétel kiértékelése így sokkal hatékonyabb.

Vajon milyen nagyságrendű különbségek adódnak, ha összehasonlítjuk a három megoldás futási idejét?

Az 1. megoldás futási ideje 1104156 ms, a 2. megoldásé 257055 ms, a 3. megoldásé 121 ms. A konkrét értékek helyett a nagyságrendet megfigyelve a különbség nagyon látványos.

Mindhárom megoldás helyes és megkapjuk az intervallumban található öt barátságos számpárt: (220; 284), (1184; 1210), (2620; 2924), (5020; 5564), (6232; 6368).

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

Források:

A feladat a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 9-12. óra: Metódusok, rekurzió alkalomhoz kötődik.

Hány éves a kapitány?

Hány éves a kapitány?

Hány éves a kapitány?A problémamegoldó, logikus gondolkodásra nevelő képzések anyagában, illetve felvételi feladatsorokban is sokszor megtalálható – többféle változatban is.

Lássunk egyet a népszerű „Hány éves a kapitány?” típusú feladatok közül!

Három elefántot kell berakodnunk – szólt a hajóskapitány az első tiszthez.
És hány évesek ezek az elefántok? – kérdezte az első tiszt.
Mindegyik elmúlt már két éves és életkoraik szorzata 2450 – volt a válasz.
Hát életkoraik összege?
Azt fölösleges elárulnom, mert abból még nem tudnád megállapítani életkorukat – mondta a kapitány, majd hozzátette: Az egyikük idősebb nálam.
Akkor már tudom, hogy hány évesek az elefántok – mondta az első tiszt.

Feltéve, hogy tényleg tudta; … hány éves a kapitány?

Hogyan használhatnánk a feladat megoldásához programozáshoz kötődő ismereteinket?

Állítsunk elő olyan három szorzótényezőt, amelyek szorzata 2450 és egyben írassuk ki az összegüket is a konzolra!

Az i, j, k a három elefánt életkorát jelöli. Mivel mindegyik elmúlt két éves (és feltételezzük, hogy életkoraik egész számmal kifejezhetők), így i=3-ról indul. Az elefántok lehetnek egyidősek, ezért j=i-ről és k=j-ről indul. Nincs kizárt életkor, így a változók léptethetők egyesével. Az i, j, k monoton növekvő sorozatot alkot, ezért a kiírásban nem lesznek olyan sorok, amelyek csupán a szorzótényezők sorrendjében térnek el. Durva felső becslés a 100, hiszen az elefántok általában 60-70 évig élnek. Eredményül ezt kapjuk:

Az eredményből milyen következtetés(eke)t lehet levonni és mi a megoldás?

Az egyszer előforduló összegeket ki kell zárni, mert abból az első tiszt tudná az elefántok életkorát. Többször előforduló összegként marad a 64. Tehát az elefántok lehetnek 5, 10, 49, illetve 7, 7, 50 évesek. Mivel a kapitánynál idősebb az egyik elefánt, így a kapitány nem lehet 48 éves vagy fiatalabb (mert ekkor nem lenne egyértelmű az életkora), illetve nem lehet 50 éves vagy idősebb (mert ekkor nem lenne nála idősebb elefánt). Tehát a kapitány 49 éves.

(Másképpen megközelítve: a 2450 prímtényezős felbontása 2*52*72, amiből ugyanezekre a következtetésekre juthatunk.)

A feladat további változatai

  • Egy hajó hosszának, az árbóc magasságának, a kapitány kisfia életkorának és a kapitány életkorának szorzata 303335. Hány éves a kapitány?
  • A kapitány most kétszer annyi idős, mint a hajója volt akkor, amikor a kapitány kétszer volt annyi idős, mint most a hajója. A kapitány és a hajója összesen 70 éves. Hány éves a kapitány?
  • A Fekete Kalóz néven elhíresült kalózkapitány egyik sikeres kalandja után kiszámíttatta saját maga és kisfia életkorának, valamint hajója hosszának a szorzatát. Az eredmény 26 159 lett, amelyet mint szerencseszámot egy medálra vésetett és mindig a nyakában hordott. Hány éves a kapitány? (A hajóhosszt méterekben mérték, és a mérőszám egész szám!)
  • Te vezeted az utasszállító repülőt. Budapesten felszáll 11 utas. Bécsben leszáll 5 és felszáll 9. Párizsban 1 kivételével mindenki leszáll. Hány éves a kapitány?
  • A kapitány hajója most 40 éves. Kétszer annyi idős, mint amennyi a kapitány volt akkor, amikor a hajó annyi idős volt, mint a kapitány most. Hány éves a kapitány?

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

Ajánlott irodalom

Aki kedvet kapott és beszerezne néhány könyvet – tele érdekes, gondolkodtató, kreatív, logikai feladatokkal – ajánlom az alábbiakat:

  • Katona, R. (szerk): Logikai egypercesek – az elme játékai, 2. kiadás, DFT-Hungária Könyvkiadó, Budapest, 2006, ISBN 963 9473 55 3
  • Róka, S.: 2×2 néha 5? – Paradoxonok, hibás bizonyítások, Tóth Könyvkereskedés és Kiadó Kft., Debrecen, 2008, ISBN 963 5965 24 3
  • Károlyi, Zs.: Csak logIQsan!, 2. javított kiadás, Typotex Elektronikus Kiadó Kft., Budapest, 2017, ISBN 963 279 693 5
  • Róka, S.: Egypercesek – Feladatok matematikából 14-18 éveseknek, Tóth Könyvkereskedés Kft., Debrecen, 1997
  • G. Nagy, L.: A világ legújabb logikai rejtvényei, Magyar Könyvklub, H. n., 2001, ISBN 963 547 512 8

Haladóknak ajánlom:

  • Smullyan, R.: A hölgy vagy a tigris? – és egyéb logikai feladatok, 2. javított kiadás, Typotex Kiadó Kft., Budapest, 2002, ISBN 963 7546 63 4
  • Smullyan, R.: Mi a címe ennek a könyvnek? – Drakula rejtélye és más logikai feladványok, Typotex Elektronikus Kiadó Kft., Budapest, 1996, ISBN 963 7546 64 2
  • Shasha, D.: Dr. Ecco talányos kalandjai, Typotex Kiadó – SHL Hungary Kft., 2000, ISBN 963 9132 72 1

A feladat a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 5-8. óra: Vezérlési szerkezetek alkalmához kötődik.

Péntek 13

Péntek 13

Péntek 13Sokan szerencsés vagy balszerencsés napnak tartják a péntek tizenharmadikát. Évente 1-2-3 alkalommal megtörténik, hogy a hónap 13. napja péntekre esik (minden vasárnap kezdődő hónapban). A hónap 13. napja valamivel valószínűbben péntekre esik, mint a hét bármely más napja. Átlagosan 212,35 naponként fordul elő péntek 13. Előfordulhat két egymást követő hónapban is, de akár 14 hónap is eltelhet két péntek 13 között.

A nap említése sok helyen előfordult: regényekben, filmekben, híres emberek születése vagy halála is esett péntek 13-ra. Átlag alatti közlekedési baleset szokott előfordulni ezeken a napokon – talán mert az emberek óvatosabbak. Kimutatható összefüggést/korrelációt, „péntek 13 hatást” figyeltek meg a tőzsdén is.

Hasznos lehet, ha írunk egy Java programot, amely néhány egymást követő év esetén listázza a konzolra azokat a hónapokat, amikor 13-a péntekre esik.

Tervezés

Legyen egy listFriday13(year) eljárás, amely a paraméterként átvett évben kiírja azokat a hónapokat a konzolra, amelyekben 13-a péntekre esett/esik. Például: 2017: január, október. A hónapok nevei magyar nyelven jelenjenek meg. Az adott év hónapjain végighaladó ciklus legyen hatékony. Optimalizáljunk a ciklus lépésszámára! A ciklus álljon le, ha már talált 3 hónapot (mivel nem lehet több).

1. megoldás

A megoldást a tematika Tömbök témakörében az alábbiak szerint készíthetjük el. Előismeretek: változók, operátorok, ciklusok, programozási tételek, metódusok, tömbök, String összehasonlítás. Az ismert öröknaptár algoritmusokból implementáljuk az egyiket, például:

A listFriday13v1(year) eljárásban az elemi döntés egyszerű: dayOfWeek(year, month, 13).equals("Friday"). Épít az öröknaptárt megvalósító – saját – szöveget visszaadó függvényre. A függvény az algoritmus szerinti kódok előállításához ( centuryCode, monthCode, dayCode) felhasználja a szökőév ( isLeapYear(year)) függvényt, valamint két – konstansnak is tekinthető – névtelen tömböt ( new int[], new String[]).

2. megoldás

A megoldást a tematikában Objektumorientált programozás témakörében az alábbiak szerint készíthetjük el. Felhasználjuk eddigi ismereteinket és a JDK beépített dátumkezelő (tároló, formázó) funkcióit (osztályok, interfészek, konstansok, felsorolások).

A listFriday13v2(year) eljárás a Calendar absztrakt osztály konstansait használja fel az elemi döntéshez: date.get(Calendar.DAY_OF_WEEK)==Calendar.FRIDAY. A dátumot a GregorianCalendar konstruktora példányosítja és figyelni kell a 0-bázisú hónapkezelésre. A dátum formázása során ( dfMonth) beállítjuk a megfelelően paraméterezett ( "hu") Locale típusú objektumot és a hónap hosszú nevét kérjük ( "MMMM"). A metódus generikus listába gyűjti a kiválasztott hónapok nevét, amiket végül a String.join() függvény fűz össze a megjelenítéshez.

Eredmény

A vezérlésben egy ciklus 2017-től 2036-ig szervezve az alábbi eredményt adja:

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 tematikájához kötődik a fentiek szerint: 13-16. óra: Tömbök alkalom, illetve 17-28. óra: Objektumorientált programozás alkalom.