parent
654148d09c
commit
302d2e8847
Binary file not shown.
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "minesweeper",
|
"name": "minesweeper",
|
||||||
"version": "0.86.2",
|
"version": "0.86.3",
|
||||||
"description": "Just Minesweeper!",
|
"description": "Just Minesweeper!",
|
||||||
"author": "Florine W. Dekker",
|
"author": "Florine W. Dekker",
|
||||||
"browser": "dist/bundle.js",
|
"browser": "dist/bundle.js",
|
||||||
|
|
|
@ -445,6 +445,16 @@ export class Field {
|
||||||
this.invokeEventListeners();
|
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.
|
* Runs and stores the given action such that it can be undone.
|
||||||
*
|
*
|
||||||
|
|
|
@ -198,12 +198,12 @@ export class Game {
|
||||||
this.solve = $("#solve");
|
this.solve = $("#solve");
|
||||||
this.solve.addEventListener(
|
this.solve.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
(event: MouseEvent) => {
|
async (event: MouseEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (this.field != null) {
|
if (this.field != null) {
|
||||||
this.statistics.solverUsages++;
|
this.statistics.solverUsages++;
|
||||||
Solver.solve(this.field);
|
await Solver.solveAnimated(this.field);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.display.hintSquare = null;
|
this.display.hintSquare = null;
|
||||||
|
|
|
@ -17,8 +17,43 @@ export class Solver {
|
||||||
if (field.isOver) return;
|
if (field.isOver) return;
|
||||||
if (field.hasStarted && !this.step(field.copy())) 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) {
|
if (!field.hasStarted) {
|
||||||
field.isAutoSolving = true;
|
|
||||||
field.runUndoably(() => {
|
field.runUndoably(() => {
|
||||||
const target = {x: Math.floor(field.width / 2), y: Math.floor(field.height / 2)};
|
const target = {x: Math.floor(field.width / 2), y: Math.floor(field.height / 2)};
|
||||||
const targetSquare = field.getSquareOrElse(target)!;
|
const targetSquare = field.getSquareOrElse(target)!;
|
||||||
|
@ -26,21 +61,21 @@ export class Solver {
|
||||||
if (targetSquare.hasMark) field.toggleMark(target);
|
if (targetSquare.hasMark) field.toggleMark(target);
|
||||||
field.uncover(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.
|
* Returns `true` if and only if this solver can solve the given field.
|
||||||
*
|
*
|
||||||
|
@ -127,6 +162,7 @@ export class Solver {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a suggestion for a next move based on the current state of the field.
|
* Returns a suggestion for a next move based on the current state of the field.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue