Skip to content

Commit

Permalink
Football sportState for drive info
Browse files Browse the repository at this point in the history
  • Loading branch information
dumbmatter committed Nov 5, 2023
1 parent 7707c3c commit ed0b486
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 36 deletions.
5 changes: 5 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ FBGM show field during game
- some minimum height of field, but expand dynamically for long drives
- draw vertical lines for scrimmage and togo
- light mode
- how to update numPlays
- accepted penalties only count as a play if they are added on to the end of the play. this means we sometimes need to decrease numPlays when a penalty gets accepted, but not always
- how does drive tracker handle turnover reversed on penalty?
- need to set sportState.drive to undefined when doing a kickoff at start of half/overtime
- unify logic with kickoffAfterEndOfPeriod

use team colors as foreground/background in UI in some places - already guaranteed contrast bc used for jersey numbers
- box scores
Expand Down
42 changes: 32 additions & 10 deletions src/ui/components/BoxScore.football.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import updateSortBys from "./DataTable/updateSortBys";
import { getSortClassName } from "./DataTable/Header";
import range from "lodash-es/range";
import classNames from "classnames";
import type { SportState } from "../util/processLiveGameEvents.football";

type Quarter = `Q${number}` | "OT";

Expand Down Expand Up @@ -386,20 +387,31 @@ const ScoringSummary = memo(
},
);

const FieldAndDrive = ({ boxScore }: { boxScore: BoxScore }) => {
const t = 0;
const t2 = 1;
const FieldAndDrive = ({
boxScore,
sportState,
}: {
boxScore: BoxScore;
sportState: SportState;
}) => {
const t = sportState.t;
const t2 = t === 0 ? 1 : 0;

// 12 is for 2 endzones and 10 10-yard areas in between
const NUM_SECTIONS = 12;

const DEFAULT_HEIGHT = 200;
console.log(boxScore);

const yards = sportState.scrimmage - sportState.initialScrimmage;

return (
<div className="mb-3">
<div className="d-flex">
LOGO 1st & 10, own 20
<div className="ms-auto">Drive: 5 plays, 62 yards</div>
<div className="d-flex mb-1">
{sportState.text}
<div className="ms-auto">
Drive: {sportState.numPlays} play
{sportState.numPlays === 1 ? "" : "s"}, {yards} yard
{yards === 1 ? "" : "s"}
</div>
</div>
<div
className="d-flex align-items-stretch"
Expand Down Expand Up @@ -471,12 +483,22 @@ const FieldAndDrive = ({ boxScore }: { boxScore: BoxScore }) => {
);
};

const BoxScore = ({ boxScore, Row }: { boxScore: BoxScore; Row: any }) => {
const BoxScore = ({
boxScore,
sportState,
Row,
}: {
boxScore: BoxScore;
sportState: SportState;
Row: any;
}) => {
const liveGameSim = (boxScore as any).won?.name === undefined;

return (
<div className="mb-3">
{liveGameSim ? <FieldAndDrive boxScore={boxScore} /> : undefined}
{liveGameSim ? (
<FieldAndDrive boxScore={boxScore} sportState={sportState} />
) : undefined}

<h2>Scoring Summary</h2>
<ScoringSummary
Expand Down
14 changes: 13 additions & 1 deletion src/ui/util/processLiveGameEvents.baseball.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type {
PlayByPlayEvent,
PlayByPlayEventScore,
} from "../../worker/core/GameSim.baseball/PlayByPlayLogger";
import { DEFAULT_SPORT_STATE } from "../views/LiveGame";
import {
NUM_OUTS_PER_INNING,
POS_NUMBERS_INVERSE,
Expand Down Expand Up @@ -415,6 +414,19 @@ export type SportState = {
pitcherPid: number;
};

export const DEFAULT_SPORT_STATE: SportState = {
bases: [undefined, undefined, undefined] as [
number | undefined,
number | undefined,
number | undefined,
],
outs: 0,
balls: 0,
strikes: 0,
batterPid: -1,
pitcherPid: -1,
};

// Mutates boxScore!!!
const processLiveGameEvents = ({
events,
Expand Down
41 changes: 38 additions & 3 deletions src/ui/util/processLiveGameEvents.football.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
import { getPeriodName } from "../../common";
import { helpers } from "../../ui/util";

export type SportState = {
t: 0 | 1;
numPlays: number;
initialScrimmage: number;
scrimmage: number;
plays: unknown[];
text: string;
};

export const DEFAULT_SPORT_STATE: SportState = {
t: 0,
numPlays: 0,
initialScrimmage: 0,
scrimmage: 0,
plays: [],
text: "",
};

// Mutates boxScore!!!
const processLiveGameEvents = ({
events,
boxScore,
overtimes,
quarters,
sportState,
}: {
events: any[];
boxScore: any;
overtimes: number;
quarters: string[];
sportState: SportState;
}) => {
let stop = false;
let text;
Expand Down Expand Up @@ -86,8 +106,9 @@ const processLiveGameEvents = ({
boxScore.time = e.time;
stop = true;
} else if (e.type === "clock") {
if (typeof e.awaitingKickoff === "number") {
text = `${e.time} - ${boxScore.teams[actualT].abbrev} kicking off`;
let textWithoutTime;
if (e.awaitingKickoff !== undefined) {
textWithoutTime = `${boxScore.teams[actualT].abbrev} kicking off`;
} else {
let fieldPos = "";
if (e.scrimmage === 50) {
Expand All @@ -98,13 +119,26 @@ const processLiveGameEvents = ({
fieldPos = `own ${e.scrimmage}`;
}

text = `${e.time} - ${
textWithoutTime = `${
boxScore.teams[actualT].abbrev
} ball, ${helpers.ordinal(e.down)} & ${e.toGo}, ${fieldPos}`;
}
text = `${e.time} - ${textWithoutTime}`;

boxScore.time = e.time;
stop = true;

if (e.awaitingKickoff !== undefined || sportState.t !== actualT) {
sportState.t = actualT;
sportState.numPlays = 0;
sportState.initialScrimmage = e.scrimmage;
sportState.scrimmage = e.scrimmage;
sportState.plays = [];
sportState.text = textWithoutTime;
} else {
sportState.text = textWithoutTime;
sportState.scrimmage = e.scrimmage;
}
} else if (e.type === "stat") {
// Quarter-by-quarter score
if (e.s === "pts") {
Expand Down Expand Up @@ -148,6 +182,7 @@ const processLiveGameEvents = ({
overtimes,
possessionChange,
quarters,
sportState,
text,
};
};
Expand Down
3 changes: 2 additions & 1 deletion src/ui/util/processLiveGameEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const processLiveGameEvents = ({
overtimes,
quarters,
sportState,
}) as any,
}),
basketball: processLiveGameEventsBasketball({
events,
boxScore,
Expand All @@ -37,6 +37,7 @@ const processLiveGameEvents = ({
boxScore,
overtimes,
quarters,
sportState,
}),
hockey: processLiveGameEventsHockey({
events,
Expand Down
40 changes: 19 additions & 21 deletions src/ui/views/LiveGame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import { helpers, processLiveGameEvents, toWorker } from "../util";
import type { View } from "../../common/types";
import { bySport, getPeriodName, isSport } from "../../common";
import useLocalStorageState from "use-local-storage-state";
import type { SportState } from "../util/processLiveGameEvents.baseball";
import { DEFAULT_SPORT_STATE as DEFAULT_SPORT_STATE_BASEBALL } from "../util/processLiveGameEvents.baseball";
import { DEFAULT_SPORT_STATE as DEFAULT_SPORT_STATE_FOOTBALL } from "../util/processLiveGameEvents.football";
import { HeadlineScore } from "../components/BoxScoreWrapper";

type PlayerRowProps = {
Expand Down Expand Up @@ -92,20 +93,12 @@ const getSeconds = (time: string | undefined) => {
return min * 60 + sec;
};

export const DEFAULT_SPORT_STATE = isSport("baseball")
? ({
bases: [undefined, undefined, undefined] as [
number | undefined,
number | undefined,
number | undefined,
],
outs: 0,
balls: 0,
strikes: 0,
batterPid: -1,
pitcherPid: -1,
} as SportState)
: undefined;
const DEFAULT_SPORT_STATE = bySport<any>({
baseball: DEFAULT_SPORT_STATE_BASEBALL,
basketball: undefined,
football: DEFAULT_SPORT_STATE_FOOTBALL,
hockey: undefined,
});

export const LiveGame = (props: View<"liveGame">) => {
const [paused, setPaused] = useState(false);
Expand Down Expand Up @@ -251,10 +244,13 @@ export const LiveGame = (props: View<"liveGame">) => {

if (events.current && events.current.length > 0) {
if (!pausedRef.current) {
setTimeout(() => {
processToNextPause();
setPlayIndex(prev => prev + 1);
}, 4000 / 1.2 ** speedRef.current);
setTimeout(
() => {
processToNextPause();
setPlayIndex(prev => prev + 1);
},
4000 / 1.2 ** speedRef.current,
);
}
} else {
boxScore.current.time = "0:00";
Expand Down Expand Up @@ -547,7 +543,9 @@ export const LiveGame = (props: View<"liveGame">) => {
label: "Next baserunner",
key: "T",
onClick: () => {
const initialBases = sportState.current?.bases ?? [];
const sportStateBaseball =
sportState.current as typeof DEFAULT_SPORT_STATE_BASEBALL;
const initialBases = sportStateBaseball.bases ?? [];
const initialBaserunners = new Set(
initialBases.filter(pid => pid !== undefined),
);
Expand All @@ -562,7 +560,7 @@ export const LiveGame = (props: View<"liveGame">) => {
numPlays += 1;

// Any new baserunner -> stop
const baserunners = (sportState.current?.bases ?? []).filter(
const baserunners = (sportStateBaseball.bases ?? []).filter(
pid => pid !== undefined,
);
if (baserunners.length === 0) {
Expand Down

0 comments on commit ed0b486

Please sign in to comment.