export const TICK_RATE_HZ = 120 export const SAMPLE_RATE_HZ = 40 export const STONES_PER_TEAM = 8 export const ENDS = 10 export const SHEET_WIDTH = 5.0 export const SHEET_LENGTH = 45.0 export const HOUSE_CENTER = { x: 0, y: 38.5 } export const HOUSE_RADIUS = 1.83 export const BUTTON_RADIUS = 0.1524 export const FOUR_FT_RADIUS = 0.6096 export const EIGHT_FT_RADIUS = 1.2192 export const TWELVE_FT_RADIUS = 1.8288 export const HOG_LINE_Y = 21.0 export const BACK_LINE_Y = 42.0 export const HACK_Y = 2.0 export const STONE_RADIUS = 0.15 export const MIN_SPEED = 3.0 export const MAX_SPEED = 6.45 export interface StoneState { id: number team: Team x: number y: number rotation: number active: boolean } export interface ClientThrowMessage { type: 'throw' broom_x: number broom_y: number weight: number curl: number friction: number } export interface ServerJoinedMessage { type: 'joined' room: string team: Team } export interface ServerWaitingMessage { type: 'waiting' message: string } export interface ServerGameStateMessage { type: 'game_state' end: number scores: number[] hammer: Team turn_team: Team stones: StoneState[] phase: Phase } export interface ServerTrajectoryMessage { type: 'trajectory' path: [number, number, number][] } export interface ServerEndScoredMessage { type: 'end_scored' end: number points: number scoring_team?: Team } export interface ServerGameOverMessage { type: 'game_over' scores: number[] winner: Team | null } export interface ServerErrorMessage { type: 'error' message: string } export type ServerMessageTyped = | ServerJoinedMessage | ServerWaitingMessage | ServerGameStateMessage | ServerTrajectoryMessage | ServerEndScoredMessage | ServerGameOverMessage | ServerErrorMessage export type Team = 'red' | 'yellow' export type Phase = 'waiting' | 'playing' | 'simulating' | 'scoring' | 'end_complete' | 'game_complete' export type ServerMessage = ServerMessageTyped export function isTeam(value: unknown): value is Team { return value === 'red' || value === 'yellow' }