[], 'best' => []]; // ---- On the server ------------------------------------------------------------------- // Loaded on mount, and again whenever anyone's match is recorded. #[Server, Watch, Live('rally')] public static function board(): \Unscripted\Ui\ServerCall { return new \Unscripted\Ui\ServerCall('rally', 'board', func_get_args()); } /** A match played: the game runs in the browser, so this takes its word for the score. */ #[Server] public static function record( #[Validate('required|max:16')] string $name, #[Validate('integer|between:0,2')] int $level, #[Validate('integer|between:0,2')] int $gamesWon, #[Validate('integer|between:0,2')] int $gamesLost, #[Validate('integer|between:0,200')] int $pointsWon, #[Validate('integer|between:0,200')] int $pointsLost, ): \Unscripted\Ui\ServerCall { return new \Unscripted\Ui\ServerCall('rally', 'record', func_get_args()); } // ---- In the browser ------------------------------------------------------------------- public function pick(int $level): void { $this->level = $level; } public function play(): void { if (trim($this->name) === '') { $this->error = 'Pick a name, for the results.'; return; } $this->error = null; $this->result = null; U::window()->rally->play($this->level); } #[On('rally-state')] public function changed(string $json): void { $this->game = json_decode($json, true); } #[On('rally-end')] public function ended(string $json): Generator { ['games' => $games, 'points' => $points] = json_decode($json, true); $this->result = ['games' => $games, 'points' => $points]; yield static::record($this->name, $this->level, $games[0], $games[1], $points[0], $points[1]); } /** The line under the score: whose serve, what just happened. */ private function message(): ?string { $g = $this->game; if ($g === null || in_array($g['phase'], ['idle', 'over'], true)) { return null; } if ($g['paused']) { return 'Paused · click the table to play'; } $to = fn() => $g['last'] === 0 ? 'your point' : 'their point'; return match ($g['phase']) { 'ready' => $g['why'] === 'Let' && $g['server'] === 0 ? 'Let · serve again' : ($g['server'] === 0 ? 'Your serve · click to toss, then swing up through it' : 'Their serve'), 'point' => match ($g['why']) { 'Missed' => $g['last'] === 0 ? 'Winner! Your point' : 'Missed · their point', 'Out' => 'Out · ' . $to(), 'Net' => 'Into the net · ' . $to(), 'Fault' => 'Fault · ' . $to(), default => ucfirst($to()), }, 'game' => ($g['last'] === 0 ? 'You take the game ' : 'They take the game ') . max($g['score']) . '–' . min($g['score']), default => null, }; } }; ?> @php($phase = $game['phase'] ?? 'idle') @if (!in_array($phase, ['idle'], true))
Points {{ $result['points'][0] }}–{{ $result['points'][1] }} on {{ self::LEVELS[$level] }}
@elseTable tennis against the computer. Games to 11, best of three.
@endif @if ($error){{ $error }}
@endifMove the mouse to move your paddle, up toward the net. Get near the ball and your paddle meets it; swing up through it for pace, sideways to place it. Hold the right button for backspin. Esc pauses.
@if ($board['recent'])