Un pomeriggio piovoso, sei seduto al tavolo della cucina a giocare a carte con tua nonna. Il gioco è la sua versione di Camicia.
All'inizio sembra soltanto un'altra partita amichevole: carte calate con forza sul tavolo, risate intorno al tavolo, e ogni tanto un sorriso vittorioso da parte di Nonna. Ma man mano che la partita va avanti, succede qualcosa di strano. Le stesse carte continuano a ripresentarsi. Giochi carta dopo carta, eppure la fine non sembra mai arrivare.
Cominci a chiederti. Questa partita finirà mai? O potremmo continuare a giocare per sempre?
Più tardi, spinto dalla curiosità, cerchi online e con tua sorpresa scopri che quello che è successo non è stata solo sfortuna. Tu e tua nonna potreste esservi imbattuti in una delle sequenze più lunghe possibili! All'improvviso ne sei catturato. Quello che era iniziato come una partita spensierata si è trasformato in una missione: quanto può durare davvero una partita del genere? Riesci a trovare una sequenza ancora più lunga di quella che hai giocato al tavolo della cucina? Magari persino abbastanza lunga da stabilire un nuovo record mondiale?
E così, armato soltanto di un mazzo di carte e di un po' di ingegno algoritmico, decidi di indagare...
In questo esercizio simulerai una partita molto simile al classico gioco di carte Camicia. Il programma riceverà la configurazione iniziale dei mazzi di due giocatori e dovrà simulare la partita fino alla sua conclusione (o rilevare che non finirà mai).
Un piccolo esempio di partita che finisce.
| Round | Giocatore A | Giocatore B | Pila | Penale dovuta |
|---|---|---|---|---|
| 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 | Giocatore B: 4 |
| 1 | 7 8 Q 10 | 5 6 K 9 J | 2 3 A 4 | Giocatore B: 3 |
| 1 | 7 8 Q 10 | 6 K 9 J | 2 3 A 4 5 | Giocatore B: 2 |
| 1 | 7 8 Q 10 | K 9 J | 2 3 A 4 5 6 | Giocatore B: 1 |
| 1 | 7 8 Q 10 | 9 J | 2 3 A 4 5 6 K | Giocatore A: 3 |
| 1 | 8 Q 10 | 9 J | 2 3 A 4 5 6 K 7 | Giocatore A: 2 |
| 1 | Q 10 | 9 J | 2 3 A 4 5 6 K 7 8 | Giocatore A: 1 |
| 1 | 10 | 9 J | 2 3 A 4 5 6 K 7 8 Q | Giocatore B: 2 |
| 1 | 10 | J | 2 3 A 4 5 6 K 7 8 Q 9 | Giocatore B: 1 |
| 1 | 10 | - | 2 3 A 4 5 6 K 7 8 Q 9 J | Giocatore 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 | - | - |
status: "finished", cards: 13, tricks: 1
Questo è un piccolo esempio di partita che entra in un loop.
| Round | Giocatore A | Giocatore B | Pila | Penale dovuta |
|---|---|---|---|---|
| 1 | J 2 3 | 4 J 5 | - | - |
| 1 | 2 3 | 4 J 5 | J | Giocatore 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 | Giocatore 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 | Giocatore B: 1 |
| 3 | 4 | J 3 | 5 J 2 | - |
| 4 | 4 5 J 2 | J 3 | - | - |
L'inizio del round 4 coincide con l'inizio del round 2. Ricorda: il valore delle carte numeriche non conta.
status: "loop", cards: 8, tricks: 3
"finished" o "loop"
Per chi vuole affrontare una sfida più entusiasmante, la caccia ad altri record per la partita più lunga che finisce è ancora aperta. Ci sono 653.534.134.886.878.245.000 (circa 654 trilioni) possibilità e non le abbiamo ancora calcolate tutte!
from_quote
La funzione Card.from_quote esegue il parsing di una stringa in una Card.
Questo permette di scrivere codice come questo:
card : Card
card = "Q"
Questo codice chiama implicitamente Card.from_quote("Q") in fase di compilazione.
Eseguire codice in fase di compilazione con questo approccio (o con altri metodi descritti qui sotto) può potenzialmente velocizzare il programma, dato che non deve gestire il parsing e la validazione dei dati a runtime.
Inoltre, garantisce che i dati non validi (come un formato di data errato) vengano rifiutati in fase di compilazione invece che a runtime, rendendo l'app più robusta.
Infine, rende il codice bello e leggibile.
Per esempio, ecco uno dei test di questo esercizio:
result = simulate_game({
player_a: ["2", "A"],
player_b: ["3", "4", "5", "6", "K"],
})
Tuttavia, chi legge questo codice potrebbe pensare che la funzione simulate_game accetti un record contenente due List(Str), quando in realtà è un record contenente due List(Card).
Questo può portare a confusione ed errori.
Per questo motivo, potresti preferire il formato leggermente più lungo ma più esplicito: "Q".Card, che chiama anch'esso from_quote in fase di compilazione.
Nei tuoi programmi, potresti preferire usare from_str:
Card := { ... }.{
from_str : Str -> Try(Card, [InvalidCard])
from_str = |card_str| ...
}
Puoi anche chiamare from_str (o qualsiasi altra funzione pura) in fase di compilazione, come qui:
Ok(card) = Card.from_str("Q")
Nota: mettere questa definizione al livello superiore la fa eseguire in fase di compilazione (dato che la funzione è pura e il suo input è noto in fase di compilazione).
All'interno di una funzione, puoi usare from_str a runtime.
Usa match con [] e [card, .. as rest] per distinguere un mazzo vuoto dalla sua prossima carta e dalle carte rimanenti.
Gli aggiornamenti dei record come { ..state, pile: new_pile } possono mantenere esplicite le transizioni di gioco senza stato mutabile.
Un Set può memorizzare tuple o liste come chiavi quando si tiene traccia degli stati di gioco già visti.
Iscriviti a Exercism per imparare e padroneggiare Roc con 135 esercizi e il mentoring di persone reali, tutto gratis.