implemented pushing logic
This commit is contained in:
parent
2d6180ad74
commit
ca5c0d7083
151
roborally.py
151
roborally.py
|
@ -1,7 +1,7 @@
|
||||||
import random
|
import random
|
||||||
|
import sys
|
||||||
random.seed(0)
|
random.seed(0)
|
||||||
|
|
||||||
|
|
||||||
class Card:
|
class Card:
|
||||||
possible_moves = ['forward', 'forward x2', 'forward x3', 'backward', 'turn left', 'turn right', 'turn around']
|
possible_moves = ['forward', 'forward x2', 'forward x3', 'backward', 'turn left', 'turn right', 'turn around']
|
||||||
card_counter = 0
|
card_counter = 0
|
||||||
|
@ -70,18 +70,57 @@ class Robot:
|
||||||
|
|
||||||
self.board = board
|
self.board = board
|
||||||
|
|
||||||
|
# mark the tile on the board as occupied
|
||||||
|
self.board[(x,y)].occupier = self
|
||||||
|
|
||||||
|
|
||||||
def get_accessed_tiles(self, count):
|
def get_accessed_tiles(self, count):
|
||||||
|
# create a list of all tiles the robot would enter if it drives <count> steps forward
|
||||||
tiles = []
|
tiles = []
|
||||||
if self.orientation == '>':
|
current_tile = self.board[(self.x, self.y)]
|
||||||
tiles = [self.board.get((self.x + i, self.y)) for i in range(1, count + 1)]
|
for i in range(1, count + 1):
|
||||||
elif self.orientation == '<':
|
current_tile = self.board.get(current_tile.get_neighbor_coordinates(self.orientation))
|
||||||
tiles = [self.board.get((self.x - i, self.y)) for i in range(1, count + 1)]
|
tiles.append(current_tile)
|
||||||
elif self.orientation == '^':
|
|
||||||
tiles = [self.board.get((self.x, self.y - i)) for i in range(1, count + 1)]
|
|
||||||
elif self.orientation == 'v':
|
|
||||||
tiles = [self.board.get((self.x, self.y + i)) for i in range(1, count + 1)]
|
|
||||||
return tiles
|
return tiles
|
||||||
|
|
||||||
|
def is_pushable(self, direction):
|
||||||
|
# check if the robot can be pushed in the given direction
|
||||||
|
# this is the case if there is a non-blocking tile next to the robot or if there is another robot that is pushable
|
||||||
|
robot_tile = self.board[(self.x, self.y)]
|
||||||
|
neighbor_tile = self.board.get(robot_tile.get_neighbor_coordinates(direction))
|
||||||
|
if neighbor_tile is None: # neighbor tile could not be found -> robot would be pushed out of the board
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if neighbor_tile.is_empty():
|
||||||
|
return True
|
||||||
|
elif neighbor_tile.modifier == '#': # if there's a wall on the neighbor tile the robot cannot be pushed there
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# this means there's another robot on the neighbor tile -> check if it can be pushed away
|
||||||
|
return neighbor_tile.occupant.is_pushable(direction)
|
||||||
|
|
||||||
|
def has_opposite_orientation(self, direction):
|
||||||
|
opposites = [('^', 'v'), ('>', '<'), ('v', '^'), ('<', '>')]
|
||||||
|
return (self.orientation, direction) in opposites
|
||||||
|
|
||||||
|
def get_turn_direction(self, target_orienation):
|
||||||
|
# get the direction to turn to in order to face in the same direction as the given orientation
|
||||||
|
directions = {
|
||||||
|
('^', '>'): 'turn right',
|
||||||
|
('^', 'v'): 'turn around',
|
||||||
|
('^', '<'): 'turn left',
|
||||||
|
('>', 'v'): 'turn right',
|
||||||
|
('>', '<'): 'turn around',
|
||||||
|
('>', '^'): 'turn left',
|
||||||
|
('v', '<'): 'turn right',
|
||||||
|
('v', '^'): 'turn around',
|
||||||
|
('v', '>'): 'turn left',
|
||||||
|
('<', '^'): 'turn right',
|
||||||
|
('<', '>'): 'turn around',
|
||||||
|
('<', 'v'): 'turn left',
|
||||||
|
}
|
||||||
|
return directions[(self.orientation, target_orienation)]
|
||||||
|
|
||||||
def move(self, type):
|
def move(self, type):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -100,8 +139,23 @@ class Tile:
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
|
|
||||||
|
def get_neighbor_coordinates(self, direction):
|
||||||
|
# get the coordinates of the neighboring tile in the given direction
|
||||||
|
if direction == '^':
|
||||||
|
return (self.x, self.y - 1)
|
||||||
|
elif direction == '>':
|
||||||
|
return (self.x + 1, self.y)
|
||||||
|
elif direction == 'v':
|
||||||
|
return (self.x, self.y + 1)
|
||||||
|
elif direction == '<':
|
||||||
|
return (self.x - 1, self.y)
|
||||||
|
else:
|
||||||
|
print("error: unknown direction")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def is_empty(self):
|
def is_empty(self):
|
||||||
return self.occupant is None
|
# check if the tile is non-empty and does not contain a wall
|
||||||
|
return self.occupant is None and self.modifier != '#'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.is_empty():
|
if self.is_empty():
|
||||||
|
@ -119,16 +173,20 @@ class Board:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.board = {}
|
self.board = {}
|
||||||
for x in range(Board.x_dims):
|
for x in range(Board.x_dims + 2):
|
||||||
for y in range(Board.y_dims):
|
for y in range(Board.y_dims + 2):
|
||||||
if x == 0 and (y >= 1) and (y <= 4):
|
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):
|
||||||
self.board[(x, y)] = Tile(x, y, 'v')
|
self.board[(x, y)] = Tile(x, y, 'v')
|
||||||
else:
|
else:
|
||||||
self.board[(x, y)] = Tile(x, y)
|
self.board[(x,y)] = Tile(x,y)
|
||||||
|
|
||||||
self.robots = {}
|
self.robots = {}
|
||||||
self.robots[0] = Robot(0, 0, '<', 0, self.board)
|
self.robots[0] = Robot(3, 1, '<', 0, self.board)
|
||||||
self.robots[1] = Robot(2, 0, '^', 1, self.board)
|
self.robots[1] = Robot(1, 1, 'v', 1, self.board)
|
||||||
|
|
||||||
|
|
||||||
def handle_single_action(self, action, robot):
|
def handle_single_action(self, action, robot):
|
||||||
if 'forward' in action: # driving forward
|
if 'forward' in action: # driving forward
|
||||||
|
@ -141,19 +199,45 @@ class Board:
|
||||||
accessed_tiles = robot.get_accessed_tiles(move_count)
|
accessed_tiles = robot.get_accessed_tiles(move_count)
|
||||||
|
|
||||||
for tile in accessed_tiles:
|
for tile in accessed_tiles:
|
||||||
if tile is None: # robot tries to access a tile outside of the board
|
if tile.modifier == '#': # robot hits a wall -> stop the robot
|
||||||
# TODO take robot out of the game
|
pass
|
||||||
|
elif tile.modifier == 'X': # robot drives into a pit -> take damage
|
||||||
pass
|
pass
|
||||||
elif any([(tile.x, tile.y) == (r.x, r.y) for r in
|
elif any([(tile.x, tile.y) == (r.x, r.y) for r in
|
||||||
self.robots]): # robots hits a tile occupied by another robot
|
self.robots.values()]): # robots hits a tile occupied by another robot
|
||||||
# TODO move "pushed" robot by one tile:
|
pushed_robot = next(filter(lambda r: (tile.x, tile.y) == (r.x, r.y), self.robots.values()))
|
||||||
# -> get current orientation
|
|
||||||
# -> turn the "pushed" robot to face in the same direction as the "pushing" robot
|
if pushed_robot.is_pushable(robot.orientation): # check if robot is pushable in the given direction
|
||||||
# -> move the "pushed" robot one step forward (while handling the move action of the robot recursively and pushing other robots as required)
|
if pushed_robot.orientation == robot.orientation:
|
||||||
# -> turn the "pushed" robot back to the original orientation
|
# the pushed robot can just drive forward
|
||||||
pass
|
self.handle_single_action('forward', pushed_robot)
|
||||||
|
elif pushed_robot.has_opposite_orientation(robot.orientation):
|
||||||
|
# the pushed robot can drive backward
|
||||||
|
self.handle_single_action('backward', 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(robot.orientation)
|
||||||
|
self.handle_single_action(turn_direction, pushed_robot)
|
||||||
|
|
||||||
|
# then the pushed robot drives one step forward
|
||||||
|
self.handle_single_action('forward', pushed_robot)
|
||||||
|
|
||||||
|
# afterwards we turn the robot back to the original orientation
|
||||||
|
if turn_direction == 'turn left':
|
||||||
|
turn_back_direction = 'turn right'
|
||||||
|
elif turn_direction == 'turn right':
|
||||||
|
turn_back_direction = 'turn left'
|
||||||
|
else:
|
||||||
|
print("error: invalid turn direction")
|
||||||
|
sys.exit(1)
|
||||||
|
self.handle_single_action(turn_back_direction, pushed_robot)
|
||||||
|
else: # robot is not pushable -> do not move
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
# now the tile should be empty so the robot can move into the tile
|
# now the tile should be empty so the robot can move into the tile
|
||||||
|
# TODO: possible problem: what happens when robot cannot be pushed out of the way (e.g. because it is
|
||||||
|
# blocked by a wall) -> check if robot is pushable beforehand
|
||||||
# -> register move action to process
|
# -> register move action to process
|
||||||
pass
|
pass
|
||||||
elif action == 'backward':
|
elif action == 'backward':
|
||||||
|
@ -183,26 +267,27 @@ class Board:
|
||||||
|
|
||||||
self.handle_single_action(action, robot)
|
self.handle_single_action(action, robot)
|
||||||
|
|
||||||
|
# apply the actions caused by board elements at the end of the phase
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
output = '#' * (Board.x_dims + 2) + '\n'
|
#output = '#' * (Board.x_dims + 2) + '\n'
|
||||||
for y in range(Board.y_dims):
|
output = ''
|
||||||
output += '#'
|
for y in range(Board.y_dims+2):
|
||||||
for x in range(Board.x_dims):
|
for x in range(Board.x_dims+2):
|
||||||
if any((r.x, r.y) == (x,y) for r in self.robots.values()):
|
if any((r.x, r.y) == (x,y) for r in self.robots.values()):
|
||||||
r = list(filter(lambda r: (r.x,r.y) == (x,y), self.robots.values()))[0]
|
r = list(filter(lambda r: (r.x,r.y) == (x,y), self.robots.values()))[0]
|
||||||
output += str(r.id)
|
output += str(r.id)
|
||||||
else:
|
else:
|
||||||
output += str(self.board[(x, y)])
|
output += str(self.board[(x, y)])
|
||||||
output += '#\n'
|
output += '\n'
|
||||||
output += '#' * (Board.x_dims + 2)
|
#output += '#' * (Board.x_dims + 2)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
n = 5
|
n = 5
|
||||||
player_1_cards = deck.draw_cards(3)
|
player_1_cards = random.sample(list(filter(lambda c: 'forward' in c.action, deck.deck.values())), 3)
|
||||||
player_2_cards = deck.draw_cards(3)
|
player_2_cards = random.sample(list(filter(lambda c: 'turn around' in c.action, deck.deck.values())), 3)
|
||||||
|
|
||||||
cards_1 = [(0, c) for c in player_1_cards]
|
cards_1 = [(0, c) for c in player_1_cards]
|
||||||
cards_2 = [(1, c) for c in player_2_cards]
|
cards_2 = [(1, c) for c in player_2_cards]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user