Skip to content

Instantly share code, notes, and snippets.

@Gobi03
Created September 23, 2021 11:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Gobi03/0372c3866c3dc4608a841c135b797539 to your computer and use it in GitHub Desktop.
Save Gobi03/0372c3866c3dc4608a841c135b797539 to your computer and use it in GitHub Desktop.
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