-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmain.py
More file actions
117 lines (84 loc) · 2.92 KB
/
main.py
File metadata and controls
117 lines (84 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# this is the wrapper.py entrypoint in the sandbox
import json
import sys
from typing import Callable
from seamaster.api import GameAPI
from seamaster.models.player_view import PlayerView
from seamaster.context.bot_context import BotContext
from seamaster.botbase import BotController
from submission import (
spawn_policy as _spawn_policy,
) # in sandbox submission dir will present and main.py inside represents the user code
class _WrapperState:
def __init__(self):
self.bot_strategies: dict[int, BotController] = {}
self.spawn_policy: Callable[[GameAPI], list[dict]] = _spawn_policy
self.curr_bot_id: int = -1
_STATE = _WrapperState()
def play(api: GameAPI):
tick = api.get_tick()
# linearize tick for the user algo
# because user algo might do `if tick % 10 then spawn bot`
if tick % 2 == 1:
api.view.tick = tick // 2 + 1
else:
api.view.tick = tick // 2
spawns: dict[str, dict] = {}
actions: dict[str, dict] = {}
if _STATE.curr_bot_id == -1:
_STATE.curr_bot_id = api.view.bot_id_seed
# ---- SPAWN PHASE (EVERY TICK) ----
for spec in _STATE.spawn_policy(api):
strategy_cls = spec["strategy"]
if not issubclass(strategy_cls, BotController):
raise TypeError(f"Invalid strategy class in spawn_policy: {strategy_cls}")
abilities = strategy_cls.ABILITIES
# it's up to the engine to limit
# if api.view.bot_count >= api.view.max_bots:
# continue
bot_id = _STATE.curr_bot_id
_STATE.curr_bot_id += 1
spawns[str(bot_id)] = {
"abilities": abilities,
"location": {"x": 0, "y": spec["location"]},
}
_STATE.bot_strategies[int(bot_id)] = strategy_cls(None)
# ---- ACTION PHASE ----
alive_ids: set[int] = set()
for bot in api.get_my_bots():
alive_ids.add(bot.id)
strategy = _STATE.bot_strategies.get(bot.id)
if strategy is None:
raise RuntimeError(f"Bot {bot.id} exists without a registered strategy.")
ctx = BotContext(api, bot)
strategy.ctx = ctx
try:
action = strategy.act()
except Exception as exc:
import traceback
print(
f"[USER_CODE] Error in bot {bot.id}: {exc}\n{traceback.format_exc()}",
file=sys.stderr,
)
action = None
if action is not None:
actions[str(bot.id)] = action.to_dict()
return {
"tick": tick,
"spawns": spawns,
"actions": actions,
}
def main():
print('"__READY_V1__"', flush=True)
while True:
line = sys.stdin.readline()
if not line:
break
data = json.loads(line)
view = PlayerView.from_dict(data)
api = GameAPI(view)
out = play(api)
print(json.dumps(out))
sys.stdout.flush()
if __name__ == "__main__":
main()