UNPKG

@gobstones/gobstones-lang

Version:
312 lines 9.87 kB
/* eslint-disable no-underscore-dangle */ import fs from 'fs'; class BoardFormat { constructor(formatName, description, extension, fromJboard, toJboard) { this._formatName = formatName; this._description = description; this._extension = extension; this._fromJboard = fromJboard; this._toJboard = toJboard; } get formatName() { return this._formatName; } get description() { return this._description; } get extension() { return this._extension; } get fromJboard() { return this._fromJboard; } get toJboard() { return this._toJboard; } } export function apiboardFromJboard(jboard) { const apiboard = { head: { x: jboard.head[0], y: jboard.head[1] }, width: jboard.width, height: jboard.height, table: [] }; for (let y = 0; y < jboard.height; y++) { const row = []; for (let x = 0; x < jboard.width; x++) { const cellO = jboard.board[x][y]; const cell = { blue: cellO.a > 0 ? cellO.a : undefined, black: cellO.n > 0 ? cellO.n : undefined, red: cellO.r > 0 ? cellO.r : undefined, green: cellO.v > 0 ? cellO.v : undefined }; if (cell.blue === undefined) delete cell.blue; if (cell.black === undefined) delete cell.black; if (cell.red === undefined) delete cell.red; if (cell.green === undefined) delete cell.green; row.push(cell); } apiboard.table.unshift(row); } return apiboard; } export function apiboardToJboard(apiboard) { const jboard = { head: [apiboard.head.x, apiboard.head.y], width: apiboard.width, height: apiboard.height, board: [] }; for (let x = 0; x < jboard.width; x++) { const column = []; for (let y = 0; y < jboard.height; y++) { const cell = apiboard.table[jboard.height - y - 1][x]; const ca = 'blue' in cell ? cell.blue : 0; const cn = 'black' in cell ? cell.black : 0; const cr = 'red' in cell ? cell.red : 0; const cv = 'green' in cell ? cell.green : 0; column.push({ a: ca, n: cn, r: cr, v: cv }); } jboard.board.push(column); } return jboard; } function gsboardFromJboard(jboard) { const gsboard = { x: jboard.head[0], y: jboard.head[1], sizeX: jboard.width, sizeY: jboard.height, table: [] }; for (let y = 0; y < jboard.height; y++) { const row = []; for (let x = 0; x < jboard.width; x++) { const cell = jboard.board[x][y]; row.push({ blue: cell.a, black: cell.n, red: cell.r, green: cell.v }); } gsboard.table.unshift(row); } return JSON.stringify(gsboard); } function gsboardToJboard(gsBoardString) { const gsboard = JSON.parse(gsBoardString); const jboard = { head: [gsboard.x, gsboard.y], width: gsboard.sizeX, height: gsboard.sizeY, board: [] }; for (let x = 0; x < jboard.width; x++) { const column = []; for (let y = 0; y < jboard.height; y++) { const cell = gsboard.table[jboard.height - y - 1][x]; column.push({ a: cell.blue, n: cell.black, r: cell.red, v: cell.green }); } jboard.board.push(column); } return jboard; } export function gbbFromJboard(jboard) { const gbb = []; gbb.push('GBB/1.0'); gbb.push(`size ${jboard.width.toString()} ${jboard.height.toString()}`); for (let y = 0; y < jboard.height; y++) { for (let x = 0; x < jboard.width; x++) { const cell = jboard.board[x][y]; if (cell.a + cell.n + cell.r + cell.v === 0) { continue; } let c = 'cell ' + x.toString() + ' ' + y.toString(); if (cell.a > 0) { c += ' Azul ' + cell.a.toString(); } if (cell.n > 0) { c += ' Negro ' + cell.n.toString(); } if (cell.r > 0) { c += ' Rojo ' + cell.r.toString(); } if (cell.v > 0) { c += ' Verde ' + cell.v.toString(); } gbb.push(c); } } gbb.push(`head ${jboard.head[0].toString()} ${jboard.head[1].toString()}`); return gbb.join('\n') + '\n'; } export function gbbToJboard(gbb) { let i = 0; // DUMMY const jboard = { width: 0, height: 0, head: [], board: [] }; const isWhitespace = (x) => x === ' ' || x === '\t' || x === '\r' || x === '\n'; function isNumeric(str) { for (const char of str) { if ('0123456789'.indexOf(char) === -1) { return false; } } return str.length > 0; } function skipWhitespace() { /* Skip whitespace */ while (i < gbb.length && isWhitespace(gbb[i])) { i++; } } function readToken() { const t = []; skipWhitespace(); while (i < gbb.length && !isWhitespace(gbb[i])) { t.push(gbb[i]); i++; } return t.join(''); } function readN(errmsg) { const t = readToken(); if (!isNumeric(t)) { throw Error(errmsg); } const ti = parseInt(t, 10); if (ti < 0) { throw Error(errmsg); } return ti; } function readRange(a, b, errmsg) { const t = readN(errmsg); if (t < a || t >= b) { throw Error(errmsg); } return t; } if (readToken() !== 'GBB/1.0') { throw Error('GBB/1.0: Board not in GBB/1.0 format.'); } if (readToken() !== 'size') { throw Error('GBB/1.0: Board lacks a size declaration.'); } jboard.width = readN('GBB/1.0: Board width is not a number.'); jboard.height = readN('GBB/1.0: Board height is not a number.'); if (jboard.width <= 0 || jboard.height <= 0) { throw Error('GBB/1.0: Board size should be positive.'); } jboard.head = [0, 0]; jboard.board = []; for (let w = 0; w < jboard.width; w++) { const row = []; for (let j = 0; j < jboard.height; j++) { row.push({ a: 0, n: 0, r: 0, v: 0 }); } jboard.board.push(row); } let headDeclared = false; const colores = { Azul: 'a', A: 'a', Negro: 'n', N: 'n', Rojo: 'r', R: 'r', Verde: 'v', V: 'v' }; while (i < gbb.length) { const op = readToken(); if (op === '') { break; } else if (op === 'head') { if (headDeclared) { throw Error('GBB/1.0: Head position cannot be declared twice.'); } headDeclared = true; const hx = readRange(0, jboard.width, 'GBB/1.0: Invalid head position.'); const hy = readRange(0, jboard.height, 'GBB/1.0: Invalid head position.'); jboard.head = [hx, hy]; } else if (op === 'cell') { const cx = readRange(0, jboard.width, 'GBB/1.0: Invalid cell position.'); const cy = readRange(0, jboard.height, 'GBB/1.0: Invalid cell position.'); const colorDeclared = {}; while (i < gbb.length) { const color = readToken(); if (!(color in colores)) { i -= color.length; break; } const colorId = colores[color]; if (colorId in colorDeclared) { throw Error('GBB/1.0: Color cannot be declared twice.'); } const n = readN('GBB/1.0: Invalid amount of stones.'); jboard.board[cx][cy][colorId] = n; } } else { throw Error('GBB/1.0: Malformed board: unknown command "' + op + '".'); } } return jboard; } const BOARD_FORMAT_LIST = [ new BoardFormat('jboard', 'Representation of a board as a JavaScript object for internal usage.', 'jboard', JSON.stringify, JSON.parse), new BoardFormat('gs-weblang-cli-json-board', `Representation of a board as a Javascript object used by the gs-weblang-cli tool.`, 'json', gsboardFromJboard, gsboardToJboard), new BoardFormat('gbb', 'GBB/1.0', 'gbb', gbbFromJboard, gbbToJboard) ]; export const DEFAULT_FORMAT = 'gs-weblang-cli-json-board'; export const BOARD_FORMATS = {}; for (const boardFormat of BOARD_FORMAT_LIST) { BOARD_FORMATS[boardFormat.formatName] = boardFormat; } function fileExtension(filename) { const parts = filename.split('.'); return parts[parts.length - 1]; } function fileBoardFormat(filename) { const extension = fileExtension(filename); for (const fmt of BOARD_FORMAT_LIST) { if (extension === fmt.extension) { return fmt; } } return BOARD_FORMATS[DEFAULT_FORMAT]; } export function readJboardFromFile(filename) { const format = fileBoardFormat(filename); const contents = fs.readFileSync(filename, 'utf8'); return format.toJboard(contents); } export function writeJboardToFile(filename, jboard) { const format = fileBoardFormat(filename); const contents = format.fromJboard(jboard); fs.writeFileSync(filename, contents, 'utf8'); } //# sourceMappingURL=board_formats.js.map