[], '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))
You @if (($game['server'] ?? 1) === 0 && $phase !== 'over') @endif {{ $game['score'][0] }} @for ($i = 0; $i < 2; $i++) $i < $game['games'][0]])>@endfor
@if (($game['server'] ?? 0) === 1 && $phase !== 'over') @endif Computer · {{ self::LEVELS[$level] }} {{ $game['score'][1] }} @for ($i = 0; $i < 2; $i++) $i < $game['games'][1]])>@endfor
@endif @if ($line = $this->message())

{{ $line }}

@endif @if ($phase === 'idle' || $phase === 'over')
@if ($phase === 'over' && $result) @php($won = $result['games'][0] > $result['games'][1])

$won])>{{ $won ? 'You win' : 'Computer wins' }} {{ max($result['games']) }}–{{ min($result['games']) }}

Points {{ $result['points'][0] }}–{{ $result['points'][1] }} on {{ self::LEVELS[$level] }}

@else

RALLY

Table tennis against the computer. Games to 11, best of three.

@endif
@foreach (self::LEVELS as $i => $label) @endforeach
@if ($error)

{{ $error }}

@endif

Move 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'])

Recent matches

    @foreach ($board['recent'] as $m)
  • $m['won']])>{{ $m['won'] ? 'W' : 'L' }} {{ $m['name'] }} {{ $m['games'] }} · {{ self::LEVELS[$m['level']] }}
  • @endforeach

Most wins

    @foreach ($board['best'] as $b)
  1. {{ $b['name'] }} {{ $b['wins'] }} of {{ $b['played'] }}@if ($b['hard']) · {{ $b['hard'] }} on Hard @endif
  2. @endforeach
@endif
@endif