Module main
[hide private]
[frames] | no frames]

Source Code for Module main

  1  ################################################################################## 
  2  # Copyright (c) 2011, Daniel Urieli, Peter Stone 
  3  # University of Texas at Austin 
  4  # All right reserved 
  5  #  
  6  # Based On: 
  7  #  
  8  # Copyright (c) 2000-2003, Jelle Kok, University of Amsterdam 
  9  # All rights reserved. 
 10  #  
 11  # Redistribution and use in source and binary forms, with or without 
 12  # modification, are permitted provided that the following conditions are met: 
 13  #  
 14  # 1. Redistributions of source code must retain the above copyright notice, this 
 15  # list of conditions and the following disclaimer. 
 16  #  
 17  # 2. Redistributions in binary form must reproduce the above copyright notice, 
 18  # this list of conditions and the following disclaimer in the documentation 
 19  # and/or other materials provided with the distribution. 
 20  #  
 21  # 3. Neither the name of the University of Amsterdam nor the names of its 
 22  # contributors may be used to endorse or promote products derived from this 
 23  # software without specific prior written permission. 
 24  #  
 25  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 26  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 27  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 28  # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
 29  # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 30  # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 31  # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 32  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 33  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 34  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 35  ################################################################################## 
 36   
 37   
 38   
 39   
 40  import sys 
 41  import os 
 42  import random 
 43  from math import * 
 44  from numpy import * 
 45   
 46  import seaModels 
 47  import shipModels 
 48  import state 
 49  import agents 
 50  import simulationEnvironment 
 51  import factories 
 52   
 53  #from heuristicDivide import * 
 54  from geometry import * 
 55   
56 -def default(str):
57 return str + ' [Default: %default]'
58
59 -def validateOptionCombinations(args):
60 """ 61 This functions validates we didn't mistakenly chosen options 62 that don't work with each other. 63 If options are verified we just return to the the program 64 execution. If the options are incorrect, we gracefully exit. 65 """ 66 # if( args['shipType'] == 'basic' 67 # and args['worldModel'] == 'complete' 68 # and args['strategy'] == 'circling' ): 69 # return 70 71 # if( args['shipType'] == 'basic' 72 # and args['worldModel'] == 'complete' 73 # and args['strategy'] == 'holonomicrrt' ): 74 # return 75 76 # if( args['shipType'] == 'basic' 77 # and args['worldModel'] == 'complete' 78 # and args['strategy'] == 'pid' ): 79 # return 80 81 # if( args['shipType'] == 'basic' 82 # and args['worldModel'] == 'complete' 83 # and args['strategy'] == 'measuredist' ): 84 # print 'Warning: change this combination in the future' 85 # return 86 87 if( args['shipType'] == 'basic' 88 and args['worldModel'] == 'complete' 89 and args['strategy'] == 'basicpatrol' ): 90 print 'Warning: change this combination in the future' 91 return 92 93 if( args['shipType'] == 'basic' 94 and args['worldModel'] == 'complete' 95 and args['strategy'] == 'rrt' ): 96 print 'Warning: change this combination in the future' 97 return 98 99 print 'Illegal options combination - exiting...' 100 sys.exit()
101 102 # TODO: Once we support mixed ship types, check combinations 103 # per each ship 104 105 106 107
108 -def readCommand( argv ):
109 """ 110 Processes the command used to run the simulation from the command line. 111 """ 112 from optparse import OptionParser 113 usageStr = """ 114 USAGE: python main.py <options> 115 EXAMPLE: python main.py --option <value> # TODO complete with real values 116 - #TODO explain what the example command do 117 """ 118 parser = OptionParser(usageStr) 119 120 # parser.add_option('-n', '--numGames', dest='numGames', type='int', 121 # help=default('the number of GAMES to play'), metavar='GAMES', default=1) 122 # parser.add_option('-l', '--layout', dest='layout', 123 # help=default('the LAYOUT_FILE from which to load the map layout'), 124 # metavar='LAYOUT_FILE', default='oneHunt') 125 # parser.add_option('-p', '--pacman', dest='pacman', 126 # help=default('the agent TYPE in the pacmanAgents module to use'), 127 # metavar='TYPE', default='BustersKeyboardAgent') 128 # parser.add_option('-a','--agentArgs',dest='agentArgs', 129 # help='Comma seperated values sent to agent. e.g. "opt1=val1,opt2,opt3=val3"') 130 # parser.add_option('-g', '--ghosts', dest='ghost', 131 # help=default('the ghost agent TYPE in the ghostAgents module to use'), 132 # metavar = 'TYPE', default='RandomGhost') 133 134 parser.add_option('-q', '--quietTextGraphics', action='store_true', dest='quietGraphics', 135 help=default('Generate minimal output and no graphics'), default=False ) 136 parser.add_option('-k', '--numSteps', dest='numSteps', type='int', 137 help=default("Number of steps to simulate"), default=10000) 138 parser.add_option('-d', '--inputFilesDir', dest='inputFilesDir', 139 help=default('the DIR in which input files are searched for'), 140 metavar='DIR', default='input_files') 141 parser.add_option('-f', '--patrolFile', dest='patrolFile', 142 help=default('A file defining patrol-points, ship initial positions, and patrol paths. The file is assumed to be under the input_files directory'), 143 default='shipPathsAndPositions.py') 144 parser.add_option('-r', '--resultsType', dest='resultsType', 145 help=default('Type of results the simulator outputs.'), 146 default='edgeGraphData') 147 parser.add_option('-t', '--shipType', dest='shipType', 148 help=default("The ship's model"), default='basic') 149 parser.add_option('-w', '--worldModel', dest='worldModel', 150 help=default("World model that the agent maintains"), default='complete') 151 parser.add_option('-s', '--strategy', dest='strategy', 152 help=default("Agent's desicion making strategy"), default='basicpatrol') 153 parser.add_option('-y', '--rulesOfTheSea', action='store_true', dest='rulesOfTheSea', 154 help=default('Respect the rules of the sea and yield when needed'), default=False ) 155 #### numShips is disabled because determined by the number of paths 156 # parser.add_option('-n', '--numShips', dest='numShips', type='int', 157 # help=default("Number of ships"), default=1) 158 159 160 # parser.add_option('-k', '--numghosts', type='int', dest='numGhosts', 161 # help=default('The maximum number of ghosts to use'), default=4) 162 # parser.add_option('-z', '--zoom', type='float', dest='zoom', 163 # help=default('Zoom the size of the graphics window'), default=1.0) 164 # parser.add_option('-f', '--fixRandomSeed', action='store_true', dest='fixRandomSeed', 165 # help='Fixes the random seed to always play the same game', default=False) 166 # parser.add_option('-s', '--showGhosts', action='store_true', dest='showGhosts', 167 # help='Renders the ghosts in the display (cheating)', default=False) 168 # parser.add_option('-t', '--frameTime', dest='frameTime', type='float', 169 # help=default('Time to delay between frames; <0 means keyboard'), default=0.1) 170 171 options, other = parser.parse_args() 172 if len(other) != 0: 173 raise Exception('Command line input not understood: ' + other) 174 args = dict() 175 176 # # Fix the random seed 177 # if options.fixRandomSeed: random.seed('bustersPacman') 178 # 179 # # Choose a layout 180 # args['layout'] = layout.getLayout( options.layout ) 181 # if args['layout'] == None: raise Exception("The layout " + options.layout + " cannot be found") 182 # 183 # # Choose a ghost agent 184 # ghostType = loadAgent(options.ghost, options.quietGraphics) 185 # args['ghosts'] = [ghostType( i+1 ) for i in range( options.numGhosts )] 186 # 187 # # Choose a Pacman agent 188 # noKeyboard = options.quietGraphics 189 # pacmanType = loadAgent(options.pacman, noKeyboard) 190 # agentOpts = parseAgentArgs(options.agentArgs) 191 # agentOpts['ghostAgents'] = args['ghosts'] 192 # pacman = pacmanType(**agentOpts) # Instantiate Pacman with agentArgs 193 # args['pacman'] = pacman 194 # 195 # import graphicsDisplay 196 # args['display'] = graphicsDisplay.FirstPersonPacmanGraphics(options.zoom, \ 197 # options.showGhosts, \ 198 # frameTime = options.frameTime) 199 # args['numGames'] = options.numGames 200 201 # Choose GUI / non-GUI 202 if options.quietGraphics: 203 args['withDisplay'] = False 204 else: 205 args['withDisplay'] = True 206 207 args['shipType'] = options.shipType 208 args['worldModel'] = options.worldModel 209 args['strategy'] = options.strategy 210 211 # args['numShips'] = options.numShips 212 213 args['numSteps'] = options.numSteps 214 215 args['inputFilesDir'] = options.inputFilesDir 216 217 args['patrolFile'] = options.patrolFile 218 219 args['resultsType'] = options.resultsType 220 221 args['rulesOfTheSea'] = options.rulesOfTheSea 222 223 validateOptionCombinations(args) 224 225 return args
226 227 ###################################################### 228 # Initialization Functions - # 229 # Those function are here temporarily # 230 # until there is a flexible solution # 231 # for loading different models, perhaps # 232 # as a part of the task definition language # 233 ######################################################
234 -def initWindFromFile(filePath):
235 # just execute the (python) file and return a variable generated 236 exec(compile(open(filePath).read(), filePath, 'exec')) 237 return wind
238
239 -def initWaterCurrentsFromFile(filePath):
240 # just execute the (python) file and return a variable generated 241 exec(compile(open(filePath).read(), filePath, 'exec')) 242 return waterCurrents
243
244 -def initWavesFromFile(filePath):
245 # just execute the (python) file and return a variable generated 246 exec(compile(open(filePath).read(), filePath, 'exec')) 247 return waves
248
249 -def initObstaclesFromFile(filePath):
250 # just execute the (python) file and return a variable generated 251 exec(compile(open(filePath).read(), filePath, 'exec')) 252 return obstacles
253
254 -def initShipPatrolPointsAndPathsFromFile(filePath):
255 # just execute the (python) file and return variables generated 256 exec(compile(open(filePath).read(), filePath, 'exec')) 257 return paths, patrolPoints, shipExternalStates
258 259 ###################################################### 260 # End initialization Functions # 261 ###################################################### 262 263 264 265 ###################################################### 266 # Results writing functions # 267 ###################################################### 268
269 -def writeResults(resultsType, env, patrolPoints):
270 """ 271 Write the simulation results. 272 273 TODO: this function needs to be further organized 274 once we have a better picture regarding what 275 types of results are usually needed. 276 Also the function arguments should be revised as a part 277 of the function reorganization. 278 279 @type resultsType: string 280 @param resultsType: a string identifier for the type of result to write 281 282 @type resultsType: SimulationEnvironment 283 @param resultsType: The simulation environment, used to extract data from 284 285 @type patrolPoints: array of (x,y) tuples 286 @param patrolPoints: All the points that participate in the patrol. This is required when writing data for heuristicDivide algorithm, and might be removed at some point. 287 """ 288 #TODO: this function needs to be further organized 289 # once we have a better picture regarding what 290 # types of results are usually needed. 291 if resultsType == 'worstFreq': 292 293 f = open(resultsType + '.res', 'w') 294 295 # Simulation results, K+1, K-1 296 point2freq = dict([(point, mean([l[i] - l[i-1] for i in range(1,len(l))])) for point, l in env.visitTimes.items() ]) 297 worstCaseFreq1 = max(point2freq.values()) 298 # print >> sys.stderr, 'WORSTCASE FREQ:', worstCaseFreq1 299 f.write('WORSTCASE FREQ: ' + str(worstCaseFreq1) + '\n') 300 f.write('patrolPoints=' + str(patrolPoints) + '\n') 301 f.write('visitTimes=' + str(env.visitTimes) + '\n') 302 # print >>sys.stderr, 'visitTimes =', env.visitTimes 303 304 # print >> sys.stderr, 'numShipsForPatrol', numShips 305 # worstCaseFreq2 = max( [mean([l[i] - l[i-1] for i in range(1,len(l))]) for l in env.state.times.values()] ) 306 # print >> sys.stderr, 'verification WORSTCASE FREQ:', worstCaseFreq2 307 308 # if worstCaseFreq1 != worstCaseFreq2: 309 # raise Exception('Whats going on? different worst cases freqs') 310 311 f.close() 312 313 elif resultsType == 'edgeGraphData': 314 315 f = open(resultsType + '.py', 'w') 316 f.write('patrolPoints=' + str(patrolPoints) + '\n') 317 f.write('edgeLengths=' + str(env.edgeLengths) + '\n') 318 f.close()
319 320 ###################################################### 321 # End Results writing functions # 322 ###################################################### 323 324 325 326 327 328 329 330 331 #def run(withDisplay, shipType, worldModel, strategy, numShips, inputFilesDir, patrolFile): 332 # disabled numShips, because determined by the number of paths
333 -def run(withDisplay, shipType, worldModel, strategy, inputFilesDir, patrolFile, numSteps, resultsType, rulesOfTheSea):
334 """ 335 The main flow of the application. The arguments are generated by command line options, or their defaults. 336 337 @type withDisplay: boolean 338 @param withDisplay: Tells whether to run in a GUI mode or in non-GUI mode 339 340 @type shipType: string 341 @param shipType: The ship model to allocate 342 343 @type worldModel: string 344 @param worldModel: The world model the agent has 345 346 @type strategy: string 347 @param strategy: The decision-making strategy the agent has 348 349 @type inputFilesDir: string 350 @param inputFilesDir: The directory in which the input files are 351 352 @type patrolFile: string 353 @param patrolFile: A file that defines ship positions, ship paths, and the patrol points of interest 354 355 @type numSteps: int 356 @param numSteps: Number of steps to simulate 357 358 @type resultsType: string 359 @param resultsType: Chooses which results to write 360 361 @type rulesOfTheSea: boolean 362 @param rulesOfTheSea: Tells whether to respect the rules of the sea 363 """ 364 365 wind = initWindFromFile(os.path.join(inputFilesDir, 'wind.py')) 366 waterCurrents = initWaterCurrentsFromFile(os.path.join(inputFilesDir, 'waterCurrents.py')) 367 waves = initWavesFromFile(os.path.join(inputFilesDir, 'waves.py')) 368 obstacles = initObstaclesFromFile(os.path.join(inputFilesDir, 'obstacles.py')) 369 sea = seaModels.Sea(wind, waterCurrents, waves, obstacles) 370 371 paths, patrolPoints, shipExternalStates = initShipPatrolPointsAndPathsFromFile(os.path.join(inputFilesDir, patrolFile)) 372 # print 'paths', paths 373 # print 'patrolPoints', patrolPoints 374 # print 'shipExternalStates', shipExternalStates 375 376 # used to be sent as a flag, but doesn't seem like there is a need 377 numShips = len(paths) 378 379 # Choose a ship factory 380 if shipType == 'basic': 381 shipFactory = factories.BasicShipFactory() 382 else: 383 raise Exception('Unknown ship type: ' + shipType) 384 385 # Allocate ships 386 ships = [shipFactory.create() for i in range(numShips)] 387 388 # world state 389 initialState = state.State( sea, ships, shipExternalStates ) 390 391 392 # Allocate an agent for each ship 393 # TODO: When we support mixed ship models, 394 # allocate an agent based on ship, and send it the possible actions 395 # for this ship 396 397 # Choose a world model factory 398 if worldModel == 'complete': 399 worldModelFactory = factories.CompleteWorldModelFactory() 400 else: 401 raise Exception('Unknown world model type: ' + worldModel) 402 403 # Choose a decision making strategy 404 if strategy == 'circling': 405 strategyFactory = factories.CirclingStrategyFactory() 406 elif strategy == 'rrt': 407 strategyFactory = factories.RRTStrategyFactory(paths, rulesOfTheSea) 408 elif strategy == 'pid': 409 strategyFactory = factories.PIDStrategyFactory(rulesOfTheSea) 410 elif strategy == 'measuredist': 411 strategyFactory = factories.MeasureEdgeLengthsFactory() 412 elif strategy == 'basicpatrol': 413 strategyFactory = factories.AgentBasicPatrolStrategyFactory(paths, rulesOfTheSea) 414 else: 415 raise Exception('Unknown decision making strategy: ' + strategy) 416 417 # Allocate agents with the above factories 418 shipAgents = [agents.Agent( worldModel = worldModelFactory.create(shipIndex=i), 419 strategy = strategyFactory.create(agentIndex=i) ) 420 for i,s in enumerate(ships)] 421 422 423 # Simulation module 424 env = simulationEnvironment.SimulationEnvironment( initialState, shipAgents ) 425 426 427 # start the simulation 428 import mainGUI 429 if withDisplay: 430 mainGUI.runGui(env, shipType, worldModel, strategy, numSteps) 431 else: 432 env.run(numSteps) 433 434 435 # write results 436 writeResults(resultsType, env, patrolPoints)
437 438 439 440 441 if __name__ == '__main__': 442 """ 443 The main function called when running the simulation 444 445 > python main.py 446 447 See the usage string for more details. 448 449 > python main.py --help 450 """ 451 args = readCommand( sys.argv[1:] ) # Get game components based on input 452 print 'Running simulation with the following options:' 453 for k, v in sorted(args.items()): 454 print k, '=', v 455 run( **args ) 456