Skip to content

Commit

Permalink
[PC solver] Add progress bar
Browse files Browse the repository at this point in the history
  • Loading branch information
wirelyre committed Nov 14, 2021
1 parent 9badf52 commit cda1190
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 9 deletions.
27 changes: 27 additions & 0 deletions gomen/pc-solver.html
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ <h1>PC solver</h1>
<label><input id="hold" type="checkbox" checked> Use hold</label>
</div>

<progress id="progress" style="grid-column: span 2;"></progress>

</div>

<div id="loading">Loading solver...</div>
Expand All @@ -187,14 +189,18 @@ <h1>PC solver</h1>
let queue = document.getElementById("queue");
let queueErrors = document.getElementById("queue-errors");
let hold = document.getElementById("hold");
let progress = document.getElementById("progress");
let solutions = document.getElementById("solutions");
let progressTimeout = window.setTimeout(() => { }, 0);

worker.onmessage = message => {
if (message.data.kind == "ready") {
document.getElementById("loading").remove();

if (work != null) {
worker.postMessage(work);
} else {
hideProgress();
}

return;
Expand All @@ -205,20 +211,28 @@ <h1>PC solver</h1>
initialErrors.innerText = "inital field has no solutions or is unreachable";
solutions.innerHTML = "";
solutions.classList.remove("loading");
hideProgress();
return;
} else if (message.data.kind == "possible" && message.data.query.garbage == getGarbage()[0]) {
initialErrors.innerText = "";
return;
}

if (message.data.kind == "progress") {
progress.value = message.data.amount;
return;
}

if (message.data.query.queue != work.queue
|| message.data.query.garbage != work.garbage
|| message.data.query.hold != work.hold
|| message.data.query.count != work.count) {
worker.postMessage(work);
showProgress();
return;
} else {
work = null;
hideProgress();
solutions.innerHTML = "";
solutions.classList.remove("loading");
}
Expand All @@ -234,6 +248,18 @@ <h1>PC solver</h1>
}
}

function hideProgress() {
window.clearTimeout(progressTimeout);
progress.style.display = "none";
}
function showProgress() {
progress.removeAttribute("value");
window.clearTimeout(progressTimeout);
progressTimeout = window.setTimeout(() => {
progress.style.display = "";
}, 1000);
}

function showSolutions(solns, count) {
if (solns.length == 0) {
solutions.innerText = "no solutions";
Expand Down Expand Up @@ -310,6 +336,7 @@ <h1>PC solver</h1>
solutions.classList.add("loading");
work = { queue: queue.value, garbage, hold: hold.checked };
worker.postMessage(work);
showProgress();
} else {
work = { queue: queue.value, garbage, hold: hold.checked };
}
Expand Down
11 changes: 11 additions & 0 deletions gomen/worker.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
importScripts("./pkg/solver.js");

function progress(piece_count, stage, board_idx, board_total) {
let stage_progress = board_idx / board_total;
let total_progress = (stage + stage_progress) / (2 + 2 * piece_count);

postMessage({ kind: "progress", amount: total_progress });
}

async function main() {
await wasm_bindgen("./pkg/solver_bg.wasm");
let solver = new wasm_bindgen.Solver();
Expand Down Expand Up @@ -34,6 +41,10 @@ async function main() {

let solutions = solver.solve(queue, query.garbage, query.hold).split(",");

if (solutions[0] == "") {
solutions = [];
}

postMessage({ kind: "ok", query, solutions });
}
}
Expand Down
5 changes: 5 additions & 0 deletions solver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,8 @@ fn parse_shape(shape: char) -> Option<Shape> {
_ => None,
}
}

#[wasm_bindgen]
extern "C" {
pub fn progress(piece_count: usize, stage: usize, board_idx: usize, board_total: usize);
}
57 changes: 48 additions & 9 deletions solver/src/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ fn scan(
legal_boards: &HashSet<Board>,
start: Board,
bags: &[Bag],
piece_count: usize,
can_hold: bool,
place_last: bool,
) -> Vec<ScanStage> {
Expand All @@ -26,14 +27,19 @@ fn scan(
let mut prev: ScanStage = HashMap::new();
prev.insert(start, (bags.first().unwrap().init_hold(), SmallVec::new()));

for (bag, i) in bags
for (stage, (bag, i)) in bags
.iter()
.flat_map(|b| (0..b.count).into_iter().map(move |i| (b, i)))
.skip(1)
.enumerate()
{
let mut next: ScanStage = HashMap::new();

for (&old_board, (old_queues, _preds)) in prev.iter() {
for (board_idx, (&old_board, (old_queues, _preds))) in prev.iter().enumerate() {
if board_idx % 4096 == 0 {
crate::progress(piece_count, stage, board_idx, prev.len());
}

for shape in Shape::ALL {
let is_first = i == 0;
let new_queues = bag.take(old_queues, shape, is_first, can_hold);
Expand Down Expand Up @@ -67,7 +73,11 @@ fn scan(
if place_last {
let mut next: ScanStage = HashMap::new();

for (&old_board, (old_queues, _preds)) in prev.iter() {
for (board_idx, (&old_board, (old_queues, _preds))) in prev.iter().enumerate() {
if board_idx % 4096 == 0 {
crate::progress(piece_count, piece_count, board_idx, prev.len());
}

for shape in Shape::ALL {
if old_queues.iter().any(|queue| queue.hold() == Some(shape)) {
for (_, new_board) in PiecePlacer::new(old_board, shape) {
Expand All @@ -88,6 +98,8 @@ fn scan(
prev = next;
}

crate::progress(piece_count, piece_count, 1, 1);

stages.push(prev);
stages
}
Expand Down Expand Up @@ -118,20 +130,26 @@ fn place(
culled: &HashSet<Board>,
start: BrokenBoard,
bags: &[Bag],
piece_count: usize,
can_hold: bool,
place_last: bool,
) -> HashMap<BrokenBoard, SmallVec<[QueueState; 7]>> {
let mut prev = HashMap::new();
prev.insert(start, bags.first().unwrap().init_hold());

for (bag, i) in bags
for (stage, (bag, i)) in bags
.iter()
.flat_map(|b| (0..b.count).into_iter().map(move |i| (b, i)))
.skip(1)
.enumerate()
{
let mut next: HashMap<BrokenBoard, SmallVec<[QueueState; 7]>> = HashMap::new();

for (old_board, old_queues) in prev.iter() {
for (board_idx, (old_board, old_queues)) in prev.iter().enumerate() {
if board_idx % 4096 == 0 {
crate::progress(piece_count, piece_count + 1 + stage, board_idx, prev.len());
}

for shape in Shape::ALL {
let is_first = i == 0;
let new_queues = bag.take(old_queues, shape, is_first, can_hold);
Expand Down Expand Up @@ -159,7 +177,11 @@ fn place(
if place_last {
let mut next: HashMap<BrokenBoard, SmallVec<[QueueState; 7]>> = HashMap::new();

for (old_board, old_queues) in prev.iter() {
for (board_idx, (old_board, old_queues)) in prev.iter().enumerate() {
if board_idx % 4096 == 0 {
crate::progress(piece_count, 2 * piece_count + 1, board_idx, prev.len());
}

for shape in Shape::ALL {
if old_queues.iter().any(|queue| queue.hold() == Some(shape)) {
for (piece, new_board) in PiecePlacer::new(old_board.board, shape) {
Expand All @@ -174,6 +196,8 @@ fn place(
prev = next;
}

crate::progress(piece_count, 2 * piece_count + 1, 1, 1);

prev
}

Expand All @@ -187,12 +211,27 @@ pub fn compute(
return vec![start.clone()];
}

let new_mino_count: u32 = bags.iter().map(|b| b.count as u32 * 4).sum();
let piece_count = bags.iter().map(|b| b.count as usize).sum();
let new_mino_count = piece_count as u32 * 4;
let place_last = start.board.0.count_ones() + new_mino_count <= 40;

let scanned = scan(legal_boards, start.board, bags, can_hold, place_last);
let scanned = scan(
legal_boards,
start.board,
bags,
piece_count,
can_hold,
place_last,
);
let culled = cull(&scanned);
let mut placed = place(&culled, start.clone(), bags, can_hold, place_last);
let mut placed = place(
&culled,
start.clone(),
bags,
piece_count,
can_hold,
place_last,
);

let mut solutions: Vec<BrokenBoard> =
placed.drain().map(|(board, _queue_states)| board).collect();
Expand Down

0 comments on commit cda1190

Please sign in to comment.