def _init_board(self): self.board = Board(board_size=self.grid_size) self.to_connect = list(range(1, self.n_agents)) self.connected = [] if self.train: #obstacles_n = int((self.height/4) * (self.width/random.randint(5,6))) # <<-- Arbitrary: How many obstacles_n = 2 coord_set = set([(i, j) for i in range(self.height) for j in range(self.width)]) self.obstacles = random.sample(coord_set, obstacles_n) coord_set = coord_set.difference(self.obstacles) self.goals = self.goals if self.in_place else random.sample( coord_set, self.n_agents) coord_set = coord_set.difference(self.goals) self.starts = self.starts if self.in_place else random.sample( coord_set, self.n_agents) for obstacle in self.obstacles: self.board.place_obstacle(obstacle) for i in range(0, self.n_agents): i_d = i + 1 connector = Connector(self.starts[i], i_d) self.connectors.append(connector) self.board.cover_cell(self.starts[i], connector.head) self.board.cover_cell(self.goals[i], connector.goal)
def __init__(self): # scene stuff super(InitialScreen, self).__init__() self.next_state = "GAMEPLAY" # board self.board = Board() # region positions self.positions = list() self.read_in_regions() # objects self.player = Player("Player") self.ai = Player("AI") # gui elements self.action_bar = ActionBar( 0, pygame.display.get_surface().get_height() - 80, pygame.display.get_surface().get_width(), 80, []) self.menu_bar = MenuBar(0, 0, pygame.display.get_surface().get_width(), 40, middle='Select a Starting Region') # flags self.user_choosing = True self.ai_choosing = False self.paused = False # timer for basic things self.end_time = time.time() # setup pause menu self.menu = Menu(w=300, h=400) self.menu.set_pos((pygame.display.get_surface().get_width() / 2, pygame.display.get_surface().get_height() / 2)) self.menu.set_title('Paused') self.menu.set_buttons(['Continue', 'Quit Game'])
def start_game(self): ''' kicks off the game ''' settings = {'board_type': 'europe', 'num_players': len(self.players)} self.market = Market(settings) self.resources = Resources(settings) self.board = Board(settings) self.phase_one() logger.info("Initial Order: {}".format(self.player_order)) self.started = True
def __init__(self, players_number=6): self.players_number = players_number self.cards = Cards(cn.CHARACTERS, cn.WEAPONS, cn.ROOMS) # 3 are the cards to be guessed self.cards_per_person = (self.cards.number - 3) // self.players_number self.cards_to_players = self.cards_per_person * self.players_number self.cards_on_board = self.cards.number - self.cards_to_players - 3 self.suspects = Suspects(cn.CHARACTERS, cn.WEAPONS, cn.ROOMS) self.board = Board(self.cards_on_board) self.players: Players = None
def test_city_cost(self): board = Board({}) city1_cost = board.cost_of_city("Zurich") self.assertEqual(city1_cost, 10) city2_cost = board.cost_of_city("Abcdef") self.assertEqual(city2_cost, -1) board.update_cost("Zurich") city3_cost = board.cost_of_city("Zurich") self.assertEqual(city3_cost, 15) board.update_cost("Zurich") board.update_cost("Zurich") city4_cost = board.cost_of_city("Zurich") self.assertEqual(city4_cost, -1)
def test_path_cost(self): board = Board({}) path1 = ["Kharkiv", "Kyjiv", "Budapest", "Bucuresti"] path1_cost = board.cost_of_path(path1) self.assertEqual(path1_cost, 46) path2 = ["Kyjiv"] path2_cost = board.cost_of_path(path2) self.assertEqual(path2_cost, 0) path3 = ["Paris", "Bordeaux", "Zurich"] path3_cost = board.cost_of_path(path3) self.assertEqual(path3_cost, -1) path4_cost = board.cost_of_path([]) self.assertEqual(path4_cost, 0)
def test_purchasing(self): board = Board({}) player_id = "xxx" cost1 = board.player_purchase(player_id, ["Kharkiv"]) self.assertEqual(cost1, 10) cost2 = board.player_purchase(player_id, ["Kharkiv", "Kyjiv"]) self.assertEqual(cost2, 19) cost3 = board.player_purchase(player_id, ["Kyjiv", "Budapest"]) self.assertEqual(cost3, 31) cities = board.cities_owned_by_player(player_id) self.assertTrue("Kharkiv" in cities) self.assertTrue("Kyjiv" in cities) self.assertTrue("Budapest" in cities) self.assertEqual(len(cities), 3)
class Game: ''' determine player order auction power plants (in order) buy resources (reverse order!) build generators (reverse order!) bureaucracy ''' def __init__(self): self.market = None self.players = [] self.resources = None self.auction = Auction( ) # since auction doesn't require any player settings, we can initialize it right away self.step = 1 self.phase = Phase.DETERMINE_PLAYER_ORDER self.current_player = 0 # which player's turn it is w.r.t the player_order index self.player_order = [] self.started = False self.game_end = False def get_player_name(self, player_id): for player in self.players: if player.player_id == player_id: return player.name def player_can_afford(self, player_id, amount): for player in self.players: if player.player_id == player_id: return (player.money >= amount) def add_player(self, name, player_id): existing_names = [player.name for player in self.players] while name in existing_names: name = name + "!" # avoid duplicate names by adding exclamation marks player = Player(name, player_id) self.players.append(player) return name def start_game(self): ''' kicks off the game ''' settings = {'board_type': 'europe', 'num_players': len(self.players)} self.market = Market(settings) self.resources = Resources(settings) self.board = Board(settings) self.phase_one() logger.info("Initial Order: {}".format(self.player_order)) self.started = True def next_turn(self): ''' advances the turn/phase ''' if self.current_player < (len(self.player_order) - 1): # we are still in the same phase self.current_player += 1 if self.phase == Phase.AUCTION: for player in self.players: if player.player_id == self.player_order[ self.current_player]: if not player.can_bid: self.next_turn() return logger.info( "Advancing the counter! {} is the current_player".format( self.get_player_name( self.player_order[self.current_player]))) else: logger.info("Phase over! {} is the current_player".format( self.get_player_name(self.player_order[self.current_player]))) self.current_player = 0 if self.phase == Phase.AUCTION: self.player_order.reverse() self.phase = Phase.BUY_RESOURCES elif self.phase == Phase.BUY_RESOURCES: self.phase = Phase.BUILD_GENERATORS elif self.phase == Phase.BUILD_GENERATORS: self.phase = Phase.BUREAUCRACY # wait to trigger phase_five() until all players have powered self.player_order.reverse() if self.step == 1: self.check_step_two() self.check_game_end() elif self.phase == Phase.BUREAUCRACY: self.phase_five() def check_step_two(self): if len(self.players) == 6: phase_two_trigger = 6 else: phase_two_trigger = 7 for player in self.players: if self.board.num_cities(player.player_id) >= phase_two_trigger: self.step = 2 self.market.update_phase(2) self.board.phase = 2 self.resources.phase = 2 return def check_game_end(self): num_players = len(self.players) win_cities = [0, 0, 18, 17, 17, 15, 14] num_needed = win_cities[num_players] for player in self.players: if self.board.num_cities(player.player_id) >= num_needed: self.game_end = True return def resolve_turn(self): ''' resolves the current turn due to lack of response from user ''' if self.phase == Phase.AUCTION: if self.auction.auction_in_progress: current = self.auction.can_bid[self.auction.current_bidder] else: current = self.player_order[self.current_player] self.auction_pass(current) elif self.phase == Phase.BUY_RESOURCES or self.phase == Phase.BUILD_GENERATORS: self.next_turn() elif self.phase == Phase.BUREAUCRACY: self.player_powered(self.player_order[self.current_player], 0) def phase_one(self): ''' determine player order ''' print("phase one") self.current_player = -1 if self.player_order == []: # it's the first round! we randomly choose players = [player.player_id for player in self.players] random.shuffle(players) self.player_order = players else: self.player_order = [] not_yet_picked = [player.player_id for player in self.players] while len(self.player_order) != len(self.players): top = max(not_yet_picked, key=lambda x: self.board.num_cities(x)) num_cities = self.board.num_cities(top) ties = [ player for player in self.players if self.board.num_cities(player.player_id) == num_cities ] rank = sorted(ties, key=lambda x: x.highest_powerplant(), reverse=True) for player in rank: self.player_order.append(player.player_id) not_yet_picked.remove(player.player_id) logger.info("Player Order: {}".format( [self.get_player_name(p_id) for p_id in self.player_order])) self.current_player = 0 self.phase = Phase.AUCTION def auction_pass(self, player_id): ''' player_id passed on the current auction ''' if not self.auction.auction_in_progress: # the player is the leader! They can no longer bid for player in self.players: if player.player_id == player_id: player.can_bid = False # special case! the player is not allowed to pass on the first turn if len(player.powerplants) == 0: # we only get here if the player timed out # so we force them to buy the most expensive available powerplant as punishment pplant = sorted(self.market.currently_available, lambda x: x["market_cost"])[-1] player.money -= pplant["market_cost"] player.powerplants.append(pplant) self.market.buy(pplant["market_cost"]) self.next_turn() else: self.auction.can_bid.remove(player_id) # logger.info("{} passed. Remaining Players: {}".format(player_id, self.auction.can_bid)) if len(self.auction.can_bid) == 1: self.auction.auction_in_progress = False # someone has won the bid! winner = self.auction.can_bid[0] for player in self.players: if player.player_id == winner: player.can_bid = False won_plant = self.market.buy( self.auction.currently_for_bid) player.powerplants.append(won_plant) player.money -= self.auction.current_bid logger.info( "{} won the auction! Bought powerplant {} for {} money" .format(player.name, self.auction.currently_for_bid, self.auction.current_bid)) if self.auction.to_be_trashed is not None: logger.info( "{} has too many plants! Trashing powerplant {}" .format(player.name, self.auction.to_be_trashed)) player.trash_powerplant(self.auction.to_be_trashed) if player.player_id == self.player_order[ self.current_player]: self.next_turn() break else: self.auction.advance_bid() def auction_bid(self, player_id, bid, powerplant, trash_id): ''' player_id submitted 'bid' money for the current auction or is starting a new auction ''' if self.auction.auction_in_progress: self.auction.current_bid = bid self.auction.winning_bidder = player_id self.auction.to_be_trashed = trash_id self.auction.advance_bid() else: biddable_players = [ player.player_id for player in self.players if player.can_bid ] if len(biddable_players) == 1: # special case; there is no auction for player in self.players: if player.player_id == player_id: player.can_bid = False won_plant = self.market.buy(powerplant) player.powerplants.append(won_plant) player.money -= self.auction.current_bid logger.info( "{} won the auction! Bought powerplant {} for {} money" .format(player.name, powerplant, bid)) if trash_id is not None: logger.info( "{} has too many plants! Trashing powerplant {}" .format(player.name, self.auction.to_be_trashed)) player.trash_powerplant(trash_id) self.next_turn() return else: self.auction.can_bid = [ player_code for player_code in self.player_order if player_code in biddable_players ] name = self.get_player_name(player_id) self.auction.current_bidder = 1 logger.info("{} started an auction for powerplant {}".format( name, powerplant)) self.auction.currently_for_bid = powerplant self.auction.winning_bidder = player_id self.auction.current_bid = bid self.auction.to_be_trashed = trash_id self.auction.auction_in_progress = True def buy_resources(self, player_id, r_type, amount): cost = self.resources.cost_to_buy(r_type, amount) self.resources.currently_available[r_type] -= amount name = self.get_player_name(player_id) for player in self.players: if player.player_id == player_id: player.money -= cost player.resources[r_type] += amount logger.info( "{} aquired {} of resource type {} for {} money".format( name, amount, r_type, cost)) return cost def build_generator(self, player_id, path): ''' build a generator in the designated city ''' cost_to_build = self.board.player_purchase(player_id, path) for player in self.players: if player.player_id == player_id: player.money -= cost_to_build break num_owned_cities = self.board.num_cities(player_id) if num_owned_cities >= self.market.currently_available[0][ "market_cost"]: self.market.trash_low_powerplants(num_owned_cities) return cost_to_build def plant_powered(self, player_id, plant_id, num_oil): ''' 'powers' the given powerplant and returns the amount of energy that was generated ''' for player in self.players: if player.player_id == player_id: for plant in player.powerplants: if plant["market_cost"] == plant_id: if plant["resource_type"] == RType.HYBRID: needed = plant["resource_cost"] needed_gas = needed - num_oil player.resources[RType.OIL] -= num_oil player.resources[RType.GAS] -= needed_gas elif plant["resource_type"] != RType.CLEAN: player.resources[plant["resource_type"]] -= plant[ "resource_cost"] return plant["generators"] def player_powered(self, player_id, num_powered): ''' player powers generators for money ''' amounts = [ 10, 22, 33, 44, 54, 64, 73, 82, 90, 98, 105, 112, 118, 124, 129, 134, 138, 142, 145, 148, 150 ] for player in self.players: if player.player_id == player_id: num_cities = self.board.num_cities(player_id) num_power = min(num_cities, num_powered) amount = amounts[num_power] player.money += amount name = self.get_player_name(player_id) logger.info("{} powered {} cities for {} money".format( name, num_power, amount)) if self.game_end: player.game_end_power = num_powered self.next_turn() return amount def phase_five(self): ''' bureaucracy ''' print("phase_five") # check for end game wrap up if self.game_end: winner = max(self.players, key=lambda x: x.game_end_power) ties = [ player for player in self.players if player.game_end_power == winner.game_end_power ] if len(ties) > 1: logger.info( "Tie for powering {} generators! Evaluating money".format( winner.game_end_power)) winner = max(ties, key=lambda x: x.money) logger.info("{} won the game!!".format(winner.name)) self.log_end_state() return # refresh resource market print("refreshing market") owned_resources = { RType.OIL: 0, RType.GAS: 0, RType.COAL: 0, RType.URANIUM: 0 } for player in self.players: for resource in player.resources: owned_resources[resource] += player.resources[resource] # we reset all player flags so they can bid again player.can_bid = True self.resources.refresh_market(owned_resources) # prune market step3 = self.market.bureaucracy() if step3: self.step = 3 self.resources.phase = 3 self.board.phase = 3 self.phase = Phase.DETERMINE_PLAYER_ORDER self.phase_one() def log_end_state(self): for player in self.players: logger.info("{} End Stats:".format(player.name)) logger.info("\tPowered {} Generators in Final Round".format( player.game_end_power)) logger.info("\tBuilt in {} Cities".format( self.board.num_cities(player.player_id))) logger.info("\tEnded the game with {} Money".format(player.money))
class InitialScreen(GameState): def __init__(self): # scene stuff super(InitialScreen, self).__init__() self.next_state = "GAMEPLAY" # board self.board = Board() # region positions self.positions = list() self.read_in_regions() # objects self.player = Player("Player") self.ai = Player("AI") # gui elements self.action_bar = ActionBar( 0, pygame.display.get_surface().get_height() - 80, pygame.display.get_surface().get_width(), 80, []) self.menu_bar = MenuBar(0, 0, pygame.display.get_surface().get_width(), 40, middle='Select a Starting Region') # flags self.user_choosing = True self.ai_choosing = False self.paused = False # timer for basic things self.end_time = time.time() # setup pause menu self.menu = Menu(w=300, h=400) self.menu.set_pos((pygame.display.get_surface().get_width() / 2, pygame.display.get_surface().get_height() / 2)) self.menu.set_title('Paused') self.menu.set_buttons(['Continue', 'Quit Game']) def get_event(self, event): if self.paused and self.menu.get_event(event) == 'Continue': self.paused = False elif self.paused and self.menu.get_event(event) == 'Quit Game': sys.exit(0) # close window elif event.type == pygame.QUIT: self.quit = True elif event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: self.paused = not self.paused # choose region elif not self.paused and self.user_choosing and event.type == pygame.MOUSEBUTTONDOWN: # get region and set player troops region = self.get_clicked_region(event) self.player.troops.update({str(region): 3}) self.player.set_home_region(str(region)) # change flags self.ai_choosing = True self.user_choosing = False # update timer self.end_time = time.time() + 2 def update(self, dt): if self.paused: self.menu.update() return # handle ai choosing a region if self.ai_choosing and time.time() > self.end_time: # randomly select ai region player_region = int(list(self.player.troops.keys())[0]) region = random.randint(0, len(self.positions) - 1) while abs(player_region - region) < (len(self.positions) / 2 - 1): region = random.randint(0, len(self.positions) - 1) self.ai.troops[str(region)] = 3 self.ai.home_region = str(region) # update time and flags self.end_time = time.time() + 2 self.ai_choosing = False # change to gameplay scene if not self.ai_choosing and not self.user_choosing and time.time( ) > self.end_time: self.persist_state() self.done = True self.update_menu_bar() def render(self, surface): # draw ocean surface.fill(pygame.Color("dodgerblue")) # draw board, action bar, and menu bar self.board.render(surface) self.action_bar.render(surface) self.menu_bar.render(surface) # draw regions self.draw_regions(surface) # pause menu if self.paused: self.menu.render(surface) def update_menu_bar(self): if self.user_choosing: self.menu_bar.update_middle('Select a Starting Region') elif self.ai_choosing: self.menu_bar.update_middle('AI is Choosing a Starting Region') else: self.menu_bar.update_middle('AI Has Chosen a Starting Region') def draw_regions(self, surface): # draw player labels for key, value in self.player.troops.items(): x, y = self.positions[int(key)] if key == self.player.home_region: cl = CircleLabel(str(value), x, y, rad=20, bc=(0, 0, 0), fc=(0, 200, 0)) else: cl = CircleLabel(str(value), x, y, rad=20, bc=(0, 255, 0)) cl.render(surface) # draw ai labels for key, value in self.ai.troops.items(): x, y = self.positions[int(key)] if key == self.ai.home_region: cl = CircleLabel(str(value), x, y, rad=20, bc=(0, 0, 0), fc=(200, 0, 0)) else: cl = CircleLabel(str(value), x, y, rad=20, bc=(200, 0, 0)) cl.render(surface) def get_clicked_region(self, event): pos = event.pos distance = 1000 region = 0 for (i, p) in enumerate(self.positions): region = region temp = math.sqrt( math.pow((p[0] - pos[0]), 2) + math.pow((p[1] - pos[1]), 2)) if temp < distance: distance = temp region = i return region def read_in_regions(self): with open(os.path.join('data', 'positions.txt')) as f: for line in f: line = line.rstrip() values = line.split(" ") self.positions.append((int(values[0]), int(values[1]))) def startup(self, persistent): self.persist['difficulty'] = persistent['difficulty'] def persist_state(self): self.persist['player'] = self.player self.persist['ai'] = self.ai
class CluedoGame: def __init__(self, players_number=6): self.players_number = players_number self.cards = Cards(cn.CHARACTERS, cn.WEAPONS, cn.ROOMS) # 3 are the cards to be guessed self.cards_per_person = (self.cards.number - 3) // self.players_number self.cards_to_players = self.cards_per_person * self.players_number self.cards_on_board = self.cards.number - self.cards_to_players - 3 self.suspects = Suspects(cn.CHARACTERS, cn.WEAPONS, cn.ROOMS) self.board = Board(self.cards_on_board) self.players: Players = None # 1) MAIN: Regulating the alternation of the various game phases def main(self): self.initiate_game() self.display_game_info() while self.suspects.guessing_probability < 1: action = inputs.get_user_action(self.players.active.name) if action == "1": self.accusation_made_event() self.display_game_info() if action == "1" or action == "2": # Go to the next player self.players.make_next_player_active() if action == "3": self.card_revealed_event() self.display_game_info() # If probability is 1, the game is solved self.suspects.display_guessing_probability_message() # -------------------------------------------------------------------------- # GAME SET UP # -------------------------------------------------------------------------- def initiate_game(self): """Set up a new game getting all the required items ready""" self.initiate_players() self.register_users_cards() return def initiate_players(self): """Create the list of players""" user_position = inputs.get_user_position(self.players_number) self.players = Players( self.players_number, self.cards_per_person, user_position ) return def register_users_cards(self) -> None: """Register the fact that users owns its initial cards.""" user_owned_cards = inputs.get_users_cards( self.cards_per_person, self.cards.all_cards ) self.suspects.remove_multiple_from_suspects(user_owned_cards) user = self.players.get_player_by_name("You") for card in user_owned_cards: self.update_card_owned(card, user) self.update_card_not_owned( user_owned_cards, self.players.list, player_excluded=user ) # -------------------------------------------------------------------------- # ACCUSATION HANDLING # -------------------------------------------------------------------------- def accusation_made_event(self): """Handle the entire event of an accusation being made""" cs, wp, rm = self.cards.characters, self.cards.weapons, self.cards.rooms accusation_list = inputs.get_accusation(cs, wp, rm) accusation = Accusation.from_list(accusation_list) player_showed_name = inputs.get_player_who_showed(self.players.names) player_showed = self.players.get_player_by_name(player_showed_name) players_passing = self.players.range_of_players(player_showed) self.update_card_not_owned(accusation.items_set, players_passing) # Distinguishing the actions between "You" and the other players if self.players.active.name == "You": self.card_shown_to_user(accusation, player_showed) else: self.update_card_owned(accusation.items_list, player_showed) def card_shown_to_user(self, accusation: Accusation, player_showed: Player) -> None: """Handle the event of a card being shown to the user""" card_showed = inputs.get_card_from_accusation(accusation.items_list) self.suspects.remove_one_from_suspects(card_showed) self.update_card_not_owned(card_showed, self.players.list, player_showed) self.update_card_owned(card_showed, player_showed) def update_card_not_owned( self, card_input: Union[str, list], players_list: list[Player], player_excluded=Union[None, Player], ) -> None: """Registers that one or more players do not own one or more cards""" card_input_as_set = utilities.input_to_set(card_input) for player in players_list: if player != player_excluded: player.add_cards_not_owned(card_input_as_set) def update_card_owned( self, card_input: Union[str, list], player_to_update: Player ) -> None: # Not to proceed further if information about the player is complete if player_to_update.all_cards_known: return card_input_as_set = utilities.input_to_set(card_input) player_to_update.add_cards_owned(card_input_as_set) # -------------------------------------------------------------------------- # CARD REVEALED HANDLING # -------------------------------------------------------------------------- def card_revealed_event(self) -> None: """Handles the complete event of a card being revealed""" if self.board.all_cards_revealed: print( "It looks like all the cards on the table had already been" "revealed, please retry.\n" ) return revealed_card = inputs.input_in_list( "Which card was revealed?", self.cards.all_cards ) self.register_card_revealed(revealed_card) def register_card_revealed(self, revealed_card: str) -> None: """Register that a card has been revealed""" self.suspects.remove_one_from_suspects(revealed_card) self.update_card_not_owned(revealed_card, self.players.list) self.board.add_card(revealed_card) # -------------------------------------------------------------------------- # INFORMATION DISPLAY # -------------------------------------------------------------------------- def display_game_info(self): print("########################### SUSPECTS") print(self.suspects) print("########################### PLAYERS INFO") self.players.display_players_info() print("########################### BOARD") print(self.board) print()
def main(): crossword = Board(5, 5) user_input = UserInput() crossword.read_clues("questions.csv") crossword.print_board(True) crossword.print_clues() while True: guessed = user_input.user_guess_word() user_guess = guessed[0] guess_number = guessed[1] if user_guess == ":q": break has_user_won = crossword.guess_word(user_guess, guess_number) crossword.print_board(True) crossword.print_clues() if has_user_won: print("Congratulations you have won!") break
from components.board import Board from components.led import Led from components.arm import Arm from components.ring import Ring def test(string): """Test...""" sleep(2) print "Testing" + string pg.off() LOW_BRIGHTNESS = 1 BRIGHTNESS = 100 BLIND = 255 pg = Board() test("all") pg.all(BRIGHTNESS) test("led") for i in range(Led.NUMBER): pg.off() pg.led(i+1, BRIGHTNESS) sleep(2) test("arm") for i in range(Arm.NUMBER): pg.off() pg.arm(i+1, BRIGHTNESS) sleep(2)
def main(): """Let's get it on...""" board = Board(n_players=N_PLAYERS, n_decks=N_DECKS) board.play()
class MultiPathGridEnv(): def __init__(self, obstacles, starts, goals, grid_size=[20, 15], obs_size=[1000, 1000], agents_n=1, train=False, in_place=False): # **kwargs self.train = train self.in_place = in_place self.partial_view = True if obs_size < grid_size else False self.grid_size = grid_size self.obs_size = obs_size self.obs_height = self.obs_size[0] self.obs_width = self.obs_size[1] self.height = self.grid_size[0] self.width = self.grid_size[1] self.obstacles = obstacles self.connectors = [] self.n_agents = agents_n self.action_space = list(range(0, 8)) # Assert that both these list sizes == n_agents after: self.starts = starts self.goals = goals self.episode_ended = [False] * self.n_agents self._init_board() def _init_board(self): self.board = Board(board_size=self.grid_size) self.to_connect = list(range(1, self.n_agents)) self.connected = [] if self.train: #obstacles_n = int((self.height/4) * (self.width/random.randint(5,6))) # <<-- Arbitrary: How many obstacles_n = 2 coord_set = set([(i, j) for i in range(self.height) for j in range(self.width)]) self.obstacles = random.sample(coord_set, obstacles_n) coord_set = coord_set.difference(self.obstacles) self.goals = self.goals if self.in_place else random.sample( coord_set, self.n_agents) coord_set = coord_set.difference(self.goals) self.starts = self.starts if self.in_place else random.sample( coord_set, self.n_agents) for obstacle in self.obstacles: self.board.place_obstacle(obstacle) for i in range(0, self.n_agents): i_d = i + 1 connector = Connector(self.starts[i], i_d) self.connectors.append(connector) self.board.cover_cell(self.starts[i], connector.head) self.board.cover_cell(self.goals[i], connector.goal) def step(self, moves, idx): # Assert agent == moves rewards = [] all_obs = [] for i, move in zip(idx, moves): reward, obs = self._move_connector(i, move) rewards.append(reward) all_obs.append(obs) return all_obs, rewards, self.episode_ended def start_obs(self): # Assert agent == moves all_obs = [] # TO DO for idx in range(self.n_agents): connector = self.connectors[idx] head_coord = connector.get_head() dist = self._get_euclid_distance(head_coord, self.goals[idx]) obs = (self.return_obs(head_coord), dist) all_obs.append(obs) return all_obs def reset(self): self.connectors = [] self._init_board() self.episode_ended = [False] * self.n_agents return self.start_obs() def render(self): plt.ion() plt.figure(figsize=(20, 10)) ax = plt.gca() ax.clear() clear_output(wait=True) env_plot = self.board.grid.copy() env_plot = env_plot.astype(int) colors = [ 'grey', 'white', 'pink', 'red', 'green', 'blue', 'yellow', 'purple', 'purple' ] cmap = ListedColormap(colors[:self.n_agents + 2]) ax.matshow(env_plot, cmap=cmap) plt.show() def _move_connector(self, idx, direction): connector = self.connectors[idx] prev_pos = connector.get_head() self.board.grid[prev_pos] = connector.trail reward = -1 connector.move(direction) new_pos = connector.get_head() new_dist = self._get_euclid_distance(new_pos, self.goals[idx]) if self.board.off_grid(new_pos): reward -= 10 self.episode_ended = [True] * self.n_agents #connector.pop_head() useful if we don't want to end the episode. elif self.board.cell_val(new_pos) == connector.goal: self.board.cover_cell(new_pos, connector.head) self.episode_ended[idx] = True reward += 20 elif self.board.cell_val(new_pos) != self.board.EMPTY_CELL: reward -= 10 self.episode_ended = [True] * self.n_agents else: self.board.cover_cell(new_pos, connector.head) if direction % 2 == 1 and self.board.diag_collision( prev_pos, new_pos, direction): reward -= 10 self.episode_ended[idx] = True return_obs = self.return_obs(connector.get_head()) return reward, (return_obs, new_dist) def return_obs(self, head): obs = self.partial_obs(head) if self.partial_view else self.board.grid obs_shaped = np.expand_dims(obs * 10, axis=0) return obs_shaped def partial_obs(self, head): # Get bounding indices: top_loc = head[0] - self.obs_height // 2 bottom_loc = head[0] + 1 + self.obs_height // 2 left_loc = head[1] - self.obs_width // 2 right_loc = head[1] + 1 + self.obs_width // 2 if top_loc < 0: top = 0 top_obs = np.abs(top_loc) else: top = top_loc top_obs = 0 if bottom_loc > self.height: bottom = self.height bottom_obs = self.obs_height - np.abs(bottom_loc - self.height) else: bottom = bottom_loc bottom_obs = self.obs_height if left_loc < 0: left = 0 left_obs = np.abs(left_loc) else: left = left_loc left_obs = 0 if right_loc > self.width: right = self.width right_obs = self.obs_width - np.abs(right_loc - self.width) else: right = right_loc right_obs = self.obs_width obs = self.board.grid[top:bottom, left:right] padded_obs = np.ones((self.obs_height, self.obs_width)) * [-1] padded_obs[top_obs:bottom_obs, left_obs:right_obs] = obs return padded_obs def _get_euclid_distance(self, head, goal): head = np.array(head) goal = np.array(goal) vector_dist = head - goal euclid_dist = np.sqrt(vector_dist[0]**2 + vector_dist[1]**2) return euclid_dist
def test_init(self): ''' make sure we can load the board without error ''' settings = {} board = Board(settings)