Skip to content

Instantly share code, notes, and snippets.

@TsuMakoto
Last active March 13, 2022 14:10
Show Gist options
  • Save TsuMakoto/15ec80fc23adc4d826b5631801b2c8a5 to your computer and use it in GitHub Desktop.
Save TsuMakoto/15ec80fc23adc4d826b5631801b2c8a5 to your computer and use it in GitHub Desktop.
import sys
# Deliver more ore to hq (left side of the map) than your opponent. Use radars to find ore but beware of traps!
def std_err(args):
print(args, file=sys.stderr, flush=True)
def get_line():
i = input()
std_err(i)
return i
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def eq(self, point):
return self.x == point.x and self.y == point.y
def is_out_range(self):
return self.x < 0 or self.y < 0
def distance(self, point):
return abs(self.x - point.x) + abs(self.y - point.y)
# TARGET_RADAR_POINTS = [Point(*cord)
# for cord in [
# [3, 9], [8, 6], [14, 9], [20, 6], [26, 9],
# # [2, 3], [3, 14],
# [9, 12], # [8, 0],
# [14, 3], #[16, 14],
# [20, 12], # [20, 0],
# [26, 3], #[27, 14]
# ]
# ]
TARGET_RADAR_POINTS = [Point(*cord)
for cord in [
[5,3],[5,11],[10,7],[15,3],[15,11],[20,7],[25,3],[25,11]
]
]
class Entity():
def __init__(self, id, type, x, y, item):
self.id = id
self.type = type
self.point = Point(x, y)
self.item = item
def item_is_none(self):
return self.item == -1
def item_is_radar(self):
return self.item == 2
def item_is_trap(self):
return self.item == 3
def item_is_crystal(self):
return self.item == 4
def eq(self, entity):
return self.id == entity.id
class Agent(Entity):
def __init__(self, id, type, x, y, item):
super().__init__(id, type, x, y, item)
if self.is_dead():
self.item = 0
self.command = ""
def is_dead(self):
return self.point.eq(Point(-1, -1))
def next_action(self, command):
self.command = command
class Radar(Entity):
pass
class Trap(Entity):
pass
class AssignEntity():
def __init__(self, agents, opp_agents, radars, traps):
self.agents = agents
self.opp_agents = opp_agents
self.radars = radars
self.traps = traps
# entity_id: unique id of the entity
# entity_type: 0 for your robot, 1 for other robot, 2 for radar, 3 for trap
# x, y: position of the entity
# item: if this entity is a robot, the item it is carrying (-1 for NONE, 2 for RADAR, 3 for TRAP, 4 for ORE)
def assign(self, entity):
[lambda: self.agents.append(Agent(*entity)),
lambda: self.opp_agents.append(Agent(*entity)),
lambda: self.radars.append(Radar(*entity)),
lambda: self.traps.append(Trap(*entity))][entity[1]]()
class OreMap():
def __init__(self, width, height):
self.width = width
self.height = height
self.map = [("? " * width).split() for _ in range(height)]
self.crystal_points = []
# ore: amount of ore or "?" if unknown
# hole: 1 if cell has a hole
def update(self, point, cell):
self.map[point.y][point.x] = cell if cell == "?" else int(cell)
if self.is_crystal_pos(point):
# クリスタルの場所である場合
if not any([point.eq(p) for p in self.crystal_points]):
# クリスタルマップに存在しない場合
self.crystal_points.append(point)
else:
# クリスタルの場所でない、もしくはなくなった場合
self.crystal_points = [p for p in self.crystal_points if not p.eq(point)]
def is_crystal_pos(self, point):
cell = self.cell_info(point)
return cell != "?" and cell > 0
def cell_info(self, point):
return self.map[point.y][point.x]
def after_target_cell(self, point):
# 掘るのでクリスタルを一つ減らす
cell = self.cell_info(point)
if cell != "?":
self.update(point, cell - 1)
class HoleMap():
def __init__(self, width, height):
self.width = width
self.height = height
self.map = [[0 for _ in range(width)] for _ in range(height)]
def update(self, point, cell):
self.map[point.y][point.x] = cell
def cell_info(self, point):
return self.map[point.y][point.x]
def is_trap(self, point: Point, ore_map: OreMap):
return self.cell_info(point) == 1 and not ore_map.is_crystal_pos(point)
class Score():
def __init__(self):
self.me = 0
self.opponent = 0
def update(self, me, opponent):
self.me = me
self.opponent = opponent
def diff(self):
return self.me - self.opponent
class Cooldown():
def __init__(self):
self.radar = 0
self.trap = 0
def update(self, radar, trap):
self.radar = radar
self.trap = trap
class GlobalInfo():
def __init__(self, width, height):
self.width = width
self.height = height
self.trap_map = [[False for _ in range(width)] for _ in range(height)]
self.turn = 1
self.opp_agents = []
def is_trap(self, point: Point):
return self.trap_map[point.y][point.x]
def turn_up(self):
self.turn += 1
def update_trap_map(self, point: Point):
if self.trap_map[point.y][point.x]:
self.trap_map[point.y][point.x] = False
else:
self.trap_map[point.y][point.x] = True
class GameInput():
def __init__(self, width, height):
self.score = Score()
self.ore_map = OreMap(width, height)
self.hole_map = HoleMap(width, height)
self.cooldown = Cooldown()
self.agents = []
self.opp_agents = []
self.radars = []
self.traps = []
self.target_radar_point = Point(-1, -1)
class AgentCommand():
def __init__(self, agent):
self.agent = agent
class Wait(AgentCommand):
def __call__(self):
self.agent.next_action("WAIT")
def is_need(self):
return self.agent.is_dead()
class Move(AgentCommand):
def __call__(self, input: GameInput, global_info: GlobalInfo):
# レーダーを所持している場合
if self.agent.item_is_radar():
self.agent.next_action(
" ".join(["MOVE", str(input.target_radar_point.x), str(input.target_radar_point.y)]))
return
# クリスタルを所持している場合
if self.agent.item_is_crystal():
self.agent.next_action(" ".join(["MOVE", str(0), str(self.agent.point.y)]))
return
# 通常ならクリスタルのある場所へ移動する
point = Point(-1, -1)
for crystal_point in input.ore_map.crystal_points:
# トラップのある場所には行かない
if global_info.is_trap(crystal_point):
continue
if point.is_out_range():
point = crystal_point
continue
if point.distance(self.agent.point) > crystal_point.distance(self.agent.point):
# トラップを所持しているエージェントは
# クリスタルが2つ以上のところへ向かう
# if self.agent.item_is_trap():
# if input.ore_map.cell_info(point) > 1:
point = crystal_point
if point.is_out_range():
self.agent.next_action("WAIT")
return
self.agent.next_action(" ".join(["MOVE", str(point.x), str(point.y)]))
input.ore_map.after_target_cell(point)
def is_need(self, input: GameInput, global_info: GlobalInfo):
# 現在、アイテムを所持しているなら移動する
if not self.agent.item_is_none():
return True
# 現座標にクリスタルが埋まっているなら移動しない
# if input.ore_map.is_crystal_pos(self.agent.point):
# return False
# クリスタルの埋まっている場所が見つからないなら移動しない
if input.ore_map.crystal_points == []:
return False
return True
class Dig(AgentCommand):
def __call__(self, input: GameInput, global_info: GlobalInfo):
# レーダーを所持していて、レーダー設置座標なら掘る
if self.agent.item_is_radar():
self.agent.next_action(
" ".join(["DIG", str(input.target_radar_point.x), str(input.target_radar_point.y)]))
else:
# レーダーを所持しておらず、クリスタルがあるなら掘る
p = self.agent.point
if input.ore_map.is_crystal_pos(p):
self.agent.next_action(" ".join(["DIG", str(p.x), str(p.y)]))
input.ore_map.after_target_cell(p)
if self.agent.item_is_trap():
# トラップを持っている場合
global_info.update_trap_map(p)
def is_need(self, input: GameInput, global_info: GlobalInfo):
# トラップがあるなら掘らない
if global_info.is_trap(self.agent.point):
return False
if self.agent.item_is_radar():
# レーダーを所持していて、レーダー設置座標
if input.target_radar_point.eq(self.agent.point):
return True
# elif # トラップについて。。。
elif self.agent.item_is_crystal():
# クリスタルを所持しているなら掘らない
return False
else:
# アイテムを所持しておらず、クリスタルがあるなら掘る
if input.ore_map.is_crystal_pos(self.agent.point):
return True
return False
class SelfBomb(AgentCommand):
def __call__(self, input: GameInput, global_info: GlobalInfo):
point = Point(-1, -1)
for x in range(global_info.width):
for y in range(global_info.height):
trap_point = Point(x, y)
if not global_info.is_trap(Point(x, y)):
continue
if point.is_out_range():
point = trap_point
elif point.distance(self.agent.point) > trap_point.distance(self.agent.point):
point = trap_point
global_info.update_trap_map(point)
self.agent.next_action(" ".join(["DIG", str(point.x), str(point.y)]))
def is_need(self, input: GameInput, global_info: GlobalInfo):
if input.score.diff() >= 10:
return True
return False
class RequestRadar(AgentCommand):
def __call__(self):
self.agent.next_action("REQUEST RADAR")
def is_need(self, input: GameInput, global_info: GlobalInfo):
# すでにトラップを持っているならリクエストしない
if self.agent.item_is_trap():
return False
# 現座標にクリスタルが埋まっているならリクエストしない
if input.ore_map.is_crystal_pos(self.agent.point):
return False
# cooldownが0でない場合はリクエストしない
if input.cooldown.radar != 0:
return False
# target_radar_pointがなければリクエストしない
if input.target_radar_point.is_out_range():
return False
# レーダー持ちのエージェントがいる場合は、リクエストしない
if any([agent.item_is_radar() for agent in input.agents]):
return False
# すでに他のAgentがレーダー取得に向かっているならリクエストしない
if any([agent.command == "REQUEST RADAR" for agent in input.agents]):
return False
return True
class RequestTrap(AgentCommand):
def __call__(self):
self.agent.next_action("REQUEST TRAP")
def is_need(self, input: GameInput, global_info: GlobalInfo):
# 50ターン以降はトラップを要求しない
if global_info.turn > 150:
return False
# すでにレーダーを持っているならリクエストしない
if self.agent.item_is_radar():
return False
# cooldownが0でない場合、リクエストしない
if input.cooldown.trap != 0:
return False
# 本部にいない場合、リクエストしない
if self.agent.point.x != 0:
return False
return True
def strategy(turn, input: GameInput, global_info: GlobalInfo):
for agent in sorted(input.agents, key=lambda a: a.point.x):
# agentが死んでいるならwaitへ
wait_command = Wait(agent)
if wait_command.is_need():
wait_command()
continue
# self_bomb = SelfBomb(agent)
# if self_bomb.is_need(input, global_info):
# self_bomb(input, global_info)
# continue
# レーダーコマンドに関して
radar_command = RequestRadar(agent)
# レーダーを要求するか判定
if radar_command.is_need(input, global_info):
radar_command()
continue
# トラップコマンドに関して
trap_command = RequestTrap(agent)
# トラップを要求するか
if trap_command.is_need(input, global_info):
trap_command()
continue
# 穴を掘るかの判定
dig_command = Dig(agent)
if dig_command.is_need(input, global_info):
dig_command(input, global_info)
continue
# 移動するかを判定
move_command = Move(agent)
if move_command.is_need(input, global_info):
move_command(input, global_info)
continue
# なにもなければ、Wait
wait_command()
def do_game(input, global_info: GlobalInfo):
if global_info.turn == 1:
RequestRadar(input.agents[0])()
RequestTrap(input.agents[1])()
for i in range(3):
agent = input.agents[i+2]
agent.next_action(" ".join(["MOVE", str(3), str(agent.point.y)]))
elif global_info.turn == 2:
Move(input.agents[0])(input, global_info)
input.agents[1].next_action(" ".join(["MOVE", str(3), str(input.agents[1].point.y)]))
for i in range(3):
agent = input.agents[i+2]
agent.next_action(" ".join(["DIG", str(3), str(agent.point.y)]))
elif global_info.turn == 3:
Dig(input.agents[0])(input, global_info)
for i in range(4):
Wait(input.agents[i+1])()
else:
strategy(global_info.turn, input, global_info)
def turn_of_input(game_input: GameInput, global_info: GlobalInfo):
game_input.score.update(*[int(i) for i in get_line().split()])
for y in range(height):
line = get_line().split()
for x in range(width):
game_input.ore_map.update(Point(x, y), line[2 * x])
game_input.hole_map.update(Point(x, y), line[2 * x + 1])
entity_count, *cooldown = [int(i) for i in get_line().split()]
game_input.cooldown.update(*cooldown)
assign_entity = AssignEntity(
game_input.agents,
game_input.opp_agents,
game_input.radars,
game_input.traps)
for i in range(entity_count):
entity = [int(j) for j in get_line().split()]
assign_entity.assign(entity)
for radar_point in TARGET_RADAR_POINTS:
breakpoint = False
for radar in game_input.radars:
# レーダー設置ポイントで、トラップがなければ、設定
if radar.point.eq(radar_point):
breakpoint = True
break
if global_info.is_trap(radar_point):
breakpoint = True
break
if not breakpoint:
game_input.target_radar_point = radar_point
break
width, height = [int(i) for i in get_line().split()]
global_info = GlobalInfo(width, height)
# game loop
for i in range(200):
game_input = GameInput(width, height)
turn_of_input(game_input, global_info)
turn = i + 1
do_game(game_input, global_info)
for agent in game_input.agents:
print(agent.command)
global_info.turn_up()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment