codingame/training/bender.py

199 lines
5.5 KiB
Python

import sys
import math
from enum import Enum
class Coordinate:
def __init__(self, r, c):
self.r = r
self.c = c
def __str__(self):
return str((self.r, self.c))
class Direction(Enum):
SOUTH = 1
EAST = 2
NORTH = 3
WEST = 4
class Game:
def __init__(self, city_map):
self.city_map = city_map
self.bender = Bender(self.city_map)
def run(self):
while self.bender.alive:
self.bender.step()
class Bender:
def __init__(self, city_map, position=None):
self.direction = Direction.SOUTH
self._position = position
self.fury = False
self.alive = True
self.city_map = city_map
self.invert = False
self.instructions = []
if not self.position:
for i, r in enumerate(self.city_map):
if '@' in r:
r, c = i, ''.join(r).find('@')
self.position = Coordinate(r, c)
@property
def position(self):
return self._position
@position.setter
def position(self, value):
self._position = value
# self.print_map()
def print_map(self, file=sys.stderr):
for r, row in enumerate(self.city_map):
if r != self.position.r:
line = ''.join(row)
else:
line = ''.join(row[:self.position.c]) + '*' + ''.join(row[self.position.c+1:])
print(line, file=file)
def step(self):
next_item = self.get_next_item()
if next_item == '#' or (next_item == 'X' and not self.fury):
self.bypass_obstacle()
self.step()
else:
self.step_forward()
if next_item == 'X' and self.fury:
self.city_map[self.position.r][self.position.c] = ' '
elif next_item == 'B':
self.fury = not self.fury
elif next_item == 'T':
self.beam_me_up()
elif next_item == 'I':
self.invert = not self.invert
elif next_item == 'S':
self.direction = Direction.SOUTH
elif next_item == 'E':
self.direction = Direction.EAST
elif next_item == 'N':
self.direction = Direction.NORTH
elif next_item == 'W':
self.direction = Direction.WEST
elif next_item == '$':
self.alive = False
for instruction in self.instructions:
print(instruction)
self.check_loop()
def check_loop(self):
if len(self.instructions) > 1000:
print('LOOP')
self.alive = False
def beam_me_up(self):
b_r, b_c = self.position.r, self.position.c
for i, row in enumerate(self.city_map):
if 'T' in row:
t_r, t_c = i, ''.join(row).find('T')
if t_r != b_r or t_c != b_c:
self.position = Coordinate(t_r, t_c)
return
def bypass_obstacle(self):
if not self.invert:
self.direction = Direction.SOUTH
if not self.is_obstacle(self.get_next_item()):
return
self.direction = Direction.EAST
if not self.is_obstacle(self.get_next_item()):
return
self.direction = Direction.NORTH
if not self.is_obstacle(self.get_next_item()):
return
self.direction = Direction.WEST
if not self.is_obstacle(self.get_next_item()):
return
else:
self.direction = Direction.WEST
if not self.is_obstacle(self.get_next_item()):
return
self.direction = Direction.NORTH
if not self.is_obstacle(self.get_next_item()):
return
self.direction = Direction.EAST
if not self.is_obstacle(self.get_next_item()):
return
self.direction = Direction.SOUTH
if not self.is_obstacle(self.get_next_item()):
return
def step_forward(self):
if self.direction == Direction.SOUTH:
self.position.r += 1
self.instructions.append('SOUTH')
elif self.direction == Direction.NORTH:
self.position.r -= 1
self.instructions.append('NORTH')
elif self.direction == Direction.EAST:
self.position.c += 1
self.instructions.append('EAST')
elif self.direction == Direction.WEST:
self.position.c -= 1
self.instructions.append('WEST')
# self.print_map()
def get_next_item(self):
if self.direction == Direction.SOUTH:
return self.city_map[self.position.r + 1][self.position.c]
elif self.direction == Direction.NORTH:
return self.city_map[self.position.r - 1][self.position.c]
elif self.direction == Direction.EAST:
return self.city_map[self.position.r][self.position.c + 1]
elif self.direction == Direction.WEST:
return self.city_map[self.position.r][self.position.c - 1]
def is_obstacle(self, next_item):
if self.fury:
return next_item == '#'
else:
return next_item == '#' or next_item == 'X'
def main():
l, c = [int(i) for i in input().split()]
city_map = []
for i in range(l):
city_map.append(list(input()))
game = Game(city_map)
game.run()
if __name__ == '__main__':
main()