minesweeper/src/main/js/Game.ts

173 lines
5.3 KiB
TypeScript
Raw Normal View History

2020-07-31 23:12:16 +02:00
// @ts-ignore
import {$} from "@fwdekker/template";
import {Display} from "./Display";
import {Field} from "./Field";
import {Solver} from "./Solver";
/**
* Controls the interaction with a game of Minesweeper.
*/
export class Game {
private readonly canvas: HTMLCanvasElement;
private readonly solveForm: HTMLFormElement;
private readonly settingsForm: HTMLFormElement;
private readonly widthInput: HTMLInputElement;
private readonly heightInput: HTMLInputElement;
private readonly minesInput: HTMLInputElement;
private readonly seedInput: HTMLInputElement;
private field: Field | null;
2020-07-31 23:12:16 +02:00
private display: Display;
private leftDown: boolean;
private rightDown: boolean;
private holdsAfterChord: boolean;
/**
* Constructs and starts a new game of Minesweeper.
*/
constructor() {
this.canvas = $("#canvas");
this.solveForm = $("#solveForm");
this.settingsForm = $("#settingsForm");
this.widthInput = $("#settingsWidth");
this.heightInput = $("#settingsHeight");
this.minesInput = $("#settingsMines");
this.seedInput = $("#settingsSeed");
this.field = null; // Placeholder
2020-07-31 23:12:16 +02:00
this.display = new Display(this.canvas, this.field);
this.display.startDrawLoop();
this.leftDown = false;
this.rightDown = false;
this.holdsAfterChord = false;
// Set up event handlers
2020-07-31 23:12:16 +02:00
this.solveForm.addEventListener(
"submit",
event => {
event.preventDefault();
if (this.field !== null)
new Solver().solve(this.field);
2020-07-31 23:12:16 +02:00
}
);
this.widthInput.addEventListener("change", _ => this.setMineLimit());
this.heightInput.addEventListener("change", _ => this.setMineLimit());
2020-07-31 23:12:16 +02:00
this.settingsForm.addEventListener(
"submit",
event => {
event.preventDefault();
this.field = this.createNewField();
this.display.setField(this.field);
2020-07-31 23:12:16 +02:00
}
);
2020-07-31 23:12:16 +02:00
this.canvas.addEventListener(
"mousemove",
event => this.display.mouseSquare = this.display.posToSquare({x: event.clientX, y: event.clientY})
);
this.canvas.addEventListener(
"mouseleave",
_ => {
this.display.mouseSquare = null;
this.leftDown = false;
this.rightDown = false;
this.holdsAfterChord = false;
this.display.mouseHoldChord = false;
}
);
this.canvas.addEventListener(
"contextmenu",
event => event.preventDefault()
);
this.canvas.addEventListener(
"mousedown",
event => {
event.preventDefault();
2020-07-31 23:12:16 +02:00
const square = this.display.posToSquare({x: event.clientX, y: event.clientY});
switch (event.button) {
case 0:
this.leftDown = true;
break;
case 2:
if (!this.leftDown && square !== null) square.flag();
this.rightDown = true;
break;
}
this.display.mouseHoldChord = this.leftDown && this.rightDown;
}
);
this.canvas.addEventListener(
"mouseup",
event => {
event.preventDefault();
const square = this.display.posToSquare({x: event.clientX, y: event.clientY});
switch (event.button) {
case 0:
if (square !== null && this.leftDown && this.rightDown)
square.chord();
else if (square !== null && !this.holdsAfterChord && this.leftDown)
square.uncover();
this.leftDown = false;
this.holdsAfterChord = this.rightDown;
break;
case 1:
if (square !== null) square.chord();
break;
case 2:
if (square !== null && this.leftDown && this.rightDown)
square.chord();
this.rightDown = false;
this.holdsAfterChord = this.leftDown;
break;
}
this.display.mouseHoldChord = this.leftDown && this.rightDown;
}
);
// Create field with current settings
this.setMineLimit();
if (this.settingsForm.reportValidity()) {
this.field = this.createNewField();
this.display.setField(this.field);
}
2020-07-31 23:12:16 +02:00
}
/**
* Creates a new field according to the current settings.
*
* @return the newly created field
*/
createNewField(): Field {
return new Field(
+this.widthInput.value,
+this.heightInput.value,
+this.minesInput.value,
+this.seedInput.value
);
}
/**
* Adjusts the limits on the mine count input field.
*/
setMineLimit(): void {
this.minesInput.max = "" + Field.maxMines(+this.widthInput.value, +this.heightInput.value);
}
2020-07-31 23:12:16 +02:00
}