Repository navigation
Expand file tree
/
Copy pathworker.js
More file actions
126 lines (110 loc) · 3.91 KB
/
Copy pathworker.js
File metadata and controls
126 lines (110 loc) · 3.91 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
118
119
120
121
122
123
124
125
126
importScripts("https://cdn.jsdelivr.net/pyodide/v0.25.0/full/pyodide.js");
let pyodide;
async function init() {
try {
pyodide = await loadPyodide();
await pyodide.loadPackage("numpy");
// Fetch python source files from the current directory and write to Pyodide Virtual FS
const files = ["state.py", "Alpha_Beta.py", "MCTS.py", "random_agent.py"];
for (let f of files) {
let res = await fetch(`${f}`);
if (!res.ok) {
console.warn(`Could not fetch ${f}`);
continue;
}
let code = await res.text();
pyodide.FS.writeFile(f, code);
}
// Set up a python wrapper to manage state and interface with JS
pyodide.runPython(`
import numpy as np
from state import State_2, UltimateTTT_Move
import Alpha_Beta
import MCTS
import random_agent
agents = {
'Alpha_Beta': Alpha_Beta,
'MCTS': MCTS,
'random_agent': random_agent
}
game_state = State_2()
def init_game():
global game_state
game_state = State_2()
# Reset Alpha_Beta globals just in case
Alpha_Beta.numMoves = 0
Alpha_Beta.transposition_table.clear()
return get_state_json()
def play_move(board_idx, x, y, value):
global game_state
_ = game_state.get_valid_moves
move = UltimateTTT_Move(board_idx, x, y, value)
if game_state.is_valid_move(move):
game_state.act_move(move)
_ = game_state.get_valid_moves
return get_state_json()
return None
def ai_move(agent_name, remain_time):
global game_state
try:
agent = agents.get(agent_name, random_agent)
move = agent.select_move(game_state, remain_time)
if move:
game_state.act_move(move)
_ = game_state.get_valid_moves
return get_state_json()
except Exception as e:
import traceback
return '{"error": ' + json.dumps(traceback.format_exc()) + '}'
import json
def get_state_json():
global game_state
return json.dumps({
"global_cells": game_state.global_cells.tolist(),
"blocks": [b.tolist() for b in game_state.blocks],
"player_to_move": int(game_state.player_to_move),
"previous_move": {
"index_local_board": int(game_state.previous_move.index_local_board),
"x": int(game_state.previous_move.x),
"y": int(game_state.previous_move.y),
"value": int(game_state.previous_move.value)
} if game_state.previous_move else None,
"game_over": bool(game_state.game_over),
"free_move": bool(game_state.free_move)
})
`);
postMessage({ type: 'READY' });
} catch (err) {
console.error(err);
postMessage({ type: 'ERROR', payload: err.toString() });
}
}
init();
onmessage = async (e) => {
const { type, payload } = e.data;
try {
if (type === 'INIT') {
const res = pyodide.runPython(`init_game()`);
postMessage({ type: 'INIT_STATE', payload: JSON.parse(res) });
} else if (type === 'PLAY') {
const { board_idx, x, y, value } = payload;
const res = pyodide.runPython(`play_move(${board_idx}, ${x}, ${y}, ${value})`);
if (res) {
postMessage({ type: 'STATE', payload: JSON.parse(res) });
} else {
postMessage({ type: 'INVALID_MOVE' });
}
} else if (type === 'AI_MOVE') {
const { agent_name, remain_time } = payload;
const res = pyodide.runPython(`ai_move('${agent_name}', ${remain_time})`);
const parsedRes = JSON.parse(res);
if (parsedRes.error) {
postMessage({ type: 'ERROR', payload: parsedRes.error });
} else {
postMessage({ type: 'STATE', payload: parsedRes });
}
}
} catch(err) {
postMessage({ type: 'ERROR', payload: err.toString() });
}
}