-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrisk.py
More file actions
99 lines (81 loc) · 4.72 KB
/
Copy pathrisk.py
File metadata and controls
99 lines (81 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# This program was created by Julian Garratt (2020)
from random import randint
import sys
import statistics
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
import heapq
import argparse
def generateRoll():
return randint(1,6)
def friendlyWon(friendly_dice_roll, enemy_dice_roll):
if (friendly_dice_roll <= enemy_dice_roll): return False
else: return True
class game:
def __init__(self, friendly_soldiers, enemy_soldiers):
self.friendly_soldiers = friendly_soldiers
self.enemy_soldiers = enemy_soldiers
self.round = 0
def no_friendly_dice(self): # get maximum number of friendly dice
if self.friendly_soldiers >= 3: return 3 # dice roll is equal to 3 if they have more than 3 soldiers
else: return self.friendly_soldiers-1 # else return dice roll as less than 3 (greater than 0) Note that its -1 as friendly must have at least 1 soldier
def no_enemy_dice(self): # get maximum number of enemey dice
if self.enemy_soldiers >= 2: return 2 # max that an enemy can roll is 2
else: return 1
def get_rolls(self, number_of_dice):
dice_rolls = []
for _ in range(0,number_of_dice): # get random rolls for each dice that the player has
dice_rolls.append(generateRoll())
return dice_rolls
def process_battle(self, friendly_rolls, enemy_rolls): # get the maximum number of friendly soldiers lost given friendly rolls and enemy rolls
battle_size = min(len(friendly_rolls), len(enemy_rolls)) # battle size determines how many dice can both players use (i.e. if enemy only has 2 dice then only best 2 friendly dice can be used)
best_enemy_rolls = heapq.nlargest(battle_size, enemy_rolls) # get highest N enemy rolls
best_friendly_rolls = heapq.nlargest(battle_size, friendly_rolls) # get highest N friendly rolls
for i in range(0,battle_size): # check the highest enemy roll and friendly roll, then 2nd highest, 3rd....
if friendlyWon(best_friendly_rolls[i], best_enemy_rolls[i]) is True: self.enemy_soldiers -= 1 # if friendly one then enemy loses a soldier
else: self.friendly_soldiers -= 1 # if enemy one friendly loses a soldier
def playGame(self):
# Initialise record of soldiers to return
friendly_soldiers = []
rounds = []
rounds.append(self.round)
friendly_soldiers.append(self.friendly_soldiers)
while (self.friendly_soldiers > 1 and self.enemy_soldiers > 0): ## while the game is playing do
friendly_rolls = self.get_rolls(self.no_friendly_dice())
enemy_rolls = self.get_rolls(self.no_enemy_dice())
self.process_battle(friendly_rolls, enemy_rolls)
self.round += 1
friendly_soldiers.append(self.friendly_soldiers)
rounds.append(self.round)
print("Round = %d | Friendly Soldiers = %d Enemy Soldiers = %d" % (self.round, self.friendly_soldiers, self.enemy_soldiers))
if self.friendly_soldiers == 1: return False # friendly lost (friendly cannot get to 0 when attacking)
else: return True # friendly won
if __name__ == "__main__":
parser = argparse.ArgumentParser(prog="risk",
description="Simulates long run battle phase outcomes for the game Risk and prints a chart.")
parser.add_argument("-n",
default=1000,
help="Number of simulations to run. Anywhere from 1000-10000 is a good number. The larger this number, the closer the values approximate the true win rate",
type=int)
args = parser.parse_args()
friendly_soldiers_list = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
enemy_soldiers_list = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
results = [[0 for i in range(len(friendly_soldiers_list)+1)] for j in range(len(enemy_soldiers_list)+1)]
for _ in range(0, args.n): # this controls how long the simulation will run for
for friendly_soldiers in friendly_soldiers_list:
for enemy_soldiers in enemy_soldiers_list:
new_game = game(friendly_soldiers,enemy_soldiers)
result = new_game.playGame()
results[enemy_soldiers][friendly_soldiers] += result
plt.pcolormesh(results, cmap = 'seismic')
plt.xlim(1,len(friendly_soldiers_list)+1)
plt.ylim(1,len(enemy_soldiers_list)+1)
plt.xticks(np.linspace(1,16,16)) # you can customise the x/y ticks but it's not really recommended
plt.yticks(np.linspace(1,16,16))
plt.xlabel("Friendly Armies")
plt.ylabel("Enemy Armies")
plt.title("Proportion of Friendly Wins")
cbar = plt.colorbar(ticks = [0,(args.n/2),args.n])
cbar.set_ticklabels(['low','medium','high'])
plt.show()