| 1 | """The project's referee. Overcooked is cooperative: a route's bot is a cook, and the season's field are the partners |
| 2 | it cooks with. check: with each partner, on each layout, in both seats, one episode of 400 steps; the score is the |
| 3 | mean reward (20 for each soup served), each partner a subtask. practice: one episode with each partner on the first |
| 4 | layout, a replay of each in replays/. |
| 5 | python3 -I referee/play.py check|practice <route folder> |
| 6 | """ |
| 7 | import json, os, sys |
| 8 | |
| 9 | ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 10 | sys.path.insert(0, os.path.join(ROOT, 'kit')) |
| 11 | import league |
| 12 | from host import Child |
| 13 | from overcooked_ai_py.mdp.actions import Action |
| 14 | from overcooked_ai_py.mdp.overcooked_env import OvercookedEnv |
| 15 | from overcooked_ai_py.mdp.overcooked_mdp import OvercookedGridworld |
| 16 | |
| 17 | LAYOUTS = ['cramped_room', 'asymmetric_advantages', 'coordination_ring'] |
| 18 | HORIZON = 400 |
| 19 | |
| 20 | |
| 21 | def cook(folder): |
| 22 | bot = os.path.join(league.bot_dir(folder), 'bot.py') |
| 23 | if not os.path.isfile(bot): |
| 24 | sys.exit(f'No bot in {folder}: add bot.py with make_agent(mdp, mlam) or a class Agent') |
| 25 | return Child([sys.executable, '-s', os.path.join(ROOT, 'referee', 'child.py'), bot], cwd=os.path.dirname(bot), limit=1.0, start=60) |
| 26 | |
| 27 | |
| 28 | def episode(cooks, layout, seed): |
| 29 | mdp = OvercookedGridworld.from_layout_name(layout) |
| 30 | env = OvercookedEnv.from_mdp(mdp, horizon=HORIZON, info_level=0) |
| 31 | for seat, c in enumerate(cooks): |
| 32 | c.ask({'episode': {'layout': layout, 'seat': seat, 'seed': seed + seat, 'horizon': HORIZON}}, limit=120) |
| 33 | frames, score, done = [], 0, False |
| 34 | while not done: |
| 35 | s = env.state.to_dict() |
| 36 | frames.append({'state': s, 'score': score}) |
| 37 | picks = [c.ask({'state': s}) for c in cooks] |
| 38 | joint = tuple(Action.INDEX_TO_ACTION[p] if isinstance(p, int) and 0 <= p < len(Action.INDEX_TO_ACTION) else Action.STAY for p in picks) |
| 39 | _, r, done, _ = env.step(joint) |
| 40 | score += r |
| 41 | frames.append({'state': env.state.to_dict(), 'score': score}) |
| 42 | return score, {'game': 'overcooked', 'layout': layout, 'terrain': mdp.terrain_mtx, 'horizon': HORIZON, 'score': score, 'frames': frames} |
| 43 | |
| 44 | |
| 45 | def main(mode, route): |
| 46 | me = cook(route) |
| 47 | name = league.route_name() |
| 48 | reps = league.Replays() if mode == 'practice' else None |
| 49 | subtasks = {} |
| 50 | for partner in league.field(os.path.join(ROOT, 'field')): |
| 51 | them = cook(os.path.join(ROOT, 'field', partner)) |
| 52 | got = [] |
| 53 | for k, layout in enumerate(LAYOUTS if mode == 'check' else LAYOUTS[:1]): |
| 54 | for seat in (0, 1) if mode == 'check' else (0,): |
| 55 | cooks = [me, them] if seat == 0 else [them, me] |
| 56 | score, replay = episode(cooks, layout, 1000 * k + seat) |
| 57 | got.append(score) |
| 58 | if reps: |
| 59 | who = [name, partner] if seat == 0 else [partner, name] |
| 60 | replay['players'] = who |
| 61 | reps.add(f'{partner}-{layout}.json', replay, f'{who[0]} (blue) and {who[1]} (green) in {layout.replace("_", " ")}', who, f'{int(score // 20)} soups served, {int(score)} points') |
| 62 | them.close() |
| 63 | subtasks[partner] = sum(got) / len(got) |
| 64 | me.close() |
| 65 | league.write_metrics(sum(subtasks.values()) / len(subtasks), subtasks) |
| 66 | |
| 67 | |
| 68 | if __name__ == '__main__': |
| 69 | main(sys.argv[1], sys.argv[2]) |