implemented core game logic with generated commands
This commit is contained in:
parent
ca5c0d7083
commit
ca11f3476c
195
roborally.py
195
roborally.py
|
@ -62,6 +62,25 @@ deck = CardDeck()
|
|||
|
||||
|
||||
class Robot:
|
||||
# dictionary mapping the current orientation and a turn command to the resulting orientation
|
||||
resulting_orientation = {
|
||||
'^': {'turn left': '<', 'turn right': '>', 'turn around': 'v'},
|
||||
'>': {'turn left': '^', 'turn right': 'v', 'turn around': '<'},
|
||||
'v': {'turn left': '>', 'turn right': '<', 'turn around': '^'},
|
||||
'<': {'turn left': 'v', 'turn right': '^', 'turn around': '>'},
|
||||
}
|
||||
|
||||
# dictionary mapping the current orientation and the target orientation to the necessary turn command
|
||||
necessary_turn = {
|
||||
'^': {'>': 'turn right', 'v': 'turn around', '<': 'turn left'},
|
||||
'>': {'v': 'turn right', '<': 'turn around', '^': 'turn left'},
|
||||
'v': {'<': 'turn right', '^': 'turn around', '>': 'turn left'},
|
||||
'<': {'^': 'turn right', '>': 'turn around', 'v': 'turn left'},
|
||||
}
|
||||
|
||||
# dictionary mapping an orientation to its opposite
|
||||
opposites = {'^': 'v', '>': '<', 'v': '^', '<': '>'}
|
||||
|
||||
def __init__(self, x, y, orientation, id, board):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
@ -71,7 +90,7 @@ class Robot:
|
|||
self.board = board
|
||||
|
||||
# mark the tile on the board as occupied
|
||||
self.board[(x,y)].occupier = self
|
||||
self.board[(x,y)].occupant = self
|
||||
|
||||
|
||||
def get_accessed_tiles(self, count):
|
||||
|
@ -104,25 +123,57 @@ class Robot:
|
|||
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)]
|
||||
return Robot.necessary_turn[self.orientation][target_orienation]
|
||||
|
||||
def get_opposite_orientation(self):
|
||||
return Robot.opposites[self.orientation]
|
||||
|
||||
def turn(self, type):
|
||||
# change the orientation of the robot
|
||||
self.orientation = Robot.resulting_orientation[self.orientation][type]
|
||||
|
||||
return "{}, {}".format(self.id, type)
|
||||
|
||||
def move(self, type):
|
||||
pass
|
||||
# move the robot forward or backward
|
||||
# this involves
|
||||
tile = self.board[(self.x, self.y)]
|
||||
if type == 'forward':
|
||||
target_tile = self.board[tile.get_neighbor_coordinates(self.orientation)]
|
||||
|
||||
if target_tile.occupant is not None:
|
||||
print("error: target tile is not empty")
|
||||
sys.exit(1)
|
||||
|
||||
tile.occupant = None # delete the robot from the current tile
|
||||
target_tile.occupant = self # place the robot in the next tile
|
||||
self.x = target_tile.x
|
||||
self.y = target_tile.y
|
||||
|
||||
# return the move for sending to the controller
|
||||
return "{}, forward".format(self.id)
|
||||
elif type == 'backward':
|
||||
opposite_orientation = self.get_opposite_orientation()
|
||||
target_tile = tile.get_neighbor_coordinates(opposite_orientation)
|
||||
|
||||
if target_tile.occupant is not None:
|
||||
print("error: target tile is not empty")
|
||||
sys.exit(1)
|
||||
|
||||
tile.occupant = None # delete the robot from the current tile
|
||||
target_tile.occupant = self # place the robot in the next tile
|
||||
self.x = target_tile.x
|
||||
self.y = target_tile.y
|
||||
|
||||
# return the move for sending to the controller
|
||||
return "{}, backward".format(self.id)
|
||||
else:
|
||||
print("error: invalid move")
|
||||
sys.exit(1)
|
||||
|
||||
def nop(self):
|
||||
# do nothing command
|
||||
return "{}, nop".format(self.id)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.id)
|
||||
|
@ -163,9 +214,15 @@ class Tile:
|
|||
return ' '
|
||||
else:
|
||||
return self.modifier
|
||||
else:
|
||||
if self.occupant is None:
|
||||
return self.modifier
|
||||
else:
|
||||
return str(self.occupant)
|
||||
|
||||
def __repr__(self):
|
||||
return "({}, {}) occ: {} mod: {}".format(self.x, self.y, self.occupant, self.modifier)
|
||||
|
||||
|
||||
class Board:
|
||||
x_dims = 12 # number of tiles in x direction
|
||||
|
@ -185,10 +242,42 @@ class Board:
|
|||
|
||||
self.robots = {}
|
||||
self.robots[0] = Robot(3, 1, '<', 0, self.board)
|
||||
self.robots[1] = Robot(1, 1, 'v', 1, self.board)
|
||||
self.robots[1] = Robot(2, 1, 'v', 1, self.board)
|
||||
|
||||
def handle_push(self, pushing_robot, pushed_robot):
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
||||
# 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)
|
||||
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'))
|
||||
return cmd_list
|
||||
|
||||
def handle_single_action(self, action, robot):
|
||||
cmd_list = []
|
||||
if 'forward' in action: # driving forward
|
||||
if "x2" in action:
|
||||
move_count = 2
|
||||
|
@ -199,58 +288,38 @@ class Board:
|
|||
accessed_tiles = robot.get_accessed_tiles(move_count)
|
||||
|
||||
for tile in accessed_tiles:
|
||||
if tile.modifier == '#': # robot hits a wall -> stop the robot
|
||||
pass
|
||||
elif tile.modifier == 'X': # robot drives into a pit -> take damage
|
||||
pass
|
||||
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('forward'))
|
||||
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.orientation): # check if robot is pushable in the given direction
|
||||
if pushed_robot.orientation == robot.orientation:
|
||||
# the pushed robot can just drive forward
|
||||
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)
|
||||
cmd_list += self.handle_push(pushing_robot=robot, pushed_robot=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'
|
||||
cmd_list.append(robot.nop())
|
||||
return cmd_list
|
||||
else:
|
||||
print("error: invalid turn direction")
|
||||
# this case should not happen
|
||||
print("error: unknown state occured")
|
||||
sys.exit(1)
|
||||
self.handle_single_action(turn_back_direction, pushed_robot)
|
||||
else: # robot is not pushable -> do not move
|
||||
pass
|
||||
else:
|
||||
# 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
|
||||
pass
|
||||
elif action == 'backward':
|
||||
# basically do the same as with forward
|
||||
pass
|
||||
elif action == 'turn left':
|
||||
pass
|
||||
elif action == 'turn right':
|
||||
pass
|
||||
elif action == 'turn around':
|
||||
pass
|
||||
else: # this means we have a turn action
|
||||
cmd_list.append(robot.turn(action))
|
||||
|
||||
return cmd_list
|
||||
|
||||
def apply_actions(self, cards):
|
||||
cmd_list = []
|
||||
# apply the actions to the board and generate a list of movement commands
|
||||
|
||||
for i, phase in enumerate(cards): # process register phases
|
||||
|
@ -265,7 +334,9 @@ class Board:
|
|||
|
||||
print("robot {} action {}".format(robot, action))
|
||||
|
||||
self.handle_single_action(action, robot)
|
||||
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
|
||||
pass
|
||||
|
@ -286,8 +357,8 @@ class Board:
|
|||
|
||||
if __name__ == "__main__":
|
||||
n = 5
|
||||
player_1_cards = random.sample(list(filter(lambda c: 'forward' in c.action, deck.deck.values())), 3)
|
||||
player_2_cards = random.sample(list(filter(lambda c: 'turn around' in c.action, deck.deck.values())), 3)
|
||||
player_1_cards = random.sample(list(filter(lambda c: 'forward' 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)
|
||||
|
||||
cards_1 = [(0, c) for c in player_1_cards]
|
||||
cards_2 = [(1, c) for c in player_2_cards]
|
||||
|
|
Loading…
Reference in New Issue
Block a user