bupticybee commited on
Commit
c5cd6a7
·
1 Parent(s): 34085e8

:new: add stuff

Browse files
Files changed (2) hide show
  1. squid_game.py +60 -39
  2. squid_game_core.py +9 -8
squid_game.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  import gradio as gr
2
  from squid_game_core import (
3
  parse_tier_map,
@@ -17,10 +19,24 @@ def validate_distribution(dist_str: str) -> Tuple[bool, str, List[int]]:
17
  dist = [int(x.strip()) for x in dist_str.split(',')]
18
  if any(x < 0 for x in dist):
19
  return False, "Distribution cannot contain negative numbers", []
 
 
20
  return True, "", dist
21
  except ValueError:
22
  return False, "Distribution must be comma-separated integers (e.g., '0,1,2')", []
23
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  def validate_tier_map(tier_str: str) -> Tuple[bool, str]:
25
  """Validate the tier map string format"""
26
  try:
@@ -39,13 +55,18 @@ def validate_tier_map(tier_str: str) -> Tuple[bool, str]:
39
  except ValueError:
40
  return False, "Invalid format. Example: '1:1.0\\n2-4:2.0\\n5-6:3.0'"
41
 
42
- def solve_game(distribution: str, total_squids: int, tier_map_str: str) -> str:
43
  """Main function to solve the game and return formatted results"""
44
  # Validate distribution
45
  valid_dist, error_msg, dist = validate_distribution(distribution)
46
  if not valid_dist:
47
  return error_msg
48
 
 
 
 
 
 
49
  # Validate tier map
50
  valid_tier, error_msg = validate_tier_map(tier_map_str)
51
  if not valid_tier:
@@ -65,22 +86,25 @@ def solve_game(distribution: str, total_squids: int, tier_map_str: str) -> str:
65
  try:
66
  tier_map = parse_tier_map(tier_map_str)
67
  tier_map_tuple = tuple((a, b, c) for a, b, c in tier_map)
 
 
68
 
69
  # Calculate remaining squids to distribute
70
  remaining = X - sum(dist)
71
 
72
  # Get unforced expected values (full random assignment)
73
  get_expected_value.cache_clear()
74
- unforced_ev = get_expected_value(tuple(dist), remaining, tier_map_tuple)
75
 
76
  result = "Unforced Expected Values:\n"
77
  for i, ev in enumerate(unforced_ev):
78
- result += f"Player {i+1}: {ev:.3f}\n"
 
79
 
80
  # Compute each player's forced win/lose EV extremes:
81
- win_lose_results = compute_ev_win_lose_two_extremes(tuple(dist), remaining, tier_map_tuple)
82
 
83
- result += "\nForced Win/Lose Results:\n"
84
  for r in win_lose_results:
85
  result += (f"Player {r['player']+1}: forcedWinEV = {r['forcedWinEV']:.3f}, "
86
  f"forcedLoseEV = {r['forcedLoseEV']:.3f}, Diff = {r['difference']:.3f}\n")
@@ -98,13 +122,18 @@ def solve_game(distribution: str, total_squids: int, tier_map_str: str) -> str:
98
  except Exception as e:
99
  return f"Error occurred: {str(e)}"
100
 
101
- def solve_finite_game(distribution: str, total_squids: int) -> str:
102
  """Calculate the Expected Value (EV) for each player in the finite variant using tuple-based state."""
103
  # Validate distribution
104
  valid_dist, error_msg, dist = validate_distribution(distribution)
105
  if not valid_dist:
106
  return error_msg
107
 
 
 
 
 
 
108
  # Validate finite variant rules
109
  if any(x > 1 for x in dist):
110
  return "Error: In the finite variant, players can only have 0 or 1 squid."
@@ -123,35 +152,34 @@ def solve_finite_game(distribution: str, total_squids: int) -> str:
123
  return "Total squids must be an integer."
124
 
125
  try:
126
- # 清理新函数的缓存
127
  get_expected_value_finite.cache_clear()
128
 
129
  remaining = X - sum(dist)
130
- dist_tuple = tuple(dist) # 使用元组作为状态
 
131
 
132
- # 导入内部函数用于判断终局
133
  from squid_game_core import _is_terminal_finite, _compute_final_payout_finite_tuple
134
 
135
- # 如果游戏已经结束,直接计算终局收益
136
- if _is_terminal_finite(dist_tuple, remaining):
137
  final_payoffs = _compute_final_payout_finite_tuple(dist_tuple)
138
  result = "Finite Squid Game Final Payouts:\n(Game has ended or no squids left)\n\n"
139
  for i, payoff in enumerate(final_payoffs):
140
- result += f"Player {i+1}: {payoff:.4f}\n"
 
141
  return result
142
 
143
- # 计算基础EV和Forced Win/Lose EV
144
- base_ev, win_lose_results = compute_ev_win_lose_finite_tuple(dist_tuple, remaining)
145
 
146
  result = "Finite Squid Game Expected Value (EV):\n"
147
  result += "(Payout Rule: Losers pay for all winners' squids)\n\n"
148
 
149
  result += "Baseline EV (fully random):\n"
150
  for i, ev in enumerate(base_ev):
151
- result += f"Player {i+1}: {ev:.4f}\n"
 
152
 
153
  if win_lose_results:
154
- result += "\nForced Win/Lose EV (for players without a squid):\n"
155
  for r in win_lose_results:
156
  result += (f"Player {r['player']+1}: forcedWinEV = {r['forcedWinEV']:.4f}, "
157
  f"forcedLoseEV = {r['forcedLoseEV']:.4f}, Diff = {r['difference']:.4f}\n")
@@ -237,12 +265,14 @@ with gr.Blocks(title="Squid Game Calculator") as iface:
237
  placeholder="0,0",
238
  value="0,0",
239
  info="""Enter each player's current squids, separated by commas.
240
- Example: '1,0,1,2,0' represents:
241
- - Player 1 has 1 squid
242
- - Player 2 has 0 squids
243
- - Player 3 has 1 squid
244
- - Player 4 has 2 squids
245
- - Player 5 has 0 squids"""
 
 
246
  )
247
  total_squids_input = gr.Number(
248
  label="Total Squids in Game (Classic & Finite Variants Only)",
@@ -258,20 +288,11 @@ with gr.Blocks(title="Squid Game Calculator") as iface:
258
  value=DEFAULT_TIER_MAP,
259
  lines=8,
260
  info="""Define the value tiers for squids.
261
- Format: range:multiplier (one per line)
262
- Example:
263
- 0-0:0
264
- 1-2:1
265
- 3-4:2
266
- 5-6:4
267
- 7-7:8
268
- 8-8:16
269
- 9-9:32
270
- 10-100:64"""
271
  )
272
 
273
  with gr.Column():
274
- results_output = gr.Textbox(label="Results", lines=15)
275
 
276
  with gr.Row():
277
  classic_btn = gr.Button("Calculate Classic Variant", variant="primary")
@@ -280,22 +301,22 @@ with gr.Blocks(title="Squid Game Calculator") as iface:
280
 
281
  gr.Examples(
282
  examples=[
283
- ["0,0", 9, DEFAULT_TIER_MAP],
284
- ["1,0,1", 12, DEFAULT_TIER_MAP],
285
- ["2,0,2,0", 14, DEFAULT_TIER_MAP],
286
  ],
287
- inputs=[distribution_input, total_squids_input, tier_map_input],
288
  )
289
 
290
  classic_btn.click(
291
  fn=solve_game,
292
- inputs=[distribution_input, total_squids_input, tier_map_input],
293
  outputs=results_output
294
  )
295
 
296
  finite_btn.click(
297
  fn=solve_finite_game,
298
- inputs=[distribution_input, total_squids_input],
299
  outputs=results_output
300
  )
301
 
 
1
+ --- START OF FILE squid_game (1).py ---
2
+
3
  import gradio as gr
4
  from squid_game_core import (
5
  parse_tier_map,
 
19
  dist = [int(x.strip()) for x in dist_str.split(',')]
20
  if any(x < 0 for x in dist):
21
  return False, "Distribution cannot contain negative numbers", []
22
+ if not dist:
23
+ return False, "Distribution cannot be empty.", []
24
  return True, "", dist
25
  except ValueError:
26
  return False, "Distribution must be comma-separated integers (e.g., '0,1,2')", []
27
 
28
+ def validate_folded_players(folded_str: str, num_players: int) -> Tuple[bool, str, List[int]]:
29
+ """Validate the folded players string."""
30
+ try:
31
+ folded = [int(x.strip()) for x in folded_str.split(',')]
32
+ if len(folded) != num_players:
33
+ return False, f"Folded players list must have {num_players} entries, but it has {len(folded)}.", []
34
+ if any(x not in [0, 1] for x in folded):
35
+ return False, "Folded players list can only contain 0s and 1s.", []
36
+ return True, "", folded
37
+ except ValueError:
38
+ return False, "Folded players must be comma-separated integers (e.g., '0,0,1,0')", []
39
+
40
  def validate_tier_map(tier_str: str) -> Tuple[bool, str]:
41
  """Validate the tier map string format"""
42
  try:
 
55
  except ValueError:
56
  return False, "Invalid format. Example: '1:1.0\\n2-4:2.0\\n5-6:3.0'"
57
 
58
+ def solve_game(distribution: str, folded_players_str: str, total_squids: int, tier_map_str: str) -> str:
59
  """Main function to solve the game and return formatted results"""
60
  # Validate distribution
61
  valid_dist, error_msg, dist = validate_distribution(distribution)
62
  if not valid_dist:
63
  return error_msg
64
 
65
+ # Validate folded players
66
+ valid_folded, error_msg, folded = validate_folded_players(folded_players_str, len(dist))
67
+ if not valid_folded:
68
+ return error_msg
69
+
70
  # Validate tier map
71
  valid_tier, error_msg = validate_tier_map(tier_map_str)
72
  if not valid_tier:
 
86
  try:
87
  tier_map = parse_tier_map(tier_map_str)
88
  tier_map_tuple = tuple((a, b, c) for a, b, c in tier_map)
89
+ dist_tuple = tuple(dist)
90
+ folded_tuple = tuple(folded)
91
 
92
  # Calculate remaining squids to distribute
93
  remaining = X - sum(dist)
94
 
95
  # Get unforced expected values (full random assignment)
96
  get_expected_value.cache_clear()
97
+ unforced_ev = get_expected_value(dist_tuple, remaining, tier_map_tuple, folded_tuple)
98
 
99
  result = "Unforced Expected Values:\n"
100
  for i, ev in enumerate(unforced_ev):
101
+ player_status = "(Folded)" if folded[i] == 1 else ""
102
+ result += f"Player {i+1}: {ev:.3f} {player_status}\n"
103
 
104
  # Compute each player's forced win/lose EV extremes:
105
+ win_lose_results = compute_ev_win_lose_two_extremes(dist_tuple, remaining, tier_map_tuple, folded_tuple)
106
 
107
+ result += "\nForced Win/Lose Results (for non-folded players):\n"
108
  for r in win_lose_results:
109
  result += (f"Player {r['player']+1}: forcedWinEV = {r['forcedWinEV']:.3f}, "
110
  f"forcedLoseEV = {r['forcedLoseEV']:.3f}, Diff = {r['difference']:.3f}\n")
 
122
  except Exception as e:
123
  return f"Error occurred: {str(e)}"
124
 
125
+ def solve_finite_game(distribution: str, folded_players_str: str, total_squids: int) -> str:
126
  """Calculate the Expected Value (EV) for each player in the finite variant using tuple-based state."""
127
  # Validate distribution
128
  valid_dist, error_msg, dist = validate_distribution(distribution)
129
  if not valid_dist:
130
  return error_msg
131
 
132
+ # Validate folded players
133
+ valid_folded, error_msg, folded = validate_folded_players(folded_players_str, len(dist))
134
+ if not valid_folded:
135
+ return error_msg
136
+
137
  # Validate finite variant rules
138
  if any(x > 1 for x in dist):
139
  return "Error: In the finite variant, players can only have 0 or 1 squid."
 
152
  return "Total squids must be an integer."
153
 
154
  try:
 
155
  get_expected_value_finite.cache_clear()
156
 
157
  remaining = X - sum(dist)
158
+ dist_tuple = tuple(dist)
159
+ folded_tuple = tuple(folded)
160
 
 
161
  from squid_game_core import _is_terminal_finite, _compute_final_payout_finite_tuple
162
 
163
+ if _is_terminal_finite(dist_tuple, remaining, folded_tuple):
 
164
  final_payoffs = _compute_final_payout_finite_tuple(dist_tuple)
165
  result = "Finite Squid Game Final Payouts:\n(Game has ended or no squids left)\n\n"
166
  for i, payoff in enumerate(final_payoffs):
167
+ player_status = "(Folded)" if folded[i] == 1 else ""
168
+ result += f"Player {i+1}: {payoff:.4f} {player_status}\n"
169
  return result
170
 
171
+ base_ev, win_lose_results = compute_ev_win_lose_finite_tuple(dist_tuple, remaining, folded_tuple)
 
172
 
173
  result = "Finite Squid Game Expected Value (EV):\n"
174
  result += "(Payout Rule: Losers pay for all winners' squids)\n\n"
175
 
176
  result += "Baseline EV (fully random):\n"
177
  for i, ev in enumerate(base_ev):
178
+ player_status = "(Folded)" if folded[i] == 1 else ""
179
+ result += f"Player {i+1}: {ev:.4f} {player_status}\n"
180
 
181
  if win_lose_results:
182
+ result += "\nForced Win/Lose EV (for players without a squid who haven't folded):\n"
183
  for r in win_lose_results:
184
  result += (f"Player {r['player']+1}: forcedWinEV = {r['forcedWinEV']:.4f}, "
185
  f"forcedLoseEV = {r['forcedLoseEV']:.4f}, Diff = {r['difference']:.4f}\n")
 
265
  placeholder="0,0",
266
  value="0,0",
267
  info="""Enter each player's current squids, separated by commas.
268
+ Example: '1,0,1,2,0' represents 5 players."""
269
+ )
270
+ folded_players_input = gr.Textbox(
271
+ label="Folded Players (0 = Playing, 1 = Folded)",
272
+ placeholder="0,0",
273
+ value="0,0",
274
+ info="""Enter 0 for playing, 1 for folded. Must match the number of players.
275
+ Example: '0,0,1,0,0' means Player 3 has folded and won't receive any more squids."""
276
  )
277
  total_squids_input = gr.Number(
278
  label="Total Squids in Game (Classic & Finite Variants Only)",
 
288
  value=DEFAULT_TIER_MAP,
289
  lines=8,
290
  info="""Define the value tiers for squids.
291
+ Format: range:multiplier (one per line)"""
 
 
 
 
 
 
 
 
 
292
  )
293
 
294
  with gr.Column():
295
+ results_output = gr.Textbox(label="Results", lines=20)
296
 
297
  with gr.Row():
298
  classic_btn = gr.Button("Calculate Classic Variant", variant="primary")
 
301
 
302
  gr.Examples(
303
  examples=[
304
+ ["0,0", "0,0", 9, DEFAULT_TIER_MAP],
305
+ ["1,0,1", "0,0,0", 12, DEFAULT_TIER_MAP],
306
+ ["2,0,2,0", "0,1,0,0", 14, DEFAULT_TIER_MAP],
307
  ],
308
+ inputs=[distribution_input, folded_players_input, total_squids_input, tier_map_input],
309
  )
310
 
311
  classic_btn.click(
312
  fn=solve_game,
313
+ inputs=[distribution_input, folded_players_input, total_squids_input, tier_map_input],
314
  outputs=results_output
315
  )
316
 
317
  finite_btn.click(
318
  fn=solve_finite_game,
319
+ inputs=[distribution_input, folded_players_input, total_squids_input],
320
  outputs=results_output
321
  )
322
 
squid_game_core.py CHANGED
@@ -139,7 +139,8 @@ def get_expected_value_forced_lose(
139
  i,
140
  distribution,
141
  leftover,
142
- tier_map_tuple
 
143
  ):
144
  """
145
  假设下一只乌贼 100% 不会给玩家 i,
@@ -161,7 +162,7 @@ def get_expected_value_forced_lose(
161
  # Probability = 1/(n-1)
162
 
163
  accumulated = [0.0]*n
164
- valid_winners = [w for w in range(n) if w != i]
165
 
166
  for w in valid_winners:
167
  dist_next = list(distribution)
@@ -176,7 +177,7 @@ def get_expected_value_forced_lose(
176
 
177
  return tuple(accumulated)
178
 
179
- def compute_ev_win_lose_two_extremes(distribution, leftover, tier_map_tuple):
180
  """
181
  返回一个数据结构,记录每个玩家 i 在:
182
  - forced_win 时的期望收益
@@ -188,7 +189,7 @@ def compute_ev_win_lose_two_extremes(distribution, leftover, tier_map_tuple):
188
 
189
  for i in range(n):
190
  forced_win_vec = get_expected_value_forced_win(i, distribution, leftover, tier_map_tuple)
191
- forced_lose_vec = get_expected_value_forced_lose(i, distribution, leftover, tier_map_tuple)
192
 
193
  # 我们可能只关心玩家 i 本人的比较, 也可以把全部人都算,
194
  # 这里演示只关心 i
@@ -394,7 +395,7 @@ def get_expected_value_finite_forced_win(i, distribution, remaining):
394
  # 在新状态上进行完全随机的EV计算
395
  return get_expected_value_finite(tuple(new_dist_list), remaining - 1)
396
 
397
- def get_expected_value_finite_forced_lose(i, distribution, remaining):
398
  """
399
  (模仿 get_expected_value_forced_lose)
400
  假设下一个鱿鱼 100% 不会给玩家 i。
@@ -407,7 +408,7 @@ def get_expected_value_finite_forced_lose(i, distribution, remaining):
407
  accumulated_ev = [0.0] * n
408
 
409
  # 找出除了i之外所有合格的候选人
410
- eligible_players = [p for p, count in enumerate(distribution) if p != i]
411
  num_eligible = len(eligible_players)
412
 
413
  if num_eligible == 0: # 如果除了i没有别人可选了,游戏结束
@@ -432,7 +433,7 @@ def get_expected_value_finite_forced_lose(i, distribution, remaining):
432
 
433
  return tuple(accumulated_ev)
434
 
435
- def compute_ev_win_lose_finite_tuple(distribution, remaining):
436
  """
437
  包装函数,为每个合格玩家计算 forced_win 和 forced_lose 的EV。
438
  """
@@ -445,7 +446,7 @@ def compute_ev_win_lose_finite_tuple(distribution, remaining):
445
 
446
  for i in eligible_players:
447
  win_ev_vec = get_expected_value_finite_forced_win(i, distribution, remaining)
448
- lose_ev_vec = get_expected_value_finite_forced_lose(i, distribution, remaining)
449
 
450
  forced_win_i = win_ev_vec[i]
451
  forced_lose_i = lose_ev_vec[i]
 
139
  i,
140
  distribution,
141
  leftover,
142
+ tier_map_tuple,
143
+ folded_players
144
  ):
145
  """
146
  假设下一只乌贼 100% 不会给玩家 i,
 
162
  # Probability = 1/(n-1)
163
 
164
  accumulated = [0.0]*n
165
+ valid_winners = [w for w in range(n) if (w != i and not folded_players[w])]
166
 
167
  for w in valid_winners:
168
  dist_next = list(distribution)
 
177
 
178
  return tuple(accumulated)
179
 
180
+ def compute_ev_win_lose_two_extremes(distribution, leftover, tier_map_tuple,folded_players):
181
  """
182
  返回一个数据结构,记录每个玩家 i 在:
183
  - forced_win 时的期望收益
 
189
 
190
  for i in range(n):
191
  forced_win_vec = get_expected_value_forced_win(i, distribution, leftover, tier_map_tuple)
192
+ forced_lose_vec = get_expected_value_forced_lose(i, distribution, leftover, tier_map_tuple,folded_players)
193
 
194
  # 我们可能只关心玩家 i 本人的比较, 也可以把全部人都算,
195
  # 这里演示只关心 i
 
395
  # 在新状态上进行完全随机的EV计算
396
  return get_expected_value_finite(tuple(new_dist_list), remaining - 1)
397
 
398
+ def get_expected_value_finite_forced_lose(i, distribution, remaining,folded_players):
399
  """
400
  (模仿 get_expected_value_forced_lose)
401
  假设下一个鱿鱼 100% 不会给玩家 i。
 
408
  accumulated_ev = [0.0] * n
409
 
410
  # 找出除了i之外所有合格的候选人
411
+ eligible_players = [p for p, count in enumerate(distribution) if (p != i and not folded_players[p])]
412
  num_eligible = len(eligible_players)
413
 
414
  if num_eligible == 0: # 如果除了i没有别人可选了,游戏结束
 
433
 
434
  return tuple(accumulated_ev)
435
 
436
+ def compute_ev_win_lose_finite_tuple(distribution, remaining,folded_players):
437
  """
438
  包装函数,为每个合格玩家计算 forced_win 和 forced_lose 的EV。
439
  """
 
446
 
447
  for i in eligible_players:
448
  win_ev_vec = get_expected_value_finite_forced_win(i, distribution, remaining)
449
+ lose_ev_vec = get_expected_value_finite_forced_lose(i, distribution, remaining,folded_players)
450
 
451
  forced_win_i = win_ev_vec[i]
452
  forced_lose_i = lose_ev_vec[i]