games: the ladder gets played, and the rack learns where to stand
Trivia had every Go test passing and had never been in a browser, which this plan's own rule says means nothing. So: play it. The game itself holds up. The clock drains honestly and does not restart on a reload, the multiple compounds, walking pays exactly what the felt quoted, the reveal marks the right answer, and the auto-submit at zero lands as a timeout rather than an illegal move. The next question's answer never crosses the wire. Two bugs only the browser could show: - The spot printed double the stake after every settled game. standing() set spot.amount and *then* poured the chips on, and pour grows the pile from what it is told is already there. The money was always right; the number under the chips was not, which is the one rule the felt is built on. - The house rack sat on top of the multiplier at 390px. Its 5.75rem inset is not a margin, it is the width of blackjack's shoe — so on a phone the rack sits in the middle of the felt. It now shrinks on small screens and pulls into the corner where the corner is empty; data-at says which rack is which, because pulling blackjack's to the edge slides it under the deck. The dev rig seeds its own question bank now (one real OpenTDB batch per difficulty), because a fresh dev database 503s every start otherwise.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
@@ -9,6 +10,10 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"pete/internal/games/trivia"
|
||||
"pete/internal/opentdb"
|
||||
"pete/internal/storage"
|
||||
)
|
||||
|
||||
// TestDevCasino is not a test. It is the casino, running, on a port, with one
|
||||
@@ -30,6 +35,7 @@ func TestDevCasino(t *testing.T) {
|
||||
|
||||
s := newCasino(t)
|
||||
fund(t, 5000)
|
||||
seedTriviaBank(t)
|
||||
|
||||
payload, _ := json.Marshal(SessionUser{
|
||||
Sub: "sub-1", Username: "reala", Name: "Reala",
|
||||
@@ -63,3 +69,43 @@ func TestDevCasino(t *testing.T) {
|
||||
t.Cleanup(func() { _ = srv.Close() })
|
||||
_ = srv.Serve(ln)
|
||||
}
|
||||
|
||||
// seedTriviaBank puts enough questions in the bank to deal a ladder of each
|
||||
// difficulty.
|
||||
//
|
||||
// The rig does not run StartTriviaBank — a dev casino that spends its first two
|
||||
// minutes dripping four hundred questions per difficulty out of a free API is a
|
||||
// dev casino you cannot use. But a fresh database has an empty bank, and an
|
||||
// empty bank means every start 503s, so the rig would be unable to show you the
|
||||
// one game it exists to show you.
|
||||
//
|
||||
// One real batch per difficulty, through the real client: fifty questions is
|
||||
// four ladders' worth, and it means what the browser renders came out of OpenTDB
|
||||
// and through the same decode-and-store path production uses, entities and all.
|
||||
func seedTriviaBank(t *testing.T) {
|
||||
t.Helper()
|
||||
ctx := context.Background()
|
||||
client := opentdb.New()
|
||||
|
||||
for i, tier := range trivia.Tiers {
|
||||
have, err := storage.CountTrivia(tier.Difficulty)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if have >= trivia.Rungs {
|
||||
continue
|
||||
}
|
||||
if i > 0 {
|
||||
time.Sleep(opentdb.Politeness) // the API asks; asking faster earns nothing
|
||||
}
|
||||
qs, err := client.Fetch(ctx, tier.Difficulty, opentdb.Batch)
|
||||
if err != nil {
|
||||
t.Fatalf("seeding the trivia bank (%s): %v", tier.Difficulty, err)
|
||||
}
|
||||
added, err := storage.AddTriviaQuestions(tier.Difficulty, qs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("BANK %-6s %d questions\n", tier.Difficulty, added)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -860,6 +860,26 @@ html[data-phase="night"] {
|
||||
.pete-rack span[data-chip="100"] { --chip: #2b2118; }
|
||||
.pete-rack span[data-chip="500"] { --chip: #b079d6; }
|
||||
|
||||
/* On a phone the rack has to get out of the way. At its desk size it is a
|
||||
147px block sitting 92px in from the edge — a corner on a wide felt, but the
|
||||
middle of the table on a 390px one, where it sat on top of trivia's
|
||||
multiplier. So on a small screen it gets smaller, and where there's nothing
|
||||
in the corner it pulls into the corner.
|
||||
|
||||
Where the rack sits is the one thing that differs per table, which is what
|
||||
data-at says. Unmarked, it's alone in the corner. "shoe" means blackjack,
|
||||
where the 5.75rem inset is not a margin but the width of the shoe it sits
|
||||
beside — pull that one to the edge and it slides under the deck. "rail" means
|
||||
solitaire, where the rack isn't on the felt at all (position: static). */
|
||||
@media (max-width: 639px) {
|
||||
.pete-rack:not([data-at="rail"]) {
|
||||
gap: 0.25rem;
|
||||
padding: 0.35rem 0.4rem 0.3rem;
|
||||
}
|
||||
.pete-rack:not([data-at="rail"]) span { width: 1.15rem; }
|
||||
.pete-rack:not([data-at]) { right: 1rem; }
|
||||
}
|
||||
|
||||
/* The burst. A natural gets confetti; nothing else in the room does, which is
|
||||
what keeps it worth something. */
|
||||
.pete-spark {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -278,7 +278,10 @@
|
||||
}
|
||||
bet = amount;
|
||||
showBet();
|
||||
spot.amount = amount;
|
||||
// pour grows the pile from whatever is on the spot, and settle has just swept
|
||||
// it clean — so it must not be told the chips are already there. Setting the
|
||||
// amount first counted the standing bet twice, and the spot printed 400 under
|
||||
// a 200 stake.
|
||||
return spot.pour(purseEl, amount);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
always travelling between one of those and the spot in front of you. -->
|
||||
<section class="pete-felt relative overflow-hidden rounded-3xl p-6 sm:p-10 shadow-pete-lg border-2 border-[color:var(--ink)]/10">
|
||||
|
||||
<div class="pete-rack" data-house aria-hidden="true">
|
||||
<div class="pete-rack" data-at="shoe" data-house aria-hidden="true">
|
||||
<span data-chip="500" style="--stack: 5"></span>
|
||||
<span data-chip="100" style="--stack: 7"></span>
|
||||
<span data-chip="25" style="--stack: 4"></span>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<!-- The meter and the ladder. This row is the only one level with the house
|
||||
rack in the corner, so it is the only one that has to keep clear of it. -->
|
||||
<div class="flex flex-wrap items-center gap-x-4 gap-y-3 pr-24 sm:pr-28">
|
||||
<div class="flex flex-wrap items-center gap-x-4 gap-y-3 pr-32 sm:pr-28">
|
||||
<div class="pete-meter" data-meter>
|
||||
<span class="pete-meter-label">Worth</span>
|
||||
<span data-multiple class="pete-meter-value">—</span>
|
||||
|
||||
Reference in New Issue
Block a user