aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/render-msg.js115
-rw-r--r--static/styles.css6
2 files changed, 119 insertions, 2 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)
+ })
+}
diff --git a/static/styles.css b/static/styles.css
index 4497f90..ff94abf 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -8,11 +8,9 @@ section {
padding: 1ex;
}
-/*
.symbol {
font-family: Symbola;
}
-*/
.ssb-post img {
max-width: 100%;
@@ -160,3 +158,7 @@ table.ssb-object {
table.ssb-object td {
border: 1px solid black;
}
+
+.chess-square-dark {
+ background-color: #ccc;
+}