268 lines
7.0 KiB
TypeScript
268 lines
7.0 KiB
TypeScript
|
import {formatTime} from "./Common";
|
||
|
|
||
|
|
||
|
/**
|
||
|
* A storage for game statistics.
|
||
|
*/
|
||
|
export interface Statistics {
|
||
|
actionsUndone: number;
|
||
|
actionsRedone: number;
|
||
|
lossesUndone: number;
|
||
|
|
||
|
gamesStarted: number;
|
||
|
gamesLost: number;
|
||
|
gamesWon: number;
|
||
|
|
||
|
squaresChorded: number;
|
||
|
squaresChordedLeadingToLoss: number;
|
||
|
squaresFlagged: number;
|
||
|
squaresUncovered: number;
|
||
|
|
||
|
timeSpent: 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 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 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 timeSpent(): number {
|
||
|
return +(this.read()["timeSpent"] ?? 0);
|
||
|
}
|
||
|
|
||
|
set timeSpent(value: number) {
|
||
|
const statistics = this.read();
|
||
|
statistics["timeSpent"] = "" + value;
|
||
|
this.write(statistics);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Generates an HTML report of the current statistics.
|
||
|
*/
|
||
|
generateHtmlReport(): string {
|
||
|
const stats = this.read();
|
||
|
|
||
|
return "" +
|
||
|
`<h3>Time and history</h3>
|
||
|
<table>
|
||
|
<tr>
|
||
|
<th>Actions undone</th>
|
||
|
<td>${stats["actionsUndone"]}</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<th>Actions redone</th>
|
||
|
<td>${stats["actionsRedone"]}</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<th>Losses undone</th>
|
||
|
<td>${stats["lossesUndone"]}</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<th>Time spent</th>
|
||
|
<td>${formatTime(Math.floor(+stats["timeSpent"] / 1000), true, true)}</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
|
||
|
<h3>K/D ratio</h3>
|
||
|
<table>
|
||
|
<tr>
|
||
|
<th>Games started</th>
|
||
|
<td>${stats["gamesStarted"]}</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<th>Games lost</th>
|
||
|
<td>${stats["gamesLost"]}</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<th>Games won</th>
|
||
|
<td>${stats["gamesWon"]}</td>
|
||
|
</tr>
|
||
|
</table>
|
||
|
|
||
|
<h3>Steps taken</h3>
|
||
|
<table>
|
||
|
<tr>
|
||
|
<th>Squares chorded</th>
|
||
|
<td>${stats["squaresChorded"]}</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<th>Squares chorded leading to loss</th>
|
||
|
<td>${stats["squaresChordedLeadingToLoss"]}</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<th>Squares flagged</th>
|
||
|
<td>${stats["squaresFlagged"]}</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<th>Squares uncovered</th>
|
||
|
<td>${stats["squaresUncovered"]}</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;
|
||
|
gamesLost: number = 0;
|
||
|
gamesStarted: number = 0;
|
||
|
gamesWon: number = 0;
|
||
|
squaresChorded: number = 0;
|
||
|
squaresChordedLeadingToLoss: number = 0;
|
||
|
squaresFlagged: number = 0;
|
||
|
squaresUncovered: number = 0;
|
||
|
timeSpent: number = 0;
|
||
|
|
||
|
|
||
|
clear() {
|
||
|
this.actionsUndone = 0;
|
||
|
this.actionsRedone = 0;
|
||
|
this.lossesUndone = 0;
|
||
|
this.gamesLost = 0;
|
||
|
this.gamesStarted = 0;
|
||
|
this.gamesWon = 0;
|
||
|
this.squaresChorded = 0;
|
||
|
this.squaresChordedLeadingToLoss = 0;
|
||
|
this.squaresFlagged = 0;
|
||
|
this.squaresUncovered = 0;
|
||
|
this.timeSpent = 0;
|
||
|
}
|
||
|
}
|