xchess
Version:
Chess Engine
264 lines (211 loc) • 4.74 kB
JavaScript
export {table}
import {File, files} from './file.js'
import {Rank, ranks} from './rank.js'
import {Color} from './color.js'
import {TableWhiteCell, TableBlackCell, TableBorder} from './ansi-style.js'
// styles
const white = TableWhiteCell;
const black = TableBlackCell;
const style = {white, black};
const StyleMap = new Map();
// config
const EOL = '\n';
const INDENT = 4;
const cellPaddingLeft = 3;
const cellPaddingRight = 3;
const indexPadding = 2;
const cellWidth = cellPaddingLeft + cellPaddingRight + 1;
const indexColumnWidth = indexPadding * 2 + 1;
const tableWidth = cellWidth * files.length + indexColumnWidth * 2;
const indexRowSpace = TableBorder(space(tableWidth));
const indexColumnSpace = space(indexColumnWidth);
const cellSpaceLeft = space(cellPaddingLeft);
const cellSpaceRight = space(cellPaddingRight);
const cellSpace = space(cellWidth);
const indexColumnBg = TableBorder(indexColumnSpace);
const indexPaddingSpace = space(indexPadding);
function table(board, opts){
return Table.render(board, opts);
}
function space(length){
return ' '.repeat(length);
}
function cell(value){
return cellSpaceLeft + String(value) + cellSpaceRight;
}
function indexRowCells(files){
const cells = [];
for(const file of files)
cells.push(cell(file.name));
return cells.join('');
}
function indexRow(files){
return TableBorder(indexColumnSpace + indexRowCells(files) + indexColumnSpace);
}
function resizeCell(value){
value = String(value);
if(value.length > cellWidth)
return value.substring(0, cellWidth);
if(value.length < cellWidth)
return value.padEnd(cellWidth);
return value;
}
function styleCell(square, piece, table){
return table.flags.get(square);
}
function formatCell(square, piece, table){
if(piece) return cell(piece);
return cellSpace;
}
class Table {
static render(board, opts){
const table = new this(board, opts);
return table.render();
}
// Config
#board;
#indent;
#format;
#style;
#styleMap;
#color;
#flags;
// Runtime
#text = [];
#cells = [];
constructor(board, {
indent = INDENT,
format = formatCell,
style = styleCell,
styleMap = StyleMap,
color = Color.white,
flags = new Map(),
} = {}){
this.#board = board;
this.#indent = indent;
this.#format = format;
this.#style = style;
this.#styleMap = styleMap;
this.#color = Color.from(color);
this.#flags = flags;
}
// config
get board(){
return this.#board;
}
get indent(){
return this.#indent;
}
get format(){
return this.#format;
}
get style(){
return this.#style;
}
get styleMap(){
return this.#styleMap;
}
get color(){
return this.#color;
}
get flags(){
return this.#flags;
}
get ranks(){
if(this.color === Color.white)
return ranks;
return Rank.reverse();
}
get files(){
if(this.color === Color.white)
return files;
return File.reverse();
}
// Runtime
get text(){
return this.#text;
}
push(value){
this.#cells.push(value);
}
releaseRow(){
this.line(this.#cells.join(''));
this.#cells = [];
}
line(line){
this.#text.push(space(this.indent) + line);
}
release(){
const text = this.text;
this.#text = [];
return text.join(EOL);
}
styleCell(square){
const piece = this.board.get(square);
const styleCell = this.style(square, piece, this);
return this.styleMap.get(styleCell) ?? styleCell ?? style;
}
colorStyleCell(square){
const {color} = square;
const styleCell = this.styleCell(square);
return Object(styleCell)[color] ?? style[color];
}
// Render
indexRow(){
this.line(indexRowSpace);
this.line(indexRow(this.files));
this.line(indexRowSpace);
}
cellSpace(square){
const style = this.colorStyleCell(square);
this.push(style(cellSpace));
}
cellsSpace(rank){
for(const file of this.files)
this.cellSpace(file.squares[rank.y]);
}
indexCell(rank){
this.push(TableBorder(indexPaddingSpace + rank.name + indexPaddingSpace));
}
cell(square){
const piece = this.board.get(square);
const style = this.colorStyleCell(square);
const value = this.format(square, piece, this);
const cell = resizeCell(value);
this.push(style(cell));
}
cells(rank){
for(const file of this.files)
this.cell(file.squares[rank.y]);
}
rowSpace(rank){
this.push(indexColumnBg);
this.cellsSpace(rank);
this.push(indexColumnBg);
this.releaseRow(rank);
}
rowCells(rank){
this.indexCell(rank);
this.cells(rank);
this.indexCell(rank);
this.releaseRow();
}
row(rank){
this.rowSpace(rank);
this.rowCells(rank);
this.rowSpace(rank);
}
rows(){
for(const rank of this.ranks)
this.row(rank);
}
table(){
this.indexRow();
this.rows();
this.indexRow();
}
render(){
this.table();
return this.release();
}
}