Valaki sertést, kecskét és juhot vásárolt, összesen 100 állatot, pontosan 100 aranyért. A sertés darabja 3 és fél arany, a kecskéé 1 és egyharmad, a juhoké fél arany. Hány darabot vehetett az egyes állatokból?
Tudjuk, hogy a feladatnak három megoldása van:
- 5 db sertés és 42 db kecske és 53 db juh
- 10 db sertés és 24 db kecske és 66 db juh
- 15 db sertés és 6 db kecske és 79 db juh
Klasszikus informatikai megközelítést – egymásba ágyazott ciklusokat – bemutattam már: Euler állatos feladata. A brute force alapgondolat fokozatos finomítását követően néhány ötleteket is adtam a továbbfejlesztéshez. Ez igazi örökzöld feladat. Látogatottsága alapján rendületlenül népszerű ez a blog bejegyzés az it-tanfolyam.hu szakmai blogban. Többek között ez inspirált a feladattal való további foglalkozásra.
Mit jelent a geometriai megközelítés?
Egy térbeli pont három koordinátával leírható. Az (s, k, j) ponthármas jelenti a sertések, kecskék és juhok számát. Az RGB színkockához hasonlóan (amibe belefér az összes ábrázolható színhez tartozó koordinátapont), most is elférünk egy kockában. Legyen a kocka egyik csúcsa az origó és az élei legyenek 100 egység hosszúak. A feladat megfogalmazása alapján két egyenlet (e1 és e2) írható fel 3-3 együtthatóval. Mindkét egyenlet meghatároz egy síkot (s1 és s2) a térben, amelynek ábrázoljuk a kockába eső síkmetszeteit. A két sík metszésvonala egyenes (e3), amire esnek a megoldások pontjai (m1, m2, m3). Lépésenként haladunk a geometriai ábrázolás során.
A grafikus felületen történő ábrázoláshoz, rajzoláshoz két korábbi projektünkből indulunk ki. A Kígyókocka grafikus felületen feladat ismertet egy grafikus keretrendszert JavaFX-ben megvalósítva. A három részből álló Naprendszer szimuláció esettanulmányunk pedig ismerteti az ábrázoláshoz szükséges elméleti hátteret, homogén transzformációkat, vetületi leképezést, Java forráskódot is bemutat a transzformációs mátrix alkalmazására. Az eddig említett három blog bejegyzést mind összeépítve készültek a továbbiak.
A geometriai megoldást lépésenként, saját fejlesztésű, grafikus felhasználói felülettel rendelkező, JavaFX alapú programról készült képernyőképek mutatják be – markáns Java forráskód-részletekkel.
Hogy jelenik meg a megoldásokat tartalmazó kocka?
Elegendő ábrázolni a kockának azt a három élét, amik egybeesnek a koordinátatengelyekkel. Az RGB színkockához hasonlóan piros, zöld, kék színekkel jelennek meg a három tengelyen lévő néhány pont. Az ábrázoláshoz érdemes kísérletezni egy kicsit: mekkora méretben (skála), honnan (nézőpont), milyen messziről (vetület, ideális pont, perspektíva, távolság) látszik a modelltérbeli objektum (igen, ez a kocka).
Az alábbi Java forráskód-részlet helyezi el a fenti pontokat. Mindhárom tengelyen 5-től 95-ig, 10-esével haladunk. Így elkerülhető, hogy az origóba kerüljön pont, hiszen az nem tudna egyszerre három színnel megjelenni. Mivel az állatok száma pozitív, így a koordinátapontok is nemnegatívak.
1 2 3 4 5 6 7 8 |
for(int i=5; i<=100; i+=10) { Point3D cpS=new Point3D(i, 0, 0); //sertés createPoint(cpS, 5, Color.RED); Point3D cpK=new Point3D(0, i, 0); //kecske createPoint(cpK, 5, Color.GREEN); Point3D cpJ=new Point3D(0, 0, i); //juh createPoint(cpJ, 5, Color.BLUE); } |
Hol vannak az első egyenlet síkjának pontjai?
A korábbi megoldásnál feltételként megfogalmazott első 3.5*s+4.0/3*k+0.5*j==100 egyenlet egyszerű átalakításokkal megadja a piros és zöld síkbeli ponthoz tartozó kék térbeli pontot: j=(600-21*s-8*k)/3. Ezek az s1 síkra esnek. A citromsárga pontokat páros koordinátapárokra vizsgált feltétel jelöli ki. A narancssárga vonal behatárolja ezt a síkmetszetet. Ez a négyszög (trapéz) esik bele a kockába.
A citromsárga pontokat az első egymásba ágyazott ciklusok adják hozzá az ábrázolt modelltérhez: érzékeltetve a síkbeli pontokat. A narancssárga pontokkal a második egymásba ágyazott ciklusok bővítik a modellteret: behatárolva a kockabeli négyszög síkrészletet. (A trapéz oldalait szakaszként is lehetne ábrázolni, de ez a kellően sűrű ponthalmaz is elegendő).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
for(int s=0; s<=100; s+=2) for(int k=0; k<=100; k+=2) { int j=(600-21*s-8*k)/3; if(0<=j && j<=100) { Point3D cpE1=new Point3D(s, k, j); createPoint(cpE1, 3, Color.YELLOW); } } for(double s=0; s<=100; s+=0.1) for(double k=0; k<=100; k+=0.1) { long j=Math.round((600-21*s-8*k)/3); if(((s==0 || s==100) && 0<=j && j<=100) || ((k==0 || k==100) && 0<=j && j<=100) || (j==0 || j==100)) { Point3D cpE1=new Point3D(s, k, j); createPoint(cpE1, 2, Color.ORANGE); } } |
Hol vannak a második egyenlet síkjának pontjai?
Hasonlóan az eddigiekhez. A korábbi s+k+j==100 feltételből adódik a szintén feltételként megfogalmazott j==100-s-k egyenlet. Ezek az s2 síkra esnek. Világosszürke pontok érzékeltetik a síkot és sötétszürke pontok adják a síkrészlet határait. A síkból ez a háromszög esik bele a kockába.
A Java forráskód nagyon hasonló az előzőhöz.
Hogyan helyezkedik el a két sík a kockában?
Egyben kirajzoltatva a fentieket, könnyen adódik ez az ábra:
Hol van a két sík metszésvonala?
Mivel a két sík nem esik egybe, így van metszésvonaluk. Ez egy egyenes, amiből csak az az e3 szakasz rész szükséges, ami a kockába esik. Bíbor (magenta) szín jelöli az alábbi ábrán:
Ahol a két egyenlethez tartozó konkrét pontok egybeesnek, ott van a metszésvonal. A behelyettesítést behatároló ciklusok szervezéséből (a ciklusváltozók alsó és felső és határaiból) adódik, hogy csak a kockabeli szakaszt rajzolja ki az alábbi Java forráskód-részlet:
1 2 3 4 5 6 7 8 9 |
for(double s=0; s<=100; s+=0.1) for(double k=0; k<=100; k+=0.1) { long j1=Math.round((600-21*s-8*k)/3); long j2=Math.round(100-s-k); if(j1==j2) { Point3D cpE1=new Point3D(s, k, j1); createPoint(cpE1, 2, Color.MAGENTA); } } |
Hol jelenik meg a feladat három megoldása?
A két egyenlethez tartozó síkok kockába eső metszésvonalán helyezkednek el az egész koordinátákkal ábrázolható, koordináta-hármasként megjelenő pontok. Nagyobb fehér pontok jelölik ezeket az alábbi ábrán:
Az eddigiek alapján könnyen adódik a három pont/megoldást ábrázoló Java forráskód-részlet:
1 2 3 4 5 6 |
Point3D m1=new Point3D(5, 42, 53); createPoint(m1, 10, Color.WHITE); Point3D m2=new Point3D(10, 24, 66); createPoint(m2, 10, Color.WHITE); Point3D m3=new Point3D(15, 6, 79); createPoint(m3, 10, Color.WHITE); |
A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.
Ez a feladat a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 5-8. óra: Vezérlési szerkezetek, illetve 9-12. óra: Metódusok, rekurzió alkalmához, a 29-36. óra Grafikus felhasználói felület alkalmaihoz, valamint minden tanfolyamunk orientáló moduljának 1-4. óra: Programozási tételek alkalmához kapcsolódik.
Tanfolyamainkon JavaFX grafikus felülettel hangsúlyosan nem foglalkozunk, de egy-egy kész forráskódot közösen megbeszélünk, és össze is hasonlítjuk a swing-es változattal. Fejlesztünk játékprogramot, de inkább konzolosan, vagy swing-es ablakban, vagy webes alkalmazásként.
A grafikus felületek felépítésének megismerése fontos lépcső az objektumorientált programozás elmélyítéséhez, gyakorlásához. A grafikus felületekhez egy másik lényeges szemléletváltás is kapcsolódik, hiszen a korábbi algoritmusvezérelt megközelítést felváltja az eseményvezérelt (eseménykezelés). A GUI-s feladatainkat tudatosan hangsúlyozott MVC-s projektekben készítjük el.