Merge pull request #6219 from niklasf/client-side-puzzle-socket

client side puzzle socket
pull/6224/head
Thibault Duplessis 2020-03-25 09:54:17 -06:00 committed by GitHub
commit 23f1d8a81b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 94 additions and 68 deletions

View File

@ -1,4 +1,5 @@
import { piotr } from './piotr';
export { uciCharPair } from './ucicharpair';
export const initialFen: Fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';

View File

@ -0,0 +1,34 @@
type Square = number;
type Role = 'pawn' | 'knight' | 'bishop' | 'rook' | 'queen' | 'king';
interface UciMove {
from: Square;
to: Square;
promotion?: Role;
}
interface UciDrop {
role: Role;
to: Square;
}
type Uci = UciMove | UciDrop;
function square(sq: Square): number {
return 35 + sq;
}
function drop(role: Role): number {
return 35 + 64 + 8 * 5 + ['queen', 'rook', 'bishop', 'knight', 'pawn'].indexOf(role);
}
function promotion(file: number, role: Role): number {
return 35 + 64 + 8 * ['queen', 'rook', 'bishop', 'knight', 'king'].indexOf(role) + file;
}
export function uciCharPair(uci: Uci): string {
if ('role' in uci) return String.fromCharCode(square(uci.to), drop(uci.role));
else if (!uci.promotion) return String.fromCharCode(square(uci.to), square(uci.from));
else return String.fromCharCode(square(uci.from), promotion(uci.to & 7, uci.promotion));
}

View File

@ -21,6 +21,7 @@
"ceval": "2.0.0",
"chess": "2.0.0",
"chessground": "^7.6",
"chessops": "^0.3.4",
"common": "2.0.0",
"snabbdom": "ornicar/snabbdom#0.7.1-lichess",
"tree": "2.0.0"

View File

@ -400,7 +400,6 @@ export default function(opts: PuzzleOpts, redraw: Redraw): Controller {
}
const socket = socketBuild({
send: opts.socketSend,
addNode: addNode,
addDests: addDests,
reset: function() {
@ -482,7 +481,6 @@ export default function(opts: PuzzleOpts, redraw: Redraw): Controller {
getCeval,
pref: opts.pref,
trans: window.lichess.trans(opts.i18n),
socketReceive: socket.receive,
gameOver,
toggleCeval,
toggleThreatMode,

View File

@ -45,7 +45,6 @@ export interface Controller extends KeyboardController {
thanks(): boolean;
vote(v: boolean): void;
pref: PuzzlePrefs;
socketReceive: any;
userMove(orig: Key, dest: Key): void;
promotion: any;
@ -79,7 +78,6 @@ export interface PuzzleOpts {
pref: PuzzlePrefs;
data: PuzzleData;
i18n: { [key: string]: string | undefined };
socketSend: any;
}
export interface PuzzlePrefs {

View File

@ -14,7 +14,7 @@ menuHover();
const patch = init([klass, attributes]);
export default function(opts) {
export default function(opts): void {
let vnode: VNode, ctrl: Controller;
@ -27,10 +27,6 @@ export default function(opts) {
const blueprint = view(ctrl);
opts.element.innerHTML = '';
vnode = patch(opts.element, blueprint);
return {
socketReceive: ctrl.socketReceive
};
};
// that's for the rest of lichess to access chessground

View File

@ -1,63 +1,68 @@
import { Chess } from 'chessops/chess';
import { parseFen, makeFen } from 'chessops/fen';
import { makeSanAndPlay } from 'chessops/san';
import { parseSquare, makeUci, parseUci } from 'chessops/util';
import { altCastles, uciCharPair } from 'chess';
import { defined } from 'common';
export default function(opts) {
var anaMoveTimeout;
var anaDestsTimeout;
function piotr(sq: number): string {
if (sq < 26) return String.fromCharCode('a'.charCodeAt(0) + sq);
else if (sq < 52) return String.fromCharCode('A'.charCodeAt(0) + sq - 26);
else if (sq < 62) return String.fromCharCode('0'.charCodeAt(0) + sq - 52);
else if (sq == 62) return '!';
else return '?';
}
var anaDestsCache = {};
function makeDests(pos: Chess): string {
const dests = pos.allDests();
var handlers = {
node: function(data) {
clearTimeout(anaMoveTimeout);
opts.addNode(data.node, data.path);
},
stepFailure: function() {
clearTimeout(anaMoveTimeout);
opts.reset();
},
dests: function(data) {
anaDestsCache[data.path] = data;
opts.addDests(data.dests, data.path);
clearTimeout(anaDestsTimeout);
},
destsFailure: function(data) {
console.log(data);
clearTimeout(anaDestsTimeout);
// add two step castling moves (standard chess)
const king = pos.board.kingOf(pos.turn);
if (defined(king) && king & 4 && dests.has(king)) {
if (dests.get(king)!.has(0)) dests.set(king, dests.get(king)!.with(2));
if (dests.get(king)!.has(7)) dests.set(king, dests.get(king)!.with(6));
if (dests.get(king)!.has(56)) dests.set(king, dests.get(king)!.with(58));
if (dests.get(king)!.has(63)) dests.set(king, dests.get(king)!.with(62));
}
};
var sendAnaMove = function(req) {
clearTimeout(anaMoveTimeout);
opts.send('anaMove', req);
anaMoveTimeout = setTimeout(function() {
sendAnaMove(req);
}, 3000);
};
var sendAnaDests = function(req) {
clearTimeout(anaDestsTimeout);
if (anaDestsCache[req.path]) setTimeout(function() {
handlers.dests(anaDestsCache[req.path]);
}, 10);
else {
opts.send('anaDests', req);
anaDestsTimeout = setTimeout(function() {
sendAnaDests(req);
}, 3000);
const result: string[] = [];
for (const [from, squares] of dests) {
if (squares.nonEmpty()) result.push([from, ...Array.from(squares)].map(piotr).join(''));
}
};
return result.join(' ');
}
function sendAnaMove(req) {
const setup = parseFen(req.fen).unwrap();
const pos = Chess.fromSetup(setup).unwrap();
const move = {
from: parseSquare(req.orig)!,
to: parseSquare(req.dest)!,
promotion: req.promotion,
};
const san = makeSanAndPlay(pos, move);
const uci = san.startsWith('O-O') && altCastles[makeUci(move)] || makeUci(move);
setTimeout(() => opts.addNode({
ply: 2 * (pos.fullmoves - 1) + (pos.turn == 'white' ? 0 : 1),
fen: makeFen(pos.toSetup()),
dests: makeDests(pos),
children: [],
san,
uci,
id: uciCharPair(parseUci(uci)!),
}, req.path), 10);
}
function sendAnaDests(req) {
const setup = parseFen(req.fen).unwrap();
const pos = Chess.fromSetup(setup).unwrap();
setTimeout(() => opts.addDests(makeDests(pos), req.path), 10);
}
return {
send: opts.send,
receive: function(type, data) {
if (handlers[type]) {
handlers[type](data);
return true;
}
return false;
},
sendAnaMove: sendAnaMove,
sendAnaDests: sendAnaDests
sendAnaDests: sendAnaDests,
};
}

View File

@ -955,15 +955,8 @@
////////////////
function startPuzzle(cfg) {
var puzzle;
cfg.element = document.querySelector('main.puzzle');
lichess.socket = lichess.StrongSocket('/socket/v4', false, {
receive: function(t, d) {
puzzle.socketReceive(t, d);
}
});
cfg.socketSend = lichess.socket.send;
puzzle = LichessPuzzle.default(cfg);
LichessPuzzle.default(cfg);
}
////////////////////