webworker runs fish bot for suggestions
This commit is contained in:
parent
c6a20e2bcd
commit
74028e8efe
|
@ -61,6 +61,7 @@ name = "fish-webworker"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fish",
|
"fish",
|
||||||
|
"mino",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
"wee_alloc",
|
"wee_alloc",
|
||||||
|
|
|
@ -9,6 +9,7 @@ crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fish = { path = "../fish" }
|
fish = { path = "../fish" }
|
||||||
|
mino = { path = "../mino" }
|
||||||
|
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
wasm-bindgen-macro = "0.2"
|
wasm-bindgen-macro = "0.2"
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use std::{cell::RefCell, mem::MaybeUninit};
|
use std::{cell::RefCell, mem::MaybeUninit};
|
||||||
use wasm_bindgen_macro::wasm_bindgen;
|
use wasm_bindgen_macro::wasm_bindgen;
|
||||||
|
|
||||||
use fish::Weights;
|
use fish::{Bot, Weights};
|
||||||
|
use mino::srs::{PieceType, Queue};
|
||||||
|
use mino::{MatBuf, Rot};
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||||
|
@ -13,18 +15,22 @@ struct State {
|
||||||
|
|
||||||
static mut STATE: MaybeUninit<RefCell<State>> = MaybeUninit::uninit();
|
static mut STATE: MaybeUninit<RefCell<State>> = MaybeUninit::uninit();
|
||||||
|
|
||||||
fn state() -> &'static RefCell<State> {
|
impl State {
|
||||||
unsafe { STATE.assume_init_ref() }
|
fn new() -> RefCell<State> {
|
||||||
|
RefCell::new(State {
|
||||||
|
weights: Weights::default(),
|
||||||
|
max_iters: 10_000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get() -> &'static RefCell<State> {
|
||||||
|
unsafe { STATE.assume_init_ref() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(start)]
|
#[wasm_bindgen(start)]
|
||||||
fn start() {
|
fn start() {
|
||||||
let init_state = State {
|
unsafe { STATE.write(State::new()) };
|
||||||
weights: Weights::default(),
|
|
||||||
max_iters: 10_000,
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe { STATE.write(RefCell::new(init_state)) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
@ -34,8 +40,71 @@ pub fn get_version() -> String {
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn get_config() -> Vec<i32> {
|
pub fn get_config() -> Vec<i32> {
|
||||||
let state = state().borrow();
|
let state = State::get().borrow();
|
||||||
let mut config = Vec::from(state.weights.0);
|
let mut config = Vec::from(state.weights.0);
|
||||||
config.push(state.max_iters as i32);
|
config.push(state.max_iters as i32);
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn suggest(matrix: String, hold: String, next: String) -> Result<String, String> {
|
||||||
|
let matrix = parse_matrix(&matrix);
|
||||||
|
let hold = parse_hold(&hold)?;
|
||||||
|
let next = parse_queue(&next)?;
|
||||||
|
let queue = Queue::new(hold, &next);
|
||||||
|
|
||||||
|
let state = State::get().borrow();
|
||||||
|
|
||||||
|
let res = {
|
||||||
|
let mut bot = Bot::new(&state.weights, &matrix, queue);
|
||||||
|
bot.think(state.max_iters);
|
||||||
|
bot.suggest().ok_or("No suggestion found")?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(format!(
|
||||||
|
"{x},{y},{r},{ty}",
|
||||||
|
x = res.loc.x,
|
||||||
|
y = res.loc.y,
|
||||||
|
r = rot(res.loc.r),
|
||||||
|
ty = res.ty
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rot(r: Rot) -> &'static str {
|
||||||
|
match r {
|
||||||
|
Rot::N => "spawn",
|
||||||
|
Rot::E => "right",
|
||||||
|
Rot::S => "reverse",
|
||||||
|
Rot::W => "left",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_matrix(s: &str) -> MatBuf {
|
||||||
|
s.bytes()
|
||||||
|
.take(400)
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, c)| *c != b' ')
|
||||||
|
.map(|(i, _)| ((i % 10) as i16, (i / 10) as i16))
|
||||||
|
.fold(MatBuf::new(), |mut mat, (x, y)| {
|
||||||
|
mat.set(x, y);
|
||||||
|
mat
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_hold(s: &str) -> Result<Option<PieceType>, &'static str> {
|
||||||
|
match s.len() {
|
||||||
|
0 => Ok(None),
|
||||||
|
1 => {
|
||||||
|
let c = s.as_bytes()[0];
|
||||||
|
let ty = PieceType::try_from(c as char).map_err(|_| "Unrecognized hold piece")?;
|
||||||
|
Ok(Some(ty))
|
||||||
|
}
|
||||||
|
_ => Err("Expected hold piece to be a single character"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_queue(s: &str) -> Result<Vec<PieceType>, &'static str> {
|
||||||
|
s.bytes()
|
||||||
|
.map(|c| PieceType::try_from(c as char).map_err(|_| "Unrecognized next piece"))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {
|
||||||
default as init,
|
default as init,
|
||||||
get_version as getVersion,
|
get_version as getVersion,
|
||||||
get_config as getConfig,
|
get_config as getConfig,
|
||||||
|
suggest,
|
||||||
} from '../build/fish_webworker.js'
|
} from '../build/fish_webworker.js'
|
||||||
|
|
||||||
let initPromise = init('/blockfish.wasm');
|
let initPromise = init('/blockfish.wasm');
|
||||||
|
@ -16,6 +17,14 @@ async function handle(msg) {
|
||||||
return { version, config: { weights, maxIters } };
|
return { version, config: { weights, maxIters } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'suggest':
|
||||||
|
{
|
||||||
|
let res = suggest(msg.state.matrix, msg.state.hold, msg.state.next);
|
||||||
|
let [x, y, r, type] = res.split(',');
|
||||||
|
x = +x, y = +y;
|
||||||
|
return { moves: [{ x, y, r, type }] };
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw `Unrecognized message "${msg.type}"`;
|
throw `Unrecognized message "${msg.type}"`;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue