Commit Graph

4 Commits

Author SHA1 Message Date
prosolis
c62d736223 games: a ladder you climb against the clock 2026-07-14 02:11:09 -07:00
prosolis
5ca056bf20 games: you buy the deck, and win it back a card at a time
Solitaire, Vegas rules — the only shape solitaire has ever had as a
gambling game. You don't win or lose the deal: the stake buys the deck
outright, and every card you get home to a foundation pays a fifty-second
of the tier's multiple back. Cash the board whenever you like and keep
what you've banked, so a board that has gone dead is a decision rather
than a wall. No undo: the stake is spent the moment the deck is bought,
and an undo would be a way to walk a losing board backwards until it wins.

Three deals, and the two dials are the whole difficulty of Klondike.
Patient draws one with unlimited passes and pays 1.4x, so it takes 38
cards home to get square. Vegas draws three, three times round, 2.2x,
square at 24. Cutthroat draws three and gives you one pass, 3.4x, square
at 16 — most of those boards never clear, and you're ahead long before
they would.

internal/games/klondike is the same pure reducer as the other two, and
Pays() is one function for the same reason hangman's is. Two fuzzers hold
the deck together: no sequence of moves can lose or duplicate a card, and
the board stays well-formed. They earned their keep immediately — the
first thing they caught was a recycle that reversed the waste. It flips as
a block, so the card drawn first comes out first, and reversing it would
have dealt a different game on every pass and quietly broken the seed in
the audit log.

The browser never sees the stock or a face-down card, which here is most
of the deck rather than blackjack's one hole card: a column sends how many
cards are under it, never which.

The table re-renders and animates the difference. Blackjack plays back a
script because a hand only ever grows at one end; solitaire moves runs
from anywhere to anywhere and an auto-finish moves eleven cards at once,
so a script of "append this card there" would be a second engine over here
and it would be the one that's wrong. Instead the board on screen is
always exactly the board the server says exists, and each card is played
from where it just was to where it now is. The events supply only what a
diff can't: where a newly-revealed card came from, and what the board is
worth.

The rules are mirrored in JS on purpose, and only to light up the columns
a held card can go to. Being shown where a card goes is the game teaching
you; being told no after you commit is the game scolding you. The server
still decides, and a disagreement snaps the board back to what it says.

Two things came out into the open rather than being copied, which is the
rule this room runs on: casino-cards.js (the deck — faces, pips, the flip)
and PeteFX.spot() (the pile of chips and the number under it, which now
owns the rule that the number is a readout of the pile). Blackjack uses
both.

Not yet driven in a browser.
2026-07-14 01:40:14 -07:00
prosolis
fe2195e85f games: a gallows you can bet on
Hangman, and it plays for chips — which the plan had down as a free game, on
the grounds that trivia has no euro coupling in gogobee. But a free game in a
casino reads as a demo, so it stakes like everything else.

The idea that makes it a casino game rather than hangman with a wager stapled
on: the gallows is the payout meter. A wrong guess draws a limb *and* takes a
tenth off what a win is worth, because those are the same event and showing
them as one is the entire reason to bet on this. Short phrases pay 2.6x (fewer
letters, less to go on), long ones 1.6x — the floor is 1x, so a win never hands
back less than the stake, and the rake still comes out of winnings only.

State.Pays() is the number the felt quotes and the number settle() lands on.
They were briefly two sums, and the table spent an afternoon advertising a
pre-rake payout it didn't honour.

Two things the storage layer had already decided for us, and one it hadn't:
game_live_hands is keyed on the player, so "one game at a time" holds across
games for free (a live hangman 409s a blackjack deal, stake intact). But
table() unmarshalled every live row as a blackjack hand, which does not fail on
a hangman row — it quietly yields an empty hand. It dispatches on the game now.

commit() is the settle path both games share, and casinoRoutes() the one route
list, since the dev rig wires its own mux and a second copy is a copy that stops
including the newest game.

Driven in a browser, win and loss: 200 at 2.34x paid 455 and the bar landed on
it; six wrong took the stake and no more; a reload mid-phrase brought back the
board, the limbs, the multiple, the spent keys and the chips on the spot. The
browser found the two bugs a Go test can't — a lives counter under the house
rack, and a word wrapping early because the rack's clearance was on the whole
column instead of the one row beside it.
2026-07-14 01:19:05 -07:00
prosolis
c69fbb63db games: a blackjack table you can actually sit down at
The engine, the escrow and the wire were all in place; nothing had a browser on
the end of it. This is that end: a lobby, a table, and the five endpoints between
them.

The browser holds no game. It sends intents and gets back a view — the cards it
is entitled to see, and the script of how they arrived, one event per card off
the shoe. The dealer's hole card is not in the payload at all until the reveal,
because a field the client is told to ignore is a field somebody reads in
devtools. The shoe lives in game_live_hands, which also means a redeploy
mid-hand no longer costs a player their stake: the hand is still there when they
come back.

The money is ordered so nothing can be spent twice. The stake leaves the stack in
the same statement that checks it exists, before a card is dealt. Every new hand
is seated with a plain INSERT, so a double-clicked Deal is decided by the primary
key rather than by a read that raced — it loses, gets its chips back, and the
hand in progress is untouched. A double takes its raise up front and hands it
straight back if the engine refuses the move.

Cards are dealt rather than swapped in — they fly out of the shoe and turn over,
which was a requirement and not a flourish. The faces and the chips are still
plain; that's next.
2026-07-13 23:20:42 -07:00