aboutsummaryrefslogtreecommitdiff
path: root/internal/game/render_roulette.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/render_roulette.go')
-rw-r--r--internal/game/render_roulette.go59
1 files changed, 47 insertions, 12 deletions
diff --git a/internal/game/render_roulette.go b/internal/game/render_roulette.go
index 47ba5c6..159fadc 100644
--- a/internal/game/render_roulette.go
+++ b/internal/game/render_roulette.go
@@ -21,7 +21,7 @@ func renderRouletteSnapshot(s *casino.RouletteSnapshot, mode string, unicode boo
case "result":
return renderRouletteResult(s.Pockets, mode, unicode, size)
default:
- return renderRouletteLayout(s.DoubleZero, mode, unicode)
+ return renderRouletteLayout(s.DoubleZero, s.Racetrack, mode, unicode)
}
}
@@ -76,18 +76,49 @@ func repeatRoulette(s string, n int) []string {
return parts
}
+// renderRouletteRacetrack draws the French call-bet track above the board. The
+// numbers are shown in wheel order for reference; the named bets are what the
+// player places. The Neighbors line explains the one bet that takes a number.
+func renderRouletteRacetrack(mode string, unicode bool) string {
+ b := rouletteBorders(unicode)
+ tl, tr, bl, br := b.tl, b.tr, b.bl, b.br
+ if unicode {
+ tl, tr, bl, br = "╭", "╮", "╰", "╯"
+ }
+ // The panel matches the betting board's 74-column footprint.
+ const width = 72
+ bets := casino.RacetrackBets()
+ rows := make([]string, 0, len(bets)+1)
+ for _, bet := range bets {
+ label := fmt.Sprintf("%s (%d)", bet.Name, bet.Chips)
+ rows = append(rows, fmt.Sprintf("%-22s %s", label, strings.Join(bet.Series, " ")))
+ }
+ rows = append(rows, fmt.Sprintf("%-22s %s", "Neighbors (9)", "neighbors <n>: n plus four each side"))
+ lines := []string{rouletteInk(mode, tl+strings.Repeat(b.h, width)+tr)}
+ for _, row := range rows {
+ row = " " + row
+ if pad := width - color.VisibleLen(row); pad > 0 {
+ row += strings.Repeat(" ", pad)
+ }
+ lines = append(lines, rouletteInk(mode, b.v+row+b.v))
+ }
+ lines = append(lines, rouletteInk(mode, bl+strings.Repeat(b.h, width)+br))
+ return strings.Join(lines, "\n")
+}
+
// renderRouletteLayout draws the betting board. Green is reserved for the
// 0/00 lane: every other cell is red, black, or plain. The odds reminder is
// not part of the board (it is shown by the "table" command), so the board
// stays compact enough to sit in a betting menu.
-func renderRouletteLayout(double bool, mode string, unicode bool) string {
+func renderRouletteLayout(double, racetrack bool, mode string, unicode bool) string {
+ // The call bets are a single-zero layout; never draw the track on an
+ // American board even if a malformed snapshot asks for it.
+ racetrack = racetrack && !double
b := rouletteBorders(unicode)
var lines []string
- title := "ROULETTE / SINGLE ZERO"
- if double {
- title = "ROULETTE / DOUBLE ZERO"
+ if racetrack {
+ lines = append(lines, renderRouletteRacetrack(mode, unicode))
}
- lines = append(lines, rouletteInk(mode, title))
// Five columns for the zero lane, twelve four-column pockets, and a
// six-column 2:1 lane on the right holding the row bets. Four adjacent
// pockets line up exactly over each 19-column dozen.
@@ -434,11 +465,15 @@ func renderRouletteResult(pockets [3]string, mode string, unicode bool, size int
}
// rouletteReminder is the odds/cheat-sheet block, shown only by "table" (and
-// "table rules"), never with the ambient betting board.
-func (g *Game) rouletteReminder(sess *net.Session) string {
+// "table rules"), never with the ambient betting board. Racetrack tables also
+// list their call-bet syntax.
+func (g *Game) rouletteReminder(sess *net.Session, cfg casino.TableConfig) string {
text := "Numbers 35:1 | Split 17:1 | Street/trio 11:1 | Corner 8:1 | Line 5:1 | Dozens & rows 2:1 | Outside 1:1\n" +
- "Combos: split 1 2 | street 1 2 3 | corner 1 2 4 5 | line 1 2 3 4 5 6 | trio 0 1 2 | basket (double zero)\n" +
- "Low: 1-18 | High: 19-36 | Zero loses all outside bets\n" +
+ "Combos: split 1 2 | street 1 2 3 | corner 1 2 4 5 | line 1 2 3 4 5 6 | trio 0 1 2 | basket (double zero)\n"
+ if cfg.Roulette.Racetrack {
+ text += "Racetrack: bet 10 on voisins | tiers | orphelins | zero spiel | neighbors 17\n"
+ }
+ text += "Low: 1-18 | High: 19-36 | Zero loses all outside bets\n" +
"bet 10 on 17 / bet 10 on red / bet 10 on split 1 2"
return g.colorize(sess, "casino_action", text)
}
@@ -446,8 +481,8 @@ func (g *Game) rouletteReminder(sess *net.Session) string {
func (g *Game) renderCasinoRules(sess *net.Session, cfg casino.TableConfig) string {
rules := g.colorize(sess, "casino_action", cfg.RulesText())
if cfg.Game == casino.GameRoulette {
- snap := &casino.RouletteSnapshot{DoubleZero: cfg.Roulette.DoubleZero, Phase: "betting", Wheel: casino.WheelOrder(cfg.Roulette.DoubleZero)}
- rules += "\n" + g.renderCasinoSnapshot(sess, snap) + "\n" + g.rouletteReminder(sess)
+ snap := &casino.RouletteSnapshot{DoubleZero: cfg.Roulette.DoubleZero, Racetrack: cfg.Roulette.Racetrack, Phase: "betting", Wheel: casino.WheelOrder(cfg.Roulette.DoubleZero)}
+ rules += "\n" + g.renderCasinoSnapshot(sess, snap) + "\n" + g.rouletteReminder(sess, cfg)
}
return rules
}