diff --git a/roborally.py b/roborally.py index 487cc83..727ac08 100644 --- a/roborally.py +++ b/roborally.py @@ -93,13 +93,19 @@ class Robot: self.board[(x,y)].occupant = self - def get_accessed_tiles(self, count): + def get_accessed_tiles(self, count, forward=True): # create a list of all tiles the robot would enter if it drives steps forward tiles = [] current_tile = self.board[(self.x, self.y)] for i in range(1, count + 1): - current_tile = self.board.get(current_tile.get_neighbor_coordinates(self.orientation)) - tiles.append(current_tile) + if forward: + current_tile = self.board.get(current_tile.get_neighbor_coordinates(self.orientation)) + else: + current_tile = self.board.get(current_tile.get_neighbor_coordinates(Robot.opposites[self.orientation])) + if current_tile is None: + return tiles + else: + tiles.append(current_tile) return tiles def is_pushable(self, direction): @@ -154,7 +160,7 @@ class Robot: return "{}, forward".format(self.id) elif type == 'backward': opposite_orientation = self.get_opposite_orientation() - target_tile = tile.get_neighbor_coordinates(opposite_orientation) + target_tile = self.board[tile.get_neighbor_coordinates(opposite_orientation)] if target_tile.occupant is not None: print("error: target tile is not empty") @@ -235,32 +241,46 @@ class Board: if (x == 0) or (x == Board.x_dims + 1) or (y == 0) or (y == Board.y_dims + 1): # place walls around the board self.board[(x, y)] = Tile(x, y, '#') - elif x == 1 and (y >= 1) and (y <= 4): + elif x == 1 and (y >= 1) and (y < 4): self.board[(x, y)] = Tile(x, y, 'v') + elif y == 4: + self.board[(x, y)] = Tile(x, y, '>') else: self.board[(x,y)] = Tile(x,y) self.robots = {} - self.robots[0] = Robot(3, 1, '<', 0, self.board) + self.robots[0] = Robot(3, 1, '>', 0, self.board) self.robots[1] = Robot(2, 1, 'v', 1, self.board) - def handle_push(self, pushing_robot, pushed_robot): + def handle_push(self, direction, pushed_robot, forward=True, pushing_robot=None): cmd_list = [] # push robot out of the way - if pushed_robot.orientation == pushing_robot.orientation: - # the pushed robot can just drive forward - cmd_list += self.handle_single_action('forward', pushed_robot) - elif pushed_robot.has_opposite_orientation(pushing_robot.orientation): - # the pushed robot can drive backward - cmd_list += self.handle_single_action('backward', pushed_robot) + if pushed_robot.orientation == direction: + if forward: + # the pushed robot can just drive forward + cmd_list += self.handle_single_action('forward', pushed_robot) + else: + # the pushed robot can just drive backward + cmd_list += self.handle_single_action('backward', pushed_robot) + elif pushed_robot.has_opposite_orientation(direction): + if forward: + # the pushed robot can drive backward + cmd_list += self.handle_single_action('backward', pushed_robot) + else: + # the pushed robot drives forward + cmd_list += self.handle_single_action('forward', pushed_robot) else: # we first have to turn the pushed robot s.t. it faces in the same orientation as the # pushing robot - turn_direction = pushed_robot.get_turn_direction(pushing_robot.orientation) + turn_direction = pushed_robot.get_turn_direction(direction) cmd_list += self.handle_single_action(turn_direction, pushed_robot) - # then the pushed robot drives one step forward - cmd_list += self.handle_single_action('forward', pushed_robot) + if forward: + # then the pushed robot drives one step forward + cmd_list += self.handle_single_action('forward', pushed_robot) + else: + # if its pushed backward it instead drives on step backward + cmd_list += self.handle_single_action('backward', pushed_robot) # afterwards we turn the robot back to the original orientation if turn_direction == 'turn left': @@ -272,8 +292,12 @@ class Board: sys.exit(1) cmd_list += self.handle_single_action(turn_back_direction, pushed_robot) - # now the tile should be empty so the pushing robot can move into the tile - cmd_list.append(pushing_robot.move('forward')) + if pushing_robot is not None: + # now the tile should be empty so the pushing robot can move into the tile + if forward: + cmd_list.append(pushing_robot.move('forward')) + else: + cmd_list.append(pushing_robot.move('backward')) return cmd_list def handle_single_action(self, action, robot): @@ -302,7 +326,7 @@ class Board: self.robots.values()]): # robots hits a tile occupied by another robot pushed_robot = next(filter(lambda r: (tile.x, tile.y) == (r.x, r.y), self.robots.values())) if pushed_robot.is_pushable(robot.orientation): # check if robot is pushable in the given direction - cmd_list += self.handle_push(pushing_robot=robot, pushed_robot=pushed_robot) + cmd_list += self.handle_push(direction=robot.orientation, pushed_robot=pushed_robot, forward=True, pushing_robot=robot) else: cmd_list.append(robot.nop()) return cmd_list @@ -312,12 +336,47 @@ class Board: sys.exit(1) elif action == 'backward': # basically do the same as with forward - pass + accessed_tiles = robot.get_accessed_tiles(1, forward=False) + + for tile in accessed_tiles: + if tile is None: + # this case should not happen + print("error: unknown state occured") + sys.exit(1) + elif tile.is_empty(): + # if the tile is empty we can just move there + cmd_list.append(robot.move('backward')) + elif tile.modifier == '#': # robot hits a wall -> stop the robot + cmd_list.append(robot.nop()) + return cmd_list + elif any([(tile.x, tile.y) == (r.x, r.y) for r in + self.robots.values()]): # robots hits a tile occupied by another robot + pushed_robot = next(filter(lambda r: (tile.x, tile.y) == (r.x, r.y), self.robots.values())) + if pushed_robot.is_pushable(Robot.opposites[robot.orientation]): # check if robot is pushable in the given direction + cmd_list += self.handle_push(direction=robot.orientation, pushed_robot=pushed_robot, forward=False, pushing_robot=robot) + else: + cmd_list.append(robot.nop()) + return cmd_list + else: + # this case should not happen + print("error: unknown state occured") + sys.exit(1) else: # this means we have a turn action cmd_list.append(robot.turn(action)) return cmd_list + def handle_board_element(self, robot): + cmd_list = [] + tile = self.board[(robot.x, robot.y)] + if tile.modifier in ['^', '>', 'v', '<']: + # board element pushes the robot to next tile + if robot.is_pushable(tile.modifier): + cmd_list += self.handle_push(direction=tile.modifier, pushed_robot=robot, forward=True) + else: + cmd_list.append(robot.nop()) + return cmd_list + def apply_actions(self, cards): cmd_list = [] # apply the actions to the board and generate a list of movement commands @@ -335,10 +394,14 @@ class Board: print("robot {} action {}".format(robot, action)) cmd_list += self.handle_single_action(action, robot) - print(cmd_list) - pass # apply the actions caused by board elements at the end of the phase + for robot_id in self.robots: + robot = self.robots[robot_id] + cmd_list += self.handle_board_element(robot) + + print(cmd_list) + print(self) pass def __str__(self): @@ -357,8 +420,10 @@ class Board: if __name__ == "__main__": n = 5 - player_1_cards = random.sample(list(filter(lambda c: 'forward' in c.action, deck.deck.values())), n) + player_1_cards = random.sample(list(filter(lambda c: 'backward' in c.action, deck.deck.values())), n) player_2_cards = random.sample(list(filter(lambda c: 'turn around' in c.action, deck.deck.values())), n) + #player_1_cards = deck.draw_cards(40) + #player_2_cards = deck.draw_cards(40) cards_1 = [(0, c) for c in player_1_cards] cards_2 = [(1, c) for c in player_2_cards]