minesweeper/src/main/js/Statistics.ts

321 lines
8.5 KiB
TypeScript

import {formatTime} from "./Common";
/**
* A storage for game statistics.
*/
export interface Statistics {
actionsUndone: number;
actionsRedone: number;
lossesUndone: number;
timeSpent: number;
gamesStarted: number;
gamesLost: number;
gamesWon: number;
gamesWonWithoutLosing: number;
squaresChorded: number;
squaresChordedLeadingToLoss: number;
squaresFlagged: number;
squaresUncovered: number;
hintsRequested: number;
solverUsages: number;
/**
* Resets the statistics.
*/
clear(): void;
}
/**
* Stores game statistics in the browser's localstorage.
*/
export class LocalStatistics implements Statistics {
private static readonly storageKey = "/tools/minesweeper//statistics";
/**
* Reads the object stored in local storage.
*
* @return the object stored in local storage, or an empty object if there is nothing in the local storage
* @private
*/
private read(): { [key: string]: string } {
return JSON.parse(localStorage.getItem(LocalStatistics.storageKey) ?? "{}");
}
/**
* Writes the given object to local storage.
*
* @param statistics the object to write to local storage
* @private
*/
private write(statistics: { [key: string]: string }): void {
localStorage.setItem(LocalStatistics.storageKey, JSON.stringify(statistics));
}
clear(): void {
localStorage.removeItem(LocalStatistics.storageKey);
}
get actionsUndone(): number {
return +(this.read()["actionsUndone"] ?? 0);
}
set actionsUndone(value: number) {
const statistics = this.read();
statistics["actionsUndone"] = "" + value;
this.write(statistics);
}
get actionsRedone(): number {
return +(this.read()["actionsRedone"] ?? 0);
}
set actionsRedone(value: number) {
const statistics = this.read();
statistics["actionsRedone"] = "" + value;
this.write(statistics);
}
get lossesUndone(): number {
return +(this.read()["lossesUndone"] ?? 0);
}
set lossesUndone(value: number) {
const statistics = this.read();
statistics["lossesUndone"] = "" + value;
this.write(statistics);
}
get timeSpent(): number {
return +(this.read()["timeSpent"] ?? 0);
}
set timeSpent(value: number) {
const statistics = this.read();
statistics["timeSpent"] = "" + value;
this.write(statistics);
}
get gamesStarted(): number {
return +(this.read()["gamesStarted"] ?? 0);
}
set gamesStarted(value: number) {
const statistics = this.read();
statistics["gamesStarted"] = "" + value;
this.write(statistics);
}
get gamesLost(): number {
return +(this.read()["gamesLost"] ?? 0);
}
set gamesLost(value: number) {
const statistics = this.read();
statistics["gamesLost"] = "" + value;
this.write(statistics);
}
get gamesWon(): number {
return +(this.read()["gamesWon"] ?? 0);
}
set gamesWon(value: number) {
const statistics = this.read();
statistics["gamesWon"] = "" + value;
this.write(statistics);
}
get gamesWonWithoutLosing(): number {
return +(this.read()["gamesWonWithoutLosing"] ?? 0);
}
set gamesWonWithoutLosing(value: number) {
const statistics = this.read();
statistics["gamesWonWithoutLosing"] = "" + value;
this.write(statistics);
}
get squaresChorded(): number {
return +(this.read()["squaresChorded"] ?? 0);
}
set squaresChorded(value: number) {
const statistics = this.read();
statistics["squaresChorded"] = "" + value;
this.write(statistics);
}
get squaresChordedLeadingToLoss(): number {
return +(this.read()["squaresChordedLeadingToLoss"] ?? 0);
}
set squaresChordedLeadingToLoss(value: number) {
const statistics = this.read();
statistics["squaresChordedLeadingToLoss"] = "" + value;
this.write(statistics);
}
get squaresFlagged(): number {
return +(this.read()["squaresFlagged"] ?? 0);
}
set squaresFlagged(value: number) {
const statistics = this.read();
statistics["squaresFlagged"] = "" + value;
this.write(statistics);
}
get squaresUncovered(): number {
return +(this.read()["squaresUncovered"] ?? 0);
}
set squaresUncovered(value: number) {
const statistics = this.read();
statistics["squaresUncovered"] = "" + value;
this.write(statistics);
}
get hintsRequested(): number {
return +(this.read()["hintsRequested"] ?? 0);
}
set hintsRequested(value: number) {
const statistics = this.read();
statistics["hintsRequested"] = "" + value;
this.write(statistics);
}
get solverUsages(): number {
return +(this.read()["solverUsages"] ?? 0);
}
set solverUsages(value: number) {
const statistics = this.read();
statistics["solverUsages"] = "" + value;
this.write(statistics);
}
/**
* Generates an HTML report of the current statistics.
*/
generateHtmlReport(): string {
return "" +
`<h3>Time and history</h3>
<table>
<tr>
<th>Actions undone</th>
<td>${this.actionsUndone}</td>
</tr>
<tr>
<th>Actions redone</th>
<td>${this.actionsRedone}</td>
</tr>
<tr>
<th>Losses undone</th>
<td>${this.lossesUndone}</td>
</tr>
<tr>
<th>Time spent</th>
<td>${formatTime(Math.floor(+this.timeSpent / 1000), true, true)}</td>
</tr>
</table>
<h3>K/D ratio</h3>
<table>
<tr>
<th>Games started</th>
<td>${this.gamesStarted}</td>
</tr>
<tr>
<th>Games lost</th>
<td>${this.gamesLost}</td>
</tr>
<tr>
<th>Games won</th>
<td>${this.gamesWon}</td>
</tr>
<tr>
<th>Games won without losing</th>
<td>${this.gamesWonWithoutLosing}</td>
</tr>
</table>
<h3>Steps taken</h3>
<table>
<tr>
<th>Squares chorded</th>
<td>${this.squaresChorded}</td>
</tr>
<tr>
<th>Squares chorded leading to loss</th>
<td>${this.squaresChordedLeadingToLoss}</td>
</tr>
<tr>
<th>Squares flagged</th>
<td>${this.squaresFlagged}</td>
</tr>
<tr>
<th>Squares uncovered</th>
<td>${this.squaresUncovered}</td>
</tr>
</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>
</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;
timeSpent: number = 0;
gamesLost: number = 0;
gamesStarted: number = 0;
gamesWon: number = 0;
gamesWonWithoutLosing: number = 0;
squaresChorded: number = 0;
squaresChordedLeadingToLoss: number = 0;
squaresFlagged: number = 0;
squaresUncovered: number = 0;
hintsRequested: number = 0;
solverUsages: number = 0;
clear() {
this.actionsUndone = 0;
this.actionsRedone = 0;
this.lossesUndone = 0;
this.timeSpent = 0;
this.gamesLost = 0;
this.gamesStarted = 0;
this.gamesWon = 0;
this.gamesWonWithoutLosing = 0;
this.squaresChorded = 0;
this.squaresChordedLeadingToLoss = 0;
this.squaresFlagged = 0;
this.squaresUncovered = 0;
this.hintsRequested = 0;
this.solverUsages = 0;
}
}