Skip to content

Commit 24b4295

Browse files
authored
Add practice exercise camicia (#779)
1 parent 5269cf0 commit 24b4295

9 files changed

Lines changed: 689 additions & 0 deletions

File tree

config.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,28 @@
16601660
"strings"
16611661
],
16621662
"difficulty": 8
1663+
},
1664+
{
1665+
"slug": "camicia",
1666+
"name": "Camicia",
1667+
"uuid": "e719ea76-2ada-4360-b5f9-5e7a538a3505",
1668+
"practices": [
1669+
"tail-call-recursion"
1670+
],
1671+
"prerequisites": [
1672+
"recursion",
1673+
"tail-call-recursion",
1674+
"lists",
1675+
"records",
1676+
"pattern-matching",
1677+
"custom-types",
1678+
"comparison",
1679+
"set",
1680+
"let",
1681+
"booleans",
1682+
"tuples"
1683+
],
1684+
"difficulty": 7
16631685
}
16641686
],
16651687
"foregone": [
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Instructions
2+
3+
In this exercise, you will simulate a game very similar to the classic card game **Camicia**.
4+
Your program will receive the initial configuration of two players' decks and must simulate the game until it ends (or detect that it will never end).
5+
6+
## Rules
7+
8+
- The deck is split between **two players**.
9+
The player's cards are read from left to right, where the leftmost card is the top of the deck.
10+
- A round consists of both players playing at least one card.
11+
- Players take turns placing the **top card** of their deck onto a central pile.
12+
- If the card is a **number card** (2-10), play simply passes to the other player.
13+
- If the card is a **payment card**, a penalty must be paid:
14+
- **J** → opponent must pay 1 card
15+
- **Q** → opponent must pay 2 cards
16+
- **K** → opponent must pay 3 cards
17+
- **A** → opponent must pay 4 cards
18+
- If the player paying a penalty reveals another payment card, that player stops paying the penalty.
19+
The other player must then pay a penalty based on the new payment card.
20+
- If the penalty is fully paid without interruption, the player who placed the **last payment card** collects the central pile and places it at the bottom of their deck.
21+
That player then starts the next round.
22+
- If a player runs out of cards and is unable to play a card (either while paying a penalty or when it is their turn), the other player collects the central pile.
23+
- The moment when a player collects cards from the central pile is called a **trick**.
24+
- If a player has all the cards in their possession after a trick, the game **ends**.
25+
- The game **enters a loop** as soon as the decks are identical to what they were earlier during the game, **not** counting number cards!
26+
27+
## Examples
28+
29+
A small example of a match that ends.
30+
31+
| Round | Player A | Player B | Pile | Penalty Due |
32+
| :---- | :----------- | :------------------------- | :------------------------- | :---------- |
33+
| 1 | 2 A 7 8 Q 10 | 3 4 5 6 K 9 J | | - |
34+
| 1 | A 7 8 Q 10 | 3 4 5 6 K 9 J | 2 | - |
35+
| 1 | A 7 8 Q 10 | 4 5 6 K 9 J | 2 3 | - |
36+
| 1 | 7 8 Q 10 | 4 5 6 K 9 J | 2 3 A | Player B: 4 |
37+
| 1 | 7 8 Q 10 | 5 6 K 9 J | 2 3 A 4 | Player B: 3 |
38+
| 1 | 7 8 Q 10 | 6 K 9 J | 2 3 A 4 5 | Player B: 2 |
39+
| 1 | 7 8 Q 10 | K 9 J | 2 3 A 4 5 6 | Player B: 1 |
40+
| 1 | 7 8 Q 10 | 9 J | 2 3 A 4 5 6 K | Player A: 3 |
41+
| 1 | 8 Q 10 | 9 J | 2 3 A 4 5 6 K 7 | Player A: 2 |
42+
| 1 | Q 10 | 9 J | 2 3 A 4 5 6 K 7 8 | Player A: 1 |
43+
| 1 | 10 | 9 J | 2 3 A 4 5 6 K 7 8 Q | Player B: 2 |
44+
| 1 | 10 | J | 2 3 A 4 5 6 K 7 8 Q 9 | Player B: 1 |
45+
| 1 | 10 | - | 2 3 A 4 5 6 K 7 8 Q 9 J | Player A: 1 |
46+
| 1 | - | - | 2 3 A 4 5 6 K 7 8 Q 9 J 10 | - |
47+
| 2 | - | 2 3 A 4 5 6 K 7 8 Q 9 J 10 | - | - |
48+
49+
status: `"finished"`, cards: 13, tricks: 1
50+
51+
This is a small example of a match that loops.
52+
53+
| Round | Player A | Player B | Pile | Penalty Due |
54+
| :---- | :------- | :------- | :---- | :---------- |
55+
| 1 | J 2 3 | 4 J 5 | - | - |
56+
| 1 | 2 3 | 4 J 5 | J | Player B: 1 |
57+
| 1 | 2 3 | J 5 | J 4 | - |
58+
| 2 | 2 3 J 4 | J 5 | - | - |
59+
| 2 | 3 J 4 | J 5 | 2 | - |
60+
| 2 | 3 J 4 | 5 | 2 J | Player A: 1 |
61+
| 2 | J 4 | 5 | 2 J 3 | - |
62+
| 3 | J 4 | 5 2 J 3 | - | - |
63+
| 3 | J 4 | 2 J 3 | 5 | - |
64+
| 3 | 4 | 2 J 3 | 5 J | Player B: 1 |
65+
| 3 | 4 | J 3 | 5 J 2 | - |
66+
| 4 | 4 5 J 2 | J 3 | - | - |
67+
68+
The start of round 4 matches the start of round 2.
69+
Recall, the value of the number cards does not matter.
70+
71+
status: `"loop"`, cards: 8, tricks: 3
72+
73+
## Your Task
74+
75+
- Using the input, simulate the game following the rules above.
76+
- Determine the following information regarding the game:
77+
- **Status**: `"finished"` or `"loop"`
78+
- **Cards**: total number of cards played throughout the game
79+
- **Tricks**: number of times the central pile was collected
80+
81+
~~~~exercism/advanced
82+
For those who want to take on a more exciting challenge, the hunt for other records for the longest game with an end is still open.
83+
There are 653,534,134,886,878,245,000 (approximately 654 quintillion) possibilities, and we haven't calculated them all yet!
84+
~~~~
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Introduction
2+
3+
One rainy afternoon, you sit at the kitchen table playing cards with your grandmother.
4+
The game is her take on [Camicia][bmn].
5+
6+
At first it feels like just another friendly match: cards slapped down, laughter across the table, the occasional victorious grin from Nonna.
7+
But as the game stretches on, something strange happens.
8+
The same cards keep cycling back.
9+
You play card after card, yet the end never seems to come.
10+
11+
You start to wonder.
12+
_Will this game ever finish?
13+
Or could we keep playing forever?_
14+
15+
Later, driven by curiosity, you search online and to your surprise you discover that what happened wasn't just bad luck.
16+
You and your grandmother may have stumbled upon one of the longest possible sequences!
17+
Suddenly, you're hooked.
18+
What began as a casual game has turned into a quest: _how long can such a game really last?_
19+
_Can you find a sequence even longer than the one you played at the kitchen table?_
20+
_Perhaps even long enough to set a new world record?_
21+
22+
And so, armed with nothing but a deck of cards and some algorithmic ingenuity, you decide to investigate...
23+
24+
[bmn]: https://en.wikipedia.org/wiki/Beggar-my-neighbour
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"jiegillet"
4+
],
5+
"files": {
6+
"solution": [
7+
"src/Camicia.elm"
8+
],
9+
"test": [
10+
"tests/Tests.elm"
11+
],
12+
"example": [
13+
".meta/src/Camicia.example.elm"
14+
]
15+
},
16+
"blurb": "Simulate the card game and determine whether the match ends or enters an infinite loop.",
17+
"source": "Beggar-My-Neighbour",
18+
"source_url": "https://www.richardpmann.com/beggar-my-neighbour-records.html"
19+
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
module Camicia exposing (Card(..), Status(..), simulateGame)
2+
3+
import Set exposing (Set)
4+
5+
6+
type Card
7+
= Ace
8+
| Two
9+
| Three
10+
| Four
11+
| Five
12+
| Six
13+
| Seven
14+
| Eight
15+
| Nine
16+
| Ten
17+
| Jack
18+
| Queen
19+
| King
20+
21+
22+
type Status
23+
= Finished
24+
| Loop
25+
26+
27+
type Turn
28+
= PlayerA
29+
| PlayerAWithPenalty Int
30+
| PlayerB
31+
| PlayerBWithPenalty Int
32+
33+
34+
type alias Game =
35+
{ status : Status
36+
, cards : Int
37+
, tricks : Int
38+
39+
-- (Int, Int) is (payment value, count), I would prefer a type but Set needs something comparable
40+
, history : Set ( List ( Int, Int ), List ( Int, Int ) )
41+
, playerA : List Card
42+
, playerB : List Card
43+
, pile : List Card
44+
, turn : Turn
45+
}
46+
47+
48+
simulateGame : List Card -> List Card -> { status : Status, cards : Int, tricks : Int }
49+
simulateGame playerA playerB =
50+
let
51+
initialGame =
52+
Game Loop 0 0 Set.empty playerA playerB [] PlayerA
53+
54+
finalGame =
55+
gameLoop initialGame
56+
in
57+
{ status = finalGame.status, cards = finalGame.cards, tricks = finalGame.tricks }
58+
59+
60+
paymentValue : Card -> Int
61+
paymentValue card =
62+
case card of
63+
Jack ->
64+
1
65+
66+
Queen ->
67+
2
68+
69+
King ->
70+
3
71+
72+
Ace ->
73+
4
74+
75+
_ ->
76+
0
77+
78+
79+
gameSnapshot : Game -> ( List ( Int, Int ), List ( Int, Int ) )
80+
gameSnapshot { playerA, playerB } =
81+
let
82+
contract =
83+
List.foldl countCards []
84+
85+
countCards card count =
86+
case ( paymentValue card, count ) of
87+
( value, [] ) ->
88+
[ ( value, 1 ) ]
89+
90+
( value, ( lastValue, n ) :: rest ) ->
91+
if value == lastValue then
92+
( lastValue, n + 1 ) :: rest
93+
94+
else
95+
( value, 1 ) :: count
96+
in
97+
( contract playerA, contract playerB )
98+
99+
100+
gameLoop : Game -> Game
101+
gameLoop ({ playerA, playerB, cards, tricks, history, turn, pile } as currentGame) =
102+
let
103+
snapshot =
104+
gameSnapshot currentGame
105+
106+
game =
107+
if List.isEmpty pile then
108+
{ currentGame | history = Set.insert snapshot history }
109+
110+
else
111+
currentGame
112+
in
113+
if List.isEmpty pile && Set.member snapshot history then
114+
game
115+
116+
else
117+
case ( turn, playerA, playerB ) of
118+
( PlayerA, card :: rest, _ ) ->
119+
gameLoop
120+
{ game
121+
| turn =
122+
if paymentValue card > 0 then
123+
PlayerBWithPenalty (paymentValue card)
124+
125+
else
126+
PlayerB
127+
, playerA = rest
128+
, pile = card :: pile
129+
, cards = cards + 1
130+
}
131+
132+
( PlayerAWithPenalty 0, _ :: _, _ ) ->
133+
gameLoop { game | turn = PlayerB, pile = [], playerB = playerB ++ List.reverse pile, tricks = tricks + 1 }
134+
135+
( PlayerAWithPenalty penalty, card :: rest, _ ) ->
136+
gameLoop
137+
{ game
138+
| turn =
139+
if paymentValue card > 0 then
140+
PlayerBWithPenalty (paymentValue card)
141+
142+
else
143+
PlayerAWithPenalty (penalty - 1)
144+
, playerA = rest
145+
, pile = card :: pile
146+
, cards = cards + 1
147+
}
148+
149+
( PlayerB, _, card :: rest ) ->
150+
gameLoop
151+
{ game
152+
| turn =
153+
if paymentValue card > 0 then
154+
PlayerAWithPenalty (paymentValue card)
155+
156+
else
157+
PlayerA
158+
, playerB = rest
159+
, pile = card :: pile
160+
, cards = cards + 1
161+
}
162+
163+
( PlayerBWithPenalty 0, _, _ :: _ ) ->
164+
gameLoop { game | turn = PlayerA, pile = [], playerA = playerA ++ List.reverse pile, tricks = tricks + 1 }
165+
166+
( PlayerBWithPenalty penalty, _, card :: rest ) ->
167+
gameLoop
168+
{ game
169+
| turn =
170+
if paymentValue card > 0 then
171+
PlayerAWithPenalty (paymentValue card)
172+
173+
else
174+
PlayerBWithPenalty (penalty - 1)
175+
, playerB = rest
176+
, pile = card :: pile
177+
, cards = cards + 1
178+
}
179+
180+
_ ->
181+
{ game | status = Finished, tricks = tricks + 1 }

0 commit comments

Comments
 (0)