Last active
January 16, 2024 10:18
-
-
Save FrankRuns/72e38aaba7b4c66668e5959c22cb73aa to your computer and use it in GitHub Desktop.
Python sim for the card Uno
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"A pretty ugly notebook to simulate games of the card game Uno." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 26, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import random\n", | |
"import pandas as pd\n", | |
"import numpy as np\n", | |
"import math\n", | |
"from matplotlib import pyplot as plt" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Setup" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Create the deck" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def create_reds():\n", | |
" reds = []\n", | |
" for j in [1,2]:\n", | |
" for i in range(1,10):\n", | |
" reds.append('R_' + str(i)) \n", | |
" reds.append('R_0')\n", | |
" return reds\n", | |
"\n", | |
"def create_blues():\n", | |
" blues = []\n", | |
" for j in [1,2]:\n", | |
" for i in range(1,10):\n", | |
" blues.append('B_' + str(i)) \n", | |
" blues.append('B_0')\n", | |
" return blues\n", | |
"\n", | |
"def create_greens():\n", | |
" greens = []\n", | |
" for j in [1,2]:\n", | |
" for i in range(1,10):\n", | |
" greens.append('G_' + str(i)) \n", | |
" greens.append('G_0')\n", | |
" return greens\n", | |
"\n", | |
"def create_yellows():\n", | |
" yellows = []\n", | |
" for j in [1,2]:\n", | |
" for i in range(1,10):\n", | |
" yellows.append('Y_' + str(i)) \n", | |
" yellows.append('Y_0')\n", | |
" return yellows\n", | |
"\n", | |
"def create_draw_twos():\n", | |
" return ['R_dt', 'B_dt', 'Y_dt', 'G_dt', 'R_dt', 'B_dt', 'Y_dt', 'G_dt']\n", | |
"\n", | |
"def create_skips():\n", | |
" return ['R_sk', 'B_sk', 'Y_sk', 'G_sk', 'R_sk', 'B_sk', 'Y_sk', 'G_sk']\n", | |
"\n", | |
"def create_reverses():\n", | |
" return ['R_re', 'B_re', 'Y_re', 'G_re', 'R_re', 'B_re', 'Y_re', 'G_re']\n", | |
"\n", | |
"def create_wild_regs():\n", | |
" return ['w_r', 'w_r', 'w_r', 'w_r']\n", | |
"\n", | |
"def create_wild_draw_4s():\n", | |
" return ['w_d4', 'w_d4', 'w_d4', 'w_d4']\n", | |
"\n", | |
"def create_deck():\n", | |
" reds = create_reds() * 2\n", | |
" blues = create_blues() * 2\n", | |
" greens = create_greens() * 2\n", | |
" yellows = create_yellows() * 2\n", | |
" draw_twos = create_draw_twos() * 2\n", | |
" skips = create_skips() * 2\n", | |
" reverses = create_reverses() * 2\n", | |
" wilds_reg = create_wild_regs() * 2\n", | |
" wilds_draw = create_wild_draw_4s() * 2\n", | |
" deck = reds + blues + yellows + greens + draw_twos + skips + reverses + wilds_reg + wilds_draw\n", | |
" return deck" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"deck = create_deck()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"All good.\n" | |
] | |
} | |
], | |
"source": [ | |
"# does it work?\n", | |
"if len(deck) == 108 * 2:\n", | |
" print('All good.')\n", | |
"else: \n", | |
" print('SOMETHING IS WRONG.')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Initialize the game giving each player cards (4-players hard coded)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def initialize_hands(deck):\n", | |
" \n", | |
" players = {\n", | |
" 'player_1':[],\n", | |
" 'player_2':[],\n", | |
" 'player_3':[],\n", | |
" 'player_4':[]\n", | |
" }\n", | |
" \n", | |
" import random\n", | |
"\n", | |
" for i in range(1, 8):\n", | |
" for key in players:\n", | |
" pick = deck.pop(random.randint(0,len(deck)-1))\n", | |
" players[key].append(pick)\n", | |
" \n", | |
" return players" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"players = initialize_hands(deck)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"All good.\n", | |
"All good.\n", | |
"All good.\n", | |
"All good.\n" | |
] | |
} | |
], | |
"source": [ | |
"# does it work?\n", | |
"for key in players:\n", | |
" if len(players[key]) == 7:\n", | |
" print('All good.')\n", | |
" else:\n", | |
" print('SOMETHING IS WRONG.')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Create order of play (both forward and backwards)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"['player_1', 'player_2', 'player_3', 'player_4']\n" | |
] | |
} | |
], | |
"source": [ | |
"forward_order = list(players.keys())\n", | |
"print(forward_order)\n", | |
"reverse_order = forward_order[::-1]" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"All good.\n" | |
] | |
} | |
], | |
"source": [ | |
"# does it work?\n", | |
"if forward_order[0] == reverse_order[3]:\n", | |
" print('All good.')\n", | |
"else:\n", | |
" print('SOMETHING IS WRONG.')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Choose the initial card" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def choose_initial_card(deck):\n", | |
" initial_card = deck.pop(random.randint(0,len(deck)-1))\n", | |
" if initial_card not in create_draw_twos() + create_skips() + create_reverses() + create_wild_regs() + create_wild_draw_4s():\n", | |
" return initial_card\n", | |
" else:\n", | |
" return choose_initial_card(deck)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"initial_card = choose_initial_card(deck)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 14, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"All good.\n" | |
] | |
} | |
], | |
"source": [ | |
"# does it work? initial card shouldn't be action card (according to rule book)...\n", | |
"if initial_card.split('_')[0] in ['R','G','B','Y'] and initial_card.split('_')[1] in ['0','1','2','3','4','5','6','7','8','9']:\n", | |
" print('All good.')\n", | |
"else:\n", | |
" print('SOMETHING IS WRONG.')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Define player's action based on card at play and the players hand" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def player_action(card_at_play, player, action_color, deck):\n", | |
" '''\n", | |
" card_at_play (str): current card to be played\n", | |
" player (str): player at turn\n", | |
" '''\n", | |
"\n", | |
" temp_options = []\n", | |
" \n", | |
" # if card is not action card\n", | |
" if card_at_play in create_reds() + create_blues() + create_greens() + create_yellows():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == card_at_play.split('_')[0] or card.split('_')[1] == card_at_play.split('_')[1] or card.split('_')[0] == 'w':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # if card is action card\n", | |
" \n", | |
" # if card is wild card (regular and draw 4)\n", | |
" if card_at_play in create_wild_regs() or card_at_play in create_wild_draw_4s():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == action_color or card.split('_')[0] == 'w':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # if card is reverse\n", | |
" if card_at_play in create_reverses():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == card_at_play.split('_')[0] or card.split('_')[0] == 'w' or card.split('_')[1] == 're':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # if card is skip\n", | |
" if card_at_play in create_skips():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == card_at_play.split('_')[0] or card.split('_')[0] == 'w' or card.split('_')[1] == 'sk':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # if card is draw 2\n", | |
" if card_at_play in create_draw_twos():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == card_at_play.split('_')[0] or card.split('_')[0] == 'w' or card.split('_')[1] == 'dt':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # determine move, either draw or play\n", | |
" if len(temp_options) == 0:\n", | |
" # print('no cards can be played, draw card from deck.')\n", | |
" new_card = deck.pop(random.randint(0,len(deck)-1))\n", | |
" players[player].append(new_card)\n", | |
" pick = card_at_play\n", | |
" card_reset = 0\n", | |
" else:\n", | |
" # print('cards can be played, choose randomly.')\n", | |
" pick = random.choice(temp_options)\n", | |
" players[player].remove(pick)\n", | |
" card_reset = 1\n", | |
" \n", | |
" return {'pick':pick, 'card_reset':card_reset}\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Potential strategy action: what if player always plays action card if available?" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 16, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def player_strategy(card_at_play, player, action_color, deck):\n", | |
" '''\n", | |
" card_at_play (str): current card to be played\n", | |
" player (str): player at turn\n", | |
" '''\n", | |
"\n", | |
" temp_options = []\n", | |
" \n", | |
" # if card is not action card\n", | |
" if card_at_play in create_reds() + create_blues() + create_greens() + create_yellows():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == card_at_play.split('_')[0] or card.split('_')[1] == card_at_play.split('_')[1] or card.split('_')[0] == 'w':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # if card is action card\n", | |
" \n", | |
" # if card is wild card (regular and draw 4)\n", | |
" if card_at_play in create_wild_regs() or card_at_play in create_wild_draw_4s():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == action_color or card.split('_')[0] == 'w':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # if card is reverse\n", | |
" if card_at_play in create_reverses():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == card_at_play.split('_')[0] or card.split('_')[0] == 'w' or card.split('_')[1] == 're':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # if card is skip\n", | |
" if card_at_play in create_skips():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == card_at_play.split('_')[0] or card.split('_')[0] == 'w' or card.split('_')[1] == 'sk':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # if card is draw 2\n", | |
" if card_at_play in create_draw_twos():\n", | |
" for card in players[player]:\n", | |
" if card.split('_')[0] == card_at_play.split('_')[0] or card.split('_')[0] == 'w' or card.split('_')[1] == 'dt':\n", | |
" temp_options.append(card) \n", | |
" \n", | |
" # determine move, either draw or play\n", | |
" if len(temp_options) == 0:\n", | |
" # print('no cards can be played, draw card from deck.')\n", | |
" new_card = deck.pop(random.randint(0,len(deck)-1))\n", | |
" players[player].append(new_card)\n", | |
" pick = card_at_play\n", | |
" card_reset = 0\n", | |
" else:\n", | |
" # print('cards can be played, choose randomly.')\n", | |
" action_cards = create_wild_regs() + create_wild_draw_4s() + create_reverses() + create_skips() + create_draw_twos()\n", | |
" action_options = [x for x in temp_options if x in action_cards]\n", | |
" if len(action_options) > 0:\n", | |
" pick = random.choice(action_options)\n", | |
" else:\n", | |
" pick = random.choice(temp_options)\n", | |
" players[player].remove(pick)\n", | |
" card_reset = 1\n", | |
" \n", | |
" return {'pick':pick, 'card_reset':card_reset}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"{'player_1': ['w_d4', 'B_6', 'w_r', 'G_8', 'G_3', 'R_re', 'w_d4'],\n", | |
" 'player_2': ['G_re', 'R_sk', 'B_6', 'R_6', 'G_sk', 'B_2', 'w_r'],\n", | |
" 'player_3': ['G_8', 'B_6', 'B_sk', 'G_3', 'G_6', 'B_re', 'R_1'],\n", | |
" 'player_4': ['G_3', 'B_3', 'Y_5', 'w_d4', 'R_3', 'Y_re', 'Y_7']}" | |
] | |
}, | |
"execution_count": 17, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# check players hands\n", | |
"players" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Based on card played, identify next player" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# I need a function that determines who is playing\n", | |
"def identify_player(current_order, current_player, current_card, card_reset):\n", | |
"\n", | |
" if current_order == 'f':\n", | |
" if current_card.split('_')[1] == 'sk' and card_reset == 1:\n", | |
" if current_player == 'player_1':\n", | |
" next_player = 'player_3'\n", | |
" elif current_player == 'player_2':\n", | |
" next_player = 'player_4'\n", | |
" elif current_player == 'player_3':\n", | |
" next_player = 'player_1'\n", | |
" else:\n", | |
" next_player = 'player_2'\n", | |
" else:\n", | |
" next_player = forward_order.index(current_player) + 1\n", | |
" if next_player > len(forward_order) - 1:\n", | |
" next_player = forward_order[0]\n", | |
" else:\n", | |
" next_player = forward_order[next_player] \n", | |
"\n", | |
" else: \n", | |
" if current_card.split('_')[1] == 'sk' and card_reset == 1:\n", | |
" if current_player == 'player_1':\n", | |
" next_player = 'player_3'\n", | |
" elif current_player == 'player_2':\n", | |
" next_player = 'player_4'\n", | |
" elif current_player == 'player_3':\n", | |
" next_player = 'player_1'\n", | |
" else:\n", | |
" next_player = 'player_2'\n", | |
" else:\n", | |
" next_player = reverse_order.index(current_player) + 1\n", | |
" if next_player > len(reverse_order) - 1:\n", | |
" next_player = reverse_order[0]\n", | |
" else:\n", | |
" next_player = reverse_order[next_player]\n", | |
" \n", | |
" # print(f'The next player is {next_player}.')\n", | |
" return next_player\n", | |
" " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 19, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"All good.\n" | |
] | |
} | |
], | |
"source": [ | |
"# does it work?\n", | |
"if identify_player('f', 'player_4', 'G_dt', 0) == 'player_1':\n", | |
" print('All good.')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Based on card playerd, identify if order of play has switched" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 21, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def identify_order(current_card, card_reset, current_order):\n", | |
" if card_reset == 0:\n", | |
" current_order = current_order\n", | |
" else:\n", | |
" if current_card.split('_')[1] == 're':\n", | |
" if current_order == 'f':\n", | |
" current_order = 'r'\n", | |
" # print('The order has been reveresed from f to r')\n", | |
" else:\n", | |
" current_order = 'f'\n", | |
" # print('The order has been reveresed from r to f')\n", | |
" \n", | |
" return current_order" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### When 'draw' card is played, next player must draw cards" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 22, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def execute_card_draw(how_many, current_order, current_player, deck):\n", | |
"\n", | |
" '''\n", | |
" function to figure out which player draws and how many cards to draw\n", | |
" '''\n", | |
" \n", | |
" if current_order == 'f':\n", | |
" drawing_player = forward_order.index(current_player) + 1\n", | |
" if drawing_player > len(forward_order) - 1:\n", | |
" drawing_player = forward_order[0]\n", | |
" for i in range(1,how_many+1):\n", | |
" players[drawing_player].append(deck.pop(random.randint(0,len(deck)-1)))\n", | |
" else:\n", | |
" drawing_player = forward_order[drawing_player]\n", | |
" for i in range(1,how_many+1):\n", | |
" players[drawing_player].append(deck.pop(random.randint(0,len(deck)-1)))\n", | |
" else:\n", | |
" drawing_player = reverse_order.index(current_player) + 1\n", | |
" if drawing_player > len(reverse_order) - 1:\n", | |
" drawing_player = reverse_order[0]\n", | |
" for i in range(1,how_many+1):\n", | |
" players[drawing_player].append(deck.pop(random.randint(0,len(deck)-1)))\n", | |
" else:\n", | |
" drawing_player = reverse_order[drawing_player]\n", | |
" for i in range(1,how_many+1):\n", | |
" players[drawing_player].append(deck.pop(random.randint(0,len(deck)-1)))\n", | |
" \n", | |
" return [drawing_player, how_many]\n", | |
" " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 23, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"All good.\n" | |
] | |
} | |
], | |
"source": [ | |
"# does it work?\n", | |
"if execute_card_draw(4, 'r', 'player_4', deck)[0] == 'player_3':\n", | |
" print('All good.')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Run Simulations" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Single game (for testing)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 24, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# # start by doing 100 runs\n", | |
"\n", | |
"# print('------------------------------------ INITIALIZE GAME')\n", | |
"\n", | |
"# # initialize deck\n", | |
"# deck = create_deck()\n", | |
"\n", | |
"# # check for a full deck\n", | |
"# # print(deck)\n", | |
"\n", | |
"# # initialize player's hands\n", | |
"# players = initialize_hands(deck)\n", | |
"\n", | |
"# # pick first card\n", | |
"# current_card = choose_initial_card(deck)\n", | |
"# print('Initial card = ', current_card)\n", | |
"\n", | |
"# # define first player\n", | |
"# current_player = 'player_1'\n", | |
"# current_order = 'f' # for forward\n", | |
"# print('Initial player = ', current_player)\n", | |
"# print('Initial order = ', current_order)\n", | |
"\n", | |
"# # initialize wild color\n", | |
"# action_color = None\n", | |
"\n", | |
"# # execute first player action\n", | |
"\n", | |
"# print('------------------------------------ EXECUTE 1st PLAY!')\n", | |
"\n", | |
"# current_card = player_action(current_card, current_player, action_color, deck)\n", | |
"# print(f'The first card that is played is {current_card}.')\n", | |
"# current_order = identify_order(current_card['pick'], current_card['card_reset'], current_order)\n", | |
"# current_player = identify_player(current_order, current_player, current_card['pick'], current_card['card_reset'])\n", | |
"\n", | |
"# print('------------------------------------ GAME ON!')\n", | |
"\n", | |
"# # game on! \n", | |
"# for i in range(1,200):\n", | |
" \n", | |
"# # current player determines an action\n", | |
"# current_card = player_action(current_card['pick'], current_player, action_color, deck)\n", | |
"# print(f'The card that is played is {current_card}.')\n", | |
" \n", | |
"# # determine is there is a winner, else play on\n", | |
"# if len(players[current_player]) == 0:\n", | |
"# print(f'Game over. Player, {current_player} wins!')\n", | |
"# break\n", | |
" \n", | |
"# print('Game continues.')\n", | |
" \n", | |
"# # what if the current card is regular wild?\n", | |
"# if current_card['pick'].split('_')[0] == 'w':\n", | |
"# action_color = random.choice(['B','Y','R','G'])\n", | |
"# else:\n", | |
"# action_color = None\n", | |
" \n", | |
"# # what if the current card is draw 4 wild?\n", | |
"# if current_card['pick'].split('_')[1] == 'd4':\n", | |
"# execute_card_draw(4, current_order, current_player, deck)\n", | |
"\n", | |
"# # what if the current card is draw 2? \n", | |
"# if current_card['pick'].split('_')[1] == 'dt':\n", | |
"# execute_card_draw(4, current_order, current_player, deck)\n", | |
" \n", | |
"# # based on card played (or not played), determine who is next (includes when current card is reverse)\n", | |
"# current_order = identify_order(current_card['pick'], current_card['card_reset'], current_order)\n", | |
" \n", | |
"# # based on play order, determine the next player \n", | |
"# current_player = identify_player(current_order, current_player, current_card['pick'], current_card['card_reset'])\n", | |
" \n", | |
"# if len(deck) < 1:\n", | |
"# print('Game is a draw - out of cards.')\n", | |
"# break\n", | |
" \n", | |
"# print(f'The current order after round {i} is ', current_order)\n", | |
"# print(f'The player hands after round {i} is ',players)\n", | |
"# print('---------------')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Many Games" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 25, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Done\n" | |
] | |
} | |
], | |
"source": [ | |
"turns_1 = [] # will count how many turns or how many draw 2's this player gets\n", | |
"turns_2 = []\n", | |
"turns_3 = []\n", | |
"turns_4 = []\n", | |
"winners = [] # will store the winner of the game\n", | |
"round_counts = [] # will count the number of turns in a game\n", | |
"\n", | |
"for j in range(1, 50000):\n", | |
"\n", | |
" t1 = 0\n", | |
" t2 = 0\n", | |
" t3 = 0\n", | |
" t4 = 0\n", | |
" winner = None\n", | |
"\n", | |
" # initialize deck\n", | |
" sim_deck = create_deck()\n", | |
"\n", | |
" # initialize player's hands\n", | |
" players = initialize_hands(sim_deck)\n", | |
"\n", | |
" # pick first card\n", | |
" current_card = choose_initial_card(sim_deck)\n", | |
" \n", | |
" # define first player\n", | |
" current_player = 'player_1'\n", | |
" current_order = 'f' # for forward\n", | |
"\n", | |
" # initialize wild color\n", | |
" action_color = None\n", | |
"\n", | |
" # execute first player action\n", | |
"\n", | |
" current_card = player_action(current_card, current_player, action_color, sim_deck)\n", | |
" \n", | |
" if current_card['pick'].split('_')[0] == 'w':\n", | |
" action_color = random.choice(['B','Y','R','G'])\n", | |
" else:\n", | |
" action_color = None\n", | |
" # what if the current card is draw 4 wild?\n", | |
" if current_card['pick'].split('_')[1] == 'd4':\n", | |
" execute_card_draw(4, current_order, current_player, sim_deck)\n", | |
" # what if the current card is draw 2? \n", | |
" if current_card['pick'].split('_')[1] == 'dt':\n", | |
" execute_card_draw(2, current_order, current_player, sim_deck) \n", | |
"\n", | |
" current_order = identify_order(current_card['pick'], current_card['card_reset'], current_order)\n", | |
" current_player = identify_player(current_order, current_player, current_card['pick'], current_card['card_reset'])\n", | |
"\n", | |
" # game on! \n", | |
" count = 0\n", | |
" for i in range(1,188):\n", | |
"\n", | |
" # current player determines an action\n", | |
" current_card = player_action(current_card['pick'], current_player, action_color, sim_deck)\n", | |
"# if current_player == 'player_4':\n", | |
"# current_card = player_strategy(current_card['pick'], current_player, action_color, sim_deck)\n", | |
"# else:\n", | |
"# current_card = player_action(current_card['pick'], current_player, action_color, sim_deck)\n", | |
"\n", | |
" if current_player == 'player_1' and current_card['pick'].split('_')[1] in ['dt', 'd4']:\n", | |
" t1 += 1\n", | |
" if current_player == 'player_2' and current_card['pick'].split('_')[1] in ['dt', 'd4']:\n", | |
" t2 += 1\n", | |
" if current_player == 'player_3' and current_card['pick'].split('_')[1] in ['dt', 'd4']:\n", | |
" t3 += 1\n", | |
" if current_player == 'player_4' and current_card['pick'].split('_')[1] in ['dt', 'd4']:\n", | |
" t4 += 1\n", | |
" \n", | |
" # determine is there is a winner, else play on\n", | |
" if len(players[current_player]) == 0:\n", | |
" winner = current_player\n", | |
" winners.append(winner)\n", | |
" break\n", | |
"\n", | |
" if len(sim_deck) < 1:\n", | |
" print('Game is a draw - out of cards.')\n", | |
" winner = 'draw'\n", | |
" break\n", | |
" \n", | |
" # what if the current card is regular wild?\n", | |
" if current_card['pick'].split('_')[0] == 'w':\n", | |
" action_color = random.choice(['B','Y','R','G'])\n", | |
" else:\n", | |
" action_color = None\n", | |
"\n", | |
" # what if the current card is draw 4 wild?\n", | |
" if current_card['pick'].split('_')[1] == 'd4':\n", | |
" execute_card_draw(4, current_order, current_player, sim_deck)\n", | |
"\n", | |
" # what if the current card is draw 2? \n", | |
" if current_card['pick'].split('_')[1] == 'dt':\n", | |
" execute_card_draw(2, current_order, current_player, sim_deck)\n", | |
"\n", | |
" # based on card played (or not played), determine who is next (includes when current card is reverse)\n", | |
" current_order = identify_order(current_card['pick'], current_card['card_reset'], current_order)\n", | |
"\n", | |
" # based on play order, determine the next player \n", | |
" current_player = identify_player(current_order, current_player, current_card['pick'], current_card['card_reset'])\n", | |
" \n", | |
" count += 1\n", | |
" \n", | |
" round_counts.append(count)\n", | |
" turns_1.append(t1)\n", | |
" turns_2.append(t2)\n", | |
" turns_3.append(t3)\n", | |
" turns_4.append(t4) \n", | |
" \n", | |
"print('Done')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### Analyzing and visualizing many games results" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 27, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"49519\n", | |
"Counter({'player_1': 13364, 'player_2': 12271, 'player_3': 11987, 'player_4': 11897})\n", | |
"[('player_2', 24.78038732607686), ('player_4', 24.02512167046992), ('player_1', 26.98762091318484), ('player_3', 24.20687009026838)]\n" | |
] | |
} | |
], | |
"source": [ | |
"# how many wins does each player have?\n", | |
"from collections import Counter\n", | |
"print(len(winners))\n", | |
"types_counts=Counter(winners)\n", | |
"print(types_counts)\n", | |
"print([(i, types_counts[i] / len(winners) * 100.0) for i in types_counts])" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 28, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"<AxesSubplot:title={'center':'Win Dist Over 50k Games'}, xlabel='Player'>" | |
] | |
}, | |
"execution_count": 28, | |
"metadata": {}, | |
"output_type": "execute_result" | |
}, | |
{ | |
"data": { | |
"image/png": "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Fy9ezFVXXcXRRx/NSSed1OrtRgSnnHIK06ZNY+7cuQAsXbqUdevWccghh1T2Ysq455576N27NxMnTixkfd5DMLNd1qRJk975hL18+XJGjRpFnz59eOmll9iyZQsrVqzgiCOOYPbs2VxwwQUAnH322Xz1q19l4sSJvP/97+fmm2/eYb133303u+++O+eee+47tTFjxvDhD3+YiODiiy9m1KhRHHbYYcybNw/I3txPPPHEd5a/4IILmD17NgBDhw7lsssu48gjj+Swww7jqaeeYtWqVfz4xz/myiuvZMyYMdx/f9mfHW8T7yGY2S7rgAMOoHv37qxevZrFixdzzDHH8Nxzz7FkyRL69evH6NGjed/7dvxZ7rVr17Jo0SKeeuopTjrpJE499dT3zH/iiScYO3Zs2W3ecsstLF26lMcff5yNGzdy1FFHceyxx7bY14EDB/Loo48yc+ZMfvCDH3Dttddy7rnn0rt3by666KLKBqCE9xDMbJfWuJfQGAjHHHPMO8+bOhRz8skns9tuuzFixAjWrVvXpu0tWrSIM844g27durHvvvvykY98hIcffrjFdp/97GcBGDt2LKtWrWrTNlvLgWBmu7SJEyeyePFili1bxqhRo5gwYQJLlixh8eLFTJo0qWybHj16vDNd7su9I0eO5JFHHinbtqkvA3fv3p3t27e/87z0ktHGbXbr1o2tW7c2/6Iq5EAws13apEmTuP322+nfvz/dunWjf//+vPzyyyxZsoRjjjmmonUed9xxbNmyhZ/+9Kfv1B5++GHuvfdejj32WObNm8e2bdvYsGED9913H+PHj+eggw7iySefZMuWLbzyyissXLiwxe306dOHzZs3V9THchwIZrZLO+yww9i4cSMTJkx4T61fv34MHDiwmZZNk8Stt97KnXfeycEHH8zIkSO5/PLLOeCAAzjllFMYPXo0hx9+OMcddxzf//732W+//RgyZAinn346o0eP5swzz+SII45ocTuf+cxnuPXWWws7qex7GeX4slOzzrVixQo+9KEPVbsbXVa58W3uXkbeQzAzM8CBYGZmiQPBzMwAB4KZVVmtnsfc2VUyrg4EM6uanj17smnTJodCwRp/D6Fnz55taudbV5hZ1dTV1dHQ0MCGDRuq3ZUup/EX09rCgWBmVbP77ru36Re9rGP5kJGZmQEOBDMzS3zIyDqMv/lt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\n", | |
"text/plain": [ | |
"<Figure size 432x288 with 1 Axes>" | |
] | |
}, | |
"metadata": { | |
"needs_background": "light" | |
}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"# visualize player wins\n", | |
"data = pd.DataFrame.from_dict(types_counts, orient='index').reset_index()\n", | |
"data = data.sort_values(by='index')\n", | |
"data.columns = ['Player', 'Win Count']\n", | |
"data.plot.bar(x='Player', y='Win Count', title='Win Dist Over 50k Games')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 37, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"1.4273885477709554\n", | |
"1.5499509990199805\n", | |
"1.5303306066121323\n", | |
"1.5055901118022361\n", | |
"-----\n", | |
"Avg. of not player_1:\n", | |
"1.5286239058114497\n" | |
] | |
} | |
], | |
"source": [ | |
"# this is the average of how many times per game a player was hit with a draw 2 or draw 4 card...\n", | |
"import numpy as np\n", | |
"print(np.mean(turns_1))\n", | |
"print(np.mean(turns_2))\n", | |
"print(np.mean(turns_3))\n", | |
"print(np.mean(turns_4))\n", | |
"print('-----')\n", | |
"print('Avg. of not player_1:')\n", | |
"print((np.mean(turns_2) + np.mean(turns_3) + np.mean(turns_4)) / 3)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 38, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"<div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>Player</th>\n", | |
" <th>Win Count</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>player_1</td>\n", | |
" <td>13364</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>player_2</td>\n", | |
" <td>12271</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>player_3</td>\n", | |
" <td>11987</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>player_4</td>\n", | |
" <td>11897</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>" | |
], | |
"text/plain": [ | |
" Player Win Count\n", | |
"2 player_1 13364\n", | |
"0 player_2 12271\n", | |
"3 player_3 11987\n", | |
"1 player_4 11897" | |
] | |
}, | |
"execution_count": 38, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"data" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 40, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"player_1 does this % better over time than other players:\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/plain": [ | |
"0.10889226939565765" | |
] | |
}, | |
"execution_count": 40, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"print('player_1 does this % better over time than other players:')\n", | |
"(13364 - np.mean([12271, 11987, 11897])) / np.mean([12271, 11987, 11897])" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 41, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"63.723434468689376\n", | |
"16\n", | |
"187\n" | |
] | |
} | |
], | |
"source": [ | |
"# what is the avg, min, max number of turns in a game?\n", | |
"print(np.mean(round_counts))\n", | |
"print(np.min(round_counts))\n", | |
"print(np.max(round_counts))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 42, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Text(0.5, 1.0, 'Dist of Game Duration over 50k Games')" | |
] | |
}, | |
"execution_count": 42, | |
"metadata": {}, | |
"output_type": "execute_result" | |
}, | |
{ | |
"data": { | |
"image/png": "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\n", | |
"text/plain": [ | |
"<Figure size 432x288 with 1 Axes>" | |
] | |
}, | |
"metadata": { | |
"needs_background": "light" | |
}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"# create histogram for number of turns in a game\n", | |
"bins = np.linspace(math.ceil(min(round_counts)), \n", | |
" math.floor(max(round_counts)),\n", | |
" 20) # fixed number of bins\n", | |
"\n", | |
"plt.hist(round_counts, bins=bins, alpha=0.5)\n", | |
"plt.xlabel(\"Number of Turns in Game\")\n", | |
"plt.ylabel(\"Count of Games\")\n", | |
"plt.title(\"Dist of Game Duration over 50k Games\")" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.8.5" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 4 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment