parent
654148d09c
commit
302d2e8847
Binary file not shown.
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "minesweeper",
|
||||
"version": "0.86.2",
|
||||
"version": "0.86.3",
|
||||
"description": "Just Minesweeper!",
|
||||
"author": "Florine W. Dekker",
|
||||
"browser": "dist/bundle.js",
|
||||
|
|
|
@ -445,6 +445,16 @@ export class Field {
|
|||
this.invokeEventListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs `#runUndoably` asynchronously.
|
||||
*/
|
||||
async runUndoablyAsync(callback: () => Promise<void>): Promise<void> {
|
||||
this.history.startSequence();
|
||||
await callback();
|
||||
if (this.history.commitSequence())
|
||||
this.invokeEventListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs and stores the given action such that it can be undone.
|
||||
*
|
||||
|
|
|
@ -198,12 +198,12 @@ export class Game {
|
|||
this.solve = $("#solve");
|
||||
this.solve.addEventListener(
|
||||
"click",
|
||||
(event: MouseEvent) => {
|
||||
async (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (this.field != null) {
|
||||
this.statistics.solverUsages++;
|
||||
Solver.solve(this.field);
|
||||
await Solver.solveAnimated(this.field);
|
||||
}
|
||||
|
||||
this.display.hintSquare = null;
|
||||
|
|
|
@ -17,8 +17,43 @@ export class Solver {
|
|||
if (field.isOver) return;
|
||||
if (field.hasStarted && !this.step(field.copy())) return;
|
||||
|
||||
field.isAutoSolving = true;
|
||||
this.solveStart(field);
|
||||
field.runUndoably(() => {
|
||||
this.clearUserInputs(field);
|
||||
|
||||
while (this.step(field)) {
|
||||
// Intentionally left empty
|
||||
}
|
||||
});
|
||||
field.isAutoSolving = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs `#solve`, animating steps in between.
|
||||
*/
|
||||
static async solveAnimated(field: Field): Promise<void> {
|
||||
if (field.isOver) return;
|
||||
if (field.hasStarted && !this.step(field.copy())) return;
|
||||
|
||||
field.isAutoSolving = true;
|
||||
this.solveStart(field);
|
||||
await field.runUndoablyAsync(async () => {
|
||||
this.clearUserInputs(field);
|
||||
|
||||
while (this.step(field)) {
|
||||
// Timeout in between steps to create animation
|
||||
await new Promise(it => setTimeout(it, 10));
|
||||
}
|
||||
});
|
||||
field.isAutoSolving = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the field has not started yet, clicks somewhere and starts solving.
|
||||
*/
|
||||
private static solveStart(field: Field): void {
|
||||
if (!field.hasStarted) {
|
||||
field.isAutoSolving = true;
|
||||
field.runUndoably(() => {
|
||||
const target = {x: Math.floor(field.width / 2), y: Math.floor(field.height / 2)};
|
||||
const targetSquare = field.getSquareOrElse(target)!;
|
||||
|
@ -26,21 +61,21 @@ export class Solver {
|
|||
if (targetSquare.hasMark) field.toggleMark(target);
|
||||
field.uncover(target);
|
||||
});
|
||||
field.isAutoSolving = false;
|
||||
}
|
||||
|
||||
field.isAutoSolving = true;
|
||||
field.runUndoably(() => {
|
||||
field.squareList.filter(it => it.hasFlag).forEach(it => field.toggleFlag(it.coords));
|
||||
field.squareList.filter(it => it.hasMark).forEach(it => field.toggleMark(it.coords));
|
||||
|
||||
while (this.step(field)) {
|
||||
// Repeat until `step` returns false
|
||||
}
|
||||
});
|
||||
field.isAutoSolving = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the user's inputs from the given field.
|
||||
*
|
||||
* @param field the field to remove the user's inputs from
|
||||
* @private
|
||||
*/
|
||||
private static clearUserInputs(field: Field): void {
|
||||
field.squareList.filter(it => it.hasFlag).forEach(it => field.toggleFlag(it.coords));
|
||||
field.squareList.filter(it => it.hasMark).forEach(it => field.toggleMark(it.coords));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns `true` if and only if this solver can solve the given field.
|
||||
*
|
||||
|
@ -127,6 +162,7 @@ export class Solver {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a suggestion for a next move based on the current state of the field.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue