def choose(self, agentStr, index): if agentStr == 'keys': global NUM_KEYBOARD_AGENTS NUM_KEYBOARD_AGENTS += 1 if NUM_KEYBOARD_AGENTS == 1: return keyboardAgents.KeyboardAgent(index) elif NUM_KEYBOARD_AGENTS == 2: return keyboardAgents.KeyboardAgent2(index) else: raise Exception('Max of two keyboard agents supported') elif agentStr == 'offense': weightStrategy = OffenseWeightStrategy() weightStrategies.append(weightStrategy) weightStrategies.sort(key=lambda x: x.getAggressiveness(), reverse=True) agent = MattReflexCaptureAgent(index, self.debug, self.maxPlys, self.maxTime, self.lastMoveCount, weightStrategy, self.nonIterative) distanceToOpponentFood[agent] = 0.0 return agent elif agentStr == 'defense': weightStrategy = DefenseWeightStrategy() weightStrategies.append(weightStrategy) weightStrategies.sort(key=lambda x: x.getAggressiveness(), reverse=True) agent = MattReflexCaptureAgent(index, self.debug, self.maxPlys, self.maxTime, self.lastMoveCount, weightStrategy, self.nonIterative) distanceToOpponentFood[agent] = 0.0 return agent else: raise Exception("No staff agent identified by " + agentStr)
def choose(self, agentStr, index): if agentStr == 'keys': global NUM_KEYBOARD_AGENTS NUM_KEYBOARD_AGENTS += 1 if NUM_KEYBOARD_AGENTS == 1: return keyboardAgents.KeyboardAgent(index) elif NUM_KEYBOARD_AGENTS == 2: return keyboardAgents.KeyboardAgent2(index) else: raise Exception('Max of two keyboard agents supported') elif agentStr == 'offense': return OffensiveReflexAgent(index) elif agentStr == 'defense': return DefensiveReflexAgent(index) else: raise Exception("No staff agent identified by " + agentStr)
def choose(self, agentStr, index): print "agentStr:", agentStr if agentStr == 'keys': global NUM_KEYBOARD_AGENTS NUM_KEYBOARD_AGENTS += 1 if NUM_KEYBOARD_AGENTS == 1: return keyboardAgents.KeyboardAgent(index) elif NUM_KEYBOARD_AGENTS == 2: return keyboardAgents.KeyboardAgent2(index) else: raise Exception('Max of two keyboard agents supported') elif agentStr == 'offense': return AttackReflexAgent(index) elif agentStr == 'defense': return InferenceDefenseAgent(index) #elif agentStr =='router': # return RoutingAgent(index) else: raise Exception("No staff agent identified by " + agentStr)
def readCommand(argv): """ Processes the command used to run pacman from the command line. """ from optparse import OptionParser usageStr = """ USAGE: python pacman.py <options> EXAMPLES: (1) python capture.py - starts a game with two baseline agents (2) python capture.py --keys0 - starts a two-player interactive game where the arrow keys control agent 0, and all other agents are baseline agents (3) python capture.py -r baselineTeam -b myTeam - starts a fully automated game where the red team is a baseline team and blue team is myTeam """ parser = OptionParser(usageStr) parser.add_option('-r', '--red', help=default('Red team'), default='baselineTeam') parser.add_option('-b', '--blue', help=default('Blue team'), default='baselineTeam') parser.add_option('--red-name', help=default('Red team name'), default='Red') parser.add_option('--blue-name', help=default('Blue team name'), default='Blue') parser.add_option('--redOpts', help=default('Options for red team (e.g. first=keys)'), default='') parser.add_option('--blueOpts', help=default('Options for blue team (e.g. first=keys)'), default='') parser.add_option('--keys0', help='Make agent 0 (first red player) a keyboard agent', action='store_true', default=False) parser.add_option('--keys1', help='Make agent 1 (second red player) a keyboard agent', action='store_true', default=False) parser.add_option('--keys2', help='Make agent 2 (first blue player) a keyboard agent', action='store_true', default=False) parser.add_option( '--keys3', help='Make agent 3 (second blue player) a keyboard agent', action='store_true', default=False) parser.add_option( '-l', '--layout', dest='layout', help=default( 'the LAYOUT_FILE from which to load the map layout; use RANDOM for a random maze; use RANDOM<seed> to use a specified random seed, e.g., RANDOM23' ), metavar='LAYOUT_FILE', default='defaultCapture') parser.add_option('-t', '--textgraphics', action='store_true', dest='textgraphics', help='Display output as text only', default=False) parser.add_option('-q', '--quiet', action='store_true', help='Display minimal output and no graphics', default=False) parser.add_option('-Q', '--super-quiet', action='store_true', dest="super_quiet", help='Same as -q but agent output is also suppressed', default=False) parser.add_option('-z', '--zoom', type='float', dest='zoom', help=default('Zoom in the graphics'), default=1) parser.add_option('-i', '--time', type='int', dest='time', help=default('TIME limit of a game in moves'), default=1200, metavar='TIME') parser.add_option('-n', '--numGames', type='int', help=default('Number of games to play'), default=1) parser.add_option( '-f', '--fixRandomSeed', action='store_true', help='Fixes the random seed to always play the same game', default=False) parser.add_option( '--record', action='store_true', help= 'Writes game histories to a file (named by the time they were played)', default=False) parser.add_option( '--recordLog', action='store_true', help='Writes game log to a file (named by the time they were played)', default=False) parser.add_option('--replay', default=None, help='Replays a recorded game file.') parser.add_option( '--replayq', default=None, help= 'Replays a recorded game file without display to generate result log.') parser.add_option('--delay-step', type='float', dest='delay_step', help=default('Delay step in a play or replay.'), default=0.03) parser.add_option( '-x', '--numTraining', dest='numTraining', type='int', help=default('How many episodes are training (suppresses output)'), default=0) parser.add_option('-c', '--catchExceptions', action='store_true', default=False, help='Catch exceptions and enforce time limits') options, otherjunk = parser.parse_args(argv) assert len(otherjunk) == 0, "Unrecognized options: " + str(otherjunk) args = dict() # Choose a display format #if options.pygame: # import pygameDisplay # args['display'] = pygameDisplay.PacmanGraphics() if options.textgraphics: import textDisplay args['display'] = textDisplay.PacmanGraphics() elif options.quiet or options.replayq: import textDisplay args['display'] = textDisplay.NullGraphics() elif options.super_quiet: import textDisplay args['display'] = textDisplay.NullGraphics() args['muteAgents'] = True else: import captureGraphicsDisplay # Hack for agents writing to the display captureGraphicsDisplay.FRAME_TIME = 0 args['display'] = captureGraphicsDisplay.PacmanGraphics(options.red, options.blue, options.zoom, 0, capture=True) import __main__ __main__.__dict__['_display'] = args['display'] args['redTeamName'] = options.red_name args['blueTeamName'] = options.blue_name if options.fixRandomSeed: random.seed('cs188') if options.recordLog: sys.stdout = open('log-0', 'w') sys.stderr = sys.stdout # Special case: recorded games don't use the runGames method or args structure if options.replay != None: print('Replaying recorded game %s.' % options.replay) import pickle recorded = pickle.load(open(options.replay, 'rb'), encoding="bytes") recorded['display'] = args['display'] recorded['delay'] = options.delay_step recorded['redTeamName'] = options.red recorded['blueTeamName'] = options.blue recorded['waitEnd'] = False replayGame(**recorded) sys.exit(0) # Special case: recorded games don't use the runGames method or args structure if options.replayq != None: print('Replaying recorded game %s.' % options.replay) import pickle recorded = pickle.load(open(options.replayq, 'rb'), encoding="bytes") recorded['display'] = args['display'] recorded['delay'] = 0.0 recorded['redTeamName'] = options.red recorded['blueTeamName'] = options.blue recorded['waitEnd'] = False replayGame(**recorded) sys.exit(0) # Choose a pacman agent redArgs, blueArgs = parseAgentArgs(options.redOpts), parseAgentArgs( options.blueOpts) if options.numTraining > 0: redArgs['numTraining'] = options.numTraining blueArgs['numTraining'] = options.numTraining nokeyboard = options.textgraphics or options.quiet or options.numTraining > 0 print('\nRed team %s with %s:' % (options.red, redArgs)) redAgents = loadAgents(True, options.red, nokeyboard, redArgs) print('\nBlue team %s with %s:' % (options.blue, blueArgs)) blueAgents = loadAgents(False, options.blue, nokeyboard, blueArgs) args['agents'] = sum([list(el) for el in zip(redAgents, blueAgents)], []) # list of agents if None in blueAgents or None in redAgents: if None in blueAgents: print('\nBlue team failed to load!\n') if None in redAgents: print('\nRed team failed to load!\n') raise Exception('No teams found!') numKeyboardAgents = 0 for index, val in enumerate( [options.keys0, options.keys1, options.keys2, options.keys3]): if not val: continue if numKeyboardAgents == 0: agent = keyboardAgents.KeyboardAgent(index) elif numKeyboardAgents == 1: agent = keyboardAgents.KeyboardAgent2(index) else: raise Exception('Max of two keyboard agents supported') numKeyboardAgents += 1 args['agents'][index] = agent # Choose a layout import layout layouts = [] for i in range(options.numGames): if options.layout == 'RANDOM': l = layout.Layout(randomLayout().split('\n')) elif options.layout.startswith('RANDOM'): l = layout.Layout( randomLayout(int(options.layout[6:])).split('\n')) elif options.layout.lower().find('capture') == -1: raise Exception('You must use a capture layout with capture.py') else: l = layout.getLayout(options.layout) if l == None: raise Exception("The layout " + options.layout + " cannot be found") layouts.append(l) args['layouts'] = layouts args['length'] = options.time args['numGames'] = options.numGames args['numTraining'] = options.numTraining args['record'] = options.record args['catchExceptions'] = options.catchExceptions args['delay_step'] = options.delay_step return args
def readCommand( argv ): """ Processes the command used to run pacman from the command line. """ from optparse import OptionParser usageStr = """ USAGE: python pacman.py <options> EXAMPLES: (1) python capture.py - starts a game with two baseline agents (2) python capture.py --keys0 - starts a two-player interactive game where the arrow keys control agent 0, and all other agents are baseline agents (3) python capture.py -p baselineTeam -b myTeam - starts a fully automated game where the pacman team is a baseline team and ghost team is myTeam """ # TODO: Update above according to final defaults parser = OptionParser(usageStr) parser.add_option('-p', '--pacman', help=default('Pacman team'), default='phase3Team') # TODO: Think about if we should leave this default parser.add_option('-g', '--ghost', help=default('Ghost team'), default='P3oneGhostTeam') parser.add_option('--pacman-name', help=default('Pacman team name'), default='Pacman') parser.add_option('--ghost-name', help=default('Ghost team name'), default='Ghost') parser.add_option('--keys0', help='Make agent 0 (first pacman player) a keyboard agent', action='store_true',default=False) parser.add_option('--keys1', help='Make agent 1 (second pacman player) a keyboard agent', action='store_true',default=False) parser.add_option('--keys2', help='Make agent 2 (first ghost player) a keyboard agent', action='store_true',default=False) parser.add_option('--keys3', help='Make agent 3 (second ghost player) a keyboard agent', action='store_true',default=False) parser.add_option('-l', '--layout', dest='layout', help=default('the LAYOUT_FILE from which to load the map layout; use RANDOM for a random maze; use RANDOM<seed> to use a specified random seed, e.g., RANDOM23'), metavar='LAYOUT_FILE', default='defaultCapture') parser.add_option('-t', '--textgraphics', action='store_true', dest='textgraphics', help='Display output as text only', default=False) parser.add_option('-q', '--quiet', action='store_true', help='Display minimal output and no graphics', default=False) parser.add_option('-Q', '--super-quiet', action='store_true', dest="super_quiet", help='Same as -q but agent output is also suppressed', default=False) parser.add_option('-z', '--zoom', type='float', dest='zoom', help=default('Zoom in the graphics'), default=1) parser.add_option('-i', '--time', type='int', dest='time', help=default('TIME limit of a game in moves'), default=1200, metavar='TIME') parser.add_option('-n', '--numGames', type='int', help=default('Number of games to play'), default=10) parser.add_option('-f', '--fixRandomSeed', action='store_true', help='Fixes the random seed to always play the same game', default=False) parser.add_option('--record', action='store_true', help='Writes game histories to a file (named by the time they were played)', default=False) parser.add_option('--replay', default=None, help='Replays a recorded game file.') # TODO: This currently doesn't work, consider removing or fixing parser.add_option('-x', '--numTraining', dest='numTraining', type='int', help=default('How many episodes are training (suppresses output)'), default=0) parser.add_option('-c', '--catchExceptions', action='store_true', default=True, help='Catch exceptions and enforce time limits') options, otherjunk = parser.parse_args(argv) assert len(otherjunk) == 0, "Unrecognized options: " + str(otherjunk) args = dict() # Choose a display format if options.textgraphics: import textDisplay args['display'] = textDisplay.PacmanGraphics() elif options.quiet: import textDisplay args['display'] = textDisplay.NullGraphics() elif options.super_quiet: import textDisplay args['display'] = textDisplay.NullGraphics() args['muteAgents'] = True else: import captureGraphicsDisplay # Hack for agents writing to the display captureGraphicsDisplay.FRAME_TIME = 0 args['display'] = captureGraphicsDisplay.PacmanGraphics(options.pacman, options.ghost, options.zoom, 0, capture=True) import __main__ __main__.__dict__['_display'] = args['display'] args['pacmanTeamName'] = options.pacman_name args['ghostTeamName'] = options.ghost_name if options.fixRandomSeed: random.seed('cs188') # Special case: recorded games don't use the runGames method or args structure if options.replay != None: print 'Replaying recorded game %s.' % options.replay import cPickle recorded = cPickle.load(open(options.replay)) recorded['display'] = args['display'] replayGame(**recorded) sys.exit(0) # Choose a pacman agent nokeyboard = options.textgraphics or options.quiet pacmanAgents = loadAgents(True, 'phase3Team', nokeyboard, {}) ghostAgents = loadAgents(False, 'P3oneGhostTeam', nokeyboard, {}) # Assume 2 agents on the pacman side, and # variable amount (0-2) on the ghost side args['agents'] = pacmanAgents + ghostAgents numKeyboardAgents = 0 for index, val in enumerate([options.keys0, options.keys1, options.keys2, options.keys3]): if not val: continue if numKeyboardAgents == 0: agent = keyboardAgents.KeyboardAgent(index) elif numKeyboardAgents == 1: agent = keyboardAgents.KeyboardAgent2(index) else: raise Exception('Max of two keyboard agents supported') numKeyboardAgents += 1 args['agents'][index] = agent # Generate the layouts args['layouts'] = generateLayouts(LAYOUT_SEED, ghostAgents) args['length'] = options.time args['numGames'] = options.numGames args['numTraining'] = options.numTraining args['record'] = options.record args['catchExceptions'] = options.catchExceptions return args
def readCommand(argv): """ Processes the command used to run pacman from the command line. """ from optparse import OptionParser usageStr = """ USAGE: python pacman.py <options> EXAMPLES: (1) python capture.py - starts a game with two baseline agents (2) python capture.py --keys0 - starts a two-player interactive game where the arrow keys control agent 0, and all other agents are baseline agents (3) python capture.py -p baselineTeam -b myTeam - starts a fully automated game where the pacman team is a baseline team and ghost team is myTeam """ parser = OptionParser(usageStr) parser.add_option('-p', '--pacman', help=default('Pacman team'), default='team') parser.add_option('--pac0', help=default('Pacman at Index 0'), default='None') parser.add_option('--pac1', help=default('Pacman at Index 1'), default='None') parser.add_option('-g', '--ghost', help=default('Ghost team'), default='oneGhostTeam') parser.add_option('--pacman-name', help=default('Pacman team name'), default='Pacman') parser.add_option('--ghost-name', help=default('Ghost team name'), default='Ghost') parser.add_option( '--pacmanOpts', help=default('Options for pacman team (e.g. first=keys)'), default='') parser.add_option('--ghostOpts', help=default('Options for ghost team (e.g. first=keys)'), default='') parser.add_option( '--keys0', help='Make agent 0 (first pacman player) a keyboard agent', action='store_true', default=False) parser.add_option( '--keys1', help='Make agent 1 (second pacman player) a keyboard agent', action='store_true', default=False) parser.add_option( '--keys2', help='Make agent 2 (first ghost player) a keyboard agent', action='store_true', default=False) parser.add_option( '--keys3', help='Make agent 3 (second ghost player) a keyboard agent', action='store_true', default=False) parser.add_option( '-l', '--layout', dest='layout', help=default( 'the LAYOUT_FILE from which to load the map layout; use RANDOM for a random maze; use RANDOM<seed> to use a specified random seed, e.g., RANDOM23' ), metavar='LAYOUT_FILE', default='defaultCapture') parser.add_option('-t', '--textgraphics', action='store_true', dest='textgraphics', help='Display output as text only', default=False) parser.add_option('-q', '--quiet', action='store_true', help='Display minimal output and no graphics', default=False) parser.add_option('-Q', '--super-quiet', action='store_true', dest="super_quiet", help='Same as -q but agent output is also suppressed', default=False) parser.add_option('-z', '--zoom', type='float', dest='zoom', help=default('Zoom in the graphics'), default=1) parser.add_option('-i', '--time', type='int', dest='time', help=default('TIME limit of a game in moves'), default=1200, metavar='TIME') parser.add_option('-n', '--numGames', type='int', help=default('Number of games to play'), default=1) parser.add_option( '-f', '--fixRandomSeed', action='store_true', help='Fixes the random seed to always play the same game', default=False) parser.add_option( '--record', action='store_true', help= 'Writes game histories to a file (named by the time they were played)', default=False) parser.add_option('--replay', default=None, help='Replays a recorded game file.') # TODO: This currently doesn't work, consider removing or fixing parser.add_option( '-x', '--numTraining', dest='numTraining', type='int', help=default('How many episodes are training (suppresses output)'), default=0) parser.add_option('-c', '--catchExceptions', action='store_true', default=True, help='Catch exceptions and enforce time limits') options, otherjunk = parser.parse_args(argv) assert len(otherjunk) == 0, "Unrecognized options: " + str(otherjunk) args = dict() # Variable to keep track of custom team customTeam = False if options.pac0 != 'None': customTeam = True options.pacman_name = 'Team ' + options.pac0 + " + " + options.pac1 # Choose a display format if options.textgraphics: import textDisplay args['display'] = textDisplay.PacmanGraphics() elif options.quiet: import textDisplay args['display'] = textDisplay.NullGraphics() elif options.super_quiet: import textDisplay args['display'] = textDisplay.NullGraphics() args['muteAgents'] = True else: import captureGraphicsDisplay # Hack for agents writing to the display captureGraphicsDisplay.FRAME_TIME = 0 args['display'] = captureGraphicsDisplay.PacmanGraphics(options.pacman, options.ghost, options.zoom, 0, capture=True) import __main__ __main__.__dict__['_display'] = args['display'] args['pacmanTeamName'] = options.pacman_name args['ghostTeamName'] = options.ghost_name if options.fixRandomSeed: random.seed('cs188') # Special case: recorded games don't use the runGames method or args structure if options.replay != None: print('Replaying recorded game %s.' % options.replay) import pickle recorded = pickle.load(open(options.replay)) recorded['display'] = args['display'] replayGame(**recorded) sys.exit(0) # Choose a pacman agent pacmanTeamArgs, ghostTeamArgs = parseAgentArgs( options.pacmanOpts), parseAgentArgs(options.ghostOpts) if options.numTraining > 0: pacmanTeamArgs['numTraining'] = options.numTraining ghostTeamArgs['numTraining'] = options.numTraining nokeyboard = options.textgraphics or options.quiet or options.numTraining > 0 # Default, loading from the phasexTeam.py if not customTeam: pacmanAgents = loadAgents(True, options.pacman, nokeyboard, pacmanTeamArgs) print('Pacman team %s with args %s:' % (options.pacman, pacmanTeamArgs)) # Custom loading else: pacZero = loadOneAgent(True, options.pac0, 0) pacOne = loadOneAgent(True, options.pac1, 1) pacmanAgents = [pacZero, pacOne] ghostAgents = loadAgents(False, options.ghost, nokeyboard, ghostTeamArgs) if ghostAgents: print('Ghost team %s with args %s:' % (options.ghost, ghostTeamArgs)) # Assume 2 agents on the pacman side, and # variable amount (0-2) on the ghost side args['agents'] = pacmanAgents + ghostAgents numKeyboardAgents = 0 for index, val in enumerate( [options.keys0, options.keys1, options.keys2, options.keys3]): if not val: continue if numKeyboardAgents == 0: agent = keyboardAgents.KeyboardAgent(index) elif numKeyboardAgents == 1: agent = keyboardAgents.KeyboardAgent2(index) else: raise Exception('Max of two keyboard agents supported') numKeyboardAgents += 1 args['agents'][index] = agent # Choose a layout import layout if options.layout == 'RANDOM': args['layout'] = layout.Layout(randomLayout().split('\n'), maxGhosts=len(ghostAgents)) elif options.layout.startswith('RANDOM'): args['layout'] = layout.Layout(randomLayout(int( options.layout[6:])).split('\n'), maxGhosts=len(ghostAgents)) elif options.layout.lower().find('capture') == -1: raise Exception('You must use a capture layout with capture.py') else: args['layout'] = layout.getLayout(options.layout, maxGhosts=len(ghostAgents)) if args['layout'] == None: raise Exception("The layout " + options.layout + " cannot be found") args['length'] = options.time args['numGames'] = options.numGames args['numTraining'] = options.numTraining args['record'] = options.record args['catchExceptions'] = options.catchExceptions return args
def readCommand(argv): """ Processes the command used to run pacman from the command line. """ from optparse import OptionParser usageStr = """ USAGE: python run.py <options> EXAMPLES: (1) python run.py - starts an interactive game (2) python run.py #TODO to be completed """ parser = OptionParser(usageStr) # parser.add_option('-n', '--numGames', dest='numGames', type='int', # help=default('the number of GAMES to play'), metavar='GAMES', default=1) #TODO we can have a default auto mode. In this case the game will auto run and generate some stats. parser.add_option( '-r', '--role', dest='role', help=default( 'Chose either one of the three roles - thief, detective or auto'), metavar='ROLE', default='detective') parser.add_option( '-t', '--thief', dest='thief', help=default('the agent TYPE in the thief module to use'), metavar='THIEF_TYPE', default='random') parser.add_option( '-d', '--detectives', dest='detectives', help=default('the agent TYPE in the detectives module to use'), metavar='TYPE', default='RandomDetective') parser.add_option('-k', '--numDetectives', type='int', dest='numDetectives', help=default('The maximum number of detectives to use'), default=5) parser.add_option( '-D', '--detective1', dest='D1', help=default( 'The agent TYPE in the detectives module to use for detective 1'), default='KeyboardAgent') parser.add_option( '--timeout', dest='timeout', type='int', help=default( 'Maximum length of time an agent can spend computing in a single game' ), default=30) options, otherjunk = parser.parse_args(argv) if len(otherjunk) != 0: raise Exception('Command line input not understood: ' + str(otherjunk)) args = dict() print(options) #TODO There is a fancy way of loading the pacman and ghost agents here by using the script similar to pacman but right # now we will implement implement by string matching method #TODO currently assume all the detectives have the same agent type. We can later also built in arguments for defining # agent type for each detective if options.role == 'thief': args['role'] = 'thief' if options.thief == 'KeyboardAgent': args['thief'] = keyboardAgents.KeyboardAgent() elif options.thief == 'minimax': args['thief'] = thief.MinimaxAgent() # multiple elif conditions or use the load agent module from the pacman script. elif options.thief == 'random': args['thief'] = thief.RandomAgent() else: raise Exception('The agent ' + options.thief + ' is not specified in any *Agents.py.') args['detectives'] = [ detectives.RandomAgent(i + 1) for i in range(options.numDetectives) ] elif options.role == 'detective': args['role'] = 'detective1' if options.D1 == 'KeyboardAgent': args['detectives'] = [keyboardAgents.KeyboardAgent(1)] + [ detectives.RandomAgent(i + 1) for i in range(1, options.numDetectives) ] elif options.D1 == 'minimax': args['detectives'] = [detectives.MinimaxAgent(1)] + [ detectives.RandomAgent(i + 1) for i in range(1, options.numDetectives) ] # multiple elif conditions or use the load agent module from the pacman script. elif options.D1 == 'random': args['detectives'] = [ detectives.RandomAgent(i + 1) for i in range(options.numDetectives) ] else: raise Exception('The agent ' + options.D1 + ' is not specified in any *Agents.py.') args['thief'] = thief.RandomAgent() # check for the first agent type for detective, if not specified assign keyboard. else: # Check for the specification for agents for thief and detectives. If not specified for thief, then assign random. args['role'] = 'auto' args['thief'] = thief.RandomAgent() args['detectives'] = [ detectives.RandomAgent(i + 1) for i in range(options.numDetectives) ] return args