From f5e509ad060b5bd331989111e058787c955c8bda Mon Sep 17 00:00:00 2001 From: Adrien <adrien.payen@student.uclouvain.be> Date: Sun, 19 May 2024 10:28:29 +0200 Subject: [PATCH] update the readme --- README.md | 20 ++++++++++---------- markovDecision.py | 1 + plot.py | 28 ++++++++++++++-------------- strategy_comparison.png | Bin 24237 -> 0 bytes tmc.py | 1 + validation.py | 1 + 6 files changed, 27 insertions(+), 24 deletions(-) delete mode 100644 strategy_comparison.png diff --git a/README.md b/README.md index 5c77e8c..bc67f78 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Group 5 - Projet de Machine Learning -Ce projet vise à implémenter un jeu de "Snake and Ladders" ainsi que de l'entrainer afin d'obtenir la meilleure stratégie. +Ce projet vise à implémenter un jeu de "Snake and Ladders" afin d'observer quelle est la optimale parmis l'ensemble des stratégies. Ce README présente la structure et résume notre projet. @@ -10,11 +10,8 @@ Pour exécuter les différents scripts et notebooks, assurez-vous d'avoir instal ```bash pip install numpy -pip install TransitionMatrixCalculator -pip install Validation pip install matplotlib.pyplot pip install random -pip install MarkovDecisionSolver ``` ## Codes Python @@ -23,20 +20,21 @@ Ces codes permettent d'implémenter le jeu du Snake and Ladders, de déterminer ### tmc.py -Ce code définit une **classe TransitionMatrixCalculator** qui calcule les matrices de transitions en fonctions des trois scénarios possible. Les règles de ce jeux diffèrent de celles traditionnellement utilisées, en effet à chaque étape le joueur à le choix entre trois dés : safe, normal ou risqué. Ils ont une influence sur la suite du jeu, effectivement le choix de dé occassione ou non la présence de pièges sur le plateau de jeu. +Le fichier **tmc.py** définit une **class TransitionMatrixCalculator** qui calcule les matrices de transitions en fonctions des trois scénarios possible. Les règles de ce jeux diffèrent de celles traditionnellement utilisées, en effet à chaque étape le joueur à le choix entre trois dés : safe, normal ou risky. Ils ont une influence sur la suite du jeu, effectivement le choix du dé occassione ou non la présence de pièges sur le plateau de jeu. ### markovDecison.py -Ce code contient une **classe MarkovDecisionProcess** qui définit les algorithmes de Value Iteration relatifs aux différentes stratégies. La fonction **solve** permet de calculer la politique optimale. Ensuite, la fonction **markovDecision** faisant appel à la fonction **solve**, permet d'obtenir la stratégie optimale. +Le fichier **markovDecison.py** contient une **class MarkovDecisionProcess** qui définit les algorithmes de Value Iteration relatifs aux différentes stratégies. La fonction **solve** permet de calculer la politique optimale par l'algorithme de Value Iteration. Ceci est réalisé en faisant appel aux 3 fonctions **_compute_vi_safe**,**_compute_vi_normal**,**_compute_vi_risky** qui permettent de calculer pour chacun des dés la Value Iteration et de choisir le minimum d'entre toutes les valeurs. Ensuite, la fonction **markovDecision** faisant appel à la fonction **solve**, permet d'afficher la stratégie optimale (les dés devant être joué suivant un layout) et les coût théorique de chaque case en fonction d'un jeu cyclique ou acyclique. ### validation.py -Dans ce code nous définissons une **classe validation** dans laquelle nous créons différentes fonctions de simulation du jeu. Cela va permettre d'obtenir le coût empirique de notre jeu (pour la fonction **simulate_rounds**) et le nombre de tour moyen nécessaire pour atteindre la case finale du jeu (pour la fonction **state_simulation**). Ensuite, nous implémentons des fonctions permettant de comparer les résultats empiriques, des simulations de jeu, aux résultats théoriques attendus, obtenus par value iteration. +Dans ce code nous définissons une **class validation** dans laquelle nous créons différentes fonctions de simulation du jeu et d'états. Cela va permettre d'obtenir le coût empirique de notre jeu (pour la fonction **simulate_rounds**) et le nombre de tour moyen nécessaire pour atteindre la case finale du jeu (pour la fonction **state_simulation**). Ensuite, nous implémentons des fonctions permettant de comparer les résultats empiriques, des simulations de jeu (dés safe, normal, risky et random), aux résultats théoriques attendus, obtenus par value iteration. ### plot.py -Ce code permet de réaliser différents graphiques afin de comparer les résultats obtenus des stratégies. - +Ce code permet de réaliser différents graphiques afin de comparer les résultats obtenus des stratégies. 4 graphiques peuvent être imprimés via 4 fonctions différentes dépendant d'un layout : **plot_strategy_comparison**,**plot_state_based_turns**,**plot_state_based_comparison**,**plot_state_based_comparison_once**. Le layout utilisé pour comparer nos stratégies est celui-ci : layout = [0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 1, 0]. La fonction **plot_strategy_comparison** permet de comparer les différentes stratégies en fonction de leur average turns sur un histogramme. La fonction **plot_state_based_turns** renvoie un graphe permettant de comparer l'average turn pour chaque état. La fonction **plot_state_based_comparison** a été implémentée dans l'optique de comparer l'algorithme de Value Iteration (theorical cost) et différentes simulations (empirical cost : 100, 10.000 et 1000.000) permettant de montrer la précision obtenue en fonction du nombre de simulations. Enfin, la fonction **plot_state_based_comparison_once** permet de comparer le theorical cost et l'empirical cost basé sur un nombre de simulations définies. + + ## Contact Pour toute question, suggestion, ou demande de collaboration sur ce projet, n'hésitez pas à nous contacter. Pour des discussions plus approfondies sur notre recherche et notre méthodologie, nous pouvez contacter : - Audrey Ghilain à audrey.ghilain@student.uclouvain.be @@ -53,4 +51,6 @@ Nous tenons à exprimer notre gratitude envers plusieurs parties qui ont jouées - Nathanaël Kindidi - Adrien Payen -## Références \ No newline at end of file +## Références + +Cours de Monsieurs Saerens. \ No newline at end of file diff --git a/markovDecision.py b/markovDecision.py index c87b433..014e4e4 100644 --- a/markovDecision.py +++ b/markovDecision.py @@ -1,3 +1,4 @@ +# All the imports import numpy as np from tmc import TransitionMatrixCalculator as tmc diff --git a/plot.py b/plot.py index 79d5639..2dce8ea 100644 --- a/plot.py +++ b/plot.py @@ -1,6 +1,6 @@ +# All the imports import matplotlib.pyplot as plt from validation import Validation as Val -import numpy as np def plot_strategy_comparison(num_games : int): @@ -93,25 +93,25 @@ if __name__ == '__main__': ##### Paramètres ##### # Define the layout of the game board - #layout = [0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 1, 0] + layout = [0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 1, 0] + # All the layout for the comparison + #classiclayout = [0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 1, 0] #layout = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 2, 1, 0] - - #layoutfastlaneWt = [0, 0, 3, 0, 2, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0] - #layoutslowlaneWt = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 2, 1, 0] - - layout = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + #layouttpslowlane = [0, 0, 3, 0, 2, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0] # layout with a trapped slowlane + #layouttpfastlane = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 2, 1, 0] # layout with a trapped fastlane + #zerolayout = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + # Indicates whether the board is circular or linear - circle = True + circle = False # Number of games to simulate - num_games = 1000000 + num_games = 1000 # Initialize Validation instance with the specified layout and circle type validation_instance = Val(layout, circle) - ##### Launch Plots ##### - + ##### Launch Plots ##### # Run the defined plotting functions with specified parameters - #plot_strategy_comparison(num_games) + plot_strategy_comparison(num_games) plot_state_based_turns() - #plot_state_based_comparison(num_games_list = [10,100,1000]) - #plot_state_based_comparison_once(num_games) \ No newline at end of file + plot_state_based_comparison(num_games_list = [10,100,1000]) + plot_state_based_comparison_once(num_games) \ No newline at end of file diff --git a/strategy_comparison.png b/strategy_comparison.png deleted file mode 100644 index 80ce415a967a75a1577a31c42ca12267641edd5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24237 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 diff --git a/tmc.py b/tmc.py index 73b496e..d9d64ee 100644 --- a/tmc.py +++ b/tmc.py @@ -1,3 +1,4 @@ +# The import import numpy as np class TransitionMatrixCalculator: diff --git a/validation.py b/validation.py index 052645c..b76988c 100644 --- a/validation.py +++ b/validation.py @@ -1,3 +1,4 @@ +# All the imports import random as rd import numpy as np from tmc import TransitionMatrixCalculator as tmc -- GitLab