From 61fb8e950e0b30ef0ee65aa5882545e5292d9112 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Tue, 29 Sep 2026 14:35:57 -0400 Subject: fix: roulette table box drawing characters --- internal/game/render_roulette.go | 88 +++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 19 deletions(-) (limited to 'internal/game/render_roulette.go') diff --git a/internal/game/render_roulette.go b/internal/game/render_roulette.go index 95e91ff..4861939 100644 --- a/internal/game/render_roulette.go +++ b/internal/game/render_roulette.go @@ -80,26 +80,56 @@ func renderRouletteLayout(double bool, mode string, unicode bool) string { title = "ROULETTE / DOUBLE ZERO" } lines = append(lines, rouletteInk(mode, title)) - // Five columns for the zero lane, twelve four-column pockets. Four - // adjacent pockets line up exactly over each 19-column dozen. + // 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. + const rowCell = 6 gridRule := func(left, joint, right string) string { - return left + strings.Repeat(b.h, 5) + joint + strings.Join(repeatRoulette(strings.Repeat(b.h, 4), 12), joint) + right + return left + strings.Repeat(b.h, 5) + joint + + strings.Join(repeatRoulette(strings.Repeat(b.h, 4), 12), joint) + + joint + strings.Repeat(b.h, rowCell) + right + } + // The numbered grid's bottom edge closes the row-bet cells and carries the + // dozen-row dividers as downward stubs: crosses at the inner dozen + // boundaries and where the grid meets the row lane, an upward tee + // everywhere else. + gridBottom := func() string { + var sb strings.Builder + sb.WriteString(b.bl) + for col := 6; col <= 66; col += 5 { + if col == 6 { + sb.WriteString(strings.Repeat(b.h, 5)) + } else { + sb.WriteString(strings.Repeat(b.h, 4)) + } + switch col { + case 6, 26, 46, 66: + sb.WriteString(b.cross) + default: + sb.WriteString(b.teeBottom) + } + } + sb.WriteString(strings.Repeat(b.h, rowCell)) + sb.WriteString(b.br) + return sb.String() } lines = append(lines, rouletteInk(mode, gridRule(b.tl, b.teeTop, b.tr))) for row := 3; row >= 1; row-- { - zero, zeroBg := "", -1 + zero := "" switch { case double && row == 3: - zero, zeroBg = "0", 2 + zero = "0" case double && row == 1: - zero, zeroBg = "00", 2 + zero = "00" case !double && row == 2: - zero, zeroBg = "0", 2 + zero = "0" } - if zeroBg == 2 && (mode == "none" || mode == "") { + if mode == "none" || mode == "" { zero += "G" } - line := rouletteInk(mode, b.v) + roulettePaint(mode, rouletteCenter(zero, 5), zeroBg) + rouletteInk(mode, b.v) + // The 0/00 lane is one green rectangle, so its blank cells above and + // below the zeros are painted to match the pockets beside them. + line := rouletteInk(mode, b.v) + roulettePaint(mode, rouletteCenter(zero, 5), 2) + rouletteInk(mode, b.v) for n := row; n <= 36; n += 3 { pocket := strconv.Itoa(n) bg, name := roulettePocketColor(pocket) @@ -108,22 +138,32 @@ func renderRouletteLayout(double bool, mode string, unicode bool) string { } line += roulettePaint(mode, rouletteCenter(pocket, 4), bg) + rouletteInk(mode, b.v) } - line += rouletteInk(mode, fmt.Sprintf(" column%d", row)) + // row1 is the top numbered line (3,6,...36) and row3 the bottom. + line += rouletteInk(mode, rouletteCenter(fmt.Sprintf("row%d", 4-row), rowCell)+b.v) lines = append(lines, line) if row > 1 { - // The zero lane spans the grid height; only its labeled cell is green. - line = rouletteInk(mode, b.v+" "+b.teeLeft+strings.Join(repeatRoulette(strings.Repeat(b.h, 4), 12), b.cross)+b.teeRight) + line = rouletteInk(mode, b.v+" "+b.teeLeft+ + strings.Join(repeatRoulette(strings.Repeat(b.h, 4), 12), b.cross)+ + b.cross+strings.Repeat(b.h, rowCell)+b.teeRight) lines = append(lines, line) } } - lines = append(lines, rouletteInk(mode, gridRule(b.bl, b.teeBottom, b.br))) - // Outside bets share the exact 60-column numbered-grid footprint. + lines = append(lines, rouletteInk(mode, gridBottom())) + // Outside bets share the exact 60-column numbered-grid footprint. The + // dozen row gets its own bottom rule so the 1to12/13to24/25to36 boxes are + // closed and do not run into the even-money spaces below them. indent := " " dozen := indent + rouletteInk(mode, b.v) - for i := 1; i <= 3; i++ { - dozen += rouletteInk(mode, rouletteCenter(fmt.Sprintf("dozen%d", i), 19)) + rouletteInk(mode, b.v) + for _, label := range []string{"1to12", "13to24", "25to36"} { + dozen += rouletteInk(mode, rouletteCenter(label, 19)) + rouletteInk(mode, b.v) } lines = append(lines, dozen) + dozenBottom := indent + b.teeLeft + dozenJoints := []string{b.teeTop, b.cross, b.teeTop, b.cross, b.teeTop, b.teeRight} + for i := 0; i < 6; i++ { + dozenBottom += strings.Repeat(b.h, 9) + dozenJoints[i] + } + lines = append(lines, rouletteInk(mode, dozenBottom)) line := indent + rouletteInk(mode, b.v) for _, bet := range []string{"low", "even", "red", "black", "odd", "high"} { bg := -1 @@ -135,7 +175,17 @@ func renderRouletteLayout(double bool, mode string, unicode bool) string { } line += roulettePaint(mode, rouletteCenter(bet, 9), bg) + rouletteInk(mode, b.v) } - lines = append(lines, line, rouletteInk(mode, indent+b.bl+strings.Repeat(b.h, 59)+b.br)) + // The bottom rule tees upward under each outside-bet divider so the + // vertical lines below the dozens meet the table's bottom edge. + bottom := indent + b.bl + for i := 0; i < 6; i++ { + bottom += strings.Repeat(b.h, 9) + if i < 5 { + bottom += b.teeBottom + } + } + bottom += b.br + lines = append(lines, line, rouletteInk(mode, bottom)) if mode == "none" || mode == "" { lines = append(lines, "R = red, B = black, G = green") } @@ -317,9 +367,9 @@ 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 { - text := "Numbers 35:1 | Dozens / columns 2:1 | Other outside bets 1:1\n" + + text := "Numbers 35:1 | 1to12 / 13to24 / 25to36 and rows 2:1 | Other outside bets 1:1\n" + "Low: 1-18 | High: 19-36 | Zero loses all outside bets\n" + - "bet 10 on 17 / bet 10 on red / bet 10 on dozen2" + "bet 10 on 17 / bet 10 on red / bet 10 on 13to24" return g.colorize(sess, "casino_action", text) } -- cgit v1.2.3