mirror of
https://github.com/ghndrx/shellmate.git
synced 2026-02-10 06:45:02 +00:00
Clean Gambit-style board - simple ANSI, no Rich markup
- Simple box drawing characters - Direct ANSI escape codes (no Rich markup issues) - Dots on dark squares, empty on light - White pieces bright white, black pieces yellow - Clean single-line cells like Gambit
This commit is contained in:
@@ -275,139 +275,108 @@ async def run_chess_game(process, session: TerminalSession, username: str, oppon
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Stockfish not available: {e}")
|
logger.warning(f"Stockfish not available: {e}")
|
||||||
|
|
||||||
# Unicode pieces - large and visible
|
# Unicode pieces
|
||||||
PIECES = {
|
PIECES = {
|
||||||
'K': '♔', 'Q': '♕', 'R': '♖', 'B': '♗', 'N': '♘', 'P': '♙',
|
'K': '♔', 'Q': '♕', 'R': '♖', 'B': '♗', 'N': '♘', 'P': '♙',
|
||||||
'k': '♚', 'q': '♛', 'r': '♜', 'b': '♝', 'n': '♞', 'p': '♟',
|
'k': '♚', 'q': '♛', 'r': '♜', 'b': '♝', 'n': '♞', 'p': '♟',
|
||||||
}
|
}
|
||||||
|
|
||||||
def render_board():
|
def render_board():
|
||||||
|
"""Clean Gambit-style board rendering - simple and elegant."""
|
||||||
nonlocal status_msg
|
nonlocal status_msg
|
||||||
session._update_size()
|
session._update_size()
|
||||||
session.clear()
|
session.clear()
|
||||||
|
|
||||||
writer = ProcessWriter(session)
|
|
||||||
console = Console(file=writer, width=session.width, height=session.height,
|
|
||||||
force_terminal=True, color_system="truecolor")
|
|
||||||
|
|
||||||
# Decide on board size based on terminal
|
|
||||||
use_big = session.width >= 70 and session.height >= 35
|
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
|
|
||||||
# Title
|
# Title
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append("[bold bright_green]♔ S H E L L M A T E C H E S S ♔[/bold bright_green]")
|
lines.append("\033[1;32m♔ S H E L L M A T E ♔\033[0m")
|
||||||
lines.append("[bright_blue]━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[/bright_blue]")
|
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
if use_big:
|
# Column labels
|
||||||
# BIG BEAUTIFUL BOARD (5-char wide cells, 2 lines tall)
|
lines.append(" A B C D E F G H")
|
||||||
col_labels = " " + "".join(f" {c} " for c in "abcdefgh")
|
|
||||||
lines.append(f"[bold cyan]{col_labels}[/bold cyan]")
|
|
||||||
lines.append("[bright_blue] ╔══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╗[/bright_blue]")
|
|
||||||
|
|
||||||
for rank in range(7, -1, -1):
|
|
||||||
top_row = f"[bold cyan] {rank + 1} [/bold cyan][bright_blue]║[/bright_blue]"
|
|
||||||
bot_row = f" [bright_blue]║[/bright_blue]"
|
|
||||||
|
|
||||||
for file in range(8):
|
|
||||||
square = chess.square(file, rank)
|
|
||||||
piece = board.piece_at(square)
|
|
||||||
is_light = (rank + file) % 2 == 1
|
|
||||||
bg = "on grey30" if is_light else "on grey15"
|
|
||||||
|
|
||||||
if piece:
|
|
||||||
char = PIECES.get(piece.symbol(), '?')
|
|
||||||
fg = "bold white" if piece.color == chess.WHITE else "bold bright_yellow"
|
|
||||||
top_row += f"[{fg} {bg}] {char} [/{fg} {bg}]"
|
|
||||||
bot_row += f"[{bg}] [/{bg}]"
|
|
||||||
else:
|
|
||||||
top_row += f"[{bg}] [/{bg}]"
|
|
||||||
bot_row += f"[{bg}] [/{bg}]"
|
|
||||||
|
|
||||||
if file < 7:
|
|
||||||
top_row += "[bright_blue]│[/bright_blue]"
|
|
||||||
bot_row += "[bright_blue]│[/bright_blue]"
|
|
||||||
|
|
||||||
top_row += f"[bright_blue]║[/bright_blue][bold cyan] {rank + 1}[/bold cyan]"
|
|
||||||
bot_row += "[bright_blue]║[/bright_blue]"
|
|
||||||
lines.append(top_row)
|
|
||||||
lines.append(bot_row)
|
|
||||||
|
|
||||||
if rank > 0:
|
|
||||||
lines.append("[bright_blue] ╟──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────╢[/bright_blue]")
|
|
||||||
|
|
||||||
lines.append("[bright_blue] ╚══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╝[/bright_blue]")
|
|
||||||
lines.append(f"[bold cyan]{col_labels}[/bold cyan]")
|
|
||||||
else:
|
|
||||||
# COMPACT BOARD (4-char wide cells)
|
|
||||||
col_labels = " " + "".join(f" {c} " for c in "abcdefgh")
|
|
||||||
lines.append(f"[bold cyan]{col_labels}[/bold cyan]")
|
|
||||||
lines.append("[bright_blue] ╔════╤════╤════╤════╤════╤════╤════╤════╗[/bright_blue]")
|
|
||||||
|
|
||||||
for rank in range(7, -1, -1):
|
|
||||||
row = f"[bold cyan] {rank + 1} [/bold cyan][bright_blue]║[/bright_blue]"
|
|
||||||
|
|
||||||
for file in range(8):
|
|
||||||
square = chess.square(file, rank)
|
|
||||||
piece = board.piece_at(square)
|
|
||||||
is_light = (rank + file) % 2 == 1
|
|
||||||
bg = "on grey30" if is_light else "on grey15"
|
|
||||||
|
|
||||||
if piece:
|
|
||||||
char = PIECES.get(piece.symbol(), '?')
|
|
||||||
fg = "bold white" if piece.color == chess.WHITE else "bold bright_yellow"
|
|
||||||
row += f"[{fg} {bg}] {char} [/{fg} {bg}]"
|
|
||||||
else:
|
|
||||||
row += f"[{bg}] [/{bg}]"
|
|
||||||
|
|
||||||
if file < 7:
|
|
||||||
row += "[bright_blue]│[/bright_blue]"
|
|
||||||
|
|
||||||
row += f"[bright_blue]║[/bright_blue][bold cyan] {rank + 1}[/bold cyan]"
|
|
||||||
lines.append(row)
|
|
||||||
|
|
||||||
if rank > 0:
|
|
||||||
lines.append("[bright_blue] ╟────┼────┼────┼────┼────┼────┼────┼────╢[/bright_blue]")
|
|
||||||
|
|
||||||
lines.append("[bright_blue] ╚════╧════╧════╧════╧════╧════╧════╧════╝[/bright_blue]")
|
|
||||||
lines.append(f"[bold cyan]{col_labels}[/bold cyan]")
|
|
||||||
|
|
||||||
|
# Top border
|
||||||
|
lines.append(" ┌───┬───┬───┬───┬───┬───┬───┬───┐")
|
||||||
|
|
||||||
|
for rank in range(7, -1, -1):
|
||||||
|
row = f" \033[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
|
||||||
|
|
||||||
|
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 │"
|
||||||
|
else:
|
||||||
|
row += f" \033[1;33m{char}\033[0m │"
|
||||||
|
else:
|
||||||
|
# Dot for dark squares, space for light
|
||||||
|
if is_light:
|
||||||
|
row += " │"
|
||||||
|
else:
|
||||||
|
row += " \033[90m·\033[0m │"
|
||||||
|
|
||||||
|
row += f" \033[36m{rank + 1}\033[0m"
|
||||||
|
lines.append(row)
|
||||||
|
|
||||||
|
# Row separator
|
||||||
|
if rank > 0:
|
||||||
|
lines.append(" ├───┼───┼───┼───┼───┼───┼───┼───┤")
|
||||||
|
|
||||||
|
# Bottom border
|
||||||
|
lines.append(" └───┴───┴───┴───┴───┴───┴───┴───┘")
|
||||||
|
|
||||||
|
# Column labels again
|
||||||
|
lines.append(" A B C D E F G H")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
|
|
||||||
# Status
|
# Status
|
||||||
turn = "[bold white]White ♔[/bold white]" if board.turn == chess.WHITE else "[bold bright_yellow]Black ♚[/bold bright_yellow]"
|
if board.turn == chess.WHITE:
|
||||||
lines.append(f" {turn} to move")
|
lines.append(" \033[1;37mWhite ♔\033[0m to move")
|
||||||
|
else:
|
||||||
|
lines.append(" \033[1;33mBlack ♚\033[0m to move")
|
||||||
|
|
||||||
if board.is_check():
|
if board.is_check():
|
||||||
lines.append(" [bold red]⚠ CHECK! ⚠[/bold red]")
|
lines.append(" \033[1;31m⚠ CHECK! ⚠\033[0m")
|
||||||
|
|
||||||
if move_history:
|
if move_history:
|
||||||
last_moves = move_history[-5:]
|
last_moves = move_history[-5:]
|
||||||
lines.append(f" [dim]Recent: {' '.join(last_moves)}[/dim]")
|
lines.append(f" \033[90mRecent: {' '.join(last_moves)}\033[0m")
|
||||||
|
|
||||||
if status_msg:
|
if status_msg:
|
||||||
lines.append(f" [bright_yellow]{status_msg}[/bright_yellow]")
|
lines.append(f" \033[33m{status_msg}\033[0m")
|
||||||
status_msg = ""
|
status_msg = ""
|
||||||
|
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append(" [green]Enter move (e.g. e2e4)[/green] [dim]│[/dim] [red]q[/red]uit [dim]│[/dim] [red]r[/red]esign")
|
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("")
|
lines.append("")
|
||||||
|
|
||||||
# Vertical center
|
# Calculate centering
|
||||||
total_lines = len(lines)
|
board_width = 37 # Width of the board
|
||||||
top_pad = max(0, (session.height - total_lines - 2) // 2)
|
total_height = len(lines)
|
||||||
|
|
||||||
|
# Horizontal padding
|
||||||
|
left_pad = max(0, (session.width - board_width) // 2)
|
||||||
|
pad = " " * left_pad
|
||||||
|
|
||||||
|
# Vertical centering
|
||||||
|
top_pad = max(0, (session.height - total_height) // 2)
|
||||||
|
|
||||||
|
# Output
|
||||||
for _ in range(top_pad):
|
for _ in range(top_pad):
|
||||||
console.print()
|
session.write("\r\n")
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
console.print(Align.center(Text.from_markup(line)))
|
session.write(pad + line + "\r\n")
|
||||||
|
|
||||||
# Move prompt
|
# Move prompt
|
||||||
pad = " " * max(0, (session.width - 20) // 2)
|
session.write(pad + " \033[36mMove: \033[0m")
|
||||||
session.write(f"{pad}[cyan]Move: [/cyan]")
|
|
||||||
session.show_cursor()
|
session.show_cursor()
|
||||||
|
|
||||||
render_board()
|
render_board()
|
||||||
|
|||||||
Reference in New Issue
Block a user