mirror of
https://github.com/arthur-pbty/xiao.git
synced 2026-06-20 21:44:48 +02:00
Add fifty rule move and SAN notation
This commit is contained in:
@@ -5,9 +5,9 @@ const moment = require('moment');
|
|||||||
const { stripIndents } = require('common-tags');
|
const { stripIndents } = require('common-tags');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { verify, reactIfAble } = require('../../util/Util');
|
const { verify, reactIfAble } = require('../../util/Util');
|
||||||
const { drawImageWithTint, centerImagePart } = require('../../util/Canvas');
|
const { centerImagePart } = require('../../util/Canvas');
|
||||||
const { FAILURE_EMOJI_ID } = process.env;
|
const { FAILURE_EMOJI_ID } = process.env;
|
||||||
const turnRegex = /^([A-H][1-8])(?: |, ?|-?>?)?([A-H][1-8])$/;
|
const turnRegex = /^((?:[A-H][1-8])|(?:[PKRQBN]))?([A-H])?(?: |, ?|-?>?)?([A-H][1-8])$/;
|
||||||
const pieces = ['pawn', 'rook', 'knight', 'king', 'queen', 'bishop'];
|
const pieces = ['pawn', 'rook', 'knight', 'king', 'queen', 'bishop'];
|
||||||
const cols = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];
|
const cols = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];
|
||||||
|
|
||||||
@@ -71,6 +71,7 @@ module.exports = class ChessCommand extends Command {
|
|||||||
let blackTime = time === 0 ? Infinity : time * 60000;
|
let blackTime = time === 0 ? Infinity : time * 60000;
|
||||||
let whitePlayer = msg.author;
|
let whitePlayer = msg.author;
|
||||||
let blackPlayer = opponent;
|
let blackPlayer = opponent;
|
||||||
|
let fiftyRuleMove = 0;
|
||||||
if (resumeGame) {
|
if (resumeGame) {
|
||||||
await msg.reply(stripIndents`
|
await msg.reply(stripIndents`
|
||||||
You have a saved game, do you want to resume it?
|
You have a saved game, do you want to resume it?
|
||||||
@@ -84,6 +85,7 @@ module.exports = class ChessCommand extends Command {
|
|||||||
blackTime = data.blackTime === -1 ? Infinity : data.blackTime;
|
blackTime = data.blackTime === -1 ? Infinity : data.blackTime;
|
||||||
whitePlayer = data.color === 'white' ? msg.author : opponent;
|
whitePlayer = data.color === 'white' ? msg.author : opponent;
|
||||||
blackPlayer = data.color === 'black' ? msg.author : opponent;
|
blackPlayer = data.color === 'black' ? msg.author : opponent;
|
||||||
|
fiftyRuleMove = data.fiftyRuleMove;
|
||||||
await this.client.redis.del(`chess-${msg.author.id}`);
|
await this.client.redis.del(`chess-${msg.author.id}`);
|
||||||
} else {
|
} else {
|
||||||
game = new jsChess.Game();
|
game = new jsChess.Game();
|
||||||
@@ -93,7 +95,7 @@ module.exports = class ChessCommand extends Command {
|
|||||||
}
|
}
|
||||||
let prevPieces = null;
|
let prevPieces = null;
|
||||||
let saved = false;
|
let saved = false;
|
||||||
while (!game.exportJson().checkMate) {
|
while (!game.exportJson().checkMate && fiftyRuleMove <= 50) {
|
||||||
const gameState = game.exportJson();
|
const gameState = game.exportJson();
|
||||||
const user = gameState.turn === 'black' ? blackPlayer : whitePlayer;
|
const user = gameState.turn === 'black' ? blackPlayer : whitePlayer;
|
||||||
const userTime = gameState.turn === 'black' ? blackTime : whiteTime;
|
const userTime = gameState.turn === 'black' ? blackTime : whiteTime;
|
||||||
@@ -123,7 +125,8 @@ module.exports = class ChessCommand extends Command {
|
|||||||
if (res.author.id !== user.id) return false;
|
if (res.author.id !== user.id) return false;
|
||||||
const move = choice.match(turnRegex);
|
const move = choice.match(turnRegex);
|
||||||
if (!move) return false;
|
if (!move) return false;
|
||||||
if (!moves[move[1]] || !moves[move[1]].includes(move[2])) {
|
const parsed = this.parseSAN(gameState, moves, move);
|
||||||
|
if (!parsed || !moves[parsed[0]] || !moves[parsed[0]].includes(parsed[1])) {
|
||||||
reactIfAble(res, res.author, FAILURE_EMOJI_ID, '❌');
|
reactIfAble(res, res.author, FAILURE_EMOJI_ID, '❌');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -156,7 +159,13 @@ module.exports = class ChessCommand extends Command {
|
|||||||
if (gameState.turn === 'white') whiteTime -= new Date() - now;
|
if (gameState.turn === 'white') whiteTime -= new Date() - now;
|
||||||
await this.client.redis.set(
|
await this.client.redis.set(
|
||||||
`chess-${author.id}`,
|
`chess-${author.id}`,
|
||||||
this.exportGame(game, blackTime, whiteTime, whitePlayer.id === author.id ? 'white' : 'black')
|
this.exportGame(
|
||||||
|
game,
|
||||||
|
blackTime,
|
||||||
|
whiteTime,
|
||||||
|
whitePlayer.id === author.id ? 'white' : 'black',
|
||||||
|
fiftyRuleMove
|
||||||
|
)
|
||||||
);
|
);
|
||||||
saved = true;
|
saved = true;
|
||||||
break;
|
break;
|
||||||
@@ -166,6 +175,11 @@ module.exports = class ChessCommand extends Command {
|
|||||||
if (gameState.turn === 'white') whiteTime -= timeTaken - 5000;
|
if (gameState.turn === 'white') whiteTime -= timeTaken - 5000;
|
||||||
const choice = turn.first().content.toUpperCase().match(turnRegex);
|
const choice = turn.first().content.toUpperCase().match(turnRegex);
|
||||||
game.move(choice[1], choice[2]);
|
game.move(choice[1], choice[2]);
|
||||||
|
if (gameState.pieces[choice[1]].toUpperCase() === 'P') {
|
||||||
|
fiftyRuleMove = 0;
|
||||||
|
} else {
|
||||||
|
fiftyRuleMove++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.client.games.delete(msg.channel.id);
|
this.client.games.delete(msg.channel.id);
|
||||||
@@ -176,6 +190,7 @@ module.exports = class ChessCommand extends Command {
|
|||||||
If you want to delete your saved game, use ${this.client.registry.commands.get('chess-delete').usage()}.
|
If you want to delete your saved game, use ${this.client.registry.commands.get('chess-delete').usage()}.
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
if (fiftyRuleMove > 50) return msg.say('Due to the fifty move rule, this game is a draw.');
|
||||||
const gameState = game.exportJson();
|
const gameState = game.exportJson();
|
||||||
if (!gameState.checkMate) return msg.say('Game ended due to forfeit.');
|
if (!gameState.checkMate) return msg.say('Game ended due to forfeit.');
|
||||||
const winner = gameState.turn === 'black' ? whitePlayer : blackPlayer;
|
const winner = gameState.turn === 'black' ? whitePlayer : blackPlayer;
|
||||||
@@ -188,6 +203,19 @@ module.exports = class ChessCommand extends Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parseSAN(gameState, moves, move) {
|
||||||
|
if (!move || !move[3]) return null;
|
||||||
|
const initial = move[1] || 'P';
|
||||||
|
if (gameState.pieces[initial]) return [initial, move[3]];
|
||||||
|
const possiblePieces = Object.keys(gameState.pieces).filter(piece => {
|
||||||
|
if (gameState.pieces[piece] !== initial) return false;
|
||||||
|
if (move[2] && !piece.startsWith(move[2])) return false;
|
||||||
|
return moves[piece].includes(move[3]);
|
||||||
|
});
|
||||||
|
if (possiblePieces.length === 1) return [possiblePieces[0], move[3]];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
displayBoard(gameState, prevPieces) {
|
displayBoard(gameState, prevPieces) {
|
||||||
const canvas = createCanvas(this.images.board.width, this.images.board.height);
|
const canvas = createCanvas(this.images.board.width, this.images.board.height);
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
@@ -299,12 +327,13 @@ module.exports = class ChessCommand extends Command {
|
|||||||
return { name, color };
|
return { name, color };
|
||||||
}
|
}
|
||||||
|
|
||||||
exportGame(game, blackTime, whiteTime, playerColor) {
|
exportGame(game, blackTime, whiteTime, playerColor, fiftyRuleMove) {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
fen: game.exportFEN(),
|
fen: game.exportFEN(),
|
||||||
blackTime: blackTime === Infinity ? -1 : blackTime,
|
blackTime: blackTime === Infinity ? -1 : blackTime,
|
||||||
whiteTime: whiteTime === Infinity ? -1 : whiteTime,
|
whiteTime: whiteTime === Infinity ? -1 : whiteTime,
|
||||||
color: playerColor
|
color: playerColor,
|
||||||
|
fiftyRuleMove
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user