Spaces:
Sleeping
Sleeping
| # test_squid_game.py | |
| import pytest | |
| from math import isclose | |
| from functools import lru_cache | |
| # Import from our main module | |
| from squid_game_core import ( | |
| parse_tier_map, | |
| tierValue, | |
| is_terminal, | |
| compute_final_payout, | |
| get_expected_value, | |
| next_squid_gain_for_nonzero, | |
| hypothetical_next_round_gain | |
| ) | |
| def nearly_equal(a, b, tol=1e-9): | |
| return isclose(a, b, abs_tol=tol) | |
| def tier_map_example(): | |
| """ | |
| We'll define a bracket: | |
| 1-4:1 => if you have 1..4 squids => total = k * 1 | |
| 5-6:3 => if you have 5..6 squids => total = k * 3 | |
| 0 => always 0 | |
| """ | |
| # We'll store it as a tuple for use in DP | |
| # parse_tier_map would do the same, but let's define it directly | |
| return ( | |
| (0,0,0.0), | |
| (1,4,1.0), | |
| (5,6,3.0) | |
| ) | |
| def test_multiple_losers_pay_individually(tier_map_example): | |
| """ | |
| Scenario: 3 players => final distribution=(0,0,4). | |
| According to bracket (1-4:1 => 4=>4*1=4). | |
| - 2 losers => each pays 4 => each has payoff=-4 | |
| - 1 winner => receives 2 * 4=8. | |
| """ | |
| dist = (0,0,4) | |
| payoffs = compute_final_payout(dist, tier_map_example) | |
| # payoffs => [ -4, -4, 8 ] | |
| assert nearly_equal(payoffs[0], -4) | |
| assert nearly_equal(payoffs[1], -4) | |
| assert nearly_equal(payoffs[2], 8) | |
| def test_single_loser(tier_map_example): | |
| """ | |
| Scenario: 2 players => final distribution=(1,0). | |
| => 1 zero => that zero pays sum_of_winners= tierValue(1)=1 | |
| => payoff=(1, -1) because: | |
| - Winner keeps their tierValue (1) | |
| - Loser pays that amount (-1) | |
| """ | |
| dist = (1,0) | |
| payoffs = compute_final_payout(dist, tier_map_example) | |
| assert nearly_equal(payoffs[0], 1) # Winner gets tierValue(1)=1 | |
| assert nearly_equal(payoffs[1], -1) # Loser pays -1 | |
| def test_no_losers(tier_map_example): | |
| """ | |
| Scenario: 2 players => final distribution=(2,3). | |
| => no zero => no payment => payoff=(0,0). | |
| """ | |
| dist = (2,3) | |
| payoffs = compute_final_payout(dist, tier_map_example) | |
| # 2 => bracket(1..4 => *1)=>2 | |
| # 3 => bracket(1..4 => *1)=>3 | |
| # but since no zero => payoff=(0,0). | |
| assert nearly_equal(payoffs[0], 0) | |
| assert nearly_equal(payoffs[1], 0) | |
| def test_next_squid_gain_for_nonzero(tier_map_example): | |
| """ | |
| distribution=(4,0,2) => | |
| - Player0=4 => tierValue(4)=4 => tierValue(5)=15 => gain=11 | |
| (since 5 squids => bracket => 5*3=15) | |
| - Player1=0 => skip | |
| - Player2=2 => tierValue(2)=2 => tierValue(3)=3 => gain=1 | |
| """ | |
| dist = (4,0,2) | |
| gains = next_squid_gain_for_nonzero(dist, tier_map_example) | |
| assert 0 in gains | |
| assert gains[0] == 11 # 15-4 | |
| assert 2 in gains | |
| assert gains[2] == 1 # 3-2 | |
| assert 1 not in gains # because that player has 0 | |
| def test_ev_with_leftover_multiple_losers(tier_map_example): | |
| """ | |
| We'll test a DP scenario: | |
| N=3, X=4 total squids | |
| Current distribution=(0,1,1) | |
| => sum=2 => leftover=2 => not terminal. | |
| Let's see possible final states: | |
| - They could keep awarding 2 more squids in 2 rounds. | |
| - It's possible we end with multiple zeros if the 2 additional squids both go to the same non-zero player, | |
| or exactly one zero, etc. | |
| We'll just check the computed EV matches a hand-run or at least we confirm no errors. | |
| """ | |
| dist = (0,1,1) | |
| X = 4 | |
| r = X - sum(dist) # 4-2=2 | |
| # We'll do a quick partial analysis by enumerating the 2 leftover squids: | |
| # Round 1 => three possibilities: P0, P1, P2 | |
| # But let's just rely on the solver to give us a final result, | |
| # and we'll assert that we get a numeric 3-tuple and | |
| # the sum of payoffs is near 0 (since it's a zero-sum game). | |
| from squid_game import get_expected_value | |
| get_expected_value.cache_clear() | |
| ev = get_expected_value(dist, r, tier_map_example) | |
| assert len(ev) == 3 | |
| # Because it's zero-sum, the sum of EVs should be very close to 0: | |
| total_ev = sum(ev) | |
| assert nearly_equal(total_ev, 0.0), f"Sum of EVs is not near 0, got {total_ev}" | |
| # We won't do a full hand enumeration here, | |
| # but we at least confirm the DP runs and yields a plausible sum=0 result. | |
| def test_ev_multiple_losers_specific(tier_map_example): | |
| """ | |
| A more direct test for multiple losers via DP: | |
| N=3, X=2, distribution=(0,0,2) | |
| => sum=2 => leftover=0 => terminal => multiple zero => each zero pays tierValue(2)=2 => payoff=(-2,-2,4) | |
| Then we check that the DP logic returns the same final payoff if is_terminal is triggered. | |
| """ | |
| dist = (0,0,2) | |
| X = 2 | |
| r = X - sum(dist) # leftover=0 => terminal immediately | |
| from squid_game import get_expected_value | |
| get_expected_value.cache_clear() | |
| ev = get_expected_value(dist, r, tier_map_example) | |
| # With bracket => 2 => 2*1=2 => each zero pays 2 => 2 losers => winner gets 2*2=4 | |
| # payoff=( -2, -2, 4 ) | |
| assert nearly_equal(ev[0], -2) | |
| assert nearly_equal(ev[1], -2) | |
| assert nearly_equal(ev[2], 4) | |
| # sum = 0 | |
| assert nearly_equal(sum(ev), 0.0) | |
| def test_hypothetical_next_round_gain_with_penalty(): | |
| """ | |
| Test scenario: 3 players with distribution=(0,0,2) | |
| Expected values would be (-2,-2,4) as shown in test_ev_multiple_losers_specific | |
| So penalty should be 2 (abs of -2) | |
| For zero-squid players (0,1): | |
| - Getting 1 squid = tierValue(1) = 1 | |
| - Avoiding penalty share = 2/2 = 1 (penalty/zero_count) | |
| - Total gain = 2 | |
| For player with 2 squids: | |
| - Going from 2 to 3 = tierValue(3) - tierValue(2) = 3 - 2 = 1 | |
| """ | |
| tier_map = ( | |
| (0,0,0.0), | |
| (1,4,1.0), | |
| (5,6,3.0) | |
| ) | |
| dist = (0,0,2) | |
| penalty = 2 # abs of -2 from expected values | |
| gains = hypothetical_next_round_gain(dist, tier_map, penalty) | |
| # Check zero-squid players | |
| assert nearly_equal(gains[0], 2.0), f"Expected gain 2.0 for player 1, got {gains[0]}" | |
| assert nearly_equal(gains[1], 2.0), f"Expected gain 2.0 for player 2, got {gains[1]}" | |
| # Check non-zero player | |
| assert nearly_equal(gains[2], 1.0), f"Expected gain 1.0 for player 3, got {gains[2]}" | |
| def test_hypothetical_next_round_gain_no_zeros(): | |
| """ | |
| Test scenario: 2 players with distribution=(1,2) | |
| No zero-squid players, so penalty doesn't matter | |
| Player 1: going from 1 to 2 = tierValue(2) - tierValue(1) = 2 - 1 = 1 | |
| Player 2: going from 2 to 3 = tierValue(3) - tierValue(2) = 3 - 2 = 1 | |
| """ | |
| tier_map = ( | |
| (0,0,0.0), | |
| (1,4,1.0), | |
| (5,6,3.0) | |
| ) | |
| dist = (1,2) | |
| penalty = 0 # doesn't matter since no zero-squid players | |
| gains = hypothetical_next_round_gain(dist, tier_map, penalty) | |
| assert nearly_equal(gains[0], 1.0), f"Expected gain 1.0 for player 1, got {gains[0]}" | |
| assert nearly_equal(gains[1], 1.0), f"Expected gain 1.0 for player 2, got {gains[1]}" | |