Last Page Build: 2025-06-28 01:31:16 +0100


The Floor

Ari
Published: 2024-12-14

Empirical solution to Fiddler released on December 14, 2024.

Simulation

import copy
from collections import Counter
import random

import pandas as pd
import numpy as np
from utils import get_neighbors, pretty_print_matrix

import pprint as pp
from pprint import pprint
from termcolor import colored

HEIGHT= 3
WIDTH = 3
A = np.arange(HEIGHT*WIDTH).reshape(HEIGHT, WIDTH)
player_names = [x for x in range(HEIGHT*WIDTH)]
players = {}
idx = 0
for i in range(A.shape[0]):
    for j in range(A.shape[1]):
        players[player_names[idx]] = [(i,j)]
        A[i,j] = player_names[idx]
        idx +=1
A_copy = copy.deepcopy(A)

def get_secondary_cands(A, primary_locs):

    candidates = {}
    for (x,y) in primary_locs:
        # These are the neighbours of A that have other people
        nbrs = [ A[i,j] for (i,j) in get_neighbors(HEIGHT,
                                                   WIDTH,
                                                   x,
                                                   y)
                 if A[i,j] != A[x,y]]

        for name in nbrs:
            candidates[name] = None


    return candidates

def pick_primary(players):

    res = key, val = random.choice(list(players.items()))
    return key, val

def single_round(r, A, players):

    primary_name, primary_locs = pick_primary(players)
    second_cands = get_secondary_cands(A, primary_locs)
    secondary_name, _ = random.choice(list(second_cands.items()))

    game = [primary_name, secondary_name]
    loser_idx = 1 if np.random.random() <= 1/2 else 0
    winner_idx = 1 - loser_idx
    winner = game[winner_idx]
    loser = game[loser_idx]

    loser_locs = players.pop(loser)
    players[winner] +=  loser_locs
    for (i,j) in loser_locs:
        A[i,j] = winner

    # print("Round: {}, Match {} vs {} | Winner - {}".format(r+1,
    #                                                        primary_name,
    #                                                        secondary_name,
    #                                                        winner))
    # print(A)
    # print('-'*80)
    # print()


def game(A, players, rounds=HEIGHT*WIDTH-1):

    for r in range(rounds):
        single_round(r, A, players)

    return A, players


def highlight(data):
    # Find the maximum value
    max_value = max(data.values())

    # Print dictionary with highlights
    print("{")
    for key, value in data.items():
        if value == max_value:
            print(f"  '{key}': {colored(value, 'red', attrs=['bold'])},")
        else:
            print(f"  '{key}': {value},")
    print("}")

# -----------------------------------
# A full game
# -----------------------------------

win_dist = []
num_games = 300000
for _ in range(num_games):
    board, rem_players = game(copy.deepcopy(A), copy.deepcopy(players))
    win_dist.append(board[0,0])
pretty_print_matrix(A)
print("Prob they don't win")
ranking = pd.Series({x: v/num_games for x,v in Counter(win_dist).items()})
print(1- ranking.sort_values())
# -----------------------------------


# -----------------------------------
# R  rounds
# -----------------------------------
pretty_print_matrix(A)
win_dist = {x: 0 for x in player_names}
num_games = 300000
# rounds_to_survive = HEIGHT*WIDTH-1 # R
rounds_to_survive = 1 # R 
for _ in range(num_games):
    board, rem_players = game(copy.deepcopy(A),
                              copy.deepcopy(players),
                              rounds=rounds_to_survive)
    # pretty_print_matrix(board)
    # print()
    for x in rem_players:
        win_dist[x] += 1
        
print("Empirical distribution of players that survive round {}".format(
    rounds_to_survive))
ranking = pd.Series(win_dist)/num_games
print(ranking.sort_values())