From 749713a6adf0cba2eda43c25dff2bb93bb6e31cd Mon Sep 17 00:00:00 2001 From: Adrien <adrien.payen@student.uclouvain.be> Date: Tue, 7 May 2024 00:21:41 +0200 Subject: [PATCH] comments code .py --- markovDecision.py | 60 ++++++------- plot.py | 76 +++++++++++----- strategy_comparison.png | Bin 22221 -> 22200 bytes tmc.py | 41 ++++----- validation.py | 194 ++++++++++++++-------------------------- 5 files changed, 165 insertions(+), 206 deletions(-) diff --git a/markovDecision.py b/markovDecision.py index 5b6e73d..c87b433 100644 --- a/markovDecision.py +++ b/markovDecision.py @@ -1,79 +1,79 @@ import numpy as np from tmc import TransitionMatrixCalculator as tmc -class MarkovDecisionSolver: +class MarkovDecisionProcess : def __init__(self, layout: list, circle: bool): + # Initialize the Markov Decision Process solver with layout and game mode (circle or not) self.Numberk = 15 self.tmc_instance = tmc() + + # Compute transition matrices for safe, normal, and risky scenarios self.safe_dice = self.tmc_instance._compute_safe_matrix() - self.normal_dice, _ = self.tmc_instance._compute_normal_matrix(layout, circle) # Make sure to capture only the normal_dice component - self.risky_dice, _ = self.tmc_instance._compute_risky_matrix(layout, circle) # Make sure to capture only the risky_dice component + self.normal_dice, _ = self.tmc_instance._compute_normal_matrix(layout, circle) + self.risky_dice, _ = self.tmc_instance._compute_risky_matrix(layout, circle) + + # Identify jail states in the layout self.jail = [i for i, x in enumerate(layout) if x == 3] + + # Initialize value and dice decision arrays self.ValueI = np.zeros(self.Numberk) - self.DiceForStates = np.zeros(self.Numberk - 1) + self.Dice = np.zeros(self.Numberk - 1) - def _compute_vi_safe(self, k): + def _compute_vi_safe(self, k : int ): + # Compute the expected value using safe dice transition matrix for state k return np.dot(self.safe_dice[k], self.ValueI) + np.sum(self.normal_dice[k][self.jail]) - def _compute_vi_normal(self, k): + def _compute_vi_normal(self, k : int ): + # Compute the expected value using normal dice transition matrix for state k vi_normal = np.dot(self.normal_dice[k], self.ValueI) + np.sum(self.normal_dice[k][self.jail]) return vi_normal - def _compute_vi_risky(self, k): + def _compute_vi_risky(self, k : int ): + # Compute the expected value using risky dice transition matrix for state k vi_risky = np.dot(self.risky_dice[k], self.ValueI) + np.sum(self.risky_dice[k][self.jail]) return vi_risky def solve(self): + # Iteratively solve the Markov Decision Process until convergence i = 0 while True: ValueINew = np.zeros(self.Numberk) i += 1 for k in range(self.Numberk - 1): + # Compute expected values for safe, normal, and risky decisions at state k vi_safe = self._compute_vi_safe(k) vi_normal = self._compute_vi_normal(k) vi_risky = self._compute_vi_risky(k) - # Compute the minimum value among vi_safe, vi_normal, and vi_risky + # Determine the minimum value among safe, normal, and risky decisions min_value = min(vi_safe, vi_normal, vi_risky) - # Find which index (safe, normal, or risky) corresponds to the minimum value + # Record the dice decision (safe=1, normal=2, risky=3) corresponding to the minimum value if min_value == vi_safe: ValueINew[k] = 1 + vi_safe - self.DiceForStates[k] = 1 + self.Dice[k] = 1 elif min_value == vi_normal: ValueINew[k] = 1 + vi_normal - self.DiceForStates[k] = 2 + self.Dice[k] = 2 else: ValueINew[k] = 1 + vi_risky - self.DiceForStates[k] = 3 - + self.Dice[k] = 3 + # Check for convergence if np.allclose(ValueINew, self.ValueI): self.ValueI = ValueINew break self.ValueI = ValueINew + # Return the expected values and dice decisions for each state Expec = self.ValueI[:-1] - return [Expec, self.DiceForStates] + return [Expec, self.Dice] def markovDecision(layout : list, circle : bool): - solver = MarkovDecisionSolver(layout, circle) - return solver.solve() - -""" -# Exemple d'utilisation de la fonction markovDecision avec les paramètres layout et circle -layout = [0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 1, 0] - - -# Résolution du problème avec différents modes de jeu -result_false = markovDecision(layout, circle=False) -print("\nWin as soon as land on or overstep the final square") -print(result_false) - -result_true = markovDecision(layout, circle=True) -print("\nStopping on the square to win") -print(result_true)""" \ No newline at end of file + # Solve the Markov Decision Problem for the given layout and game mode + solver = MarkovDecisionProcess(layout, circle) + return solver.solve() \ No newline at end of file diff --git a/plot.py b/plot.py index d841495..dd9d81a 100644 --- a/plot.py +++ b/plot.py @@ -2,29 +2,24 @@ import matplotlib.pyplot as plt from validation import Validation as Val import numpy as np -# Example layout and circle settings -layout = [0, 0, 3, 0, 2, 0, 2, 0, 0, 0, 3, 0, 0, 1, 0] -circle = False -# Create an instance of validation -validation_instance = Val(layout, circle) - - -# Plotting function for strategy comparison -def plot_strategy_comparison(num_games=10000): +def plot_strategy_comparison(num_games : int): + """Plot a bar chart comparing average costs of different strategies over specified number of games.""" + + # Compare strategies and get their costs strategy_costs = validation_instance.compare_strategies(num_games=num_games) - # Bar plot for strategy comparison + # Plotting the bar chart plt.figure(figsize=(10, 6)) plt.bar(strategy_costs.keys(), strategy_costs.values(), color=['blue', 'green', 'orange', 'red', 'purple']) plt.xlabel('Strategies') plt.ylabel('Average Cost') plt.title('Comparison of Strategies') - plt.savefig('strategy_comparison.png') # Save the plot plt.show() -# Plotting function for state-based average turns for all strategies on the same plot -def plot_state_based_turns(save=True): + +def plot_state_based_turns(): + """Plot the average number of turns per state for different strategies.""" strategies = [validation_instance.optimal_policy, validation_instance.safe_strategy, validation_instance.normal_strategy, @@ -33,8 +28,9 @@ def plot_state_based_turns(save=True): strategy_names = ['Optimal', 'SafeDice', 'NormalDice', 'RiskyDice', 'Random'] plt.figure(figsize=(12, 6)) + # Simulate and plot average turns for each strategy for strategy, name in zip(strategies, strategy_names): - mean_turns = validation_instance.simulate_state(strategy, layout, circle) + mean_turns = validation_instance.simulate_state(strategy, layout, circle, num_games) plt.plot(range(len(mean_turns)), mean_turns, marker='o', linestyle='-', label=name) plt.xlabel('State') @@ -42,13 +38,35 @@ def plot_state_based_turns(save=True): plt.title('Average Turns per State for Different Strategies') plt.grid(True) plt.legend() + plt.show() + + +def plot_state_based_comparison(num_games_list): + """Plot a comparison between optimal turns and empirical turns per state for different num_games.""" + plt.figure(figsize=(12, 6)) # Create a single figure for all plots + + optimal_turns = None # Initialize optimal_turns to None + + for num_games in num_games_list: + _, empirical_turns = validation_instance.compare_state_based_turns(num_games=num_games) + + # Plotting empirical turns per state for the current num_games + plt.plot(range(len(empirical_turns)), empirical_turns, marker='x', linestyle='-', label=f'Empirical (num_games={num_games})') - #if save: - #plt.savefig('state_based_turns_all_strategies.png') # Save the plot + if optimal_turns is None: + # Only fetch optimal_turns once (for the first num_games) + optimal_turns, _ = validation_instance.compare_state_based_turns(num_games=num_games) + plt.plot(range(len(optimal_turns)), optimal_turns, marker='o', linestyle='-', label=f'ValueIteration') + plt.xlabel('State') + plt.ylabel('Average Turns') + plt.title('Average Turns per State - ValueIteration vs. Empirical') + plt.grid(True) + plt.legend() plt.show() -def plot_state_based_comparison(validation_instance, num_games=10000): + +def plot_state_based_comparison_once(num_games : int): optimal_turns, empirical_turns = validation_instance.compare_state_based_turns(num_games=num_games) # Plotting the state-based average turns comparison @@ -70,13 +88,23 @@ def plot_state_based_comparison(validation_instance, num_games=10000): - -# Main function to generate and save plots if __name__ == '__main__': - # Example of strategy comparison plot - plot_strategy_comparison(num_games=10000) - # Example of state-based average turns plot for all strategies on the same plot - plot_state_based_turns(save=True) + ##### 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] + # Indicates whether the board is circular or linear + circle = False + # Number of games to simulate + num_games = 10000 + # Initialize Validation instance with the specified layout and circle type + validation_instance = Val(layout, circle) + + ##### Launch Plots ##### - plot_state_based_comparison(validation_instance, num_games=10000) \ No newline at end of file + # Run the defined plotting functions with specified parameters + 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 diff --git a/strategy_comparison.png b/strategy_comparison.png index bcabdaa67b4519b11c1a7cfcc24ba2a35e5327d1..cf7d61d9ba5784ff527eee96c0de4ca903563ab4 100644 GIT binary patch literal 22200 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	KsU*>^IxAewCr8D$uo=SUuAV2X)Z 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 bsdP$eYX-a1IMtl_60*k?k0l*Fd-=ZsSMU-l literal 22221 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%0AJWuVfN-Dx>F?<K1)+rG{J3jXPMjDQkmRk$o|V- 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 diff --git a/tmc.py b/tmc.py index cb3b32b..73b496e 100644 --- a/tmc.py +++ b/tmc.py @@ -2,12 +2,14 @@ import numpy as np class TransitionMatrixCalculator: def __init__(self): + # Initialize the size of the transition matrices self.size = 15 self.matrix_safe = np.zeros((self.size , self.size )) self.matrix_normal = np.zeros((self.size , self.size )) self.matrix_risky = np.zeros((self.size , self.size )) - def compute_transition_matrix(self, layout, circle=False): + def compute_transition_matrix(self, layout : list , circle : bool): + # Compute transition matrices for safe, normal, and risky scenarios self.matrix_safe = self._compute_safe_matrix() self.matrix_normal, _ = self._compute_normal_matrix(layout, circle) self.matrix_risky, _ = self._compute_risky_matrix(layout, circle) @@ -16,11 +18,12 @@ class TransitionMatrixCalculator: def _compute_safe_matrix(self): + # Compute transition matrix for safe scenario p = np.zeros((self.size ,self.size )) for k in range(self.size - 1): if k == 2: - p[k,k+1] = 1/4 # slow lane - p[k,k+8] = 1/4 # fast lane + p[k,k+1] = 1/4 + p[k,k+8] = 1/4 elif k == 9: p[k,k+5] = 1/2 else: @@ -29,14 +32,15 @@ class TransitionMatrixCalculator: p[self.size -1,self.size -1] = 1 return p - def _compute_normal_matrix(self, layout, circle=False): + def _compute_normal_matrix(self, layout : list , circle : bool): + # Compute transition matrix for normal scenario p = np.zeros((self.size ,self.size )) jail = np.zeros((self.size ,self.size )) for k in range(self.size - 1): if k == 2: - p[k,k+1:k+3] = 1/6 # slow lane # slow lane - p[k,k+8:k+10] = 1/6 # fast lane # fast lane + p[k,k+1:k+3] = 1/6 + p[k,k+8:k+10] = 1/6 elif k == 8: p[k,k+1] = 1/3 p[k,k+6] = 1/3 @@ -73,14 +77,15 @@ class TransitionMatrixCalculator: p[self.size -1,self.size -1] = 1 return p, jail - def _compute_risky_matrix(self, layout, circle=False): + def _compute_risky_matrix(self, layout : list , circle : bool): + # Compute transition matrix for risky scenario p = np.zeros((self.size ,self.size )) jail = np.zeros((self.size ,self.size )) for k in range(self.size -1): if k == 2: - p[k,k+1:k+4] = 1/8 # slow lane - p[k,k+8:k+11] = 1/8 # fast lane + p[k,k+1:k+4] = 1/8 + p[k,k+8:k+11] = 1/8 elif k == 7: p[k,k+1:k+3] = 1/4 p[k,k+7] = 1/4 @@ -131,20 +136,4 @@ class TransitionMatrixCalculator: jail[k,j] = p[k,j] p[self.size -1,self.size-1] = 1 - return p, jail - -""" - def display_matrices(self): - print("Safe Matrix:") - print(self.matrix_safe) - print("\nNormal Matrix:") - print(self.matrix_normal) - print("\nRisky Matrix:") - print(self.matrix_risky) - -# Example Usage: -layout_example = [0]*15 -calculator = TransitionMatrixCalculator() -calculator.compute_transition_matrix(layout_example, circle=True) -calculator.display_matrices() -""" \ No newline at end of file + return p, jail \ No newline at end of file diff --git a/validation.py b/validation.py index 02e656b..7e72b5e 100644 --- a/validation.py +++ b/validation.py @@ -1,44 +1,55 @@ import random as rd import numpy as np from tmc import TransitionMatrixCalculator as tmc -from markovDecision import MarkovDecisionSolver as mD - +from markovDecision import MarkovDecisionProcess as mD +# Class for performing validation and simulation class Validation: - def __init__(self, layout, circle=False): + def __init__(self, layout : list, circle : bool): + # Initialize with layout and circle configuration self.layout = layout self.circle = circle + + # Initialize TransitionMatrixCalculator instance for transition matrix computation self.tmc_instance = tmc() + + # Compute transition matrices for safe, normal, and risky dice self.safe_dice = self.tmc_instance._compute_safe_matrix() self.normal_dice, _ = self.tmc_instance._compute_normal_matrix(layout, circle) self.risky_dice, _ = self.tmc_instance._compute_risky_matrix(layout, circle) + # Use MarkovDecisionSolver to find optimal policy and expected costs solver = mD(self.layout, self.circle) self.expec, self.optimal_policy = solver.solve() + # Predefined strategies for different dice types self.safe_strategy = [1] * len(layout) self.normal_strategy = [2] * len(layout) self.risky_strategy = [3] * len(layout) self.random_strategy = [rd.choice([0, 1, 2, 3]) for _ in range(len(layout))] + # Dictionary to store costs by dice type self.costs_by_dice_type = { 'SafeDice': [0] * len(layout), 'NormalDice': [0] * len(layout), 'RiskyDice': [0] * len(layout) } - for i, die_type in enumerate(self.layout): + # Assign costs based on dice type to the respective lists in the dictionary + for i, die_type in enumerate(self.layout) : self.costs_by_dice_type['SafeDice'][i] = 1 if die_type == 3 else 0 self.costs_by_dice_type['NormalDice'][i] = 2 if die_type == 3 else 0 self.costs_by_dice_type['RiskyDice'][i] = 3 if die_type == 3 else 0 - def simulate_game(self, strategy, n_iterations=10000): + + def simulate_game(self, strategy: list, n_iterations: int): + """Simulate the game using a given strategy over multiple iterations.""" transition_matrices = [self.safe_dice, self.normal_dice, self.risky_dice] - number_turns = [] + total_turns = np.zeros(n_iterations) - for _ in range(n_iterations): - total_turns = 0 - k = 0 # initial state + for i in range(n_iterations): + k = 0 + turns = 0 while k < len(self.layout) - 1: action = strategy[k] @@ -50,32 +61,34 @@ class Validation: k = np.random.choice(len(self.layout), p=flattened_probs) - if self.layout[k] == 3 and action == 2: - total_turns += 1 if np.random.uniform(0, 1) < 0.5 else 2 - elif self.layout[k] == 3 and action == 3: - total_turns += 2 + if self.layout[k] == 3: + if action == 2: + turns += np.random.choice([1, 2], p=[0.5, 0.5]) + elif action == 3: + turns += 2 else: - total_turns += 1 + turns += 1 + + total_turns[i] = turns - number_turns.append(total_turns) + return np.mean(total_turns) - return np.mean(number_turns) - def simulate_state(self, strategy, layout, circle, n_iterations=10000): + def simulate_state(self, strategy: list, layout: list, circle: bool, n_iterations: int): + """Simulate game states using a given strategy.""" safe_dice = self.tmc_instance._compute_safe_matrix() normal_dice = self.tmc_instance._compute_normal_matrix(layout, circle)[0] risky_dice = self.tmc_instance._compute_risky_matrix(layout, circle)[0] transition_matrices = [safe_dice, normal_dice, risky_dice] - number_turns = [] - number_mean = [] + total_turns = [] for _ in range(n_iterations): - number_turns = [] + state_turns = np.zeros(len(layout) - 1) # Utiliser un tableau numpy pour stocker les tours par état for state in range(len(layout) - 1): - total_turns = 0 k = state + turns = 0 while k < len(layout) - 1: action = strategy[k] @@ -87,25 +100,27 @@ class Validation: k = np.random.choice(len(layout), p=flattened_probs) - if layout[k] == 3 and action == 2: - total_turns += 1 if np.random.uniform(0, 1) < 0.5 else 2 - elif layout[k] == 3 and action == 3: - total_turns += 2 + if layout[k] == 3: + if action == 2: + turns += np.random.choice([1, 2], p=[0.5, 0.5]) # Utiliser numpy pour la randomisation + elif action == 3: + turns += 2 else: - total_turns += 1 + turns += 1 - number_turns.append(total_turns) + state_turns[state] = turns - number_mean.append(number_turns) + total_turns.append(state_turns) - # calculate the average number of turns for each state - mean_turns = np.mean(number_mean, axis=0) + mean_turns = np.mean(total_turns, axis=0) return mean_turns - def play_optimal_policy(self, n_iterations=10000): + def play_optimal_policy(self, n_iterations : int): + """Play using the optimal policy for a number of iterations.""" return self.simulate_game(self.optimal_policy, n_iterations) - def play_dice_strategy(self, dice_choice, n_iterations=10000): + def play_dice_strategy(self, dice_choice, n_iterations : int): + """Play using a specific dice strategy for a number of iterations.""" strategy = { 'SafeDice': self.safe_strategy, 'NormalDice': self.normal_strategy, @@ -117,33 +132,13 @@ class Validation: return self.simulate_game(strategy, n_iterations) - def play_random_strategy(self, n_iterations=10000): + def play_random_strategy(self, n_iterations : int ): + """Play using a random strategy for a number of iterations.""" return self.simulate_game(self.random_strategy, n_iterations) - def play_empirical_strategy(self): - k = 0 - total_turns = 0 - - while k < len(self.layout) - 1: - action = self.optimal_policy[k] - action_index = int(action) - 1 - transition_matrix = self.normal_dice - - flattened_probs = transition_matrix[k] - flattened_probs /= np.sum(flattened_probs) - k = np.random.choice(len(self.layout), p=flattened_probs) - - if self.layout[k] == 3 and action == 2: - total_turns += 1 if np.random.uniform(0, 1) < 0.5 else 2 - elif self.layout[k] == 3 and action == 3: - total_turns += 2 - else: - total_turns += 1 - - return total_turns - - def compare_empirical_vs_value_iteration(self, num_games=10000): + def compare_empirical_vs_value_iteration(self, num_games : int): + """Compare expected value iteration turns with empirical turns.""" value_iteration_turns = self.expec empirical_turns = self.simulate_state(self.optimal_policy, self.layout, self.circle, n_iterations=num_games) @@ -153,14 +148,29 @@ class Validation: } return mean_turns_by_state + + def empirical_cost_of_square(self, strategy: list, n_iterations: int): + """Calculate the empirical cost of a square for a given strategy.""" + total_square_costs = [] + + for _ in range(n_iterations): + game_cost = self.simulate_game(strategy, 1) + square_cost = game_cost ** 2 + total_square_costs.append(square_cost) + + empirical_cost = np.mean(total_square_costs) + return empirical_cost - def compare_state_based_turns(self, num_games=10000): + + def compare_state_based_turns(self, num_games : int ): + # Compare the expected turns from value iteration with empirical state-based turns value_iteration = self.expec empirical_turns = self.simulate_state(self.optimal_policy, self.layout, self.circle, n_iterations=num_games) return value_iteration, empirical_turns - def compare_strategies(self, num_games=10000): + def compare_strategies(self, num_games : int): + # Compare the costs of different strategies over a number of games optimal_cost = self.simulate_game(self.optimal_policy, n_iterations=num_games) dice1_cost = self.simulate_game(self.safe_strategy, n_iterations=num_games) dice2_cost = self.simulate_game(self.normal_strategy, n_iterations=num_games) @@ -174,71 +184,3 @@ class Validation: 'RiskyDice': dice3_cost, 'Random': random_cost } - -""" -# Exemple d'utilisation -layout = [0, 0, 3, 0, 2, 0, 2, 0, 0, 0, 3, 0, 0, 1, 0] -circle = False -validation_instance = Validation(layout, circle) - -# Comparaison entre la stratégie empirique et la value iteration -turns_by_state = validation_instance.compare_empirical_vs_value_iteration(num_games=1000000) - -# Affichage des moyennes de tours pour chaque état -num_states = len(layout) -for state in range(num_states - 1): - print(f"État {state}:") - print(f" ValueIteration - Tours moyens : {turns_by_state['ValueIteration'][state]:.2f}") - print(f" Empirical - Tours moyens : {turns_by_state['Empirical'][state]:.2f}") - -# Exécution de la stratégie empirique une fois -empirical_strategy_result = validation_instance.play_empirical_strategy() -print("Coût de la stratégie empirique sur un tour :", empirical_strategy_result) - -# Comparaison entre la stratégie empirique et la value iteration sur plusieurs jeux -comparison_result = validation_instance.compare_empirical_vs_value_iteration(num_games=1000000) -print("Coût moyen de la stratégie de value iteration :", comparison_result['ValueIteration']) -print("Coût moyen de la stratégie empirique :", comparison_result['Empirical']) - -# Coûts des différentes stratégies -optimal_cost = validation_instance.play_optimal_policy(n_iterations=1000000) -print("Optimal Strategy Cost:", optimal_cost) - -dice1_cost = validation_instance.play_dice_strategy('SafeDice', n_iterations=1000000) -print("Safe Dice Strategy Cost:", dice1_cost) - -dice2_cost = validation_instance.play_dice_strategy('NormalDice', n_iterations=1000000) -print("Normal Dice Strategy Cost:", dice2_cost) - -dice3_cost = validation_instance.play_dice_strategy('RiskyDice', n_iterations=1000000) -print("Risky Dice Strategy Cost:", dice3_cost) - -random_cost = validation_instance.play_random_strategy(n_iterations=1000000) -print("Random Strategy Cost:", random_cost) - -# Comparaison entre les stratégies -strategy_comparison = validation_instance.compare_strategies(num_games=1000000) -print("Strategy Comparison Results:", strategy_comparison) - -# Calcul des tours moyens pour différentes stratégies -optimal_policy = validation_instance.optimal_policy -mean_turns_optimal = validation_instance.simulate_state(optimal_policy, layout, circle, n_iterations=1000000) -print("Mean Turns for Optimal Strategy:", mean_turns_optimal) - -safe_dice_strategy = validation_instance.safe_strategy -mean_turns_safe_dice = validation_instance.simulate_state(safe_dice_strategy, layout, circle, n_iterations=1000000) -print("Mean Turns for Safe Dice Strategy:", mean_turns_safe_dice) - -normal_dice_strategy = validation_instance.normal_strategy -mean_turns_normal_dice = validation_instance.simulate_state(normal_dice_strategy, layout, circle, n_iterations=1000000) -print("Mean Turns for Normal Dice Strategy:", mean_turns_normal_dice) - -risky_dice_strategy = validation_instance.risky_strategy -mean_turns_risky_dice = validation_instance.simulate_state(risky_dice_strategy, layout, circle, n_iterations=1000000) -print("Mean Turns for Risky Dice Strategy:", mean_turns_risky_dice) - -random_dice_strategy = validation_instance.random_strategy -mean_turns_random_dice = validation_instance.simulate_state(random_dice_strategy, layout, circle, n_iterations=1000000) -print("Mean Turns for Random Dice Strategy:", mean_turns_random_dice) - -""" \ No newline at end of file -- GitLab