-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGrandTable.py
More file actions
145 lines (113 loc) · 6 KB
/
GrandTable.py
File metadata and controls
145 lines (113 loc) · 6 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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# NOTE: This is a suggestion of how you could begin implementing the Grand Table,
# feel free to come up with your own way. You may change almost everything of this class,
# it just has to calculate the grand table on a matrix suite,
# given a list of strategies, restarts and rounds per restart.
import copy
import os
from statistics import mean
from typing import List
import MatrixSuite
from Game import Game
from Strategies import Strategy
class GrandTable:
"""Calculate the grand table on a MatrixSuite for the given strategies, restarts and rounds per restart.
Class attributes:
*matrix_suite*: The MatrixSuite that the game is played on,
should generate a new payoff matrix after each restart.
*row_strategies*: List of N instances of Strategy subclasses, which should be included in the Grand Table.
*col_strategies*: List of N instances of Strategy subclasses, which should be included in the Grand Table.
Either row or col strategies should be a deepcopy of strategies so they don't refer to the same instances.
Credit: Thanks Vincent and Wiebe for noticing that this is necessary.
*restarts*: Number of restarts that should occur during the calculation of the Grand Table.
*rounds*: Number of rounds that should be played for each restart.
*games*: Instance of Game for every combination of *strategies*, so N x N.
The outer list are row players and the inner list are column players.
*grand_table*: Same 2D list as *games* but only contains the resulting score.
"""
matrix_suite: MatrixSuite
row_strategies: List[Strategy]
col_strategies: List[Strategy]
restarts: int
rounds: int
games: List[List[Game]]
grand_table: List[List[float]]
def __init__(self, matrix_suite: MatrixSuite, strategies: List[Strategy],
nr_of_restarts: int, rounds_per_restart: int) -> None:
self.row_strategies = strategies
self.col_strategies = copy.deepcopy(strategies)
self.matrix_suite = matrix_suite
self.games = [[Game(copy.deepcopy(self.matrix_suite), row_player, col_player)
for col_player in self.col_strategies]
for row_player in self.row_strategies]
self.grand_table = [[0
for _ in self.col_strategies]
for _ in self.row_strategies]
self.restarts = nr_of_restarts
self.rounds = rounds_per_restart
def __repr__(self) -> str:
out: str = ""
# Determine format string with enough padding for the longest strategy name.
# padding = max(map(lambda s: len(s.name), self.strategies))
# You know what, to make it easier, just make everything 7 characters at most.
padding = "7"
# If you want to know how this works, look up Pythons format method on google.
name_format_row = '{:>' + padding + "." + padding + '}'
name_format_col = '{:^' + padding + "." + padding + '}'
score_format = '{:^' + padding + '.2f}'
# Create the table header
header = name_format_row.format("") + "||"
for strat in self.col_strategies:
header += name_format_col.format(strat.name) + "|"
header += "|" + name_format_col.format("MEAN") + "|"
hline = "=" * len(header)
out = out + hline + "\n" + header + "\n"
# Now create each row of the table
for i, row in enumerate(self.grand_table):
# Add the name of the strategy to the row.
out += name_format_row.format(self.row_strategies[i].name) + "||"
for score in row:
out += score_format.format(score) + "|"
out += "|" + score_format.format(mean(row)) + "|"
out += "\n"
# Add one last horizontal line
out = out + hline + "\n"
return out
# Additional method: save grand table to file in LaTeX notation
def to_latex(self, filename: str):
path = path = os.path.dirname(__file__) + "\\grand_tables\\" + filename + ".txt"
f = open(path, "w+")
f.write("\\begin{tabular}{|" + "c|" * (len(self.col_strategies)+2) + "}\n")
f.write("\\hline\n")
header = ""
for strat in self.col_strategies:
header += " & \\textit{" + strat.name + "}"
header += " & \\textbf{MEAN} \\\\ \\hline \n"
f.write(header)
for i, row in enumerate(self.grand_table):
# Add the name of the strategy to the row.
out = "\\textit{" + self.row_strategies[i].name + "}"
for score in row:
out += " & " + str(round(score, 2))
out += " & " + str(round(mean(row), 2)) + " \\\\ \\hline \n"
f.write(out)
f.write("\\end{tabular}")
f.close()
# Methods to play all games for the specified number of rounds and handle the restarts, can go here.
def play_games(self) -> None:
"""
Plays the game for a *restarts* number of time. At each restart, it updates the *grand_table*
At the end of each restart it averages the payoff of each strategy against each other strategy
with the relative payoffs of the previous restarts
"""
for row_strategy in range(0, len(self.row_strategies)):
for col_strategy in range(0, len(self.col_strategies)):
game = self.games[row_strategy][col_strategy]
print("Playing ", self.row_strategies[row_strategy], " against ", self.col_strategies[col_strategy])
for restart in range(0, self.restarts+1):
game.initialize(game.matrix_suite)
if restart > 0: # The first matrix is already initialised
game.matrix_suite.generate_new_payoff_matrix()
game.initialize(game.matrix_suite)
payoff = game.play(self.rounds)
self.grand_table[row_strategy][col_strategy] += payoff
self.grand_table[row_strategy][col_strategy] /= self.restarts