Add bot to play against.

This commit is contained in:
Greyson Parrelli
2026-07-23 15:58:12 -04:00
parent 3825dbacec
commit db1a6ef290
23 changed files with 1852 additions and 23 deletions
+25
View File
@@ -1,7 +1,14 @@
import { useState } from 'react'
import { createGame, joinGame } from '../api'
import type { BotDifficulty } from '../api'
import type { Session } from '../types'
const BOT_LEVELS: { value: BotDifficulty; label: string; blurb: string }[] = [
{ value: 'easy', label: '🐣 Easy', blurb: 'Learns you the ropes' },
{ value: 'medium', label: '🐺 Medium', blurb: 'Puts up a fight' },
{ value: 'hard', label: '🦁 Hard', blurb: 'Shows no mercy' },
]
// Home is the create/join screen shown when there's no active session.
export function Home({ onSession }: { onSession: (s: Session) => void }) {
const [name, setName] = useState('')
@@ -50,6 +57,24 @@ export function Home({ onSession }: { onSession: (s: Session) => void }) {
Host a new game
</button>
<div className="home-divider">
<span>or challenge the computer</span>
</div>
<div className="home-bots">
{BOT_LEVELS.map((b) => (
<button
key={b.value}
className="btn btn-secondary"
disabled={busy}
title={b.blurb}
onClick={() => run(() => createGame(name, b.value))}
>
{b.label}
</button>
))}
</div>
<div className="home-divider">
<span>or join a friend</span>
</div>
+8 -2
View File
@@ -93,7 +93,13 @@ export function Table({ session, onLeave }: { session: Session; onLeave: () => v
key={p.id}
className={`topbar-player ${p.seat === view.youSeat ? 'is-you' : ''}`}
>
<span className={`conn-dot ${p.connected ? 'on' : 'off'}`} />
{p.isBot ? (
<span className="bot-dot" title="Computer player">
🤖
</span>
) : (
<span className={`conn-dot ${p.connected ? 'on' : 'off'}`} />
)}
<span className="topbar-name">{p.name}</span>
<span className="chip">🏆 {p.trophies}</span>
{(view.phase === 'shop' || view.phase === 'cleanup') && (
@@ -127,7 +133,7 @@ export function Table({ session, onLeave }: { session: Session; onLeave: () => v
)}
</div>
{opponents.some((p) => !p.connected) && view.phase !== 'lobby' && (
{opponents.some((p) => !p.connected && !p.isBot) && view.phase !== 'lobby' && (
<div className="banner banner-warn">An opponent is disconnected</div>
)}
{error && <div className="toast">{error}</div>}