Skip to content

Commit 9598e47

Browse files
authored
[New Exercise]: Camicia (#424)
Add exercise `camicia`
1 parent 1c087fb commit 9598e47

8 files changed

Lines changed: 696 additions & 0 deletions

File tree

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,14 @@
11031103
"prerequisites": [],
11041104
"difficulty": 5
11051105
},
1106+
{
1107+
"slug": "camicia",
1108+
"name": "Camicia",
1109+
"uuid": "7aaaf5fa-1a22-433b-9c0d-0e1c035eba3d",
1110+
"practices": [],
1111+
"prerequisites": [],
1112+
"difficulty": 5
1113+
},
11061114
{
11071115
"slug": "rectangles",
11081116
"name": "Rectangles",
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: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
using namespace System.Collections.Generic
2+
using namespace System.Text
3+
4+
enum Status {
5+
Finished
6+
Loop
7+
}
8+
9+
Function Invoke-Camicia() {
10+
<#
11+
.SYNOPSIS
12+
Simulate a game very similar to the classic card game Camicia.
13+
14+
.DESCRIPTION
15+
Given two hands of cards, simulate a game (similar to Camicia) until it ends (or detect if it is in a loop).
16+
Read instruction for rules and game example.
17+
18+
.PARAMETER PlayerA
19+
An array of string(s) represents the first player's cards.
20+
21+
.PARAMETER PlayerB
22+
An array of string(s) represents the second player's cards.
23+
#>
24+
[CmdletBinding()]
25+
Param(
26+
[string[]]$PlayerA,
27+
[string[]]$PlayerB
28+
)
29+
$gameState = [GameState]::New($PlayerA, $PlayerB)
30+
$stateSet = [HashSet[string]]::new()
31+
$resultStatus = [Status]::Loop
32+
33+
while ($true) {
34+
$stateRepresent = $gameState.ToString()
35+
if ($stateSet.Contains($stateRepresent)) {
36+
break
37+
}
38+
if ($stateRepresent -match '[JQKA]') {
39+
$stateSet.Add($stateRepresent) | Out-Null
40+
}
41+
PlayTurn($gameState)
42+
if ($gameState.HasWinner()) {
43+
$resultStatus = [Status]::Finished
44+
break
45+
}
46+
}
47+
[PSCustomObject]@{
48+
Status = $resultStatus
49+
Cards = $gameState.CardsPlayed
50+
Tricks = $gameState.Tricks
51+
}
52+
}
53+
54+
Function PlayTurn ([GameState]$state) {
55+
while ($true) {
56+
$startDebt = $state.Debt
57+
$player = $state.PlayerTurn -eq "A" ? $state.PAHand : $state.PBHand
58+
$other = $state.PlayerTurn -eq "A" ? $state.PBHand : $state.PAHand
59+
if ($player.Count -eq 0) {
60+
$state.Piles | ForEach-Object { $other.Enqueue($_) }
61+
$state.Piles.Clear()
62+
$state.Tricks++
63+
break
64+
}
65+
66+
$top = $player.Dequeue()
67+
$state.Piles.Add($top)
68+
$state.CardsPlayed++
69+
70+
if ($state.PaymentCards -match $top)
71+
{
72+
$state.Debt = $state.PaymentCards.IndexOf($top) + 1
73+
$state.SwitchPlayer()
74+
} else {
75+
$state.Debt = $state.Debt -gt 0 ? $state.Debt - 1 : 0
76+
if ($startDebt -gt 0 -and $state.Debt -eq 0) {
77+
$state.SwitchPlayer()
78+
$state.Piles | ForEach-Object { $other.Enqueue($_) }
79+
$state.Piles.Clear()
80+
$state.Tricks++
81+
break
82+
}
83+
84+
if ($state.Debt -eq 0) {
85+
$state.SwitchPlayer()
86+
}
87+
}
88+
}
89+
}
90+
91+
class GameState {
92+
[Queue[string]]$PAHand
93+
[Queue[string]]$PBHand
94+
[List[string]]$Piles
95+
[string]$PlayerTurn
96+
[int]$Tricks
97+
[int]$Debt
98+
[string]$PaymentCards
99+
[int]$CardsPlayed
100+
101+
GameState([string[]]$PlayerA, [string[]]$PlayerB) {
102+
$this.PAHand = [Queue[string]]::New($PlayerA)
103+
$this.PBHand = [Queue[string]]::New($PlayerB)
104+
$this.Piles = [List[string]]::New()
105+
$this.PlayerTurn = "A"
106+
$this.Tricks = 0
107+
$this.Debt = 0
108+
$this.PaymentCards = "JQKA"
109+
}
110+
111+
[bool]HasWinner() {
112+
return ($this.Piles.Count -eq 0) -and ($this.PAHand.Count -eq 0 -or $this.PBHand.Count -eq 0)
113+
}
114+
115+
[string]ToString() {
116+
$sb = [StringBuilder]::new()
117+
foreach ($card in $this.PAHand) {
118+
$sb.Append( $card -match '[JQKA]' ? $card : '_')
119+
}
120+
$sb.Append(' ')
121+
foreach ($card in $this.PBHand) {
122+
$sb.Append( $card -match '[JQKA]' ? $card : '_')
123+
}
124+
return $sb.ToString()
125+
}
126+
127+
[void] SwitchPlayer() {
128+
$this.PlayerTurn = $this.PlayerTurn -eq "A" ? "B" : "A"
129+
}
130+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"glaxxie"
4+
],
5+
"files": {
6+
"solution": [
7+
"Camicia.ps1"
8+
],
9+
"test": [
10+
"Camicia.tests.ps1"
11+
],
12+
"example": [
13+
".meta/Camicia.example.ps1"
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: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[0b7f737c-3ecd-4a55-b34d-e65c62a85c28]
13+
description = "two cards, one trick"
14+
15+
[27c19d75-53a5-48e5-b33b-232c3884d4f3]
16+
description = "three cards, one trick"
17+
18+
[9b02dd49-efaf-4b71-adca-a05c18a7c5b0]
19+
description = "four cards, one trick"
20+
21+
[fa3f4479-466a-4734-a001-ab79bfe27260]
22+
description = "the ace reigns supreme"
23+
24+
[07629689-f589-4f54-a6d1-8ce22776ce72]
25+
description = "the king beats ace"
26+
27+
[54d4a1c5-76fb-4d1e-8358-0e0296ac0601]
28+
description = "the queen seduces the king"
29+
30+
[c875500c-ff3d-47a4-bd1e-b60b90da80aa]
31+
description = "the jack betrays the queen"
32+
33+
[436875da-96ca-4149-be22-0b78173b8125]
34+
description = "the 10 just wants to put on a show"
35+
36+
[5be39bb6-1b34-4ce6-a1cd-0fcc142bb272]
37+
description = "simple loop with decks of 3 cards"
38+
39+
[2795dc21-0a2a-4c38-87c2-5a42e1ff15eb]
40+
description = "the story is starting to get a bit complicated"
41+
42+
[6999dfac-3fdc-41e2-b64b-38f4be228712]
43+
description = "two tricks"
44+
45+
[83dcd4f3-e089-4d54-855a-73f5346543a3]
46+
description = "more tricks"
47+
48+
[3107985a-f43e-486a-9ce8-db51547a9941]
49+
description = "simple loop with decks of 4 cards"
50+
51+
[dca32c31-11ed-49f6-b078-79ab912c1f7b]
52+
description = "easy card combination"
53+
54+
[1f8488d0-48d3-45ae-b819-59cedad0a5f4]
55+
description = "easy card combination, inverted decks"
56+
57+
[98878d35-623a-4d05-b81a-7bdc569eb88d]
58+
description = "mirrored decks"
59+
60+
[3e0ba597-ca10-484b-87a3-31a7df7d6da3]
61+
description = "opposite decks"
62+
63+
[92334ddb-aaa7-47fa-ab36-e928a8a6a67c]
64+
description = "random decks #1"
65+
66+
[30477523-9651-4860-84a3-e1ac461bb7fa]
67+
description = "random decks #2"
68+
69+
[20967de8-9e94-4e0e-9010-14bc1c157432]
70+
description = "Kleber 1999"
71+
72+
[9f2fdfe8-27f3-4323-816d-6bce98a9c6f7]
73+
description = "Collins 2006"
74+
75+
[c90b6f8d-7013-49f3-b5cb-14ea006cca1d]
76+
description = "Mann and Wu 2007"
77+
78+
[a3f1fbc5-1d0b-499a-92a5-22932dfc6bc8]
79+
description = "Nessler 2012"
80+
81+
[9cefb1ba-e6d1-4ab7-9d8f-76d8e0976d5f]
82+
description = "Anderson 2013"
83+
84+
[d37c0318-5be6-48d0-ab72-a7aaaff86179]
85+
description = "Rucklidge 2014"
86+
87+
[4305e479-ba87-432f-8a29-cd2bd75d2f05]
88+
description = "Nessler 2021"
89+
90+
[252f5cc3-b86d-4251-87ce-f920b7a6a559]
91+
description = "Nessler 2022"
92+
93+
[b9efcfa4-842f-4542-8112-8389c714d958]
94+
description = "Casella 2024, first infinite game found"

0 commit comments

Comments
 (0)