Large terminal-filling board with background shading

- Big board (7-char cells, 3 rows tall) for 80x40+ terminals
- Compact board (5-char cells, 2 rows tall) for smaller
- Dark square shading with ANSI 256-color backgrounds
- Better visual hierarchy and spacing
- Simpler prompt (>)
This commit is contained in:
Greg Hendrickson
2026-01-27 20:35:31 +00:00
parent 2ffb72a328
commit 38c83fbe51

View File

@@ -282,83 +282,156 @@ async def run_chess_game(process, session: TerminalSession, username: str, oppon
}
def render_board():
"""Clean Gambit-style board rendering - simple and elegant."""
"""Large, terminal-filling chess board."""
nonlocal status_msg
session._update_size()
session.clear()
# Determine cell size based on terminal
# Big board for terminals 80+ wide, 40+ tall
big = session.width >= 80 and session.height >= 40
lines = []
# Title
lines.append("")
lines.append("\033[1;32m♔ S H E L L M A T E ♔\033[0m")
if big:
lines.append("\033[1;32m♔ S H E L L M A T E ♔\033[0m")
lines.append("\033[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m")
else:
lines.append("\033[1;32m♔ SHELLMATE ♔\033[0m")
lines.append("")
# Column labels
lines.append(" A B C D E F G H")
# Top border
lines.append(" ┌───┬───┬───┬───┬───┬───┬───┬───┐")
for rank in range(7, -1, -1):
row = f" \033[36m{rank + 1}\033[0m │"
if big:
# BIG BOARD - 7 char wide cells, 3 rows tall
cell_w = 7
lines.append(" A B C D E F G H")
lines.append(" ╔═══════╤═══════╤═══════╤═══════╤═══════╤═══════╤═══════╤═══════╗")
for file in range(8):
square = chess.square(file, rank)
piece = board.piece_at(square)
is_light = (rank + file) % 2 == 1
for rank in range(7, -1, -1):
# Top padding row
pad_row = ""
for file in range(8):
is_light = (rank + file) % 2 == 1
fill = " " if is_light else "\033[48;5;236m \033[0m"
pad_row += fill
if file < 7:
pad_row += ""
pad_row += ""
lines.append(pad_row)
if piece:
char = PIECES.get(piece.symbol(), '?')
# White pieces bright, black pieces yellow
if piece.color == chess.WHITE:
row += f" \033[1;37m{char}\033[0m │"
# Piece row
piece_row = f" \033[1;36m{rank + 1}\033[0m ║"
for file in range(8):
square = chess.square(file, rank)
piece = board.piece_at(square)
is_light = (rank + file) % 2 == 1
bg = "" if is_light else "\033[48;5;236m"
bg_end = "" if is_light else "\033[0m"
if piece:
char = PIECES.get(piece.symbol(), '?')
if piece.color == chess.WHITE:
piece_row += f"{bg} \033[1;97m{char}\033[0m{bg} {bg_end}"
else:
piece_row += f"{bg} \033[1;33m{char}\033[0m{bg} {bg_end}"
else:
row += f" \033[1;33m{char}\033[0m │"
else:
# Dot for dark squares, space for light
if is_light:
row += " "
piece_row += f"{bg} {bg_end}"
if file < 7:
piece_row += ""
piece_row += f" \033[1;36m{rank + 1}\033[0m"
lines.append(piece_row)
# Bottom padding row
pad_row = ""
for file in range(8):
is_light = (rank + file) % 2 == 1
fill = " " if is_light else "\033[48;5;236m \033[0m"
pad_row += fill
if file < 7:
pad_row += ""
pad_row += ""
lines.append(pad_row)
# Row separator
if rank > 0:
lines.append(" ╟───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────╢")
lines.append(" ╚═══════╧═══════╧═══════╧═══════╧═══════╧═══════╧═══════╧═══════╝")
lines.append(" A B C D E F G H")
board_width = 73
else:
# COMPACT BOARD - 5 char cells, 2 rows tall
lines.append(" A B C D E F G H")
lines.append(" ╔═════╤═════╤═════╤═════╤═════╤═════╤═════╤═════╗")
for rank in range(7, -1, -1):
# Piece row
piece_row = f" \033[1;36m{rank + 1}\033[0m ║"
for file in range(8):
square = chess.square(file, rank)
piece = board.piece_at(square)
is_light = (rank + file) % 2 == 1
bg = "" if is_light else "\033[48;5;236m"
bg_end = "" if is_light else "\033[0m"
if piece:
char = PIECES.get(piece.symbol(), '?')
if piece.color == chess.WHITE:
piece_row += f"{bg} \033[1;97m{char}\033[0m{bg} {bg_end}"
else:
piece_row += f"{bg} \033[1;33m{char}\033[0m{bg} {bg_end}"
else:
row += " \033[90m·\033[0m │"
piece_row += f"{bg} {bg_end}"
if file < 7:
piece_row += ""
piece_row += f"\033[1;36m{rank + 1}\033[0m"
lines.append(piece_row)
# Padding row
pad_row = ""
for file in range(8):
is_light = (rank + file) % 2 == 1
fill = " " if is_light else "\033[48;5;236m \033[0m"
pad_row += fill
if file < 7:
pad_row += ""
pad_row += ""
lines.append(pad_row)
if rank > 0:
lines.append(" ╟─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────╢")
row += f" \033[36m{rank + 1}\033[0m"
lines.append(row)
# Row separator
if rank > 0:
lines.append(" ├───┼───┼───┼───┼───┼───┼───┼───┤")
lines.append(" ╚═════╧═════╧═════╧═════╧═════╧═════╧═════╧═════╝")
lines.append(" A B C D E F G H")
board_width = 57
# Bottom border
lines.append(" └───┴───┴───┴───┴───┴───┴───┴───┘")
# Column labels again
lines.append(" A B C D E F G H")
lines.append("")
# Status
if board.turn == chess.WHITE:
lines.append(" \033[1;37mWhite ♔\033[0m to move")
lines.append(" \033[1;97mWhite ♔\033[0m to move")
else:
lines.append(" \033[1;33mBlack ♚\033[0m to move")
lines.append(" \033[1;33mBlack ♚\033[0m to move")
if board.is_check():
lines.append(" \033[1;31m⚠ CHECK! ⚠\033[0m")
lines.append(" \033[1;31m⚠ CHECK! ⚠\033[0m")
if move_history:
last_moves = move_history[-5:]
lines.append(f" \033[90mRecent: {' '.join(last_moves)}\033[0m")
lines.append(f" \033[90mRecent: {' '.join(last_moves)}\033[0m")
if status_msg:
lines.append(f" \033[33m{status_msg}\033[0m")
lines.append(f" \033[33m{status_msg}\033[0m")
status_msg = ""
lines.append("")
lines.append(" \033[32mMove:\033[0m e2e4 \033[90m│\033[0m \033[31mq\033[0muit \033[90m│\033[0m \033[31mr\033[0mesign")
lines.append(" \033[32mType move\033[0m (e.g. e2e4) \033[31mq\033[0m = quit \033[31mr\033[0m = resign")
lines.append("")
# Calculate centering
board_width = 37 # Width of the board
total_height = len(lines)
# Horizontal padding
@@ -376,7 +449,7 @@ async def run_chess_game(process, session: TerminalSession, username: str, oppon
session.write(pad + line + "\r\n")
# Move prompt
session.write(pad + " \033[36mMove: \033[0m")
session.write(pad + " \033[36m> \033[0m")
session.show_cursor()
render_board()