Skip to content

Commit c15e3fe

Browse files
committed
Move solution to the .meta package
1 parent a510e82 commit c15e3fe

File tree

2 files changed

+180
-160
lines changed

2 files changed

+180
-160
lines changed
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import java.util.ArrayDeque;
2+
import java.util.Deque;
3+
import java.util.HashSet;
4+
import java.util.List;
5+
import java.util.Set;
6+
7+
public class Camicia {
8+
9+
private Status status;
10+
private int cards;
11+
private int tricks;
12+
13+
private enum Player {
14+
PLAYER_A, PLAYER_B
15+
}
16+
17+
private enum Status {
18+
FINISHED, LOOP
19+
}
20+
21+
private static int penaltyOf(String card) {
22+
return switch (card) {
23+
case "J" -> 1;
24+
case "Q" -> 2;
25+
case "K" -> 3;
26+
case "A" -> 4;
27+
default -> 0;
28+
};
29+
}
30+
31+
private static boolean isPaymentCard(String card) {
32+
return penaltyOf(card) > 0;
33+
}
34+
35+
/**
36+
* Return a snapshot of the current state
37+
*/
38+
private static String stateKey(Deque<String> deckA, Deque<String> deckB) {
39+
StringBuilder sb = new StringBuilder();
40+
41+
for (String card : deckA) {
42+
sb.append(isPaymentCard(card) ? card : "N");
43+
}
44+
45+
sb.append('|');
46+
47+
for (String card : deckB) {
48+
sb.append(isPaymentCard(card) ? card : "N");
49+
}
50+
51+
return sb.toString();
52+
}
53+
54+
private static Player otherPlayer(Player player) {
55+
return player == Player.PLAYER_A ? Player.PLAYER_B : Player.PLAYER_A;
56+
}
57+
58+
private static Deque<String> deckOf(Player player, Deque<String> deckA, Deque<String> deckB) {
59+
return player == Player.PLAYER_A ? deckA : deckB;
60+
}
61+
62+
public void simulateGame(List<String> playerA, List<String> playerB) {
63+
Deque<String> deckA = new ArrayDeque<>(playerA);
64+
Deque<String> deckB = new ArrayDeque<>(playerB);
65+
66+
int cardsPlayed = 0;
67+
int tricksCount = 0;
68+
Player current = Player.PLAYER_A;
69+
70+
Set<String> seenStates = new HashSet<>();
71+
72+
while (true) {
73+
String key = stateKey(deckA, deckB);
74+
// Key already exists, which means this is a loop
75+
if (!seenStates.add(key)) {
76+
finishGame(Status.LOOP, cardsPlayed, tricksCount);
77+
return;
78+
}
79+
80+
// Otherwise, play next round
81+
RoundResult result = playRound(deckA, deckB, current);
82+
83+
cardsPlayed += result.pileSize();
84+
tricksCount++;
85+
86+
// Check if someone wins and finish the game
87+
if (hasWinner(deckA, deckB)) {
88+
finishGame(Status.FINISHED, cardsPlayed, tricksCount);
89+
return;
90+
}
91+
92+
// Otherwise, play next round
93+
current = result.nextStarter();
94+
}
95+
}
96+
97+
private RoundResult playRound(Deque<String> deckA, Deque<String> deckB, Player startingPlayer) {
98+
Deque<String> pile = new ArrayDeque<>(); // cards played in this round
99+
Player currentPlayer = startingPlayer;
100+
int pendingPenalty = 0;
101+
102+
while (true) {
103+
Deque<String> currentPlayerDeck = deckOf(currentPlayer, deckA, deckB);
104+
Player opponent = otherPlayer(currentPlayer);
105+
Deque<String> opponentDeck = deckOf(opponent, deckA, deckB);
106+
107+
// Current player deck is empty, opponent collects all pile, end this round
108+
if (currentPlayerDeck.isEmpty()) {
109+
opponentDeck.addAll(pile);
110+
return new RoundResult(opponent, pile.size());
111+
}
112+
113+
// Otherwise, current player plays 1 card, add to pile
114+
String card = currentPlayerDeck.poll();
115+
pile.addLast(card);
116+
117+
// Current player must pay off pending penalty
118+
if (pendingPenalty > 0) {
119+
// And player reveals a payment card
120+
if (isPaymentCard(card)) {
121+
// reset penalty based on new card, switch turn
122+
pendingPenalty = penaltyOf(card);
123+
currentPlayer = opponent;
124+
} else {
125+
// Otherwise, deduct penalty
126+
pendingPenalty--;
127+
// No pending penalty
128+
if (pendingPenalty == 0) {
129+
// Opponent collects all pile and win the round
130+
deckOf(opponent, deckA, deckB).addAll(pile);
131+
return new RoundResult(opponent, pile.size());
132+
}
133+
}
134+
} else {
135+
// Normal gameplay, without pending penalty
136+
// If player reveals a payment card, update penalty
137+
if (isPaymentCard(card)) {
138+
pendingPenalty = penaltyOf(card);
139+
}
140+
currentPlayer = opponent;
141+
}
142+
}
143+
}
144+
145+
private void finishGame(Status status, int cardsPlayed, int tricksCount) {
146+
this.status = status;
147+
this.cards = cardsPlayed;
148+
this.tricks = tricksCount;
149+
}
150+
151+
private boolean hasWinner(Deque<String> deckA, Deque<String> deckB) {
152+
return deckA.isEmpty() || deckB.isEmpty();
153+
}
154+
155+
public String getStatus() {
156+
return status != null ? status.name().toLowerCase() : "";
157+
}
158+
159+
public int getCards() {
160+
return cards;
161+
}
162+
163+
public int getTricks() {
164+
return tricks;
165+
}
166+
167+
/**
168+
* Immutable round result
169+
*/
170+
private record RoundResult(Player nextStarter, int pileSize) {
171+
}
172+
}
Lines changed: 8 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,20 @@
1-
import java.util.ArrayDeque;
2-
import java.util.Deque;
3-
import java.util.HashSet;
41
import java.util.List;
5-
import java.util.Set;
62

73
public class Camicia {
84

9-
private Status status;
10-
private int cards;
11-
private int tricks;
12-
13-
private enum Player {
14-
PLAYER_A, PLAYER_B
15-
}
16-
17-
private enum Status {
18-
FINISHED, LOOP
19-
}
20-
21-
private static int penaltyOf(String card) {
22-
return switch (card) {
23-
case "J" -> 1;
24-
case "Q" -> 2;
25-
case "K" -> 3;
26-
case "A" -> 4;
27-
default -> 0;
28-
};
29-
}
30-
31-
private static boolean isPaymentCard(String card) {
32-
return penaltyOf(card) > 0;
33-
}
34-
35-
/**
36-
* Return a snapshot of the current state
37-
*/
38-
private static String stateKey(Deque<String> deckA, Deque<String> deckB) {
39-
StringBuilder sb = new StringBuilder();
40-
41-
for (String card : deckA) {
42-
sb.append(isPaymentCard(card) ? card : "N");
43-
}
44-
45-
sb.append('|');
46-
47-
for (String card : deckB) {
48-
sb.append(isPaymentCard(card) ? card : "N");
49-
}
50-
51-
return sb.toString();
52-
}
53-
54-
private static Player otherPlayer(Player player) {
55-
return player == Player.PLAYER_A ? Player.PLAYER_B : Player.PLAYER_A;
56-
}
57-
58-
private static Deque<String> deckOf(Player player, Deque<String> deckA, Deque<String> deckB) {
59-
return player == Player.PLAYER_A ? deckA : deckB;
60-
}
61-
62-
public void simulateGame(List<String> playerA, List<String> playerB) {
63-
Deque<String> deckA = new ArrayDeque<>(playerA);
64-
Deque<String> deckB = new ArrayDeque<>(playerB);
65-
66-
int cardsPlayed = 0;
67-
int tricksCount = 0;
68-
Player current = Player.PLAYER_A;
69-
70-
Set<String> seenStates = new HashSet<>();
71-
72-
while (true) {
73-
String key = stateKey(deckA, deckB);
74-
// Key already exists, which means this is a loop
75-
if (!seenStates.add(key)) {
76-
finishGame(Status.LOOP, cardsPlayed, tricksCount);
77-
return;
78-
}
79-
80-
// Otherwise, play next round
81-
RoundResult result = playRound(deckA, deckB, current);
82-
83-
cardsPlayed += result.pileSize();
84-
tricksCount++;
85-
86-
// Check if someone wins and finish the game
87-
if (hasWinner(deckA, deckB)) {
88-
finishGame(Status.FINISHED, cardsPlayed, tricksCount);
89-
return;
90-
}
91-
92-
// Otherwise, play next round
93-
current = result.nextStarter();
94-
}
95-
}
96-
97-
private RoundResult playRound(Deque<String> deckA, Deque<String> deckB, Player startingPlayer) {
98-
Deque<String> pile = new ArrayDeque<>(); // cards played in this round
99-
Player currentPlayer = startingPlayer;
100-
int pendingPenalty = 0;
101-
102-
while (true) {
103-
Deque<String> currentPlayerDeck = deckOf(currentPlayer, deckA, deckB);
104-
Player opponent = otherPlayer(currentPlayer);
105-
Deque<String> opponentDeck = deckOf(opponent, deckA, deckB);
106-
107-
// Current player deck is empty, opponent collects all pile, end this round
108-
if (currentPlayerDeck.isEmpty()) {
109-
opponentDeck.addAll(pile);
110-
return new RoundResult(opponent, pile.size());
111-
}
112-
113-
// Otherwise, current player plays 1 card, add to pile
114-
String card = currentPlayerDeck.poll();
115-
pile.addLast(card);
116-
117-
// Current player must pay off pending penalty
118-
if (pendingPenalty > 0) {
119-
// And player reveals a payment card
120-
if (isPaymentCard(card)) {
121-
// reset penalty based on new card, switch turn
122-
pendingPenalty = penaltyOf(card);
123-
currentPlayer = opponent;
124-
} else {
125-
// Otherwise, deduct penalty
126-
pendingPenalty--;
127-
// No pending penalty
128-
if (pendingPenalty == 0) {
129-
// Opponent collects all pile and win the round
130-
deckOf(opponent, deckA, deckB).addAll(pile);
131-
return new RoundResult(opponent, pile.size());
132-
}
133-
}
134-
} else {
135-
// Normal gameplay, without pending penalty
136-
// If player reveals a payment card, update penalty
137-
if (isPaymentCard(card)) {
138-
pendingPenalty = penaltyOf(card);
139-
}
140-
currentPlayer = opponent;
141-
}
142-
}
143-
}
144-
145-
private void finishGame(Status status, int cardsPlayed, int tricksCount) {
146-
this.status = status;
147-
this.cards = cardsPlayed;
148-
this.tricks = tricksCount;
149-
}
150-
151-
private boolean hasWinner(Deque<String> deckA, Deque<String> deckB) {
152-
return deckA.isEmpty() || deckB.isEmpty();
153-
}
154-
155-
public String getStatus() {
156-
return status != null ? status.name().toLowerCase() : "";
5+
void simulateGame(List<String> playerA, List<String> playerB) {
6+
throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
1577
}
1588

159-
public int getCards() {
160-
return cards;
9+
String getStatus() {
10+
throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
16111
}
16212

163-
public int getTricks() {
164-
return tricks;
13+
int getCards() {
14+
throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
16515
}
16616

167-
/**
168-
* Immutable round result
169-
*/
170-
private record RoundResult(Player nextStarter, int pileSize) {
17+
int getTricks() {
18+
throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
17119
}
17220
}

0 commit comments

Comments
 (0)