Fibonacci-spirál

Fibonacci nap

Fibonacci nap 2018A Fibonacci-spirál a népszerű Fibonacci-sorozat elemei által meghatározott oldalhosszúságú négyzetekbe rajzolt maximális sugarú negyedkörök megfelelően összeillesztett darabjaiból/sorozatából áll. Sokszor hasonlítják az arany spirálhoz (jól közelíti), amely az aranymetszéshez kötődik.

A Fibonacci-spirál

Vegyük a Fibonacci-sorozat első 10 elemét! Rajzoljuk egymás mellé az alábbi elrendezésben belülről kifelé haladva az 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 oldalhosszúságú négyzeteket (az alábbi ábrán vékony sárgával jelölve). Piros színnel rajzoljuk bele a négyzetekbe a négyzet oldalhosszával megegyező sugarú negyedköröket. A negyedkörök megfelelő elrendezésben folytonos görbét alkotnak, és ezt nevezzük Fibonacci-spirálnak (az alábbi ábrán vastag pirossal jelölve).

Fibonacci-spirál 1

A rajzolás bármeddig folytatható, mert a sorozat végtelen, a négyzetek illeszkednek és az ábra rekurzív, önhasonló. Az alábbi animáció mutatja, hogyan alakul a spirál a nézőpont közelítésével. A viselkedés távolítás során is azonos lenne.

Fibonacci-spirál 2

Korábban blogoltunk már a Fibonacci napról, amelyet minden évben november 23-án ünneplünk. A sorozat első néhány eleméből összeáll a 11.23. és értelmezhető dátumként. Most nem a sorozat elemeinek előállítására fókuszálunk, hanem arra, hogy ezekből felépítsük a Fibonacci-spirált.

Készítsünk Java programot!

Grafikus felületű Java programot készítünk, amely 21 animációs fázisban mutatja be a Fibonacci-sorozat első 10 eleméből álló Fibonacci-spirál felépítését. A rajzolás fázisai:

  • Az 1. fázis a kiindulópontként tekinthető fehér, üres rajzlap. A rajzlap fekvő, mérete 890*550 pixel, amelyre éppen elfér a 10 negyedkörből álló spirál.
  • A 2-11. fázisban megfelelő pozícióba/koordinátákra kerülnek fel az ábra vázát alkotó négyzetek, belülről kifelé haladva. A négyzetek oldalainak hosszúsága a sorozat elemeinek megfelelő. A szomszédos négyzetek különböző színekkel kitöltöttek és mindegyikben megjelenik a sorozat megfelelő eleme.
  • A 12-21. fázisban – szintén belülről kifelé haladva – a négyzetek törlődnek és helyükre a spirált alkotó negyedkörök kerülnek fekete színnel. A 21. fázist tekintjük végeredménynek.

A fázisok kézzel, nyilakkal jelölt (Első, Előző, Következő, Utolsó) vezérlő nyomógombokkal megjeleníthetők, illetve egyben, időzítve animációként is lejátszható a rajzolási folyamat. Az elkészült program működése megfigyelhető az ábrán:

Fibonacci-spirál Java program

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.

Címkefelhő generálása

szófelhő logó

szófelhő logóA címkefelhők/szófelhők népszerűek, sok weboldalon megtalálhatóak. A CMS rendszerekben beépített szolgáltatás is lehet, vagy külön bővítmény/plugin is megvalósíthatja. Egy szövegben előforduló szavakból a gyakrabban előfordulókat nagyobb betűmérettel emeli ki. Eredménye lehet listás, táblázatos, esetleg képpé generált is. Kétféleképpen is megközelíthető, erre utal a Word Cloud és a Tag Cloud elnevezés. Utóbbi inkább egy blog taxonomiájához kapcsolódik és kategóriákra/címkékre érvényesül. A szakmai blogunkhoz is tartozik egy táblázatos címkefelhő. A szófelhő a szöveg betűméretén túl megjelenítheti a szavak előfordulását, például Java forráskód (31).

Példánkban tetszőleges szöveget dolgozunk fel. Ebből felépítünk egy előfordulást is mutató listás szófelhőt, amely rendezett, és a szavak betűmérete 32-16-ig változik. Azok a szavak kerülnek a szófelhőbe, amelyek legalább 5-ször előfordulnak. Kezelünk kivételeket is, például olyan szavakat, amiket nem érdemes szófelhőbe tenni. Lépésenként haladva ismertetjük a megvalósító forráskódot, és külön megjeleníthetők az egyes lépések részeredményei.

A Java programozási nyelv csomagjait, osztályait, interfészeit, metódusait, műveleteit használjuk. Különböző adatszerkezetek kerülnek elő: tömb, generikus lista, generikus map, generikus folyam. Építünk a Stream API szolgáltatásaira és a lambda kifejezésekre. A megvalósítás könnyen testre szabható, kezeli a tipikusan előforduló igényeket.

1. Szövegforrás előkészítése

Generálunk egy 10 bekezdésből álló szöveget a Lorem Ipsum – All the facts – Lipsum generator weboldalon és a későbbi feldolgozáshoz mentjük a Java projekt files mappájába  lorem.txt néven. A fájl mérete: 5781 bájt. Szövegfájl:

2. Szöveges tartalom előkészítése

A megadott útvonalról a java.nio csomag metódusaival betöltjük a szövegfájl tartalmát byte[]-be, majd az s szövegbe. A replace() metódus hívásaival eltávolítjuk a szövegből a sor és bekezdés végét jelző soremelés ( LF="\n") és kocsi vissza ( CR="\r") vezérlőkaraktereket, a vessző és a pont írásjeleket (mindet külön-külön cseréljük a semmire), végül kisbetűssé alakítjuk ( toLowerCase()) a szöveget. A szöveg 5563 db karakterből áll. Előkészített szöveg:

3. Szólista elkészítése

A szóközök mentén darabolva ( split()) a szöveget elkészül belőle egy névtelen szövegtömb ( String[]), amit rögtön átalakítunk ( Arrays.asList()) szöveg típusú generikus listává ( List<String>). A lista 826 db elemből áll. Generikus lista:

4. Csoportosítás és megszámolás

A szólistát csoportosítjuk és megszámoljuk, hogy az egyes szavak hányszor fordulnak elő (másképpen: egy-egy csoport hány elemű). Elkészül a wordCountMap generikus map, amely kulcs-érték párok halmaza (leképezés). A kulcs a szó ( String), az érték a darabszáma ( Long). Alkalmazkodunk ahhoz, hogy a csoportosítás során használt counting() megszámoló művelet Long típusú értéket ad vissza. 188 db kulcs-érték párt kapunk. Generikus map:

5. Szűrés és rendezés

A generikus map-et kétszer szűrjük ( filter() művelet) úgy, hogy a kivételeket tartalmazó exceptList-ben ne szerepeljen a szó, valamint csak a legalább 5-ször előforduló szavakat hagyjuk meg. 71 db elemből álló folyam marad. Ebből a maradékból készítünk rendezett generikus folyamot ( sortedWordCountStream). A sorted() művelet két kulcs-érték párt hasonlít össze. A rendezés érték/darabszám szerint ( getValue()) csökkenő, azon belül kulcs/szavak szerint ( getKey()) növekvő sorrendet biztosít. Másképpen: ha az értékek megegyeznek, akkor a növekvő sorrendet a szavak ábécé sorrendje határozza meg, egyébként a darabszámok csökkenő sorrendje dönti el. Most már könnyen látható, hogy a leggyakrabban előforduló kevés szóból 15 van, 14 előfordulás nincs… Rendezett generikus folyam:

6. Saját típusú listává konvertálás

Definiálunk egy WordCount POJO-t, String típusú word nevű, Long típusú count nevű, int típusú fontSize nevű tulajdonságokkal, getter/setter metódusokkal, és toString() függvénnyel.

A map() intermediate művelettel a rendezett generikus folyamot bejárva, előállítjuk a POJO/ WordCount  típusú kimeneti objektumok rendezett generikus listáját. Továbbra is 71 elemmel dolgozunk. Rendezett generikus lista:

7. Darabszámok összegyűjtése

A POJO típusú rendezett generikus listában lévő objektumoktól elkért darabszámok ( getCount() POJO függvény) közül a különbözőeket ( distinct() művelet) összegyűjtjük egy Long típusú generikus listába ( distinctCountList). Az egyediesítő művelet nincs hatással az adatok sorrendjére. Tízféle előfordulást kapunk. Generikus lista:

8. Betűméret lépésköze

A szófelhőben a szavak gyakorisága alapján határozzuk meg a betűméretet. A betűméret 32-ről indul és fokozatosan csökken 16-ig. A betűméret léptetéséhez a tízféle gyakoriság/előfordulás meghatározza a stepFontSize  lépésközt. Lépésköz:

9. Betűméret kiszámítása

Csoportváltást alkalmazunk és a csoportot gi-vel indexeljük. Egy csoportba azok a POJO objektumok tartoznak, amelyeknél a szavak előfordulása megegyezik. Az algoritmus 2. lépésében az aktuális csoportra érvényesen kiszámítjuk a betűméretet ( fontSize), ami az algoritmus 3. lépésében a csoportba tartozó minden POJO objektumnál beállításra kerül a setFontSize() POJO eljárással. Az algoritmus 4. lépésében léptetjük a csoport gi indexét. A POJO-k esetén először csak a word és count tulajdonságok kerültek beállításra, de most már a fontSize tulajdonság is értéket kapott. Generikus lista:

10. HTML tartalom előállítása

A generikus lista POJO objektumain végighaladva, a forEach() záró művelettel összeállítható a weboldal szófelhőt tartalmazó része ( sbHTML). A 71 db szóból álló szófelhő HTML forráskódjának mérete 3409 bájt. HTML forráskód:

Eredmény

Szöveges formában:

lorem ipsum szófelhő

Képként (a 3. lépés részeredményéből a WordClouds.com weboldalon generálva):

lorem ipsum szófelhő eredmény

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 több alkalmához is kötődik. A Stream API-val és a lambda kifejezésekkel sokszor foglalkozunk.

Dr. Sheldon Cooper szólánc játéka

Sheldon, Agymenők

Sheldon szólánc kiemelt képDr. Sheldon Cooper karakterét nem kell bemutatni. Az Agymenők (The Big Bang Theory) című sorozat 2. évad 5. epizódjának címe A vitatkozás nagymestere (The Euclid Alternative). Nagyon találó az epizód címe magyarul. Miközben Penny reggel Sheldont munkába viszi, Sheldon az autóban kémiai elemek nevéből álló szólánc játékával különösen Penny agyára megy (pedig a játékot Penny nyeri 😀):

A játék során Sheldon az alábbi kémiai elemeket mondja:

  • magyar nyelven: Hélium ↦ Mangán ↦ Neptúnium ↦ Magnézium ↦ Molibdén ↦ Nitrogén ↦ Nobélium ↦ Mendelévium
  • angol nyelven: Helium ↦ Mercury ↦ Ytterbium ↦ Molybdenum ↦ Magnesium ↦ Manganese ↦ Europium ↦ Mendelevium

Támogassuk meg ezt a játékot! Készítsünk olyan programot Java nyelven, ami segít(ene) felkészülni Sheldon szólánc játékára!

A szükséges lépések áttekintése

  • Gyűjtsük össze a kémiai elemek nevét magyar nyelven a Wikipédia – Kémiai elemek listája szócikkéből és rendezzük ábécé sorrendbe!
  • Építsük be az elemlistát a program adatmodelljébe!
  • Indítsuk el a lépésszámláló nulláról! Ha a lépésszámláló páros, akkor az ’A’ játékos, egyébként a ’B’ játékos lép.
  • Készítsük elő a játékmenet tárolására alkalmas adatszerkezetet, szöveget, listát!
  • Kezdetben kínáljuk fel a teljes elemlistát úgy, hogy mindig egy és csak egy legyen belőle kiválasztható!
  • A kiválasztást követően tároljuk el a játékmenetben az elemet, töröljük ezt az elemlistából, majd kínáljuk fel azoknak az elemeknek a listáját, amelyek kezdőbetűje megegyezik az előzőleg kiválasztott elem utolsó betűjével és növeljük meg a lépésszámlálót!
  • Amíg a felkínálható elemek listája nem üres, addig az előző lépést ismételjük meg!
  • A játék végén az nyert, aki a játékmenet utolsó elemét választotta ki. Írjuk ki a nevét és a lépésszámot!

A grafikus felületű megvalósítás képernyőképe rövid játékmenettel

Szólánc képernyőkép

Ötletek a megvalósításra és a továbbfejlesztésre

  • A program Java nyelven konzolos menükezeléssel, asztali alkalmazásként swing-esen többféle GUI komponens használatával és eseménykezeléssel, böngészőben futó JSP webalkalmazásként többféle űrlapmezővel, illetve HTML+CSS+JavaScript alapon is implementálható.
  • A kémiai elemek listája lecserélhető az angol nevekre. Ekkor figyeljünk arra, hogy a kis- és nagybetűket ne különböztessük meg az utolsó-első betű párosítása során.
  • Lehet a játék bármikor megszakítható, illetve a vége után újrakezdhető.
  • A program mérhetné a játék során az eltelt időt.
  • A program lehetne peer-to-peer vagy szerver-kliens elosztott és megvalósíthatna hálózatos kommunikációt.
  • A program mobil alkalmazásként is implementálható.

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

Többféleképpen is hozzájuthatunk az adatokhoz attól függően, hogy milyen előismeretekkel rendelkezünk a különböző tanfolyamainkon:

  • A Java SE szoftverfejlesztő tanfolyamon dolgozhatunk szövegtömbbel, generikus kollekcióval (listával/halmazzal), konzolos és swing-es változatot is készíthetünk. Ehhez a feladathoz objektumorientált alapok mindenképpen szükségesek. Kézzel előállított szövegfájlból olvasva (mentve a Wikipédia oldaláról a táblázatot) hozzájuthatunk a kémiai elemek nevéhez, amihez kivételkezelés is szükséges.
  • A Java EE szoftverfejlesztő tanfolyamon megvalósítható, hogy a program kivételkezeléssel hálózati kapcsolatot épít, majd közvetlenül olvassa és/vagy menti a Wikipédia HTML tartalmából a kémiai elemek nevét szövegfájlba vagy generikus kollekcióba, amivel a feladat visszavezethető az SE szemléletű megközelítésre. Böngészőben futó JSP és/vagy Servlet technológiára építő webalkalmazásként is megvalósítható a feladat.

KSH táblázatból dolgozunk

KSH-logo

KSH-logoA Központi Statisztikai Hivatal honlapján elérhető STADAT táblákból könnyen kinyerhetjük a nekünk szükséges adatokat. A témastruktúrába sorolt online és XLS exportként is böngészhető táblázatokban megtalálhatjuk logikusan csoportosítva összesítve az adatokat régiónként (megyénként), évenként, százalékosan. Az XLS fájlformátum Java nyelven a JExcel API-val hatékonyan feldolgozható. Lássunk erre egy példát!

Feladat

A KSH 2.1.2.35. táblázatából gyűjtsük ki a 19 magyar megyére + Budapestre vonatkozóan a gazdaságilag aktívak létszámát és az első évet alapnak tekintve adjuk meg évenként a változást százalékosan!

Tervezés

A KSH témastruktúrában a táblázat elérési útja:

  • 2. Társadalom,
  • 2.1. Munkaerőpiac,
  • 2.1.2. A munkaerőpiac alakulása Magyarországon (1998–2018) -> Területi adatok,
  • 2.1.2.35. A 15–64 éves népesség gazdasági aktivitása megyénként és régiónként (1998–2018)

Online böngészhető táblázat:
https://www.ksh.hu/docs/hun/xstadat/xstadat_hosszu/mpal2_01_02_35.html.

Letölthető táblázat (XLS formátumban): https://www.ksh.hu/docs/hun/xstadat/xstadat_hosszu/xls/h2_1_2_35.xls.

A táblázat A oszlopában szerepelnek a régiók, megyék, időszakok (vegyesen, szövegként) és a D oszlopában a gazdaságilag aktívak (ezer fő, valós számként). A fejlécet nem szabad feldolgozni. 1998-tól 2018-ig 546 sorból áll az adatsor. A csoportosítás 26 régiót és megyét tartalmaz, amiből a 6 régiót (például: Közép-Dunántúl) ki kell hagyni.

A megyékre vonatkozóan 440 sort kell feldolgozni. Ebből az első sor a megye (vagy Budapest) neve, a többi (2019-ben 21 db) sorban találhatók az adatok (időszak). Olyan algoritmusban érdemes gondolkodni, ami a jövőben is működik. Ha csoportváltást alkalmazunk, akkor nem számít, hogy megyénként minden évben egy sornyival több adat lesz majd. A KSH táblázatok szerkezete nagyon ritkán változik, így bátran írható rájuk testre szabott forráskód (ezeket nem kell évente frissíteni).

Az évenkénti változást százalékosan nem tartalmazza a táblázat, ezt nekünk kell kiszámítani. A valós számok formázását érdemes egységesíteni, például a gazdaságilag aktívak létszámát 3 tizedesre, a változást 2 tizedesre kerekítve.

A belső adatábrázolást érdemes átgondolni. Hasznos, ha az időszakhoz tartozó három összetartozó adatot egyetlen Data POJO-ba fogjuk össze ( String period, double active és double change). Ezeket generikus listába szervezve ( ArrayList<Data> list) könnyen hozzájuk rendelhető a megye ( String county) és ezek együtt alkotják a Region POJO-t. A Region és Data kapcsolati fokszáma: 1:N. 2019-ben N=21 .

Részlet a megoldásból

A JExcel API használatához a Java projekthez hozzá kell adni a jxl.jar fájlt. A XLS fájl olvasható közvetlenül a webről is, de egyszerűbb helyi fájlrendszerbe mentett változatból dolgozni ( ./files/h2_1_2_35.xls). A megyék nevében található ékezetes karakterek miatt ügyelni kell a megfelelő karakterkódolásra ( Cp1252). A munkafüzet azonosítását követően hivatkozni kell a feldolgozandó munkalapra ( 2.1.2.35.). Az adatfeldolgozás során kihagyott régiókat (kivételeket) érdemes listába gyűjteni ( skipRegionList). A csoportváltást a két egymásba ágyazott ciklus valósítja meg. Ügyelni kell az adatok formátumának ellenőrzésére.

Eredmények

Például Somogy megyére az alábbi adatokat kapjuk eredményként (XLS formátumban, Excel-be betöltve, tipikus háttérszín kiemeléssel: szélsőértékek a C oszlopban, negatív értékek a D oszlopban):

KSH-result

További programozható feladatok

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 (ha az XLS fájlt a helyi fájlrendszerből érjük el), és a Java EE szoftverfejlesztő tanfolyam tematikájához kapcsolódik (ha az XLS fájl tartalmát közvetlenül a webről olvassuk).

Denevérek a barlangban

Évekkel ezelőtt hálózatos Java EE esettanulmányt akartunk készíteni Lengyel Borisz kollégával. Ötleteltünk: milyen technológiával és hogyan kommunikáljon egymással a szerver és a kliens(ek). A távoli metódushívás (Remote Method Invocation) mellett döntöttünk és elkészült a denevérek a barlangban projekt, amely evolúciós projektként azóta több változatot is megélt. A felhasználói felület (barlang) betölt néhány képet (denevér kliensek), amelyek a szerver segítségével mozognak.

Ismertetjük a tervezés folyamatát, a kliens és szerver funkcióit részletesen, végül ötleteket adunk a továbbfejlesztésre.

A főbb feladatokat így határoztuk meg:

  • az RMI kommunikációs módszer megismertetése,
  • az RMI szolgáltatás reprezentálása látványos grafikus/swinges klienssel,
  • alternatíva nyújtása a TCP protokoll közvetlenül csatlakozó socket-jére.

Elkészítettük az alábbi osztálydiagramot (persze ez nem az első változat):

Denevérek a barlangban - Osztálydiagram

A szerver és kliens funkcióit megvalósító osztályok/interfészek feladatait így határoztuk meg:

BarlangDenevérInterfész interfész:

  • véletlen 5 és 10 közötti a denevérek száma,
  • méretek a GUI-hoz.

Denevér osztály:

  • megvalósítja az RMI kliens funkciót,
  • JLabel leszármazott, külső képfájlt tölt be ( bat.jpg),
  • egyedi azonosítója van,
  • eldönti mozgásának irányát (4) és léptékét (3), mintha ultrahangot adna,
  • a szerver megadja neki, hogy az új helyre elmozdulhat-e,
  • saját magát képes mozgatni.

Pozíció interfész:

  • öröklődik a java.rmi.Remote interfészből,
  • két távolról hívható metódus fejét tartalmazza.

BarlangSzerver osztály:

  • megvalósítja az RMI szerver funkciót,
  • implementálja a Pozíció interfészt,
  • JFrame leszármazott,
  • figyel arra, hogy a denevérek ne mozogjanak ki a barlangból.

BarlangFelület osztály:

  • JFrame leszármazott,
  • GUI az RMI kliensek megjelenítéséhez.

BarlangSzerverTérkép osztály:

  • JPanel leszármazott,
  • GUI a szerveren a kliensek mozgásának követésére.

Ha futtatjuk az elkészült szerver és kliens programot, akkor ezt láthatjuk:

Denevérek a barlangban - animáció

A fejlesztés és tesztelés közben sok-sok továbbfejlesztési ötletet/javaslatot fogalmaztunk meg:

  • háttérkép a barlangról,
  • a háttérkép megvalósíthat labirintust, koordináta-rendszert,
  • átlátszó illetve egyedi képfájlok a denevéreknek,
  • a denevérek mozgásának tetszőleges iránya (360°),
  • a denevérek mozgásának egyedi léptéke,
  • a denevérek figyeljenek egymásra (ne ütközzenek össze),
  • a denevérek figyeljenek a környezetükre (ne ütközzenek bele sziklákba, cseppkövekbe),
  • a szerver követheti a denevérek útvonalát,
  • a szerver archiválhat, szerializálhat, készíthet statisztikát.

A bejegyzéshez tartozó – több lépésben továbbfejlesztett – forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A feladat a Java EE szoftverfejlesztő tanfolyam 21-24. óra: RMI alapú kommunikáció alkalmához kapcsolódik.