diff --git a/challenge_coders_of_the_caribbean.py b/challenge_coders_of_the_caribbean.py index 9fe223b..6581380 100644 --- a/challenge_coders_of_the_caribbean.py +++ b/challenge_coders_of_the_caribbean.py @@ -1,19 +1,24 @@ import math import random -from enum import Enum -from typing import List, Union, Sequence, TypeVar, Optional, Dict - import sys - -BARREL = 'BARREL' -SHIP = 'SHIP' -MINE = 'MINE' -CANNONBALL = 'CANNONBALL' +from enum import Enum, IntEnum +from typing import List, Sequence, Optional, Dict DEFAULT_SHOOT_WAIT = 2 DEFAULT_MINE_WAIT = 4 +class EntityType(Enum): + BARREL = 'BARREL' + SHIP = 'SHIP' + MINE = 'MINE' + CANNONBALL = 'CANNONBALL' + + +class Orientation(IntEnum): + RIGHT, TOP_RIGHT, TOP_LEFT, LEFT, BOTTOM_LEFT, BOTTOM_RIGHT = range(6) + + class Action(Enum): MINE = 'MINE' MOVE = 'MOVE' @@ -63,6 +68,8 @@ class GameMap: def add_my_ship(self, ship: 'Ship'): my_ship = self.my_ships.get(ship.id, None) if my_ship: + my_ship.x = ship.x + my_ship.y = ship.y my_ship.orientation = ship.orientation my_ship.speed = ship.speed my_ship.stock = ship.stock @@ -85,6 +92,9 @@ class GameMap: def _add_to_map(self, entity: 'Entity'): self.map[entity.coord] = entity + def get_at(self, tile: 'Tile'): + return self.map[tile.coord] + class Tile: def __init__(self, x: int, y: int): @@ -95,6 +105,40 @@ class Tile: def coord(self): return '{};{}'.format(self.x, self.y) + def top_left(self): + y = self.y - 1 + x = self.x + if self.y % 2 == 0: + x -= 1 + return Tile(x, y) + + def top_right(self): + y = self.y - 1 + x = self.x + if self.y % 2 != 0: + x += 1 + return Tile(x, y) + + def left(self): + return Tile(self.x - 1, self.y) + + def right(self): + return Tile(self.x + 1, self.y) + + def bottom_left(self): + y = self.y + 1 + x = self.x + if self.y % 2 == 0: + x -= 1 + return Tile(x, y) + + def bottom_right(self): + y = self.y + 1 + x = self.x + if self.y % 2 != 0: + x += 1 + return Tile(x, y) + def __repr__(self): return 'Tile(x={}, y={})'.format(self.x, self.y) @@ -145,46 +189,97 @@ class Ship(Entity): entity_id: int, x: int, y: int, orientation: int, speed: int, stock: int, mine: bool = True): super().__init__(game_map, entity_id, x, y) - self.orientation = orientation + + self.orientation = Orientation(orientation) self.speed = speed self.stock = stock self.mine = mine self.mine_wait = DEFAULT_MINE_WAIT self.shoot_wait = DEFAULT_SHOOT_WAIT - self.action = None # type: Optional[Action] - self.target = None # type: Optional[Tile] def play_turn(self): - if self.action is Action.MINE: - self.mine_wait = DEFAULT_MINE_WAIT - elif self.action is Action.FIRE: - self.shoot_wait = DEFAULT_SHOOT_WAIT + action = None + target = None - if self.target: - print('{} {} {}'.format(self.action.value, self.target.x, self.target.y)) + rand = random.random() + perr('rand', rand) + perr('pos', self.tile) + perr('mine_wait', self.mine_wait) + perr('shoot_wait', self.shoot_wait) + + perr('on path', self.tiles_on_path()) + for tile in self.tiles_on_path(): + if isinstance(tile, Mine) or isinstance(tile, Cannonball): + action, target = self.avoid(tile) + break + + if not action: + if (self.mine_wait > 0 and self.shoot_wait > 0) or rand > 0.4: + target = Tile(random.randint(0, 23), random.randint(0, 21)) + if self.game_map.barrels: + target = self.nearest_barrel() + + action = Action.MOVE + elif rand > 0.2: + action = Action.FIRE + target = self.nearest_opponent() + else: + action = Action.MINE + + if action is Action.MINE: + self.mine_wait = DEFAULT_MINE_WAIT + elif action is Action.FIRE: + self.shoot_wait = DEFAULT_SHOOT_WAIT + + if target: + print('{} {} {}'.format(action.value, target.x, target.y)) else: - print(self.action.value) - self.action = None - self.target = None + print(action.value) + self.mine_wait -= 1 self.shoot_wait -= 1 - def drop_mine(self): - self.action = Action.MINE + def avoid(self, tile: Tile): + action = Action.MOVE + target = None + if self.orientation is Orientation.RIGHT: + target = tile.top_right() + elif self.orientation is Orientation.TOP_RIGHT: + target = tile.right() + elif self.orientation is Orientation.TOP_LEFT: + target = tile.left() + elif self.orientation is Orientation.LEFT: + target = tile.top_left() + elif self.orientation is Orientation.BOTTOM_LEFT: + target = tile.left() + elif self.orientation is Orientation.BOTTOM_RIGHT: + target = tile.right() + return action, target - def wait(self): - self.action = Action.WAIT + @property + def tile(self): + return Tile(self.x, self.y) - def slower(self): - self.action = Action.SLOWER + def tiles_on_path(self): + tile = self.tile + perr('tile', tile) + tiles = [] + for _ in range(self.speed + 1): + if self.orientation is Orientation.RIGHT: + tile = tile.right() + elif self.orientation is Orientation.TOP_RIGHT: + tile = tile.top_right() + elif self.orientation is Orientation.TOP_LEFT: + tile = tile.top_left() + elif self.orientation is Orientation.LEFT: + tile = tile.left() + elif self.orientation is Orientation.BOTTOM_LEFT: + tile = tile.bottom_left() + elif self.orientation is Orientation.BOTTOM_RIGHT: + tile = tile.bottom_right() + tiles.append(tile) - def shoot(self, target: 'Entity'): - self.action = Action.FIRE - self.target = target - - def move(self, target: Tile): - self.action = Action.MOVE - self.target = target + return tiles def __repr__(self): return ('Ship(id={}, x={}, y={}, orientation={}, speed={}, stock={}, mine={})' @@ -226,12 +321,13 @@ def main(): entity_id = int(entity_id) x = int(x) y = int(y) + entity_type = EntityType(entity_type) - if entity_type == BARREL: + if entity_type is EntityType.BARREL: rhum_quantity = int(arg_1) game_map.add_barrel(Barrel(game_map, entity_id, x, y, rhum_quantity)) - elif entity_type == SHIP: + elif entity_type is EntityType.SHIP: orientation = int(arg_1) speed = int(arg_2) rhum_stock = int(arg_3) @@ -242,10 +338,10 @@ def main(): else: game_map.add_opponent_ship(ship) - elif entity_type == MINE: + elif entity_type is EntityType.MINE: game_map.add_mine(Mine(game_map, entity_id, x, y)) - elif entity_type == CANNONBALL: + elif entity_type is EntityType.CANNONBALL: shooter_id = int(arg_1) turns_before_impact = int(arg_2) game_map.add_cannonball(Cannonball(game_map, entity_id, x, y, shooter_id, turns_before_impact)) @@ -254,24 +350,6 @@ def main(): # Play for ship in game_map.my_ships.values(): - rand = random.random() - perr('rand', rand) - perr('mine_wait', ship.mine_wait) - perr('shoot_wait', ship.shoot_wait) - - if (ship.mine_wait > 0 and ship.shoot_wait > 0) or rand > 0.4: - target = Tile(random.randint(0, 23), random.randint(0, 21)) - if game_map.barrels: - target = ship.nearest_barrel() - - ship.move(target) - - elif rand > 0.2: - opponent = ship.nearest_opponent() - ship.shoot(opponent) - else: - ship.drop_mine() - ship.play_turn()