Skip to content

Commit

Permalink
feat(Current): Display player handicap
Browse files Browse the repository at this point in the history
  • Loading branch information
PrettyCoffee committed Oct 16, 2024
1 parent a56dfe0 commit dfd4f5a
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 15 deletions.
27 changes: 25 additions & 2 deletions src/app/routes/current/Current.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Dispatch, useMemo, useState } from "react"

import { AlertTriangle } from "lucide-react"
import { AlertTriangle, ChevronsDown } from "lucide-react"

import { TitleTooltip } from "~/components/feedback/TitleTooltip"
import { Tooltip } from "~/components/feedback/Tooltip"
import { InputLabel } from "~/components/inputs/InputLabel"
import { Textarea } from "~/components/inputs/Textarea"
import { Icon } from "~/components/primitives/Icon"
import { Text } from "~/components/primitives/Text"
import { useHandicap } from "~/data/handicap"
import { Player, usePlayerGameStats, usePlayers } from "~/data/players"
import { useRuleset } from "~/data/ruleset"
import { borderColor } from "~/utils/colors"
Expand Down Expand Up @@ -49,6 +52,24 @@ const ErrorHint = ({ errors }: { errors: string[] }) => (
</Tooltip.Root>
)

const Handicap = ({ id }: { id: string }) => {
const handicap = useHandicap()
const isPlayer = handicap.playerId === id
if (!isPlayer || handicap.amount < 0.01) return null

const percentage = (handicap.amount * 100).toFixed(0)
const tooltip = `Player has a handicap of ${percentage}% due to ${handicap.wins} successive wins`

return (
<TitleTooltip asChild title={tooltip} side="bottom">
<Text className="h-full text-red-300" size="xs">
<Icon icon={ChevronsDown} size="xs" color="current" />
{` -${percentage}%`}
</Text>
</TitleTooltip>
)
}

const PlayerGames = ({
id,
color,
Expand Down Expand Up @@ -89,7 +110,9 @@ const PlayerGames = ({
return (
<div key={id} className="col-span-1">
<div className="flex items-center gap-2 px-3">
<InputLabel htmlFor={id}>{name}</InputLabel>
<InputLabel htmlFor={id}>
{name} <Handicap id={id} />
</InputLabel>
<div className="flex-1" />
<Counter current={amountOfGames} limit={rules.gamesPerPerson} />
{errors.length > 0 && <ErrorHint errors={errors} />}
Expand Down
22 changes: 12 additions & 10 deletions src/app/routes/spinner/useSpinner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef, useState } from "react"

import clickSound from "~/assets/click-enhanced.mp3"
import { audioSettingsAtom } from "~/data/audioSettings"
import { useHandicap } from "~/data/handicap"
import { Handicap, useHandicap } from "~/data/handicap"
import { Player } from "~/data/players"
import { resetIdle } from "~/hooks/useIdle"
import { randomBetween, sum } from "~/utils/number"
Expand All @@ -13,23 +13,25 @@ const playClickSound = () =>

const getWinner = (
games: { player: Player; name: string }[],
handicap: { handicap: number; playerId?: string }
handicap: Handicap
) => {
const values = games.map(({ player }) =>
handicap.playerId === player.id ? 1 - handicap.handicap : 1
handicap.playerId === player.id ? 1 - handicap.amount : 1
)
const max = sum(values)
const winnerValue = randomBetween(0, max)

const { winner } = values.reduce(
({ sum, winner }, current, index) => {
if (winner >= 0) {
return { sum, winner }
(result, current, index) => {
if (result.winner >= 0) {
return result
}
if (sum + current >= winnerValue) {
return { sum, winner: index }
}
return { sum: sum + current, winner }

const newSum = result.sum + current
if (newSum >= winnerValue) result.winner = index
else result.sum = newSum

return result
},
{ sum: 0, winner: -1 }
)
Expand Down
13 changes: 10 additions & 3 deletions src/data/handicap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,31 @@ export const calcHandicap = (wins: number, max: number, severity = 0.75) => {
return Math.round(result * 100) / 100
}

export interface Handicap {
wins: number
amount: number
playerId?: string
}

const handicapAtom = createSelector(
[gamesSlice, rulesetAtom],
(games, ruleset) => {
(games, ruleset): Handicap => {
const reversedGames = games.reverse()

let wins = 0
let latestPlayer: string | undefined = undefined
while (!latestPlayer || reversedGames[wins]?.playerId === latestPlayer) {
const current = reversedGames[wins]
wins++
if (!current) break
if (!latestPlayer) {
latestPlayer = current.playerId
}
wins++
}

return {
handicap: calcHandicap(wins, ruleset.gamesPerPerson, ruleset.handicap),
wins,
amount: calcHandicap(wins, ruleset.gamesPerPerson, ruleset.handicap),
playerId: latestPlayer,
}
}
Expand Down

0 comments on commit dfd4f5a

Please sign in to comment.