webworker runs fish bot for suggestions

This commit is contained in:
milo 2024-03-05 20:26:49 -05:00
parent c6a20e2bcd
commit 74028e8efe
4 changed files with 90 additions and 10 deletions

View File

@ -61,6 +61,7 @@ name = "fish-webworker"
version = "0.1.0"
dependencies = [
"fish",
"mino",
"wasm-bindgen",
"wasm-bindgen-macro",
"wee_alloc",

View File

@ -9,6 +9,7 @@ crate-type = ["cdylib"]
[dependencies]
fish = { path = "../fish" }
mino = { path = "../mino" }
wasm-bindgen = "0.2"
wasm-bindgen-macro = "0.2"

View File

@ -1,7 +1,9 @@
use std::{cell::RefCell, mem::MaybeUninit};
use wasm_bindgen_macro::wasm_bindgen;
use fish::Weights;
use fish::{Bot, Weights};
use mino::srs::{PieceType, Queue};
use mino::{MatBuf, Rot};
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
@ -13,18 +15,22 @@ struct State {
static mut STATE: MaybeUninit<RefCell<State>> = MaybeUninit::uninit();
fn state() -> &'static RefCell<State> {
unsafe { STATE.assume_init_ref() }
impl State {
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)]
fn start() {
let init_state = State {
weights: Weights::default(),
max_iters: 10_000,
};
unsafe { STATE.write(RefCell::new(init_state)) };
unsafe { STATE.write(State::new()) };
}
#[wasm_bindgen]
@ -34,8 +40,71 @@ pub fn get_version() -> String {
#[wasm_bindgen]
pub fn get_config() -> Vec<i32> {
let state = state().borrow();
let state = State::get().borrow();
let mut config = Vec::from(state.weights.0);
config.push(state.max_iters as i32);
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()
}

View File

@ -2,6 +2,7 @@ import {
default as init,
get_version as getVersion,
get_config as getConfig,
suggest,
} from '../build/fish_webworker.js'
let initPromise = init('/blockfish.wasm');
@ -16,6 +17,14 @@ async function handle(msg) {
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:
throw `Unrecognized message "${msg.type}"`;
}