11import importlib .util
22import sys
33import random
4+ import inspect
45import os
56import pickle
67import time
78from matplotlib import pyplot as plt
89
910class plots_stats :
1011 def printWinPercentage ():
11- results = saving .loadResults ()
12+ results = results_manager .loadResults ()
1213 total_sims = len (results )
1314 wins = sum (1 for result in results if result ["escaped" ])
1415
@@ -17,7 +18,7 @@ def printWinPercentage():
1718 print (f"\n Win percentage: { winStr } %" )
1819
1920 def printAvgBoxChecks ():
20- results = saving .loadResults ()
21+ results = results_manager .loadResults ()
2122 total_sims = len (results )
2223 num_prisoners = len (results [0 ]["prisoners" ])
2324 checksPerPrisoner = {i : 0 for i in range (num_prisoners )}
@@ -38,7 +39,7 @@ def printAvgBoxChecks():
3839 plt .show ()
3940
4041 def printPctFinds ():
41- results = saving .loadResults ()
42+ results = results_manager .loadResults ()
4243 total_sims = len (results )
4344 num_prisoners = len (results [0 ]["prisoners" ])
4445 findsPerPrisoner = {i : 0 for i in range (num_prisoners )}
@@ -85,7 +86,7 @@ def run():
8586 else :
8687 print ("Invalid choice. Please select a valid option." )
8788
88- class saving :
89+ class results_manager :
8990 def save (results , checkpoint ):
9091 with open (resultsPath + '.tmp' , 'wb' ) as file :
9192 pickle .dump (results , file )
@@ -122,59 +123,82 @@ def loadCheckpoint():
122123 checkpoint = pickle .load (file )
123124 return checkpoint
124125 return None
125-
126- def importConfigModule ():
127- configPath = os .path .join (working_dir , "config.py" )
128- spec = importlib .util .spec_from_file_location ("config" , configPath )
129- if spec is None or spec .loader is None :
130- raise FileNotFoundError (f"Could not load config.py from { working_dir } " )
131- config = importlib .util .module_from_spec (spec )
132- sys .modules ["config" ] = config
133- spec .loader .exec_module (config )
134- return config
135-
136- def getWorkingDir ():
137- global working_dir
138- global resultsPath
139- global checkpointPath
140- while True :
141- working_dir = os .path .abspath (input ("Enter the working directory: " ).strip ())
142- if os .path .isdir (working_dir ):
143- resultsPath = os .path .join (working_dir , 'results.pkl' )
144- checkpointPath = os .path .join (working_dir , 'checkpoint.pkl' )
145- return working_dir
146- else :
147- print (f"Directory { working_dir } does not exist. Please try again." )
126+
127+ def createNewSimulation ():
128+ global working_dir
129+ global resultsPath
130+ global checkpointPath
131+ global configPath
132+ global prisonerStrategy
133+ global config
134+ while True :
135+ simID = input ("Enter new simulation ID: " ).strip ()
136+ working_dir = os .path .join (base_dir , "results" , simID )
137+ resultsPath = os .path .join (working_dir , "results.pkl" )
138+ checkpointPath = os .path .join (working_dir , "checkpoint.pkl" )
139+ configPath = os .path .join (working_dir , "config.pkl" )
140+ if not os .path .exists (working_dir ):
141+ os .makedirs (working_dir )
142+ break
143+ print ("Simulation ID already exists. Please choose a different ID." )
144+ import config as baseConfig
145+ prisonerStrategy = baseConfig .prisonerStrategy
146+ prisonerStrategy_string = inspect .getsource (baseConfig .prisonerStrategy )
147+ config = {"CONFIG" : baseConfig .getConfig (), "prisonerStrategy" : prisonerStrategy_string }
148+ with open (configPath , 'wb' ) as file :
149+ pickle .dump (config , file )
150+
151+ def loadSimulation ():
152+ global working_dir
153+ global resultsPath
154+ global checkpointPath
155+ global configPath
156+ global prisonerStrategy
157+ global config
158+ while True :
159+ simID = input ("Enter simulation ID: " ).strip ()
160+ working_dir = os .path .join (base_dir , "results" , simID )
161+ resultsPath = os .path .join (working_dir , "results.pkl" )
162+ checkpointPath = os .path .join (working_dir , "checkpoint.pkl" )
163+ configPath = os .path .join (working_dir , "config.pkl" )
164+ if os .path .exists (configPath ):
165+ break
166+ print ("Invalid simulation ID. Please try again." )
167+ with open (configPath , 'rb' ) as file :
168+ config = pickle .load (file )
169+ namespace = {}
170+ exec (config ["prisonerStrategy" ], namespace )
171+ prisonerStrategy = namespace ["prisonerStrategy" ]
148172
149173def simulatePrisoners ():
150- results = saving .loadResults ()
151- checkpoint = saving .loadCheckpoint ()
174+ results = results_manager .loadResults ()
175+ checkpoint = results_manager .loadCheckpoint ()
152176 if checkpoint and results :
153177 startSim = checkpoint .get ("last_simulation" ) + 1
154- rng = random .Random (cfg .get ("seed" , None ))
178+ rng = random .Random (config [ "CONFIG" ] .get ("seed" , None ))
155179 rng .setstate (checkpoint .get ("rng_state" ))
156180 print (f"Resuming from simulation { startSim } ." )
157181 else :
158182 startSim = 0
159183 results = []
160- rng = random .Random (cfg .get ("seed" , None ))
184+ rng = random .Random (config [ "CONFIG" ] .get ("seed" , None ))
161185 checkpoint = {"last_simulation" : - 1 , "rng_state" : rng .getstate ()}
162186 print ("Starting new simulations." )
163187
164- if startSim >= cfg ["num_simulations" ]:
188+ if startSim >= config [ "CONFIG" ] ["num_simulations" ]:
165189 print ("All simulations have already been completed." )
166190 return
167191
168- for sim in range (startSim , cfg ["num_simulations" ]):
169- prisoners = {i : [0 , False ] for i in range (cfg ["num_prisoners" ])}
192+ for sim in range (startSim , config [ "CONFIG" ] ["num_simulations" ]):
193+ prisoners = {i : [0 , False ] for i in range (config [ "CONFIG" ] ["num_prisoners" ])}
170194 boxes = list (prisoners .keys ())
171195 rng .shuffle (boxes )
172196 results .append ({"escaped" : None , "prisoners" : []})
173197
174198 for prisonerId in prisoners :
175199 checkedBoxes = {}
176- for _ in range (cfg ["total_box_checks" ]):
177- choice = config . prisonerStrategy (rng , prisonerId , prisoners , cfg ["total_box_checks" ], checkedBoxes )
200+ for _ in range (config [ "CONFIG" ] ["total_box_checks" ]):
201+ choice = prisonerStrategy (rng , prisonerId , prisoners , config [ "CONFIG" ] ["total_box_checks" ], checkedBoxes )
178202 if boxes [choice ] == prisonerId :
179203 checkedBoxes [choice ] = boxes [choice ]
180204 prisoners [prisonerId ] = (checkedBoxes , True )
@@ -187,31 +211,35 @@ def simulatePrisoners():
187211 for prisoner in prisoners :
188212 results [- 1 ]["prisoners" ].append ({"found" : prisoners [prisoner ][1 ], "checked_boxes" : prisoners [prisoner ][0 ]})
189213
190- saving .save (results , {"last_simulation" : sim , "rng_state" : rng .getstate ()})
214+ results_manager .save (results , {"last_simulation" : sim , "rng_state" : rng .getstate ()})
191215 print ("All simulations completed." )
192216
193217if __name__ == "__main__" :
194218 base_dir = os .path .dirname (os .path .abspath (__file__ ))
195- working_dir = getWorkingDir ()
196- config = importConfigModule ()
197- cfg = config .getConfig ()
198-
199219 while True :
200- print (f"\n Working directory: { working_dir } " )
201220 print (f"\n Choose an option:" )
202- print (f"1. Change working directory" )
203- print (f"2. Run simulations" )
204- print (f"3. Plot results" )
205- print (f"4. Exit" )
206- choice = input ("Make a selection (1-4): " ).strip ()
221+ print (f"1. Create new simulation" )
222+ print (f"2. Load simulation" )
223+ print (f"3. Simulate prisoners (load or create simulation first)" )
224+ print (f"4. Show plots and statistics (load or create simulation first)" )
225+ print (f"5. Exit" )
226+ choice = input ("Make a selection (1-5): " ).strip ()
207227 if choice == '1' :
208- getWorkingDir ()
228+ results_manager . createNewSimulation ()
209229 elif choice == '2' :
210- simulatePrisoners ()
230+ results_manager . loadSimulation ()
211231 elif choice == '3' :
212- plots_stats .run ()
232+ if config is None :
233+ print ("\n Please create or load a simulation first." )
234+ else :
235+ simulatePrisoners ()
213236 elif choice == '4' :
237+ if config is None :
238+ print ("\n Please create or load a simulation first." )
239+ else :
240+ plots_stats .run ()
241+ elif choice == '5' :
214242 print ("Exiting." )
215- break
243+ sys . exit ( 0 )
216244 else :
217245 print ("Invalid choice. Please select a valid option." )
0 commit comments