Skip to content
Snippets Groups Projects
Unverified Commit c8587538 authored by Gabriel Santamaria's avatar Gabriel Santamaria
Browse files

Adding first statistics

parent 19ec737b
No related branches found
No related tags found
No related merge requests found
......@@ -51,7 +51,7 @@ def index(ply: Player):
# The ultimate goal is to find the perfect couple
# that will make MCTS win most of the time.
ucb = [UCB.ucb, UCB.ucb_tuned]
weights = np.arange(0, 10, 1)
weights = np.arange(0.7, 10, 1)
levels = np.arange(3, 10, 1)
......
......@@ -139,8 +139,29 @@ Pour calculer les coups à étendre, nous utilisons aussi des heuristiques basé
De même, nous avons introduit un *score de blocage* qui reflète la capacité d'une action d'un joueur à réduire le nombre de coups légaux pour le tour suivant du joueur ennemie.
Ces heuristiques sont inspirées des travaux présentés dans [4] et [5], notamment sur la détermination des noeuds à étendre, à sélectionner ainsi que sur le déroulement des simulations.
Pour plus de détails sur le calcul de ces scores, voir le fichier source [rules.py](../game/rules.py).
Nous avons cependant ajouté un calcul des récompenses intelligent pour attirer l'exploration de l'arbre vers les noeuds qui maximisent le score de mobilité de l'adversaire tout en minimisant le sien.
Nous désignerons par $PM(g)$, $EM(g)$, et $EB(g)$ les scores de mobilité du joueur, de l'ennemi ainsi que le score de blocage de l'ennemi pour une grille donnée $g$.
Alors, la récompense $R$ issue d'une simulation dont la grille résultante est $g$ est la suivante:
$$
R(g, s) = \begin{cases}
EM(g) - PM(g) - EB(g) & \text{si } s = 0 \\
-PM(g) & \text{si } s = -1 \text{ et } PM(g) > 0 \\
-\alpha & \text{si } s = -1 \text{ et } PM(g) = 0 \\
EM(g) & \text{si } s = 1 \text{ et } EM(g) > 0 \\
\beta & \text{si } s = 1 \text{ et } EM(g) = 0 \\
\end{cases}
$$
Où $\alpha$ et $\beta$ sont des constantes que nous avons fixé expérimentalement à $\alpha = \beta = 8$.
## Pour le jeu Gopher
*Todo*
......@@ -159,6 +180,23 @@ Les paramètres que nous avons fait varier sont:
- Le poids d'exploration `C` de l'UCB1
- Le niveau des simulations de minimax à l'intérieur des simulations du MCTS comme décrit dans [5] pour voir l'impact du niveau des minimax sur les performances de l'algorithme.
# Comparaison avec *Minimax*
Nous avons comparé les performances de notre algorithme avec celles de l'algorithme *Minimax* avec coupures Alpha-Beta.
## Pour Dodo
Les statistiques ont été réalisées sur des grilles de taille $4 \times 4$ et sur 40 parties (20 en tant que joueur 1, 20 en tant que joueur 2) pour chaque algorithme. L'algorithme MCTS est toujours le même, avec le même nombre de simulations (à savoir $512$).
| Minimax Depth | % Win (Minimax) | % Win (MCTS) | Temps / coup (Minimax) | Temps / coup (MCTS) |
| ------------- | --------------- | ------------ | ---------------------- | ------------------- |
| 10 | 2.50% | 97.50% | 0.03s | 1.76 |
| 15 | | | | |
| 20 | | | | |
| 25 | | | | |
| 30 | | | | |
# Références
- [1] https://gist.github.com/qpwo/c538c6f73727e254fdc7fab81024f6e1
......
doc/videos/mcts_alpha_dodo.gif

79.8 KiB | W: | H:

doc/videos/mcts_alpha_dodo.gif

122 KiB | W: | H:

doc/videos/mcts_alpha_dodo.gif
doc/videos/mcts_alpha_dodo.gif
doc/videos/mcts_alpha_dodo.gif
doc/videos/mcts_alpha_dodo.gif
  • 2-up
  • Swipe
  • Onion skin
doc/videos/mcts_alpha_dodo_30.gif

91.8 KiB

......@@ -8,8 +8,7 @@ from tqdm import tqdm
from api import State, Player, Time, Environment, Action
from hexgrid.grid import HexGrid
from game.rules import Rules, Dodo
from game.strategy import MCTSStrategy, StrategyAlphaBeta
from game.helpers.mcts import UCB
from game.strategy import Strategy, MCTSStrategy, StrategyAlphaBeta
from game.utils import other
......@@ -59,7 +58,7 @@ def strategy(
alpha_index, mcts_index = 0, 1
def index(ply: Player):
def index(ply: Strategy):
if isinstance(ply, MCTSStrategy):
return mcts_index
......@@ -76,68 +75,45 @@ def run(n=100, debug=False):
grid: HexGrid = HexGrid.split_state(4, 2, 1)
rules: Rules = Dodo()
if i % 2 == 0:
player_one = StrategyAlphaBeta(grid, rules, 1, depth=30)
player_two = MCTSStrategy(grid, rules, 2)
else:
player_one = MCTSStrategy(grid, rules, 1)
player_two = StrategyAlphaBeta(grid, rules, 2, depth=30)
player_one = MCTSStrategy(grid, rules, 1)
player_two = StrategyAlphaBeta(grid, rules, 2, depth=10)
ply = 1
ply_mcts = 1
ply_alpha = 1
if isinstance(player_one, MCTSStrategy):
ply_mcts = 1
ply_alpha = 2
else:
ply_mcts = 2
ply_alpha = 1
labels = [
("MCTS Algorithm, nsim=256", ply_mcts),
("Alphabeta Algorithm, depth=20", ply_alpha),
]
if debug:
grid.debug_plot(save=True, labels=labels)
grid.debug_plot(save=True)
while not rules.game_over(grid):
if ply == 1:
s = time.time()
action = player_one.get_action(grid, ply)
ttimes[index(player_one)] += time.time() - s
ttimes[0] += time.time() - s
grid.move(action, ply)
niters[index(player_one)] += 1
niters[0] += 1
else:
s = time.time()
action = player_two.get_action(grid, ply)
ttimes[index(player_two)] += time.time() - s
ttimes[1] += time.time() - s
grid.move(action, ply)
niters[index(player_two)] += 1
niters[1] += 1
if debug:
grid.debug_plot(save=True, labels=labels)
grid.debug_plot(save=True)
ply = other(ply)
if debug:
grid.debug_plot(save=True, labels=labels)
grid.debug_plot(save=True)
if rules.has_won(grid, 1):
wins[index(player_one)] += 1
wins[0] += 1
else:
wins[index(player_two)] += 1
wins[1] += 1
return wins, ttimes, niters, n
w, t, ni, n = run(10, False)
w, t, ni, n = run(20, False)
print(
f"MCTS | Wins percentage: {w[mcts_index] / n * 100:.2f}% | Time: {t[mcts_index] / ni[mcts_index]:.2f}"
)
print(
f"AlphaBeta | Wins percentage: {w[alpha_index] / n * 100:.2f}% | Time: {t[alpha_index] / ni[alpha_index]:.2f}"
)
print(f"MCTS | Wins percentage: {w[0] / n * 100:.2f}% | Time: {t[0] / ni[0]:.2f}")
print(f"AlphaBeta | Wins percentage: {w[1] / n * 100:.2f}% | Time: {t[1] / ni[1]:.2f}")
......@@ -23,6 +23,8 @@ from .rules import Rules, Dodo
sys.setrecursionlimit(10**6)
WORKERS_DIVISOR = 1
class Strategy:
"""
......@@ -186,10 +188,10 @@ class MCTSStrategy(Strategy):
grid: HexGrid,
rules: Rules,
ply: Player,
simulations: int = 256,
simulations: int = 512,
exploration_weight: float = 0.7,
threshold: int = 30,
ucb=UCB.ucb_tuned,
threshold: int = 10,
ucb=UCB.ucb,
minimax_level: int = 10,
):
super().__init__(grid, rules, ply)
......@@ -291,7 +293,6 @@ class MCTSStrategy(Strategy):
if score == 0:
pmobility = self.rules.mobility(state, self.player)
emobility = self.rules.mobility(state, utils.other(self.player))
# print("Zero score")
score = (
emobility
- pmobility
......@@ -508,7 +509,9 @@ class MCTSStrategy(Strategy):
self.root.untried_actions = self.legals
self.__expand(self.root, self.rules, self.player)
nworkers = cpu_count() // 2 # Number of workers we're going to use
nworkers = (
cpu_count() // WORKERS_DIVISOR
) # Number of workers we're going to use
sims_per_worker = self.simulations // nworkers
nodes = []
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment