Created
September 23, 2021 11:35
-
-
Save Gobi03/0372c3866c3dc4608a841c135b797539 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import random | |
import time | |
import json | |
import math | |
from typing import Iterable, List, Set, Tuple | |
from urllib.request import urlopen | |
# ゲームサーバのアドレス / トークン | |
GAME_SERVER = os.getenv('GAME_SERVER', 'https://contest.2021-autumn.gbc.tenka1.klab.jp') | |
# TODO: コメントアウトで本番デプロイ | |
#GAME_SERVER = 'https://contest.2021-autumn.gbc.tenka1.klab.jp/staging' # 開発用環境 | |
TOKEN = os.getenv('TOKEN', 'bb7f6b058d9c0ab5211cdb81ddec4d8e') | |
# 補助関数 | |
# API仕様書: https://github.com/KLab/tenka1-2021-autumn/blob/tenka1/apispec.md | |
def call_api(x: str) -> dict: | |
url = f'{GAME_SERVER}{x}' | |
print(url) | |
with urlopen(url) as res: | |
return json.loads(res.read()) | |
def call_game() -> dict: | |
return call_api(f'/api/game/{TOKEN}') | |
def call_move(index: int, x: int, y: int) -> dict: | |
return call_api(f'/api/move/{TOKEN}/{index}-{x}-{y}') | |
def call_will_move(index: int, x: int, y: int, t: int) -> dict: | |
return call_api(f'/api/will_move/{TOKEN}/{index}-{x}-{y}-{t}') | |
def call_resources(ids: Iterable[int]) -> dict: | |
return call_api(f'/api/resources/{TOKEN}/{"-".join(map(str, ids))}') | |
def calc_score(game) -> float: | |
a = sorted(o["amount"] for o in game["owned_resource"]) | |
return a[0] + 0.1 * a[1] + 0.01 * a[2] | |
# user define # | |
Coord = Tuple[int, int] | |
# ms で返す. coord * coord -> int | |
def calc_move_time(p1: Coord, p2: Coord) -> int: | |
return 100 * math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) | |
def to_Coord(dict_pos: dict) -> Coord: | |
return (int(dict_pos["x"]), int(dict_pos["y"])) | |
# 収穫量を計算 | |
def calc_yield(agent: dict, resource: dict) -> int: | |
t = resource["t1"] - (agent["move_start_time"] + calc_move_time(agent["pos"], resource["pos"])) | |
return resource["weight"] * t | |
def to_owned_resource(game) -> dict: | |
orce = game["owned_resource"] | |
return {"A": orce[0]["amount"], "B": orce[1]["amount"], "C": orce[2]["amount"]} | |
# 対象リソースの評価関数 | |
# 小さいほど良い | |
def evaluation(agent: dict, resource: dict, game) -> int: | |
move_time = calc_move_time(agent["pos"], resource["pos"]) | |
orce = to_owned_resource(game) | |
denom = orce["A"] + orce["B"] + orce["C"] | |
score = move_time * (orce[resource["type"]] / denom) | |
score *= 1.3 ** max(0, resource["targeted_num"]-1) | |
if calc_yield(agent, resource) <= 0: | |
score = 1e18 | |
return score | |
class Bot: | |
def solve(self): | |
while True: | |
game = call_game() | |
if game["status"] != "ok": | |
print(game["status"]) | |
break | |
# A: 38.06 B: 18.04 C: 23.83 Score: 20.81 みたいなフォーマットでスコアの出力 | |
print(' '.join(f'{o["type"]}: {o["amount"]:.2f}' for o in game["owned_resource"]), f'Score: {calc_score(game):.2f}') | |
# 出現済みかつ未消滅の資源を resources に追加 | |
resources: List[dict] = [] | |
for r in game["resource"]: | |
if r["t0"] - 500 <= game["now"] < r["t1"]: | |
r["pos"] = to_Coord(r) | |
del r["x"] | |
del r["y"] | |
r["targeted_num"] = 0 # 取得対象にされてる自マシン数 | |
resources.append(r) | |
# 移動予定地点にリソースが無い回収車をリストアップ & 移動予定地のリソース削除 | |
agent_list: List[dict] = [] | |
for i in range(5): | |
agent = {} | |
agent["id"] = i + 1 | |
agent["pos"] = to_Coord(game["agent"][i]["move"][-1]) # 回収車の予定移動座標 | |
# 既に移動予定になっているリソースとエージェントをいい感じに | |
flag = False # 移動予定地が有るか | |
next_resources = [] | |
for r in resources: | |
if r["pos"] == agent["pos"]: | |
r["targeted_num"] += 1 | |
# 次の周期までに収穫期間が終わるなら | |
if r["t1"] - game["now"] < 1000: | |
agent["move_start_time"] = r["t1"] | |
else: | |
flag = True | |
else: | |
next_resources.append(r) | |
#resources = next_resources | |
# 実質使われないはず(上の時点で終わってるはず) | |
if not flag: # 移動予定地にリソーずが無ければ | |
agent["move_start_time"] = game["now"] | |
agent_list.append(agent) | |
#resources = [r for r in resources if r["targeted_num"] < 2] | |
# index_list の中身を順に最短距離座標に割り当てて行く | |
for agent in agent_list: | |
if not resources: | |
break | |
# 移動時間で昇順ソート | |
l = list(sorted(map(lambda r: (evaluation(agent, r, game), r), resources), key=lambda p: p[0])) | |
#print(l) | |
_, r = l[0] # 目的地の座標 | |
r["targeted_num"] += 1 | |
gx, gy = r["pos"] | |
call_will_move(agent["id"], gx, gy, agent["move_start_time"]) | |
#resources = [r for r in resources if r["pos"] != (gx, gy)] | |
# resources = [r for r in resources if r["targeted_num"] < 2] | |
time.sleep(1.0) | |
if __name__ == "__main__": | |
bot = Bot() | |
bot.solve() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment