sidnvy commited on
Commit
81ed7f7
·
verified ·
1 Parent(s): 950537f

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. squid_game.py +190 -54
  2. squid_game_core.py +97 -0
squid_game.py CHANGED
@@ -3,6 +3,9 @@ from squid_game_core import (
3
  parse_tier_map,
4
  get_expected_value,
5
  compute_ev_win_lose_two_extremes,
 
 
 
6
  )
7
  from typing import List, Tuple
8
 
@@ -93,6 +96,100 @@ def solve_game(distribution: str, total_squids: int, tier_map_str: str) -> str:
93
  except Exception as e:
94
  return f"Error occurred: {str(e)}"
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  # Default value for tier map used in interface
97
  DEFAULT_TIER_MAP = """0-0:0
98
  1-2:1
@@ -103,64 +200,103 @@ DEFAULT_TIER_MAP = """0-0:0
103
  9-9:32
104
  10-100:64"""
105
 
106
- iface = gr.Interface(
107
- fn=solve_game,
108
- inputs=[
109
- gr.Textbox(
110
- label="Players' Current Squids",
111
- placeholder="0,0",
112
- value="0,0",
113
- info="""Enter each player's current squids, separated by commas.
114
- Example: '1,0,1,2,0' represents:
115
- - Player 1 has 1 squid
116
- - Player 2 has 0 squids
117
- - Player 3 has 1 squid
118
- - Player 4 has 2 squids
119
- - Player 5 has 0 squids"""
120
- ),
121
- gr.Number(
122
- label="Total Squids in Game",
123
- value=9,
124
- minimum=0,
125
- step=1,
126
- precision=0,
127
- info="The total number of squids to be distributed (must be ≥ sum of current squids)"
128
- ),
129
- gr.Textbox(
130
- label="Squid Value Tiers",
131
- placeholder=DEFAULT_TIER_MAP,
132
- value=DEFAULT_TIER_MAP,
133
- lines=8,
134
- info="""Define the value tiers for squids.
135
- Format: range:multiplier (one per line)
136
- Example:
137
- 0-0:0
138
- 1-2:1
139
- 3-4:2
140
- 5-6:4
141
- 7-7:8
142
- 8-8:16
143
- 9-9:32
144
- 10-100:64"""
145
- )
146
- ],
147
- outputs=gr.Textbox(label="Results", lines=15),
148
- title="Squid Game Expected Value Calculator",
149
- description="""
150
  Calculate the expected payoff for each player in the Squid Game.
151
-
152
- Rules:
153
  1. Players take turns collecting squids randomly.
154
  2. The game ends when either:
155
  - Exactly one player has 0 squids, OR
156
  - There are no squids left to distribute.
157
- """,
158
- examples=[
159
- ["0,0", 9, DEFAULT_TIER_MAP],
160
- ["1,0,1", 12, DEFAULT_TIER_MAP],
161
- ["2,0,2,0", 14, DEFAULT_TIER_MAP],
162
- ]
163
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
  if __name__ == "__main__":
166
- iface.launch()
 
3
  parse_tier_map,
4
  get_expected_value,
5
  compute_ev_win_lose_two_extremes,
6
+ finite_squid_game_probabilities,
7
+ dp_ev,
8
+ infinite_squid_game_expected_counts_partial,
9
  )
10
  from typing import List, Tuple
11
 
 
96
  except Exception as e:
97
  return f"Error occurred: {str(e)}"
98
 
99
+ def solve_finite_game(distribution: str, total_squids: int) -> str:
100
+ """Calculate the probability of each player getting a squid in the finite variant"""
101
+ # Validate distribution
102
+ valid_dist, error_msg, dist = validate_distribution(distribution)
103
+ if not valid_dist:
104
+ return error_msg
105
+
106
+ # Validate that no player has more than 1 squid (finite variant rule)
107
+ if any(x > 1 for x in dist):
108
+ return "Error: In the finite variant, players can only have 0 or 1 squid. Please adjust your input."
109
+
110
+ # Validate total squids
111
+ try:
112
+ X = int(total_squids)
113
+ if X < 0:
114
+ return "Total squids cannot be negative"
115
+
116
+ # Check if total squids exceeds number of players
117
+ if X > len(dist):
118
+ return f"Error: In the finite variant, total squids cannot exceed the number of players ({len(dist)})"
119
+
120
+ # Check if remaining squids + already distributed squids exceeds number of players
121
+ current_sum = sum(dist)
122
+ if current_sum + (X - current_sum) > len(dist):
123
+ return f"Error: Total squids to distribute ({X}) plus already distributed squids ({current_sum}) cannot exceed the number of players ({len(dist)})"
124
+ except ValueError:
125
+ return "Total squids must be an integer"
126
+
127
+ try:
128
+ # Clear cache for new calculation
129
+ dp_ev.cache_clear()
130
+
131
+ # Calculate probabilities using the finite variant
132
+ n = len(dist) # Number of players
133
+
134
+ # Calculate remaining squids to distribute
135
+ remaining = X - sum(dist)
136
+
137
+ # Create bitmask for players who already have squids
138
+ bitmask_u = (1 << n) - 1 # Start with all 1s
139
+ for i, val in enumerate(dist):
140
+ if val == 1: # If player already has a squid
141
+ bitmask_u ^= (1 << i) # Set bit to 0
142
+
143
+ # Calculate probabilities
144
+ probs = dp_ev(n, bitmask_u, remaining)
145
+
146
+ result = "Finite Squid Game Probabilities:\n"
147
+ result += "(Probability of each player getting a squid)\n\n"
148
+
149
+ for i, prob in enumerate(probs):
150
+ result += f"Player {i+1}: {prob:.4f}\n"
151
+
152
+ return result
153
+
154
+ except Exception as e:
155
+ return f"Error occurred: {str(e)}"
156
+
157
+ def solve_infinite_game(distribution: str) -> str:
158
+ """Calculate the expected final squid count for each player in the infinite variant"""
159
+ # Validate distribution
160
+ valid_dist, error_msg, dist = validate_distribution(distribution)
161
+ if not valid_dist:
162
+ return error_msg
163
+
164
+ try:
165
+ # Calculate expected final counts
166
+ expected_counts = infinite_squid_game_expected_counts_partial(dist)
167
+
168
+ result = "Infinite Squid Game Expected Final Counts:\n"
169
+ result += "(Expected number of squids each player will have at the end)\n\n"
170
+
171
+ for i, count in enumerate(expected_counts):
172
+ if count == float('inf'):
173
+ result += f"Player {i+1}: ∞ (infinite)\n"
174
+ else:
175
+ result += f"Player {i+1}: {count:.4f}\n"
176
+
177
+ # Add explanation based on zero count
178
+ zero_count = sum(1 for x in dist if x == 0)
179
+ if zero_count == 1:
180
+ result += "\nExplanation: Game ends immediately as there is exactly one player with 0 squids."
181
+ elif zero_count == 0:
182
+ result += "\nExplanation: Game never ends (infinite loop) as there are no players with 0 squids."
183
+ else:
184
+ H_z = sum(1.0 / k for k in range(1, zero_count+1))
185
+ increment = (H_z - 1.0)
186
+ result += f"\nExplanation: Each player is expected to receive {increment:.4f} additional squids before the game ends."
187
+
188
+ return result
189
+
190
+ except Exception as e:
191
+ return f"Error occurred: {str(e)}"
192
+
193
  # Default value for tier map used in interface
194
  DEFAULT_TIER_MAP = """0-0:0
195
  1-2:1
 
200
  9-9:32
201
  10-100:64"""
202
 
203
+ with gr.Blocks(title="Squid Game Calculator") as iface:
204
+ gr.Markdown("""
205
+ # Squid Game Expected Value Calculator
206
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  Calculate the expected payoff for each player in the Squid Game.
208
+
209
+ **Classic Variant Rules:**
210
  1. Players take turns collecting squids randomly.
211
  2. The game ends when either:
212
  - Exactly one player has 0 squids, OR
213
  - There are no squids left to distribute.
214
+
215
+ **Finite Variant Rules:**
216
+ 1. Players take turns collecting squids randomly.
217
+ 2. Once a player gets a squid, they can't get another one.
218
+ 3. The game ends when all squids are distributed or only one player remains without a squid.
219
+
220
+ **Infinite Variant Rules:**
221
+ 1. Players take turns collecting squids randomly (unlimited supply).
222
+ 2. Players accumulate squids over time.
223
+ 3. The game ends only when exactly one player has 0 squids.
224
+ """)
225
+
226
+ with gr.Row():
227
+ with gr.Column():
228
+ distribution_input = gr.Textbox(
229
+ label="Players' Current Squids",
230
+ placeholder="0,0",
231
+ value="0,0",
232
+ info="""Enter each player's current squids, separated by commas.
233
+ Example: '1,0,1,2,0' represents:
234
+ - Player 1 has 1 squid
235
+ - Player 2 has 0 squids
236
+ - Player 3 has 1 squid
237
+ - Player 4 has 2 squids
238
+ - Player 5 has 0 squids"""
239
+ )
240
+ total_squids_input = gr.Number(
241
+ label="Total Squids in Game (Classic & Finite Variants Only)",
242
+ value=9,
243
+ minimum=0,
244
+ step=1,
245
+ precision=0,
246
+ info="The total number of squids to be distributed (must be ≥ sum of current squids for classic variant)"
247
+ )
248
+ tier_map_input = gr.Textbox(
249
+ label="Squid Value Tiers (Classic Variant Only)",
250
+ placeholder=DEFAULT_TIER_MAP,
251
+ value=DEFAULT_TIER_MAP,
252
+ lines=8,
253
+ info="""Define the value tiers for squids.
254
+ Format: range:multiplier (one per line)
255
+ Example:
256
+ 0-0:0
257
+ 1-2:1
258
+ 3-4:2
259
+ 5-6:4
260
+ 7-7:8
261
+ 8-8:16
262
+ 9-9:32
263
+ 10-100:64"""
264
+ )
265
+
266
+ with gr.Column():
267
+ results_output = gr.Textbox(label="Results", lines=15)
268
+
269
+ with gr.Row():
270
+ classic_btn = gr.Button("Calculate Classic Variant", variant="primary")
271
+ finite_btn = gr.Button("Calculate Finite Variant", variant="stop")
272
+ infinite_btn = gr.Button("Calculate Infinite Variant", variant="secondary")
273
+
274
+ gr.Examples(
275
+ examples=[
276
+ ["0,0", 9, DEFAULT_TIER_MAP],
277
+ ["1,0,1", 12, DEFAULT_TIER_MAP],
278
+ ["2,0,2,0", 14, DEFAULT_TIER_MAP],
279
+ ],
280
+ inputs=[distribution_input, total_squids_input, tier_map_input],
281
+ )
282
+
283
+ classic_btn.click(
284
+ fn=solve_game,
285
+ inputs=[distribution_input, total_squids_input, tier_map_input],
286
+ outputs=results_output
287
+ )
288
+
289
+ finite_btn.click(
290
+ fn=solve_finite_game,
291
+ inputs=[distribution_input, total_squids_input],
292
+ outputs=results_output
293
+ )
294
+
295
+ infinite_btn.click(
296
+ fn=solve_infinite_game,
297
+ inputs=[distribution_input],
298
+ outputs=results_output
299
+ )
300
 
301
  if __name__ == "__main__":
302
+ iface.launch()
squid_game_core.py CHANGED
@@ -1,6 +1,7 @@
1
  # squid_game.py
2
 
3
  from functools import lru_cache
 
4
 
5
  def parse_tier_map(tier_str: str):
6
  """
@@ -204,3 +205,99 @@ def compute_ev_win_lose_two_extremes(distribution, leftover, tier_map_tuple):
204
  'difference': diff_i
205
  })
206
  return results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # squid_game.py
2
 
3
  from functools import lru_cache
4
+ import math
5
 
6
  def parse_tier_map(tier_str: str):
7
  """
 
205
  'difference': diff_i
206
  })
207
  return results
208
+
209
+ # Infinite Squid Game Implementation
210
+ def infinite_squid_game_expected_counts_partial(distribution):
211
+ """
212
+ For the "infinite squid + cumulative score, stop when only 1 player has 0" game,
213
+ given the current distribution (list/tuple, representing each player's current count),
214
+ returns a list representing the expected number of squids each player will have at the end of the game.
215
+
216
+ Rule summary:
217
+ - If the current number of players with 0 squids = z:
218
+ * z=1 => Game stops immediately, no more squids distributed => final value = current holdings
219
+ * z=0 => "Exactly 1 player with 0" can never occur, infinite loop => return inf
220
+ * z>=2 => Expected to distribute n*(H_z -1) more times (H_z=1+1/2+...+1/z),
221
+ Expected number of times each player is selected = (H_z-1),
222
+ Therefore final = distribution[i] + (H_z-1).
223
+ """
224
+ n = len(distribution)
225
+ zero_count = sum(1 for x in distribution if x == 0)
226
+
227
+ # Already satisfied or exceeded "end/cannot end" condition
228
+ if zero_count == 1:
229
+ # Game ends immediately => maintain current state
230
+ return list(distribution)
231
+ if zero_count == 0:
232
+ # "Exactly 1 player with 0" can never occur => game never ends => infinite score
233
+ return [math.inf]*n
234
+
235
+ # zero_count >= 2 => continue distributing squids until z=1
236
+ H_z = sum(1.0 / k for k in range(1, zero_count+1)) # Harmonic number H_z
237
+ increment = (H_z - 1.0)
238
+ return [x + increment for x in distribution]
239
+
240
+ # Finite Squid Game Implementation
241
+ def get_bitmask(n):
242
+ """
243
+ Returns a list [0,1,2,...,(1<<n)-1], purely for iteration reference
244
+ """
245
+ return list(range(1 << n))
246
+
247
+ def count_ones(x):
248
+ """Count how many 1s are in the binary representation of x"""
249
+ return bin(x).count("1")
250
+
251
+ @lru_cache(None)
252
+ def dp_ev(n, bitmask_u, leftover):
253
+ """
254
+ Returns a length-n tuple (prob0, prob1, ..., prob_{n-1}),
255
+ representing the "final probability" of each player getting a squid in state (U=bitmask_u, leftover).
256
+
257
+ - n: total number of players
258
+ - bitmask_u: which players haven't received a squid yet (binary mask)
259
+ - leftover: remaining squids that can be distributed
260
+ """
261
+ # 1) Terminal condition
262
+ num_u = count_ones(bitmask_u) # Number of players who haven't received a squid yet
263
+ if num_u <= 1 or leftover == 0:
264
+ # Game ends immediately
265
+ # For players who already have a squid, their probability=1
266
+ # For those who don't, probability=0
267
+ ret = []
268
+ for i in range(n):
269
+ # If i is in bitmask_u => probability=0, otherwise =1
270
+ if (bitmask_u & (1 << i)) != 0:
271
+ ret.append(0.0)
272
+ else:
273
+ ret.append(1.0)
274
+ return tuple(ret)
275
+
276
+ # 2) Not terminated => randomly select 1 person from U to give a squid
277
+ ret_accum = [0.0]*n
278
+ # Randomly select w from U with equal probability
279
+ for w in range(n):
280
+ bit_w = (1 << w)
281
+ if (bitmask_u & bit_w) != 0:
282
+ # w is in U
283
+ # Next state: after w gets a squid, remove w from bitmask
284
+ next_u = bitmask_u ^ bit_w # Set to 0
285
+ sub_ev = dp_ev(n, next_u, leftover - 1)
286
+
287
+ for i in range(n):
288
+ ret_accum[i] += sub_ev[i] / num_u
289
+
290
+ # 3) Return accumulated result
291
+ return tuple(ret_accum)
292
+
293
+ def finite_squid_game_probabilities(n, r):
294
+ """
295
+ Returns a length-n probability vector: prob[i] = probability of player i getting a squid
296
+ Based on dp_ev().
297
+
298
+ - n: number of players
299
+ - r: number of squids to distribute
300
+ """
301
+ # Initial U = (1<<n)-1, meaning no one has a squid yet
302
+ bitmask_u = (1 << n) - 1
303
+ return dp_ev(n, bitmask_u, r)