OwlOnPurge


SUBMITTED BY: OwlOnPurge

DATE: Dec. 23, 2022, 11:40 p.m.

FORMAT: Text only

SIZE: 26.7 kB

HITS: 459

  1. # pacman.py
  2. # ---------
  3. # Licensing Information: Please do not distribute or publish solutions to this
  4. # project. You are free to use and extend these projects for educational
  5. # purposes. The Pacman AI projects were developed at UC Berkeley, primarily by
  6. # John DeNero (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
  7. # For more info, see http://inst.eecs.berkeley.edu/~cs188/sp09/pacman.html
  8. """
  9. Pacman.py holds the logic for the classic pacman game along with the main
  10. code to run a game. This file is divided into three sections:
  11. (i) Your interface to the pacman world:
  12. Pacman is a complex environment. You probably don't want to
  13. read through all of the code we wrote to make the game runs
  14. correctly. This section contains the parts of the code
  15. that you will need to understand in order to complete the
  16. project. There is also some code in game.py that you should
  17. understand.
  18. (ii) The hidden secrets of pacman:
  19. This section contains all of the logic code that the pacman
  20. environment uses to decide who can move where, who dies when
  21. things collide, etc. You shouldn't need to read this section
  22. of code, but you can if you want.
  23. (iii) Framework to start a game:
  24. The final section contains the code for reading the command
  25. you use to set up the game, then starting up a new game, along with
  26. linking in all the external parts (agent functions, graphics).
  27. Check this section out to see all the options available to you.
  28. To play your first game, type 'python pacman.py' from the command line.
  29. The keys are 'a', 's', 'd', and 'w' to move (or arrow keys). Have fun!
  30. """
  31. from game import GameStateData
  32. from game import Game
  33. from game import Directions
  34. from game import Actions
  35. from util import nearestPoint
  36. from util import manhattanDistance
  37. import util, layout
  38. import sys, types, time, random, os
  39. ###################################################
  40. # YOUR INTERFACE TO THE PACMAN WORLD: A GameState #
  41. ###################################################
  42. class GameState:
  43. """
  44. A GameState specifies the full game state, including the food, capsules,
  45. agent configurations and score changes.
  46. GameStates are used by the Game object to capture the actual state of the game and
  47. can be used by agents to reason about the game.
  48. Much of the information in a GameState is stored in a GameStateData object. We
  49. strongly suggest that you access that data via the accessor methods below rather
  50. than referring to the GameStateData object directly.
  51. Note that in classic Pacman, Pacman is always agent 0.
  52. """
  53. ####################################################
  54. # Accessor methods: use these to access state data #
  55. ####################################################
  56. # static variable keeps track of which states have had getLegalActions called
  57. explored = set()
  58. def getAndResetExplored():
  59. tmp = GameState.explored.copy()
  60. GameState.explored = set()
  61. return tmp
  62. getAndResetExplored = staticmethod(getAndResetExplored)
  63. def getLegalActions( self, agentIndex=0 ):
  64. """
  65. Returns the legal actions for the agent specified.
  66. """
  67. GameState.explored.add(self)
  68. if self.isWin() or self.isLose(): return []
  69. if agentIndex == 0: # Pacman is moving
  70. return PacmanRules.getLegalActions( self )
  71. else:
  72. return GhostRules.getLegalActions( self, agentIndex )
  73. def generateSuccessor( self, agentIndex, action):
  74. """
  75. Returns the successor state after the specified agent takes the action.
  76. """
  77. # Check that successors exist
  78. if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.')
  79. # Copy current state
  80. state = GameState(self)
  81. # Let agent's logic deal with its action's effects on the board
  82. if agentIndex == 0: # Pacman is moving
  83. state.data._eaten = [False for i in range(state.getNumAgents())]
  84. PacmanRules.applyAction( state, action )
  85. else: # A ghost is moving
  86. GhostRules.applyAction( state, action, agentIndex )
  87. # Time passes
  88. if agentIndex == 0:
  89. state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around
  90. else:
  91. GhostRules.decrementTimer( state.data.agentStates[agentIndex] )
  92. # Resolve multi-agent effects
  93. GhostRules.checkDeath( state, agentIndex )
  94. # Book keeping
  95. state.data._agentMoved = agentIndex
  96. state.data.score += state.data.scoreChange
  97. return state
  98. def getLegalPacmanActions( self ):
  99. return self.getLegalActions( 0 )
  100. def generatePacmanSuccessor( self, action ):
  101. """
  102. Generates the successor state after the specified pacman move
  103. """
  104. return self.generateSuccessor( 0, action )
  105. def getPacmanState( self ):
  106. """
  107. Returns an AgentState object for pacman (in game.py)
  108. state.pos gives the current position
  109. state.direction gives the travel vector
  110. """
  111. return self.data.agentStates[0].copy()
  112. def getPacmanPosition( self ):
  113. return self.data.agentStates[0].getPosition()
  114. def getGhostStates( self ):
  115. return self.data.agentStates[1:]
  116. def getGhostState( self, agentIndex ):
  117. if agentIndex == 0 or agentIndex >= self.getNumAgents():
  118. raise Exception("Invalid index passed to getGhostState")
  119. return self.data.agentStates[agentIndex]
  120. def getGhostPosition( self, agentIndex ):
  121. if agentIndex == 0:
  122. raise Exception("Pacman's index passed to getGhostPosition")
  123. return self.data.agentStates[agentIndex].getPosition()
  124. def getGhostPositions(self):
  125. return [s.getPosition() for s in self.getGhostStates()]
  126. def getNumAgents( self ):
  127. return len( self.data.agentStates )
  128. def getScore( self ):
  129. return self.data.score
  130. def getCapsules(self):
  131. """
  132. Returns a list of positions (x,y) of the remaining capsules.
  133. """
  134. return self.data.capsules
  135. def getNumFood( self ):
  136. return self.data.food.count()
  137. def getFood(self):
  138. """
  139. Returns a Grid of boolean food indicator variables.
  140. Grids can be accessed via list notation, so to check
  141. if there is food at (x,y), just call
  142. currentFood = state.getFood()
  143. if currentFood[x][y] == True: ...
  144. """
  145. return self.data.food
  146. def getWalls(self):
  147. """
  148. Returns a Grid of boolean wall indicator variables.
  149. Grids can be accessed via list notation, so to check
  150. if there is food at (x,y), just call
  151. walls = state.getWalls()
  152. if walls[x][y] == True: ...
  153. """
  154. return self.data.layout.walls
  155. def hasFood(self, x, y):
  156. return self.data.food[x][y]
  157. def hasWall(self, x, y):
  158. return self.data.layout.walls[x][y]
  159. def isLose( self ):
  160. return self.data._lose
  161. def isWin( self ):
  162. return self.data._win
  163. #############################################
  164. # Helper methods: #
  165. # You shouldn't need to call these directly #
  166. #############################################
  167. def __init__( self, prevState = None ):
  168. """
  169. Generates a new state by copying information from its predecessor.
  170. """
  171. if prevState != None: # Initial state
  172. self.data = GameStateData(prevState.data)
  173. else:
  174. self.data = GameStateData()
  175. def deepCopy( self ):
  176. state = GameState( self )
  177. state.data = self.data.deepCopy()
  178. return state
  179. def __eq__( self, other ):
  180. """
  181. Allows two states to be compared.
  182. """
  183. return self.data == other.data
  184. def __hash__( self ):
  185. """
  186. Allows states to be keys of dictionaries.
  187. """
  188. return hash( self.data )
  189. def __str__( self ):
  190. return str(self.data)
  191. def initialize( self, layout, numGhostAgents=1000 ):
  192. """
  193. Creates an initial game state from a layout array (see layout.py).
  194. """
  195. self.data.initialize(layout, numGhostAgents)
  196. ############################################################################
  197. # THE HIDDEN SECRETS OF PACMAN #
  198. # #
  199. # You shouldn't need to look through the code in this section of the file. #
  200. ############################################################################
  201. SCARED_TIME = 40 # Moves ghosts are scared
  202. COLLISION_TOLERANCE = 0.7 # How close ghosts must be to Pacman to kill
  203. TIME_PENALTY = 1 # Number of points lost each round
  204. class ClassicGameRules:
  205. """
  206. These game rules manage the control flow of a game, deciding when
  207. and how the game starts and ends.
  208. """
  209. def __init__(self, timeout=30):
  210. self.timeout = timeout
  211. def newGame( self, layout, pacmanAgent, ghostAgents, display, quiet = False, catchExceptions=False):
  212. agents = [pacmanAgent] + ghostAgents[:layout.getNumGhosts()]
  213. initState = GameState()
  214. initState.initialize( layout, len(ghostAgents) )
  215. game = Game(agents, display, self, catchExceptions=catchExceptions)
  216. game.state = initState
  217. self.initialState = initState.deepCopy()
  218. self.quiet = quiet
  219. return game
  220. def process(self, state, game):
  221. """
  222. Checks to see whether it is time to end the game.
  223. """
  224. if state.isWin(): self.win(state, game)
  225. if state.isLose(): self.lose(state, game)
  226. def win( self, state, game ):
  227. if not self.quiet: print "Pacman emerges victorious! Score: %d" % state.data.score
  228. game.gameOver = True
  229. def lose( self, state, game ):
  230. if not self.quiet: print "Pacman died! Score: %d" % state.data.score
  231. game.gameOver = True
  232. def getProgress(self, game):
  233. return float(game.state.getNumFood()) / self.initialState.getNumFood()
  234. def agentCrash(self, game, agentIndex):
  235. if agentIndex == 0:
  236. print "Pacman crashed"
  237. else:
  238. print "A ghost crashed"
  239. def getMaxTotalTime(self, agentIndex):
  240. return self.timeout
  241. def getMaxStartupTime(self, agentIndex):
  242. return self.timeout
  243. def getMoveWarningTime(self, agentIndex):
  244. return self.timeout
  245. def getMoveTimeout(self, agentIndex):
  246. return self.timeout
  247. def getMaxTimeWarnings(self, agentIndex):
  248. return 0
  249. class PacmanRules:
  250. """
  251. These functions govern how pacman interacts with his environment under
  252. the classic game rules.
  253. """
  254. PACMAN_SPEED=1
  255. def getLegalActions( state ):
  256. """
  257. Returns a list of possible actions.
  258. """
  259. return Actions.getPossibleActions( state.getPacmanState().configuration, state.data.layout.walls )
  260. getLegalActions = staticmethod( getLegalActions )
  261. def applyAction( state, action ):
  262. """
  263. Edits the state to reflect the results of the action.
  264. """
  265. legal = PacmanRules.getLegalActions( state )
  266. if action not in legal:
  267. raise Exception("Illegal action " + str(action))
  268. pacmanState = state.data.agentStates[0]
  269. # Update Configuration
  270. vector = Actions.directionToVector( action, PacmanRules.PACMAN_SPEED )
  271. pacmanState.configuration = pacmanState.configuration.generateSuccessor( vector )
  272. # Eat
  273. next = pacmanState.configuration.getPosition()
  274. nearest = nearestPoint( next )
  275. if manhattanDistance( nearest, next ) <= 0.5 :
  276. # Remove food
  277. PacmanRules.consume( nearest, state )
  278. applyAction = staticmethod( applyAction )
  279. def consume( position, state ):
  280. x,y = position
  281. # Eat food
  282. if state.data.food[x][y]:
  283. state.data.scoreChange += 10
  284. state.data.food = state.data.food.copy()
  285. state.data.food[x][y] = False
  286. state.data._foodEaten = position
  287. # TODO: cache numFood?
  288. numFood = state.getNumFood()
  289. if numFood == 0 and not state.data._lose:
  290. state.data.scoreChange += 500
  291. state.data._win = True
  292. # Eat capsule
  293. if( position in state.getCapsules() ):
  294. state.data.capsules.remove( position )
  295. state.data._capsuleEaten = position
  296. # Reset all ghosts' scared timers
  297. for index in range( 1, len( state.data.agentStates ) ):
  298. state.data.agentStates[index].scaredTimer = SCARED_TIME
  299. consume = staticmethod( consume )
  300. class GhostRules:
  301. """
  302. These functions dictate how ghosts interact with their environment.
  303. """
  304. GHOST_SPEED=1.0
  305. def getLegalActions( state, ghostIndex ):
  306. """
  307. Ghosts cannot stop, and cannot turn around unless they
  308. reach a dead end, but can turn 90 degrees at intersections.
  309. """
  310. conf = state.getGhostState( ghostIndex ).configuration
  311. possibleActions = Actions.getPossibleActions( conf, state.data.layout.walls )
  312. reverse = Actions.reverseDirection( conf.direction )
  313. if Directions.STOP in possibleActions:
  314. possibleActions.remove( Directions.STOP )
  315. if reverse in possibleActions and len( possibleActions ) > 1:
  316. possibleActions.remove( reverse )
  317. return possibleActions
  318. getLegalActions = staticmethod( getLegalActions )
  319. def applyAction( state, action, ghostIndex):
  320. legal = GhostRules.getLegalActions( state, ghostIndex )
  321. if action not in legal:
  322. raise Exception("Illegal ghost action " + str(action))
  323. ghostState = state.data.agentStates[ghostIndex]
  324. speed = GhostRules.GHOST_SPEED
  325. if ghostState.scaredTimer > 0: speed /= 2.0
  326. vector = Actions.directionToVector( action, speed )
  327. ghostState.configuration = ghostState.configuration.generateSuccessor( vector )
  328. applyAction = staticmethod( applyAction )
  329. def decrementTimer( ghostState):
  330. timer = ghostState.scaredTimer
  331. if timer == 1:
  332. ghostState.configuration.pos = nearestPoint( ghostState.configuration.pos )
  333. ghostState.scaredTimer = max( 0, timer - 1 )
  334. decrementTimer = staticmethod( decrementTimer )
  335. def checkDeath( state, agentIndex):
  336. pacmanPosition = state.getPacmanPosition()
  337. if agentIndex == 0: # Pacman just moved; Anyone can kill him
  338. for index in range( 1, len( state.data.agentStates ) ):
  339. ghostState = state.data.agentStates[index]
  340. ghostPosition = ghostState.configuration.getPosition()
  341. if GhostRules.canKill( pacmanPosition, ghostPosition ):
  342. GhostRules.collide( state, ghostState, index )
  343. else:
  344. ghostState = state.data.agentStates[agentIndex]
  345. ghostPosition = ghostState.configuration.getPosition()
  346. if GhostRules.canKill( pacmanPosition, ghostPosition ):
  347. GhostRules.collide( state, ghostState, agentIndex )
  348. checkDeath = staticmethod( checkDeath )
  349. def collide( state, ghostState, agentIndex):
  350. if ghostState.scaredTimer > 0:
  351. state.data.scoreChange += 200
  352. GhostRules.placeGhost(state, ghostState)
  353. ghostState.scaredTimer = 0
  354. # Added for first-person
  355. state.data._eaten[agentIndex] = True
  356. else:
  357. if not state.data._win:
  358. state.data.scoreChange -= 500
  359. state.data._lose = True
  360. collide = staticmethod( collide )
  361. def canKill( pacmanPosition, ghostPosition ):
  362. return manhattanDistance( ghostPosition, pacmanPosition ) <= COLLISION_TOLERANCE
  363. canKill = staticmethod( canKill )
  364. def placeGhost(state, ghostState):
  365. ghostState.configuration = ghostState.start
  366. placeGhost = staticmethod( placeGhost )
  367. #############################
  368. # FRAMEWORK TO START A GAME #
  369. #############################
  370. def default(str):
  371. return str + ' [Default: %default]'
  372. def parseAgentArgs(str):
  373. if str == None: return {}
  374. pieces = str.split(',')
  375. opts = {}
  376. for p in pieces:
  377. if '=' in p:
  378. key, val = p.split('=')
  379. else:
  380. key,val = p, 1
  381. opts[key] = val
  382. return opts
  383. def readCommand( argv ):
  384. """
  385. Processes the command used to run pacman from the command line.
  386. """
  387. from optparse import OptionParser
  388. usageStr = """
  389. USAGE: python pacman.py <options>
  390. EXAMPLES: (1) python pacman.py
  391. - starts an interactive game
  392. (2) python pacman.py --layout smallClassic --zoom 2
  393. OR python pacman.py -l smallClassic -z 2
  394. - starts an interactive game on a smaller board, zoomed in
  395. """
  396. parser = OptionParser(usageStr)
  397. parser.add_option('-n', '--numGames', dest='numGames', type='int',
  398. help=default('the number of GAMES to play'), metavar='GAMES', default=1)
  399. parser.add_option('-l', '--layout', dest='layout',
  400. help=default('the LAYOUT_FILE from which to load the map layout'),
  401. metavar='LAYOUT_FILE', default='mediumClassic')
  402. parser.add_option('-p', '--pacman', dest='pacman',
  403. help=default('the agent TYPE in the pacmanAgents module to use'),
  404. metavar='TYPE', default='KeyboardAgent')
  405. parser.add_option('-t', '--textGraphics', action='store_true', dest='textGraphics',
  406. help='Display output as text only', default=False)
  407. parser.add_option('-q', '--quietTextGraphics', action='store_true', dest='quietGraphics',
  408. help='Generate minimal output and no graphics', default=False)
  409. parser.add_option('-g', '--ghosts', dest='ghost',
  410. help=default('the ghost agent TYPE in the ghostAgents module to use'),
  411. metavar = 'TYPE', default='RandomGhost')
  412. parser.add_option('-k', '--numghosts', type='int', dest='numGhosts',
  413. help=default('The maximum number of ghosts to use'), default=4)
  414. parser.add_option('-z', '--zoom', type='float', dest='zoom',
  415. help=default('Zoom the size of the graphics window'), default=1.0)
  416. parser.add_option('-f', '--fixRandomSeed', action='store_true', dest='fixRandomSeed',
  417. help='Fixes the random seed to always play the same game', default=False)
  418. parser.add_option('-r', '--recordActions', action='store_true', dest='record',
  419. help='Writes game histories to a file (named by the time they were played)', default=False)
  420. parser.add_option('--replay', dest='gameToReplay',
  421. help='A recorded game file (pickle) to replay', default=None)
  422. parser.add_option('-a','--agentArgs',dest='agentArgs',
  423. help='Comma separated values sent to agent. e.g. "opt1=val1,opt2,opt3=val3"')
  424. parser.add_option('-x', '--numTraining', dest='numTraining', type='int',
  425. help=default('How many episodes are training (suppresses output)'), default=0)
  426. parser.add_option('--frameTime', dest='frameTime', type='float',
  427. help=default('Time to delay between frames; <0 means keyboard'), default=0.1)
  428. parser.add_option('-c', '--catchExceptions', action='store_true', dest='catchExceptions',
  429. help='Turns on exception handling and timeouts during games', default=False)
  430. parser.add_option('--timeout', dest='timeout', type='int',
  431. help=default('Maximum length of time an agent can spend computing in a single game'), default=30)
  432. options, otherjunk = parser.parse_args(argv)
  433. if len(otherjunk) != 0:
  434. raise Exception('Command line input not understood: ' + str(otherjunk))
  435. args = dict()
  436. # Fix the random seed
  437. if options.fixRandomSeed: random.seed('cs188')
  438. # Choose a layout
  439. args['layout'] = layout.getLayout( options.layout )
  440. if args['layout'] == None: raise Exception("The layout " + options.layout + " cannot be found")
  441. # Choose a Pacman agent
  442. noKeyboard = options.gameToReplay == None and (options.textGraphics or options.quietGraphics)
  443. pacmanType = loadAgent(options.pacman, noKeyboard)
  444. agentOpts = parseAgentArgs(options.agentArgs)
  445. if options.numTraining > 0:
  446. args['numTraining'] = options.numTraining
  447. if 'numTraining' not in agentOpts: agentOpts['numTraining'] = options.numTraining
  448. pacman = pacmanType(**agentOpts) # Instantiate Pacman with agentArgs
  449. args['pacman'] = pacman
  450. # Don't display training games
  451. if 'numTrain' in agentOpts:
  452. options.numQuiet = int(agentOpts['numTrain'])
  453. options.numIgnore = int(agentOpts['numTrain'])
  454. # Choose a ghost agent
  455. ghostType = loadAgent(options.ghost, noKeyboard)
  456. args['ghosts'] = [ghostType( i+1 ) for i in range( options.numGhosts )]
  457. # Choose a display format
  458. if options.quietGraphics:
  459. import textDisplay
  460. args['display'] = textDisplay.NullGraphics()
  461. elif options.textGraphics:
  462. import textDisplay
  463. textDisplay.SLEEP_TIME = options.frameTime
  464. args['display'] = textDisplay.PacmanGraphics()
  465. else:
  466. import graphicsDisplay
  467. args['display'] = graphicsDisplay.PacmanGraphics(options.zoom, frameTime = options.frameTime)
  468. args['numGames'] = options.numGames
  469. args['record'] = options.record
  470. args['catchExceptions'] = options.catchExceptions
  471. args['timeout'] = options.timeout
  472. # Special case: recorded games don't use the runGames method or args structure
  473. if options.gameToReplay != None:
  474. print 'Replaying recorded game %s.' % options.gameToReplay
  475. import cPickle
  476. f = open(options.gameToReplay)
  477. try: recorded = cPickle.load(f)
  478. finally: f.close()
  479. recorded['display'] = args['display']
  480. replayGame(**recorded)
  481. sys.exit(0)
  482. return args
  483. def loadAgent(pacman, nographics):
  484. # Looks through all pythonPath Directories for the right module,
  485. pythonPathStr = os.path.expandvars("$PYTHONPATH")
  486. if pythonPathStr.find(';') == -1:
  487. pythonPathDirs = pythonPathStr.split(':')
  488. else:
  489. pythonPathDirs = pythonPathStr.split(';')
  490. pythonPathDirs.append('.')
  491. for moduleDir in pythonPathDirs:
  492. if not os.path.isdir(moduleDir): continue
  493. moduleNames = [f for f in os.listdir(moduleDir) if f.endswith('gents.py')]
  494. for modulename in moduleNames:
  495. try:
  496. module = __import__(modulename[:-3])
  497. except ImportError:
  498. continue
  499. if pacman in dir(module):
  500. if nographics and modulename == 'keyboardAgents.py':
  501. raise Exception('Using the keyboard requires graphics (not text display)')
  502. return getattr(module, pacman)
  503. raise Exception('The agent ' + pacman + ' is not specified in any *Agents.py.')
  504. def replayGame( layout, actions, display ):
  505. import pacmanAgents, ghostAgents
  506. rules = ClassicGameRules()
  507. agents = [pacmanAgents.GreedyAgent()] + [ghostAgents.RandomGhost(i+1) for i in range(layout.getNumGhosts())]
  508. game = rules.newGame( layout, agents[0], agents[1:], display )
  509. state = game.state
  510. display.initialize(state.data)
  511. for action in actions:
  512. # Execute the action
  513. state = state.generateSuccessor( *action )
  514. # Change the display
  515. display.update( state.data )
  516. # Allow for game specific conditions (winning, losing, etc.)
  517. rules.process(state, game)
  518. display.finish()
  519. def runGames( layout, pacman, ghosts, display, numGames, record, numTraining = 0, catchExceptions=False, timeout=30 ):
  520. import __main__
  521. __main__.__dict__['_display'] = display
  522. rules = ClassicGameRules(timeout)
  523. games = []
  524. for i in range( numGames ):
  525. beQuiet = i < numTraining
  526. if beQuiet:
  527. # Suppress output and graphics
  528. import textDisplay
  529. gameDisplay = textDisplay.NullGraphics()
  530. rules.quiet = True
  531. else:
  532. gameDisplay = display
  533. rules.quiet = False
  534. game = rules.newGame( layout, pacman, ghosts, gameDisplay, beQuiet, catchExceptions)
  535. game.run()
  536. if not beQuiet: games.append(game)
  537. if record:
  538. import time, cPickle
  539. fname = ('recorded-game-%d' % (i + 1)) + '-'.join([str(t) for t in time.localtime()[1:6]])
  540. f = file(fname, 'w')
  541. components = {'layout': layout, 'actions': game.moveHistory}
  542. cPickle.dump(components, f)
  543. f.close()
  544. if (numGames-numTraining) > 0:
  545. scores = [game.state.getScore() for game in games]
  546. wins = [game.state.isWin() for game in games]
  547. winRate = wins.count(True)/ float(len(wins))
  548. print 'Average Score:', sum(scores) / float(len(scores))
  549. print 'Scores: ', ', '.join([str(score) for score in scores])
  550. print 'Win Rate: %d/%d (%.2f)' % (wins.count(True), len(wins), winRate)
  551. print 'Record: ', ', '.join([ ['Loss', 'Win'][int(w)] for w in wins])
  552. return games
  553. if __name__ == '__main__':
  554. """
  555. The main function called when pacman.py is run
  556. from the command line:
  557. > python pacman.py
  558. See the usage string for more details.
  559. > python pacman.py --help
  560. """
  561. args = readCommand( sys.argv[1:] ) # Get game components based on input
  562. runGames( **args )
  563. # import cProfile
  564. # cProfile.run("runGames( **args )")
  565. pass

comments powered by Disqus