Egy esős délután a konyhaasztalnál ülsz, és kártyázol a nagymamáddal. Ez a játék az ő változata a Camicia nevű játékra.
Először úgy tűnik, mintha csak egy újabb barátságos játszma lenne: lapok csapódnak le az asztalra, nevetés az asztalnál, és néha Nonna diadalmas vigyora. De ahogy a játék egyre húzódik, valami furcsa dolog történik. Ugyanazok a lapok kerülnek elő újra meg újra. Egyik lapot rakod le a másik után, a vég mégsem akar eljönni.
Elkezdesz tűnődni. Vajon véget ér valaha ez a játék? Vagy akár örökké is játszhatnánk?
Később a kíváncsiságtól hajtva rákeresel az interneten, és meglepetésedre rájössz, hogy ami történt, az nem csak balszerencse volt. Lehet, hogy te és a nagymamád a leghosszabb lehetséges sorozatok egyikére bukkantatok! Hirtelen a játék rabjává válsz. Ami egy kötetlen játékként indult, az küldetéssé változott: vajon meddig tarthat igazán egy ilyen játék? Találsz-e még annál is hosszabb sorozatot, mint amilyet a konyhaasztalnál játszottatok? Esetleg olyat, amely elég hosszú ahhoz, hogy új világrekordot állítson fel?
És így, mindössze egy pakli kártyával és némi algoritmikus leleményességgel felfegyverkezve, úgy döntesz, hogy utánajársz...
Ebben a feladatban egy olyan játékot fogsz szimulálni, amely nagyon hasonlít a klasszikus Camicia kártyajátékhoz. A programod megkapja két játékos paklijának kezdeti állapotát, és szimulálnia kell a játékot, amíg véget nem ér (vagy fel kell ismernie, hogy soha nem fog véget érni).
Egy kis példa egy befejeződő játszmára.
| Kör | Játékos A | Játékos B | Kupac | Fizetendő büntetés |
|---|---|---|---|---|
| 1 | 2 A 7 8 Q 10 | 3 4 5 6 K 9 J | - | |
| 1 | A 7 8 Q 10 | 3 4 5 6 K 9 J | 2 | - |
| 1 | A 7 8 Q 10 | 4 5 6 K 9 J | 2 3 | - |
| 1 | 7 8 Q 10 | 4 5 6 K 9 J | 2 3 A | Játékos B: 4 |
| 1 | 7 8 Q 10 | 5 6 K 9 J | 2 3 A 4 | Játékos B: 3 |
| 1 | 7 8 Q 10 | 6 K 9 J | 2 3 A 4 5 | Játékos B: 2 |
| 1 | 7 8 Q 10 | K 9 J | 2 3 A 4 5 6 | Játékos B: 1 |
| 1 | 7 8 Q 10 | 9 J | 2 3 A 4 5 6 K | Játékos A: 3 |
| 1 | 8 Q 10 | 9 J | 2 3 A 4 5 6 K 7 | Játékos A: 2 |
| 1 | Q 10 | 9 J | 2 3 A 4 5 6 K 7 8 | Játékos A: 1 |
| 1 | 10 | 9 J | 2 3 A 4 5 6 K 7 8 Q | Játékos B: 2 |
| 1 | 10 | J | 2 3 A 4 5 6 K 7 8 Q 9 | Játékos B: 1 |
| 1 | 10 | - | 2 3 A 4 5 6 K 7 8 Q 9 J | Játékos A: 1 |
| 1 | - | - | 2 3 A 4 5 6 K 7 8 Q 9 J 10 | - |
| 2 | - | 2 3 A 4 5 6 K 7 8 Q 9 J 10 | - | - |
állapot: "finished", kártyák: 13, ütések: 1
Ez egy kis példa egy ciklusba kerülő játszmára.
| Kör | Játékos A | Játékos B | Kupac | Fizetendő büntetés |
|---|---|---|---|---|
| 1 | J 2 3 | 4 J 5 | - | - |
| 1 | 2 3 | 4 J 5 | J | Játékos B: 1 |
| 1 | 2 3 | J 5 | J 4 | - |
| 2 | 2 3 J 4 | J 5 | - | - |
| 2 | 3 J 4 | J 5 | 2 | - |
| 2 | 3 J 4 | 5 | 2 J | Játékos A: 1 |
| 2 | J 4 | 5 | 2 J 3 | - |
| 3 | J 4 | 5 2 J 3 | - | - |
| 3 | J 4 | 2 J 3 | 5 | - |
| 3 | 4 | 2 J 3 | 5 J | Játékos B: 1 |
| 3 | 4 | J 3 | 5 J 2 | - |
| 4 | 4 5 J 2 | J 3 | - | - |
A 4. kör kezdete megegyezik a 2. kör kezdetével. Emlékezz rá, hogy a számkártyák értéke nem számít.
állapot: "loop", kártyák: 8, ütések: 3
"finished" vagy "loop"
Azoknak, akik egy izgalmasabb kihívást szeretnének vállalni: még mindig nyitott a vadászat a leghosszabb, befejeződő játék további rekordjaira. 653 534 134 886 878 245 000 (körülbelül 654 trillió) lehetőség van, és még nem számoltuk ki mindet!
from_quote előnyei és hátrányaiA Card.from_quote függvény egy stringet alakít Card-dá. Ez lehetővé teszi, hogy ilyen kódot írj:
card : Card
card = "Q"
Ez a kód implicit módon meghívja a Card.from_quote("Q") függvényt fordítási időben. Ha ezzel a módszerrel (vagy az alább leírt egyéb módokon) futtatsz kódot fordítási időben, az potenciálisan felgyorsíthatja a programot, mivel így nem kell futásidőben a parse-olással és az adatok érvényesítésével foglalkoznia. Ráadásul gondoskodik róla, hogy az érvénytelen adatok (például egy hibás dátumformátum) már fordítási időben kiderüljenek, ne pedig futásidőben, ami robusztusabbá teszi az alkalmazásodat. Végül pedig széppé és olvashatóvá teszi a kódot. Például így néz ki a feladat egyik tesztje:
result = simulate_game({
player_a: ["2", "A"],
player_b: ["3", "4", "5", "6", "K"],
})
Lehet azonban, hogy aki ezt a kódot olvassa, azt hiszi, hogy a simulate_game függvény két List(Str)-et tartalmazó rekordot vár, pedig valójában két List(Card)-ot tartalmazó rekordról van szó. Ez zavarhoz és hibákhoz vezethet. Ezért talán inkább a kicsit hosszabb, de egyértelműbb formát választod: a "Q".Card-ot, ami szintén meghívja a from_quote függvényt fordítási időben.
A saját programjaidban viszont talán inkább a from_str függvényt használnád:
Card := { ... }.{
from_str : Str -> Try(Card, [InvalidCard])
from_str = |card_str| ...
}
A from_str függvényt (vagy bármely más tiszta függvényt) fordítási időben is meghívhatod, így:
Ok(card) = Card.from_str("Q")
Megjegyzés: ha ezt a definíciót a legfelső szintre teszed, az fordítási időben fut le (mivel a függvény tiszta, és a bemenete fordítási időben ismert). Egy függvényen belül viszont a from_str függvényt futásidőben használhatod.
A match-csel, valamint a [] és a [card, .. as rest] mintával különböztetheted meg az üres paklit a következő kártyától és a maradék kártyáktól.
A { ..state, pile: new_pile }-hez hasonló rekordfrissítésekkel a játék állapotváltásait is explicit módon tarthatod, változtatható állapot nélkül.
A Set tuple-t vagy listát is tárolhat kulcsként, amikor a korábban látott játékállapotokat követed nyomon.
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Roc nyelvet 135 feladat segítségével, valódi emberi mentorálással, mindez ingyen.