diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/render-msg.js | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/lib/render-msg.js b/lib/render-msg.js index 262b6e7..4374165 100644 --- a/lib/render-msg.js +++ b/lib/render-msg.js @@ -242,6 +242,8 @@ RenderMsg.prototype.message = function (cb) { case 'mutual/credit': return this.mutualCredit(cb) case 'mutual/account': return this.mutualAccount(cb) case 'npm-publish': return this.npmPublish(cb) + case 'ssb_chess_invite': return this.chessInvite(cb) + case 'ssb_chess_move': return this.chessMove(cb) default: return this.object(cb) } } @@ -939,3 +941,116 @@ RenderMsg.prototype.npmPublishTitle = function (cb) { return (tags.length ? tags.join(',') + ':' : '') + version }).join(',')) } + +function expandDigitToSpaces(n) { + return ' '.substr(-n) +} + +function parseFenRank (line) { + return line.replace(/\d/g, expandDigitToSpaces).split('') +} + +function parseChess(fen) { + var fields = String(fen).split(/\s+/) + var ranks = fields[0].split('/') + var f2 = fields[2] || '' + return { + board: ranks.map(parseFenRank), + /* + nextMove: fields[1] === 'b' ? 'black' + : fields[1] === 'w' ? 'white' : 'unknown', + castling: f2 === '-' ? {} : { + w: { + k: 0 < f2.indexOf('K'), + q: 0 < f2.indexOf('Q'), + }, + b: { + k: 0 < f2.indexOf('k'), + q: 0 < f2.indexOf('q'), + } + }, + enpassantTarget: fields[3] === '-' ? null : fields[3], + halfmoves: Number(fields[4]), + fullmoves: Number(fields[5]), + */ + } +} + +var chessSymbols = { + ' ': [' ', ''], + P: ['♙', 'white pawn'], + N: ['♘', 'white knight'], + B: ['♗', 'white bishop'], + R: ['♖', 'white rook'], + Q: ['♕', 'white queen'], + K: ['♔', 'white king'], + p: ['♟', 'black pawn'], + n: ['♞', 'black knight'], + b: ['♝', 'black bishop'], + r: ['♜', 'black rook'], + q: ['♛', 'black queen'], + k: ['♚', 'black king'], +} + +function renderChessSymbol(c, loc) { + var info = chessSymbols[c] || ['?', 'unknown'] + return h('span.symbol', { + title: info[1] + (loc ? ' at ' + loc : '') + }, info[0]) +} + +function chessLocToIdxs(loc) { + var m = /^([a-h])([1-8])$/.exec(loc) + if (m) return [8 - m[2], m[1].charCodeAt(0) - 97] +} + +function lookupPiece(board, loc) { + var idxs = chessLocToIdxs(loc) + return board[idxs[0]] && board[idxs[0]][idxs[1]] +} + +function chessIdxsToLoc(i, j) { + return 'abcdefgh'[j] + (8-i) +} + +RenderMsg.prototype.chessMove = function (cb) { + var self = this + var c = self.c + var fen = c.fen && c.fen.length === 2 ? c.pgnMove : c.fen + var game = parseChess(fen) + var piece = game && lookupPiece(game.board, c.dest) + self.link(self.c.root, function (err, rootLink) { + if (err) return cb(err) + self.wrap([ + h('div', h('small', '> ', rootLink)), + h('p', + // 'player ', (c.ply || ''), ' ', + 'moved ', (piece ? renderChessSymbol(piece) : ''), ' ', + 'from ', c.orig, ' ', + 'to ', c.dest + ), + h('table.chess-board', + game.board.map(function (rank, i) { + return h('tr', rank.map(function (piece, j) { + var dark = (i ^ j) & 1 + return h('td', { + class: 'chess-square-' + (dark ? 'dark' : 'light'), + }, renderChessSymbol(piece, chessIdxsToLoc(i, j))) + })) + }) + ) + ], cb) + }) +} + +RenderMsg.prototype.chessInvite = function (cb) { + var self = this + var myColor = self.c.myColor + self.link(self.c.inviting, function (err, link) { + if (err) return cb(err) + self.wrap([ + 'invites ', link, ' to play chess', + // myColor ? h('p', 'my color is ' + myColor) : '' + ], cb) + }) +} |