2020-08-08 02:41:21 +02:00
|
|
|
import {formatTime} from "./Common";
|
2020-08-12 22:01:57 +02:00
|
|
|
import {Storage} from "./Storage";
|
2020-08-08 02:41:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A storage for game statistics.
|
|
|
|
*/
|
|
|
|
export interface Statistics {
|
|
|
|
actionsUndone: number;
|
|
|
|
actionsRedone: number;
|
|
|
|
lossesUndone: number;
|
2020-08-09 17:38:39 +02:00
|
|
|
timeSpent: number;
|
2020-08-08 02:41:21 +02:00
|
|
|
|
|
|
|
gamesStarted: number;
|
|
|
|
gamesWon: number;
|
2020-08-09 14:28:25 +02:00
|
|
|
gamesWonWithoutLosing: number;
|
2020-08-08 02:41:21 +02:00
|
|
|
|
|
|
|
squaresChorded: number;
|
|
|
|
squaresChordedLeadingToLoss: number;
|
|
|
|
squaresFlagged: number;
|
2020-08-12 18:52:02 +02:00
|
|
|
squaresMarked: number;
|
2020-08-08 02:41:21 +02:00
|
|
|
squaresUncovered: number;
|
2020-08-13 10:55:53 +02:00
|
|
|
minesUncovered: number;
|
2020-08-08 02:41:21 +02:00
|
|
|
|
2020-08-09 17:38:39 +02:00
|
|
|
hintsRequested: number;
|
|
|
|
solverUsages: number;
|
2020-08-08 02:41:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resets the statistics.
|
|
|
|
*/
|
|
|
|
clear(): void;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stores game statistics in the browser's localstorage.
|
|
|
|
*/
|
|
|
|
export class LocalStatistics implements Statistics {
|
2020-08-12 22:01:57 +02:00
|
|
|
private readonly storage = new Storage("/tools/minesweeper//statistics");
|
2020-08-08 02:41:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
clear(): void {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.clear();
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
get actionsUndone(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("actionsUndone", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set actionsUndone(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("actionsUndone", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
get actionsRedone(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("actionsRedone", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set actionsRedone(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("actionsRedone", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
get lossesUndone(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("lossesUndone", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set lossesUndone(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("lossesUndone", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
2020-08-09 17:38:39 +02:00
|
|
|
get timeSpent(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("timeSpent", 0);
|
2020-08-09 17:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set timeSpent(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("timeSpent", value);
|
2020-08-09 17:38:39 +02:00
|
|
|
}
|
|
|
|
|
2020-08-08 02:41:21 +02:00
|
|
|
get gamesStarted(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("gamesStarted", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set gamesStarted(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("gamesStarted", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
get gamesWon(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("gamesWon", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set gamesWon(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("gamesWon", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
2020-08-09 14:28:25 +02:00
|
|
|
get gamesWonWithoutLosing(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("gamesWonWithoutLosing", 0);
|
2020-08-09 14:28:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set gamesWonWithoutLosing(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("gamesWonWithoutLosing", value);
|
2020-08-09 14:28:25 +02:00
|
|
|
}
|
|
|
|
|
2020-08-08 02:41:21 +02:00
|
|
|
get squaresChorded(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("squaresChorded", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set squaresChorded(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("squaresChorded", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
get squaresChordedLeadingToLoss(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("squaresChordedLeadingToLoss", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set squaresChordedLeadingToLoss(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("squaresChordedLeadingToLoss", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
get squaresFlagged(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("squaresFlagged", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set squaresFlagged(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("squaresFlagged", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
2020-08-12 18:52:02 +02:00
|
|
|
get squaresMarked(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("squaresMarked", 0);
|
2020-08-12 18:52:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set squaresMarked(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("squaresMarked", value);
|
2020-08-12 18:52:02 +02:00
|
|
|
}
|
|
|
|
|
2020-08-08 02:41:21 +02:00
|
|
|
get squaresUncovered(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("squaresUncovered", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set squaresUncovered(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("squaresUncovered", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
2020-08-13 10:55:53 +02:00
|
|
|
get minesUncovered(): number {
|
|
|
|
return this.storage.getNumber("minesUncovered", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
set minesUncovered(value: number) {
|
|
|
|
this.storage.setNumber("minesUncovered", value);
|
|
|
|
}
|
|
|
|
|
2020-08-09 17:38:39 +02:00
|
|
|
get hintsRequested(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("hintsRequested", 0);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
2020-08-09 17:38:39 +02:00
|
|
|
set hintsRequested(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("hintsRequested", value);
|
2020-08-09 17:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
get solverUsages(): number {
|
2020-08-12 22:01:57 +02:00
|
|
|
return this.storage.getNumber("solverUsages", 0);
|
2020-08-09 17:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
set solverUsages(value: number) {
|
2020-08-12 22:01:57 +02:00
|
|
|
this.storage.setNumber("solverUsages", value);
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates an HTML report of the current statistics.
|
|
|
|
*/
|
|
|
|
generateHtmlReport(): string {
|
|
|
|
return "" +
|
|
|
|
`<h3>Time and history</h3>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Actions undone</th>
|
2020-08-09 02:01:37 +02:00
|
|
|
<td>${this.actionsUndone}</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Actions redone</th>
|
2020-08-09 02:01:37 +02:00
|
|
|
<td>${this.actionsRedone}</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Losses undone</th>
|
2020-08-09 02:01:37 +02:00
|
|
|
<td>${this.lossesUndone}</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Time spent</th>
|
2020-08-09 02:01:37 +02:00
|
|
|
<td>${formatTime(Math.floor(+this.timeSpent / 1000), true, true)}</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
2020-08-12 16:32:50 +02:00
|
|
|
<h3>Wins and losses</h3>
|
2020-08-08 02:41:21 +02:00
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Games started</th>
|
2020-08-09 02:01:37 +02:00
|
|
|
<td>${this.gamesStarted}</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
|
|
|
<tr>
|
2020-08-12 16:32:50 +02:00
|
|
|
<th>Games completed</th>
|
2020-08-25 14:44:52 +02:00
|
|
|
<td>
|
|
|
|
${this.gamesWon} (${Math.round(100 * this.gamesWon / this.gamesStarted)}%)
|
|
|
|
</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
2020-08-09 14:28:25 +02:00
|
|
|
<tr>
|
2020-08-12 16:32:50 +02:00
|
|
|
<th>Games completed without losing</th>
|
2020-08-25 14:44:52 +02:00
|
|
|
<td>
|
|
|
|
${this.gamesWonWithoutLosing} (${Math.round(100 * this.gamesWonWithoutLosing / this.gamesStarted)}%)
|
|
|
|
</td>
|
2020-08-09 14:28:25 +02:00
|
|
|
</tr>
|
2020-08-08 02:41:21 +02:00
|
|
|
</table>
|
|
|
|
|
|
|
|
<h3>Steps taken</h3>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Squares chorded</th>
|
2020-08-09 02:01:37 +02:00
|
|
|
<td>${this.squaresChorded}</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Squares chorded leading to loss</th>
|
2020-08-09 02:01:37 +02:00
|
|
|
<td>${this.squaresChordedLeadingToLoss}</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Squares flagged</th>
|
2020-08-09 02:01:37 +02:00
|
|
|
<td>${this.squaresFlagged}</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
2020-08-12 18:52:02 +02:00
|
|
|
<tr>
|
|
|
|
<th>Squares marked</th>
|
|
|
|
<td>${this.squaresMarked}</td>
|
|
|
|
</tr>
|
2020-08-08 02:41:21 +02:00
|
|
|
<tr>
|
|
|
|
<th>Squares uncovered</th>
|
2020-08-09 02:01:37 +02:00
|
|
|
<td>${this.squaresUncovered}</td>
|
2020-08-08 02:41:21 +02:00
|
|
|
</tr>
|
2020-08-13 10:55:53 +02:00
|
|
|
<tr>
|
|
|
|
<th>Mines uncovered</th>
|
|
|
|
<td>${this.minesUncovered}</td>
|
|
|
|
</tr>
|
2020-08-09 17:38:39 +02:00
|
|
|
</table>
|
|
|
|
|
|
|
|
<h3>Solver usage</h3>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<th>Hints requested</th>
|
|
|
|
<td>${this.hintsRequested}</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Solver usages</th>
|
|
|
|
<td>${this.solverUsages}</td>
|
|
|
|
</tr>
|
2020-08-08 02:41:21 +02:00
|
|
|
</table>`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stores game statistics in memory, right here in the fields of this object.
|
|
|
|
*/
|
|
|
|
export class MemoryStatistics implements Statistics {
|
|
|
|
actionsUndone: number = 0;
|
|
|
|
actionsRedone: number = 0;
|
|
|
|
lossesUndone: number = 0;
|
2020-08-09 17:38:39 +02:00
|
|
|
timeSpent: number = 0;
|
2020-08-08 02:41:21 +02:00
|
|
|
gamesStarted: number = 0;
|
|
|
|
gamesWon: number = 0;
|
2020-08-09 14:28:25 +02:00
|
|
|
gamesWonWithoutLosing: number = 0;
|
2020-08-08 02:41:21 +02:00
|
|
|
squaresChorded: number = 0;
|
|
|
|
squaresChordedLeadingToLoss: number = 0;
|
|
|
|
squaresFlagged: number = 0;
|
2020-08-12 18:52:02 +02:00
|
|
|
squaresMarked: number = 0;
|
2020-08-08 02:41:21 +02:00
|
|
|
squaresUncovered: number = 0;
|
2020-08-13 10:55:53 +02:00
|
|
|
minesUncovered: number = 0;
|
2020-08-09 17:38:39 +02:00
|
|
|
hintsRequested: number = 0;
|
|
|
|
solverUsages: number = 0;
|
2020-08-08 02:41:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
clear() {
|
|
|
|
this.actionsUndone = 0;
|
|
|
|
this.actionsRedone = 0;
|
|
|
|
this.lossesUndone = 0;
|
2020-08-09 17:38:39 +02:00
|
|
|
this.timeSpent = 0;
|
2020-08-08 02:41:21 +02:00
|
|
|
this.gamesStarted = 0;
|
|
|
|
this.gamesWon = 0;
|
2020-08-09 14:28:25 +02:00
|
|
|
this.gamesWonWithoutLosing = 0;
|
2020-08-08 02:41:21 +02:00
|
|
|
this.squaresChorded = 0;
|
|
|
|
this.squaresChordedLeadingToLoss = 0;
|
|
|
|
this.squaresFlagged = 0;
|
2020-08-12 18:52:02 +02:00
|
|
|
this.squaresMarked = 0;
|
2020-08-08 02:41:21 +02:00
|
|
|
this.squaresUncovered = 0;
|
2020-08-13 10:55:53 +02:00
|
|
|
this.minesUncovered = 0;
|
2020-08-09 17:38:39 +02:00
|
|
|
this.hintsRequested = 0;
|
|
|
|
this.solverUsages = 0;
|
2020-08-08 02:41:21 +02:00
|
|
|
}
|
|
|
|
}
|