Merge pull request #6219 from niklasf/client-side-puzzle-socket
client side puzzle socketpull/6224/head
commit
23f1d8a81b
|
@ -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';
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
|
Loading…
Reference in New Issue