incognitolm commited on
Commit
5c0e13e
·
verified ·
1 Parent(s): 14df850

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +136 -72
app.py CHANGED
@@ -91,9 +91,11 @@ async def handle_action(request: Request):
91
 
92
  game = games[pin]
93
 
 
94
  if action == 'getStatus':
95
  return {"success": True, "challenge": game.get("challenge", None)}
96
 
 
97
  if action == 'steal':
98
  if game["permissions"].get(player, {}).get("steal", True):
99
  game["challenge"] = {
@@ -108,6 +110,7 @@ async def handle_action(request: Request):
108
  else:
109
  return {"success": False, "message": "You can only steal once per turn."}
110
 
 
111
  if action == 'coup':
112
  player_data = next((p for p in game["players"] if p["name"] == player), None)
113
  if not player_data:
@@ -124,11 +127,10 @@ async def handle_action(request: Request):
124
  }
125
  return {"success": True, "message": f"Coup initiated by {player} targeting {target}."}
126
 
 
127
  if action == 'assassin':
128
- # Assassin action: must be the player's turn.
129
  if game["turn"] != player:
130
  return {"success": False, "message": "Not your turn."}
131
- # Create an assassin challenge waiting for the target's decision.
132
  game["challenge"] = {
133
  "action": "assassin",
134
  "challenger": player, # the assassin
@@ -139,11 +141,45 @@ async def handle_action(request: Request):
139
  }
140
  return {"success": True, "message": f"Assassin action initiated by {player} targeting {target}. Awaiting target's response."}
141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  if action == 'challengeResponse':
143
  if not game.get("challenge"):
144
  return {"success": False, "message": "No challenge pending."}
145
 
146
- # --- Handle existing steal response ---
147
  if game["challenge"]["challengeType"] == "steal":
148
  challenger_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
149
  target_player = next(p for p in game["players"] if p["name"] == game["challenge"]["target"])
@@ -166,123 +202,151 @@ async def handle_action(request: Request):
166
  game["challenge"]["status"] = 'choose'
167
  return {"success": True, "message": f"Challenge successful. {challenger_player['name']} must choose a card to lose.", "challenge": game["challenge"]}
168
 
169
- # --- Handle Ambassador response (existing) ---
170
- elif game["challenge"]["challengeType"] == "ambassador":
171
- if response == 'allow':
172
  if "responses" not in game["challenge"]:
173
  game["challenge"]["responses"] = {}
174
- game["challenge"]["responses"][player] = 'allow'
175
  total_opponents = len(game["players"]) - 1
176
  if len(game["challenge"]["responses"]) == total_opponents:
177
- ambassador_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
178
- ambassador_player["cards"] = generate_cards()
179
  game["challenge"] = None
180
- return {"success": True, "message": f"Ambassador action accepted. {ambassador_player['name']} swaps cards with the deck."}
181
  else:
182
- return {"success": True, "message": f"{player} allowed the Ambassador action. Awaiting other responses."}
183
- elif response == 'challenge':
184
- ambassador_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
185
- if "Ambassador" in ambassador_player["cards"]:
186
  game["challenge"]["status"] = "choose"
187
- game["challenge"]["challenger"] = player # challenger loses card
188
- game["challenge"]["target"] = ambassador_player["name"]
189
- ambassador_player["cards"] = generate_cards()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  game["challenge"] = None
191
- return {"success": True, "message": f"Challenge failed. {player} must lose a card, while {ambassador_player['name']} swaps cards with the deck."}
192
  else:
 
 
 
 
 
 
 
 
 
 
193
  game["challenge"]["status"] = "choose"
194
- return {"success": True, "message": "Challenge successful. Ambassador user must choose a card to lose.", "challenge": game["challenge"]}
 
 
 
 
 
 
 
 
195
 
196
- # --- Handle Assassin/Contessa responses ---
197
  elif game["challenge"]["challengeType"] == "assassin":
198
- # Phase 1: target's decision on assassination
199
  if game["challenge"].get("phase") == "target_decision":
200
  if response == "allow":
201
- # Target accepts assassination: must lose one card.
202
  game["challenge"]["status"] = "choose"
203
- # Set the losing player to the target.
204
  game["challenge"]["challenger"] = game["challenge"]["target"]
205
  return {"success": True, "message": f"{game['challenge']['target']} must now choose a card to lose."}
206
  elif response == "challenge":
207
- # Target challenges the assassin's claim.
208
  assassin_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
209
  if "Assassin" in assassin_player["cards"]:
210
- # Assassin is truthful: target loses both cards.
211
  target_player = next(p for p in game["players"] if p["name"] == game["challenge"]["target"])
212
- target_player["cards"] = [] # remove all cards (eliminated)
213
  game["challenge"] = None
214
  return {"success": True, "message": f"Challenge failed. {target_player['name']} loses both cards."}
215
  else:
216
- # Assassin is lying: assassin must lose one card.
217
  game["challenge"]["status"] = "choose"
218
  game["challenge"]["challenger"] = assassin_player["name"]
219
  return {"success": True, "message": f"Challenge successful. {assassin_player['name']} must choose a card to lose.", "challenge": game["challenge"]}
220
  elif response == "contessa":
221
- # Target opts to block with Contessa. Shift phase.
222
  game["challenge"]["phase"] = "assassin_contessa"
223
  return {"success": True, "message": f"{game['challenge']['challenger']} must now choose to challenge or accept the Contessa."}
224
- # Phase 2: assassin responding to contessa claim.
225
  elif game["challenge"].get("phase") == "assassin_contessa":
226
  if response == "accept":
227
- # Assassin accepts contessa block: target loses one card.
228
  game["challenge"]["status"] = "choose"
229
  game["challenge"]["challenger"] = game["challenge"]["target"]
230
  return {"success": True, "message": f"{game['challenge']['target']} must now choose a card to lose."}
231
  elif response == "challenge":
232
- # Assassin challenges contessa.
233
  target_player = next(p for p in game["players"] if p["name"] == game["challenge"]["target"])
234
  if "Contessa" in target_player["cards"]:
235
- # Contessa is truthful: assassin loses one card.
236
  game["challenge"]["status"] = "choose"
237
- # Losing player is the assassin.
238
  game["challenge"]["challenger"] = game["challenge"]["challenger"]
239
  return {"success": True, "message": f"Contessa challenge successful. {game['challenge']['challenger']} must choose a card to lose.", "challenge": game["challenge"]}
240
  else:
241
- # Contessa is bluffing: target loses both cards.
242
  target_player["cards"] = []
243
  game["challenge"] = None
244
  return {"success": True, "message": f"Contessa challenge failed. {target_player['name']} loses both cards."}
245
-
246
- # --- Handle Foreign Aid responses ---
247
- elif game["challenge"]["challengeType"] == "foreignAid":
248
- if player == game["challenge"]["challenger"]:
249
- return {"success": False, "message": "Challenger cannot respond to their own action."}
250
- game["challenge"]["responses"][player] = response
251
- if response == "block":
252
- game["challenge"]["status"] = "blocked"
253
- game["challenge"] = None
254
- return {"success": True, "message": f"Foreign Aid blocked by {player}."}
255
- else:
256
  total_opponents = len(game["players"]) - 1
257
  if len(game["challenge"]["responses"]) == total_opponents:
258
- challenger_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
259
- challenger_player["coins"] += 2
260
  game["challenge"] = None
261
- return {"success": True, "message": f"Foreign Aid accepted. {challenger_player['name']} gains 2 coins."}
262
  else:
263
- return {"success": True, "message": f"{player} allowed Foreign Aid. Awaiting other responses."}
264
-
265
- if action == 'ambassador':
266
- if game["turn"] != player:
267
- return {"success": False, "message": "Not your turn."}
268
- game["challenge"] = {
269
- "action": "ambassador",
270
- "challenger": player,
271
- "challengeType": "ambassador",
272
- "status": "pending",
273
- "responses": {}
274
- }
275
- return {"success": True, "message": f"Ambassador action initiated by {player}. Waiting for opponents to respond."}
276
-
277
- if action == 'choose':
278
- acting_player = next((p for p in game["players"] if p["name"] == game["challenge"]["challenger"]), None)
279
- if acting_player and target in acting_player["cards"]:
280
- acting_player["cards"].remove(target)
281
- game["challenge"] = None
282
- return {"success": True, "message": f"{acting_player['name']} loses the {target} card."}
283
- else:
284
- return {"success": False, "message": f"Card {target} not found in {acting_player['name']}'s hand."}
285
-
286
  if action == 'income':
287
  player_found = False
288
  for p in game["players"]:
@@ -331,7 +395,7 @@ async def handle_action(request: Request):
331
  else:
332
  return {"success": True, "message": f"{player} allowed Foreign Aid. Awaiting other responses."}
333
 
334
- return {"success": True, "message": f"Action '{action}' processed for player {player}."}
335
 
336
  @app.post("/api/joinGame")
337
  async def join_game(request: Request):
 
91
 
92
  game = games[pin]
93
 
94
+ # Return pending challenge status.
95
  if action == 'getStatus':
96
  return {"success": True, "challenge": game.get("challenge", None)}
97
 
98
+ # STEAL action (existing)
99
  if action == 'steal':
100
  if game["permissions"].get(player, {}).get("steal", True):
101
  game["challenge"] = {
 
110
  else:
111
  return {"success": False, "message": "You can only steal once per turn."}
112
 
113
+ # COUP action (existing)
114
  if action == 'coup':
115
  player_data = next((p for p in game["players"] if p["name"] == player), None)
116
  if not player_data:
 
127
  }
128
  return {"success": True, "message": f"Coup initiated by {player} targeting {target}."}
129
 
130
+ # ASSASSIN action and Contessa flow (existing from previous update)
131
  if action == 'assassin':
 
132
  if game["turn"] != player:
133
  return {"success": False, "message": "Not your turn."}
 
134
  game["challenge"] = {
135
  "action": "assassin",
136
  "challenger": player, # the assassin
 
141
  }
142
  return {"success": True, "message": f"Assassin action initiated by {player} targeting {target}. Awaiting target's response."}
143
 
144
+ # DUKE TAX action (new)
145
+ if action == 'duke':
146
+ if game["turn"] != player:
147
+ return {"success": False, "message": "Not your turn."}
148
+ # Claiming Duke for Tax: create a challenge for all opponents.
149
+ game["challenge"] = {
150
+ "action": "duke",
151
+ "challenger": player, # the one claiming Duke Tax
152
+ "challengeType": "duke",
153
+ "status": "pending",
154
+ "responses": {}
155
+ }
156
+ # Mark that the player cannot perform any further gain actions this turn.
157
+ game["permissions"][player]["gain"] = False
158
+ return {"success": True, "message": f"{player} claims Duke for Tax. Waiting for opponents to respond."}
159
+
160
+ # Foreign Aid action (modified to store initiator)
161
+ if action == 'foreignAid':
162
+ if game["turn"] != player:
163
+ return {"success": False, "message": "Not your turn."}
164
+ if not game["permissions"].get(player, {}).get("gain", True):
165
+ return {"success": False, "message": "You can only earn money once per turn."}
166
+ game["challenge"] = {
167
+ "action": "foreignAid",
168
+ "challenger": player,
169
+ "initiator": player, # store who initiated foreign aid
170
+ "challengeType": "foreignAid",
171
+ "responses": {},
172
+ "status": "pending"
173
+ }
174
+ game["permissions"][player]["gain"] = False
175
+ return {"success": True, "message": f"Foreign Aid initiated by {player}. Waiting for opponents to respond."}
176
+
177
+ # CHALLENGE RESPONSE branch.
178
  if action == 'challengeResponse':
179
  if not game.get("challenge"):
180
  return {"success": False, "message": "No challenge pending."}
181
 
182
+ # STEAL challenge response (existing)
183
  if game["challenge"]["challengeType"] == "steal":
184
  challenger_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
185
  target_player = next(p for p in game["players"] if p["name"] == game["challenge"]["target"])
 
202
  game["challenge"]["status"] = 'choose'
203
  return {"success": True, "message": f"Challenge successful. {challenger_player['name']} must choose a card to lose.", "challenge": game["challenge"]}
204
 
205
+ # DUKE Tax challenge response (new)
206
+ elif game["challenge"]["challengeType"] == "duke":
207
+ if response == "allow":
208
  if "responses" not in game["challenge"]:
209
  game["challenge"]["responses"] = {}
210
+ game["challenge"]["responses"][player] = "allow"
211
  total_opponents = len(game["players"]) - 1
212
  if len(game["challenge"]["responses"]) == total_opponents:
213
+ duke_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
214
+ duke_player["coins"] += 3
215
  game["challenge"] = None
216
+ return {"success": True, "message": f"{duke_player['name']} successfully collects 3 coins with Duke Tax."}
217
  else:
218
+ return {"success": True, "message": f"{player} allowed the Duke tax. Awaiting other responses."}
219
+ elif response == "challenge":
220
+ duke_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
221
+ if "Duke" in duke_player["cards"]:
222
  game["challenge"]["status"] = "choose"
223
+ game["challenge"]["challenger"] = player # challenger loses a card
224
+ game["challenge"]["target"] = duke_player["name"]
225
+ return {"success": True, "message": f"Challenge failed. {player} must choose a card to lose.", "challenge": game["challenge"]}
226
+ else:
227
+ game["challenge"]["status"] = "choose"
228
+ game["challenge"]["challenger"] = duke_player["name"]
229
+ return {"success": True, "message": f"Challenge successful. {duke_player['name']} must choose a card to lose.", "challenge": game["challenge"]}
230
+
231
+ # FOREIGN AID response branch.
232
+ elif game["challenge"]["challengeType"] == "foreignAid":
233
+ if player == game["challenge"]["challenger"]:
234
+ return {"success": False, "message": "Challenger cannot respond to their own action."}
235
+ if response == "block":
236
+ # Instead of immediately canceling, create a new challenge for a Duke block.
237
+ # The blocking player is claiming Duke to block foreign aid.
238
+ game["challenge"] = {
239
+ "action": "foreignAidBlock",
240
+ "challengeType": "dukeBlock",
241
+ "blocker": player,
242
+ "initiator": game["challenge"]["initiator"],
243
+ "status": "pending"
244
+ }
245
+ return {"success": True, "message": f"{player} blocks Foreign Aid claiming Duke. {game['challenge']['initiator']} may now challenge this block."}
246
+ else: # response == "allow"
247
+ if "responses" not in game["challenge"]:
248
+ game["challenge"]["responses"] = {}
249
+ game["challenge"]["responses"][player] = "allow"
250
+ total_opponents = len(game["players"]) - 1
251
+ if len(game["challenge"]["responses"]) == total_opponents:
252
+ fa_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
253
+ fa_player["coins"] += 2
254
  game["challenge"] = None
255
+ return {"success": True, "message": f"Foreign Aid accepted. {fa_player['name']} gains 2 coins."}
256
  else:
257
+ return {"success": True, "message": f"{player} allowed Foreign Aid. Awaiting other responses."}
258
+
259
+ # DUKE BLOCK challenge response (new, from a foreign aid block)
260
+ elif game["challenge"]["challengeType"] == "dukeBlock":
261
+ # Only the Foreign Aid initiator may respond.
262
+ if player != game["challenge"]["initiator"]:
263
+ return {"success": False, "message": "Only the Foreign Aid initiator can respond to the Duke block challenge."}
264
+ if response == "challenge":
265
+ blocker = next(p for p in game["players"] if p["name"] == game["challenge"]["blocker"])
266
+ if "Duke" in blocker["cards"]:
267
  game["challenge"]["status"] = "choose"
268
+ game["challenge"]["challenger"] = player
269
+ return {"success": True, "message": f"Block challenge failed. {player} must choose a card to lose.", "challenge": game["challenge"]}
270
+ else:
271
+ game["challenge"]["status"] = "choose"
272
+ game["challenge"]["challenger"] = blocker["name"]
273
+ return {"success": True, "message": f"Block challenge successful. {blocker['name']} must choose a card to lose.", "challenge": game["challenge"]}
274
+ elif response == "accept":
275
+ game["challenge"] = None
276
+ return {"success": True, "message": "Foreign Aid blocked."}
277
 
278
+ # ASSASSIN/CONTESSA response branch (existing)
279
  elif game["challenge"]["challengeType"] == "assassin":
 
280
  if game["challenge"].get("phase") == "target_decision":
281
  if response == "allow":
 
282
  game["challenge"]["status"] = "choose"
 
283
  game["challenge"]["challenger"] = game["challenge"]["target"]
284
  return {"success": True, "message": f"{game['challenge']['target']} must now choose a card to lose."}
285
  elif response == "challenge":
 
286
  assassin_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
287
  if "Assassin" in assassin_player["cards"]:
 
288
  target_player = next(p for p in game["players"] if p["name"] == game["challenge"]["target"])
289
+ target_player["cards"] = [] # target loses both cards
290
  game["challenge"] = None
291
  return {"success": True, "message": f"Challenge failed. {target_player['name']} loses both cards."}
292
  else:
 
293
  game["challenge"]["status"] = "choose"
294
  game["challenge"]["challenger"] = assassin_player["name"]
295
  return {"success": True, "message": f"Challenge successful. {assassin_player['name']} must choose a card to lose.", "challenge": game["challenge"]}
296
  elif response == "contessa":
 
297
  game["challenge"]["phase"] = "assassin_contessa"
298
  return {"success": True, "message": f"{game['challenge']['challenger']} must now choose to challenge or accept the Contessa."}
 
299
  elif game["challenge"].get("phase") == "assassin_contessa":
300
  if response == "accept":
 
301
  game["challenge"]["status"] = "choose"
302
  game["challenge"]["challenger"] = game["challenge"]["target"]
303
  return {"success": True, "message": f"{game['challenge']['target']} must now choose a card to lose."}
304
  elif response == "challenge":
 
305
  target_player = next(p for p in game["players"] if p["name"] == game["challenge"]["target"])
306
  if "Contessa" in target_player["cards"]:
 
307
  game["challenge"]["status"] = "choose"
 
308
  game["challenge"]["challenger"] = game["challenge"]["challenger"]
309
  return {"success": True, "message": f"Contessa challenge successful. {game['challenge']['challenger']} must choose a card to lose.", "challenge": game["challenge"]}
310
  else:
 
311
  target_player["cards"] = []
312
  game["challenge"] = None
313
  return {"success": True, "message": f"Contessa challenge failed. {target_player['name']} loses both cards."}
314
+ # Ambassador response branch (existing)
315
+ elif game["challenge"]["challengeType"] == "ambassador":
316
+ if response == 'allow':
317
+ if "responses" not in game["challenge"]:
318
+ game["challenge"]["responses"] = {}
319
+ game["challenge"]["responses"][player] = 'allow'
 
 
 
 
 
320
  total_opponents = len(game["players"]) - 1
321
  if len(game["challenge"]["responses"]) == total_opponents:
322
+ ambassador_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
323
+ ambassador_player["cards"] = generate_cards()
324
  game["challenge"] = None
325
+ return {"success": True, "message": f"Ambassador action accepted. {ambassador_player['name']} swaps cards with the deck."}
326
  else:
327
+ return {"success": True, "message": f"{player} allowed the Ambassador action. Awaiting other responses."}
328
+ elif response == 'challenge':
329
+ ambassador_player = next(p for p in game["players"] if p["name"] == game["challenge"]["challenger"])
330
+ if "Ambassador" in ambassador_player["cards"]:
331
+ game["challenge"]["status"] = "choose"
332
+ game["challenge"]["challenger"] = player
333
+ game["challenge"]["target"] = ambassador_player["name"]
334
+ ambassador_player["cards"] = generate_cards()
335
+ game["challenge"] = None
336
+ return {"success": True, "message": f"Challenge failed. {player} must lose a card, while {ambassador_player['name']} swaps cards with the deck."}
337
+ else:
338
+ game["challenge"]["status"] = "choose"
339
+ return {"success": True, "message": "Challenge successful. Ambassador user must choose a card to lose.", "challenge": game["challenge"]}
340
+ # CHOOSE action to lose a card.
341
+ if action == 'choose':
342
+ acting_player = next((p for p in game["players"] if p["name"] == game["challenge"]["challenger"]), None)
343
+ if acting_player and target in acting_player["cards"]:
344
+ acting_player["cards"].remove(target)
345
+ game["challenge"] = None
346
+ return {"success": True, "message": f"{acting_player['name']} loses the {target} card."}
347
+ else:
348
+ return {"success": False, "message": f"Card {target} not found in {acting_player['name']}'s hand."}
349
+ # INCOME action (existing)
350
  if action == 'income':
351
  player_found = False
352
  for p in game["players"]:
 
395
  else:
396
  return {"success": True, "message": f"{player} allowed Foreign Aid. Awaiting other responses."}
397
 
398
+ return {"success": True, "message": f"Action '{action}' received for player {player}."}
399
 
400
  @app.post("/api/joinGame")
401
  async def join_game(request: Request):