-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Tim Slatcher
committed
Nov 2, 2019
1 parent
ee18809
commit a639ae4
Showing
7 changed files
with
257 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { | ||
analyzeHands, | ||
getHandResult, | ||
IGame, | ||
IGameAnalysis, | ||
IHand, | ||
IHandAnalysis, | ||
} from "@turbo-hearts-scores/shared"; | ||
|
||
export interface Stats { | ||
hands: number; | ||
jdCharges: number; | ||
ahCharges: number; | ||
tcCharges: number; | ||
qsCharges: number; | ||
tq: number; | ||
tj: number; | ||
tqj: number; | ||
tookOwnJdCharge: number; | ||
tookOwnQsCharge: number; | ||
tookOwnTcCharge: number; | ||
runs: number; | ||
antiruns: number; | ||
scoreSumSquared: number; | ||
handScoreStdDev: number; | ||
} | ||
|
||
function initialStats() { | ||
return { | ||
ahCharges: 0, | ||
hands: 0, | ||
jdCharges: 0, | ||
scoreSumSquared: 0, | ||
tcCharges: 0, | ||
qsCharges: 0, | ||
tookOwnJdCharge: 0, | ||
tookOwnQsCharge: 0, | ||
tookOwnTcCharge: 0, | ||
tq: 0, | ||
tj: 0, | ||
tqj: 0, | ||
runs: 0, | ||
antiruns: 0, | ||
handScoreStdDev: 0, | ||
}; | ||
} | ||
|
||
export class StatsHandAnalysis implements IHandAnalysis<Stats> { | ||
public initialState(): Stats { | ||
return initialStats(); | ||
} | ||
|
||
public analyze(current: Stats, hand: IHand): Stats { | ||
const handResult = getHandResult(hand); | ||
if (!handResult.valid) { | ||
return current; | ||
} | ||
current.hands++; | ||
for (const score of handResult.scores) { | ||
current.scoreSumSquared += Math.pow(score, 2); | ||
} | ||
for (const playerHand of hand.playerHands) { | ||
if (playerHand.chargedAh) { | ||
current.ahCharges++; | ||
} | ||
if (playerHand.chargedJd) { | ||
current.jdCharges++; | ||
} | ||
if (playerHand.chargedTc) { | ||
current.tcCharges++; | ||
} | ||
if (playerHand.chargedQs) { | ||
current.qsCharges++; | ||
} | ||
if (playerHand.tookJd && playerHand.tookTc) { | ||
current.tj++; | ||
} | ||
if (playerHand.tookQs && playerHand.tookTc) { | ||
current.tq++; | ||
} | ||
if (playerHand.tookQs && playerHand.tookTc && playerHand.tookJd) { | ||
current.tqj++; | ||
} | ||
if (playerHand.tookQs && playerHand.hearts === 12) { | ||
current.antiruns++; | ||
} | ||
if (playerHand.tookQs && playerHand.hearts === 13) { | ||
current.runs++; | ||
} | ||
if (playerHand.chargedQs && playerHand.tookQs) { | ||
current.tookOwnQsCharge++; | ||
} | ||
if (playerHand.chargedJd && playerHand.tookJd) { | ||
current.tookOwnJdCharge++; | ||
} | ||
if (playerHand.chargedTc && playerHand.tookTc) { | ||
current.tookOwnTcCharge++; | ||
} | ||
} | ||
current.handScoreStdDev = Math.sqrt(current.scoreSumSquared / current.hands); | ||
return current; | ||
} | ||
} | ||
|
||
export class StatsGameAnalysis implements IGameAnalysis<Stats> { | ||
public initialState(): Stats { | ||
return initialStats(); | ||
} | ||
|
||
public analyze(current: Stats, game: IGame): Stats { | ||
if (!game.players || game.players.length === 0) { | ||
return current; | ||
} | ||
if (game.players.some(p => p == null) || game.hands == null || game.hands.length === 0) { | ||
return current; | ||
} | ||
|
||
analyzeHands(game.hands, new StatsHandAnalysis(), current); | ||
|
||
return current; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
.stats-page { | ||
margin: 20px; | ||
|
||
& b { | ||
font-weight: 600; | ||
} | ||
|
||
& ul { | ||
list-style: circle; | ||
margin: 20px 40px; | ||
} | ||
|
||
& li { | ||
line-height: 30px; | ||
} | ||
|
||
& .th-card { | ||
margin-right: 2px; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { analyzeGames } from "@turbo-hearts-scores/shared"; | ||
import * as React from "react"; | ||
import { GameLoader } from "../../api/gameLoader"; | ||
import { Card } from "../components/Card"; | ||
import { Stats, StatsGameAnalysis } from "./StatsAnalysis"; | ||
|
||
interface StatsPageProps { | ||
gameLoader: GameLoader; | ||
} | ||
|
||
interface StatsPageState { | ||
stats: undefined | Stats; | ||
} | ||
|
||
export class StatsPage extends React.PureComponent<StatsPageProps, StatsPageState> { | ||
public state: StatsPageState = { | ||
stats: undefined, | ||
}; | ||
|
||
public async componentDidMount() { | ||
this.fetchGames(); | ||
} | ||
|
||
public render() { | ||
if (this.state.stats !== undefined) { | ||
return this.renderStats(this.state.stats); | ||
} | ||
return null; | ||
} | ||
|
||
private renderStats(stats: Stats) { | ||
return ( | ||
<div className="stats-page"> | ||
<h4> | ||
In <b>{stats.hands}</b> hands: | ||
</h4> | ||
<ul> | ||
<li>A player ran {this.renderPercent(stats.runs, stats.hands)} of the time.</li> | ||
<li>A player antiran {this.renderPercent(stats.antiruns, stats.hands)} of the time.</li> | ||
<li> | ||
A player was <Card rank="10" suit="CLUBS" /> | ||
<Card rank="Q" suit="SPADES" />'d in {this.renderPercent(stats.tq, stats.hands)}. | ||
</li> | ||
<li> | ||
A player took <Card rank="10" suit="CLUBS" /> | ||
<Card rank="J" suit="DIAMONDS" /> in {this.renderPercent(stats.tj, stats.hands)}. | ||
</li> | ||
<li> | ||
A player took <Card rank="10" suit="CLUBS" /> | ||
<Card rank="Q" suit="SPADES" /> | ||
<Card rank="J" suit="DIAMONDS" /> in {this.renderPercent(stats.tqj, stats.hands)}. | ||
</li> | ||
<li> | ||
The <Card rank="Q" suit="SPADES" /> was charged in{" "} | ||
{this.renderPercent(stats.qsCharges, stats.hands)}, and was taken by the charger{" "} | ||
{this.renderPercent(stats.tookOwnQsCharge, stats.qsCharges)} of the time. | ||
</li> | ||
<li> | ||
The <Card rank="J" suit="DIAMONDS" /> was charged in{" "} | ||
{this.renderPercent(stats.jdCharges, stats.hands)}, and was taken by the charger{" "} | ||
{this.renderPercent(stats.tookOwnJdCharge, stats.jdCharges)} of the time. | ||
</li> | ||
<li> | ||
The <Card rank="10" suit="CLUBS" /> was charged in{" "} | ||
{this.renderPercent(stats.tcCharges, stats.hands)}, and was taken by the charger{" "} | ||
{this.renderPercent(stats.tookOwnTcCharge, stats.tcCharges)} of the time. | ||
</li> | ||
<li> | ||
The <Card rank="A" suit="HEARTS" /> was charged in{" "} | ||
{this.renderPercent(stats.ahCharges, stats.hands)}. | ||
</li> | ||
<li> | ||
The score standard deviation was <b>{stats.handScoreStdDev.toFixed(1)}</b>. | ||
</li> | ||
</ul> | ||
</div> | ||
); | ||
} | ||
|
||
private renderPercent(p: number, n: number) { | ||
return <b>{(p / n * 100).toFixed(1)}%</b>; | ||
} | ||
|
||
private async fetchGames() { | ||
const allGames = await this.props.gameLoader.loadGames(); | ||
const stats = analyzeGames(allGames, new StatsGameAnalysis()); | ||
this.setState({ stats }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
"ban-keywords", | ||
"check-format" | ||
] | ||
} | ||
}, | ||
"forin": false | ||
} | ||
} |