Implement Coders of the Caribbean
This commit is contained in:
parent
c11457404f
commit
d939963237
1 changed files with 234 additions and 0 deletions
234
challenge_coders_of_the_caribbean.py
Normal file
234
challenge_coders_of_the_caribbean.py
Normal file
|
@ -0,0 +1,234 @@
|
|||
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'
|
||||
|
||||
DEFAULT_SHOOT_WAIT = 2
|
||||
DEFAULT_MINE_WAIT = 4
|
||||
|
||||
|
||||
class Action(Enum):
|
||||
MINE = 'MINE'
|
||||
MOVE = 'MOVE'
|
||||
FIRE = 'FIRE'
|
||||
WAIT = 'WAIT'
|
||||
SLOWER = 'SLOWER'
|
||||
|
||||
|
||||
class GameMap:
|
||||
def __init__(self,
|
||||
barrels: List['Barrel'] = None,
|
||||
my_ships: Dict[int, 'Ship'] = None,
|
||||
opponent_ships: List['Ship'] = None,
|
||||
mines: List['Mine'] = None,
|
||||
cannonballs: List['Cannonball'] = None):
|
||||
|
||||
if opponent_ships is None:
|
||||
opponent_ships = []
|
||||
if cannonballs is None:
|
||||
cannonballs = []
|
||||
if mines is None:
|
||||
mines = []
|
||||
if my_ships is None:
|
||||
my_ships = {}
|
||||
if barrels is None:
|
||||
barrels = []
|
||||
|
||||
self.opponent_ships = opponent_ships
|
||||
self.cannonballs = cannonballs
|
||||
self.mines = mines
|
||||
self.my_ships = my_ships
|
||||
self.barrels = barrels
|
||||
|
||||
def reset(self):
|
||||
self.opponent_ships = []
|
||||
self.cannonballs = []
|
||||
self.mines = []
|
||||
self.barrels = []
|
||||
|
||||
|
||||
class Tile:
|
||||
def __init__(self, x: int, y: int):
|
||||
self.y = y
|
||||
self.x = x
|
||||
|
||||
|
||||
class Entity(Tile):
|
||||
def __init__(self, game_map: GameMap, entity_id: int, x: int, y: int):
|
||||
super().__init__(x, y)
|
||||
self.game_map = game_map
|
||||
self.id = entity_id
|
||||
|
||||
def distance(self, other: 'EntityType') -> float:
|
||||
return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5
|
||||
|
||||
def nearest_barrel(self) -> Optional['Barrel']:
|
||||
return self.nearest(self.game_map.barrels)
|
||||
|
||||
def nearest_opponent(self) -> Optional['Ship']:
|
||||
return self.nearest(self.game_map.opponent_ships)
|
||||
|
||||
def nearest_mine(self) -> Optional['Mine']:
|
||||
return self.nearest(self.game_map.mines)
|
||||
|
||||
def nearest(self, entities: Sequence['EntityType']) -> Optional['EntityType']:
|
||||
nearest = None
|
||||
best_dist = math.inf
|
||||
for entity in entities:
|
||||
dist = self.distance(entity)
|
||||
if dist < best_dist:
|
||||
best_dist = dist
|
||||
nearest = entity
|
||||
return nearest
|
||||
|
||||
|
||||
class Barrel(Entity):
|
||||
def __init__(self, game_map: GameMap, entity_id: int, x: int, y: int, quantity: int):
|
||||
super().__init__(game_map, entity_id, x, y)
|
||||
self.quantity = quantity
|
||||
|
||||
|
||||
class Ship(Entity):
|
||||
def __init__(self, game_map: GameMap,
|
||||
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.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[TargetType]
|
||||
|
||||
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
|
||||
|
||||
if self.target:
|
||||
print('{} {} {}'.format(self.action.value, self.target.x, self.target.y))
|
||||
else:
|
||||
print(self.action.value)
|
||||
self.action = None
|
||||
self.target = None
|
||||
self.mine_wait -= 1
|
||||
self.shoot_wait -= 1
|
||||
|
||||
def drop_mine(self):
|
||||
self.action = Action.MINE
|
||||
|
||||
def wait(self):
|
||||
self.action = Action.WAIT
|
||||
|
||||
def slower(self):
|
||||
self.action = Action.SLOWER
|
||||
|
||||
def shoot(self, target: 'EntityType'):
|
||||
self.action = Action.FIRE
|
||||
self.target = target
|
||||
|
||||
def move(self, target: 'TargetType'):
|
||||
self.action = Action.MOVE
|
||||
self.target = target
|
||||
|
||||
|
||||
class Mine(Entity):
|
||||
def __init__(self, game_map: GameMap, entity_id: int, x: int, y: int):
|
||||
super().__init__(game_map, entity_id, x, y)
|
||||
|
||||
|
||||
class Cannonball(Entity):
|
||||
def __init__(self, game_map: GameMap, entity_id: int, x: int, y: int, shooter_id: int, turns_before_impact: int):
|
||||
super().__init__(game_map, entity_id, x, y)
|
||||
self.turns_before_impact = turns_before_impact
|
||||
self.shooter_id = shooter_id
|
||||
|
||||
|
||||
EntityType = TypeVar('EntityType', Entity, Barrel, Ship, Mine, Cannonball)
|
||||
TargetType = Union[EntityType, Tile]
|
||||
|
||||
|
||||
def main():
|
||||
random.seed()
|
||||
game_map = GameMap()
|
||||
|
||||
while True:
|
||||
my_ship_count = int(input()) # the number of remaining ships
|
||||
entity_count = int(input()) # the number of entities (e.g. ships, mines or cannonballs)
|
||||
game_map.reset()
|
||||
|
||||
# Fetch info
|
||||
for i in range(entity_count):
|
||||
entity_id, entity_type, x, y, arg_1, arg_2, arg_3, arg_4 = input().split()
|
||||
entity_id = int(entity_id)
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
|
||||
if entity_type == BARREL:
|
||||
rhum_quantity = int(arg_1)
|
||||
game_map.barrels.append(Barrel(game_map, entity_id, x, y, rhum_quantity))
|
||||
|
||||
elif entity_type == SHIP:
|
||||
orientation = int(arg_1)
|
||||
speed = int(arg_2)
|
||||
rhum_stock = int(arg_3)
|
||||
mine = int(arg_4) == 1
|
||||
ship = Ship(game_map, entity_id, x, y, orientation, speed, rhum_stock, mine)
|
||||
if mine:
|
||||
my_ship = game_map.my_ships.get(entity_id, None)
|
||||
if my_ship:
|
||||
my_ship.orientation = orientation
|
||||
my_ship.speed = speed
|
||||
my_ship.stock = rhum_stock
|
||||
else:
|
||||
game_map.my_ships[entity_id] = ship
|
||||
else:
|
||||
game_map.opponent_ships.append(ship)
|
||||
|
||||
elif entity_type == MINE:
|
||||
game_map.mines.append(Mine(game_map, entity_id, x, y))
|
||||
|
||||
elif entity_type == CANNONBALL:
|
||||
shooter_id = int(arg_1)
|
||||
turns_before_impact = int(arg_2)
|
||||
game_map.cannonballs.append(Cannonball(game_map, entity_id, x, y, shooter_id, turns_before_impact))
|
||||
|
||||
# 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()
|
||||
|
||||
|
||||
def perr(*args):
|
||||
print(*args, file=sys.stderr, flush=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue