Initial commit
This commit is contained in:
578
main.js
Normal file
578
main.js
Normal file
@@ -0,0 +1,578 @@
|
||||
HTMLElement.prototype.addChild = function (tagName, classList) {
|
||||
const el = document.createElement(tagName);
|
||||
|
||||
if (typeof classList === 'string') {
|
||||
classList = [classList];
|
||||
}
|
||||
|
||||
el.classList.add(...classList);
|
||||
|
||||
this.appendChild(el);
|
||||
return el;
|
||||
};
|
||||
|
||||
const container = document.getElementById('game-container');
|
||||
const figuresContainer = container.addChild('div', 'figures');
|
||||
const deadFiguresContainers = {
|
||||
black: container.addChild('div', ['dead-figures', 'black']),
|
||||
white: container.addChild('div', ['dead-figures', 'white']),
|
||||
};
|
||||
const board = [];
|
||||
const figures = [];
|
||||
|
||||
let currentPlayer = 'w';
|
||||
let castlings = {
|
||||
w: {
|
||||
short: true,
|
||||
long: true,
|
||||
},
|
||||
b: {
|
||||
short: true,
|
||||
long: true,
|
||||
},
|
||||
};
|
||||
let enpassant = null;
|
||||
let halfTurns = 0;
|
||||
let turn = 1;
|
||||
|
||||
let selectedFigure;
|
||||
|
||||
class Field {
|
||||
constructor(x, y, el) {
|
||||
this.element = el;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
if ((x % 2 === 0 && y % 2 === 0) || (x % 2 !== 0 && y % 2 !== 0)) {
|
||||
this.color = 'w';
|
||||
} else {
|
||||
this.color = 'b';
|
||||
}
|
||||
this.element.classList.add(this.color === 'w' ? 'white' : 'black');
|
||||
|
||||
this.element.addEventListener('click', () => {
|
||||
const figure = figures.find(figure => figure.color === currentPlayer && figure.x === this.x && figure.y === this.y);
|
||||
|
||||
if (!!selectedFigure) {
|
||||
selectedFigure.deselectFigure();
|
||||
}
|
||||
|
||||
if (!!figure) {
|
||||
figure.selectFigure();
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
this.element.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!!selectedFigure) {
|
||||
selectedFigure.moveTo(this.x, this.y);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
this.isFocused = false;
|
||||
}
|
||||
|
||||
setFocus(isFocused) {
|
||||
if (this.isFocused === isFocused)
|
||||
return;
|
||||
|
||||
this.isFocused = isFocused;
|
||||
|
||||
if (isFocused) {
|
||||
this.element.classList.add('possible-target');
|
||||
} else {
|
||||
this.element.classList.remove('possible-target');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Figure {
|
||||
constructor(x, y, color, name, char) {
|
||||
this.element = figuresContainer.addChild('div', ['figure', color === 'b' ? 'black' : 'white', name]);
|
||||
this.element.style.transform = `translate(${x * 100}%, ${y * 100}%)`;
|
||||
|
||||
this.hasMoved = false;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.color = color;
|
||||
this.char = char;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
const index = figures.findIndex(figure => figure === this);
|
||||
figures.splice(index, 1);
|
||||
|
||||
this.element.parentNode.removeChild(this.element);
|
||||
|
||||
this.element.style.transform = 'none';
|
||||
if (this.color === 'b') {
|
||||
deadFiguresContainers.black.appendChild(this.element);
|
||||
} else {
|
||||
deadFiguresContainers.white.appendChild(this.element);
|
||||
}
|
||||
}
|
||||
|
||||
getMoveSet() {
|
||||
return [];
|
||||
}
|
||||
|
||||
getMoves(moveX, moveY, x, y) {
|
||||
if (x < 0 || x >= 8 || y < 0 || y >= 8)
|
||||
return [];
|
||||
|
||||
const moves = [];
|
||||
|
||||
let stepX = moveX,
|
||||
stepY = moveY,
|
||||
repeatX = false,
|
||||
repeatY = false;
|
||||
|
||||
if (typeof moveX === 'string') {
|
||||
stepX = parseInt(moveX.split('*')[0]);
|
||||
repeatX = true;
|
||||
}
|
||||
if (typeof moveY === 'string') {
|
||||
stepY = parseInt(moveY.split('*')[0]);
|
||||
repeatY = true;
|
||||
}
|
||||
|
||||
x += stepX;
|
||||
y += stepY;
|
||||
|
||||
if (x < 0 || x >= 8 || y < 0 || y >= 8)
|
||||
return [];
|
||||
|
||||
const figure = figures.find(figure => figure.color === this.color && figure.x === x && figure.y === y);
|
||||
if (!!figure)
|
||||
return [];
|
||||
|
||||
moves.push([x, y]);
|
||||
|
||||
if (repeatX || repeatY) {
|
||||
moves.push(...this.getMoves(moveX, moveY, x, y));
|
||||
}
|
||||
|
||||
return moves;
|
||||
}
|
||||
|
||||
getPossibleTargets() {
|
||||
const moveSet = this.getMoveSet();
|
||||
|
||||
const targets = [];
|
||||
|
||||
moveSet.forEach(move => {
|
||||
const moved = this.getMoves(move[0], move[1], this.x, this.y);
|
||||
targets.push(...moved.map(move => board[move[0]][move[1]]));
|
||||
});
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
moveTo(x, y) {
|
||||
this.deselectFigure();
|
||||
const targets = this.getPossibleTargets();
|
||||
if (!targets.includes(board[x][y])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkKing(this.color)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const figure = figures.find(figure => figure.x === x && figure.y === y);
|
||||
if (!!figure) {
|
||||
if (figure.color === this.color) {
|
||||
return;
|
||||
} else {
|
||||
figure.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.hasMoved) {
|
||||
this.hasMoved = true;
|
||||
}
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
this.element.style.transform = `translate(${this.x * 100}%, ${this.y * 100}%)`;
|
||||
|
||||
switchSides();
|
||||
}
|
||||
|
||||
selectFigure() {
|
||||
if (!!selectedFigure)
|
||||
selectedFigure.deselectFigure();
|
||||
|
||||
selectedFigure = this;
|
||||
const targets = this.getPossibleTargets();
|
||||
targets.forEach(target => {
|
||||
target.setFocus(true);
|
||||
});
|
||||
|
||||
container.classList.add('focused');
|
||||
}
|
||||
|
||||
deselectFigure() {
|
||||
selectedFigure = null;
|
||||
|
||||
const targets = this.getPossibleTargets();
|
||||
targets.forEach(target => {
|
||||
target.setFocus(false);
|
||||
});
|
||||
|
||||
container.classList.remove('focused');
|
||||
}
|
||||
|
||||
getExportChar() {
|
||||
if (this.color === 'w') {
|
||||
return this.char.toUpperCase();
|
||||
} else {
|
||||
return this.char.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
static deselectAll() {
|
||||
selectedFigure = null;
|
||||
|
||||
board.forEach(col => {
|
||||
col.forEach(field => {
|
||||
field.setFocus(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class Pawn extends Figure {
|
||||
constructor(x, y, color) {
|
||||
super(x, y, color, 'pawn', 'p');
|
||||
}
|
||||
|
||||
getMoveSet() {
|
||||
let moves = [];
|
||||
if (this.color === 'b') {
|
||||
moves.push([0, 1, true]);
|
||||
if (!this.hasMoved) {
|
||||
moves.push([0, 2, true]);
|
||||
}
|
||||
moves.push([1, 1, false]);
|
||||
moves.push([-1, 1, false]);
|
||||
} else {
|
||||
moves.push([0, -1, true]);
|
||||
if (!this.hasMoved) {
|
||||
moves.push([0, -2, true]);
|
||||
}
|
||||
moves.push([1, -1, false]);
|
||||
moves.push([-1, -1, false]);
|
||||
}
|
||||
|
||||
for (let i = 0; i < moves.length; i++) {
|
||||
const move = moves[i];
|
||||
const figure = getFigure(this.x + move[0], this.y + move[1]);
|
||||
if ((move[2] && !!figure) || (!move[2] && !figure)) {
|
||||
moves.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
moves = moves.map(move => [move[0], move[1]]);
|
||||
|
||||
return moves;
|
||||
}
|
||||
|
||||
moveTo(x, y) {
|
||||
super.moveTo(x, y);
|
||||
|
||||
if (this.color === 'w' && this.y === 0) {
|
||||
this.destroy();
|
||||
// TODO: Add new figure
|
||||
} else if (this.color === 'b' && this.y === 7) {
|
||||
this.destroy();
|
||||
// TODO: Add new figure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Rook extends Figure {
|
||||
constructor(x, y, color) {
|
||||
super(x, y, color, 'rook', 'r');
|
||||
}
|
||||
|
||||
getMoveSet() {
|
||||
return [
|
||||
[0, '1*'],
|
||||
['1*', 0],
|
||||
[0, '-1*'],
|
||||
['-1*', 0],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Knight extends Figure {
|
||||
constructor(x, y, color) {
|
||||
super(x, y, color, 'knight', 'n');
|
||||
}
|
||||
|
||||
getMoveSet() {
|
||||
return [
|
||||
[2, 1],
|
||||
[2, -1],
|
||||
[1, 2],
|
||||
[-1, 2],
|
||||
[-2, 1],
|
||||
[-2, -1],
|
||||
[1, -2],
|
||||
[-1, -2],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Bishop extends Figure {
|
||||
constructor(x, y, color) {
|
||||
super(x, y, color, 'bishop', 'b');
|
||||
}
|
||||
|
||||
getMoveSet() {
|
||||
return [
|
||||
['1*', '1*'],
|
||||
['-1*', '1*'],
|
||||
['-1*', '-1*'],
|
||||
['1*', '-1*'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Queen extends Figure {
|
||||
constructor(x, y, color) {
|
||||
super(x, y, color, 'queen', 'q');
|
||||
}
|
||||
|
||||
getMoveSet() {
|
||||
return [
|
||||
['1*', 0],
|
||||
['-1*', 0],
|
||||
['1*', '1*'],
|
||||
['-1*', '1*'],
|
||||
['-1*', '-1*'],
|
||||
['1*', '-1*'],
|
||||
[0, '1*'],
|
||||
[0, '-1*'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class King extends Figure {
|
||||
constructor(x, y, color) {
|
||||
super(x, y, color, 'king', 'k');
|
||||
}
|
||||
|
||||
getMoveSet() {
|
||||
return [
|
||||
[-1, 0],
|
||||
[-1, -1],
|
||||
[0, -1],
|
||||
[1, -1],
|
||||
[1, 0],
|
||||
[1, 1],
|
||||
[0, 1],
|
||||
[-1, 1],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function createBoard() {
|
||||
const boardEl = container.addChild('div', 'board');
|
||||
for (let x = 0; x < 8; x++) {
|
||||
board.push([]);
|
||||
const colEl = boardEl.addChild('div', 'col');
|
||||
|
||||
for (let y = 0; y < 8; y++) {
|
||||
const element = colEl.addChild('div', 'field');
|
||||
const field = new Field(x, y, element);
|
||||
board[x].push(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createFigures(color) {
|
||||
for (let i = 0; i < 8; i++) {
|
||||
figures.push(new Pawn(i, color === 'b' ? 1 : 6, color));
|
||||
}
|
||||
figures.push(new Rook(0, color === 'b' ? 0 : 7, color));
|
||||
figures.push(new Knight(1, color === 'b' ? 0 : 7, color));
|
||||
figures.push(new Bishop(2, color === 'b' ? 0 : 7, color));
|
||||
figures.push(new Queen(3, color === 'b' ? 0 : 7, color));
|
||||
figures.push(new King(4, color === 'b' ? 0 : 7, color));
|
||||
figures.push(new Bishop(5, color === 'b' ? 0 : 7, color));
|
||||
figures.push(new Knight(6, color === 'b' ? 0 : 7, color));
|
||||
figures.push(new Rook(7, color === 'b' ? 0 : 7, color));
|
||||
}
|
||||
|
||||
function getFigure(x, y) {
|
||||
return figures.find(figure => figure.x === x && figure.y === y);
|
||||
}
|
||||
|
||||
function checkKing(color) {
|
||||
const king = figures.find(figure => figure instanceof King && figure.color === color);
|
||||
|
||||
let isChecked = false;
|
||||
figures.forEach(figure => {
|
||||
if (figure.color === color)
|
||||
return;
|
||||
|
||||
const possibleMoves = figure.getPossibleTargets();
|
||||
possibleMoves.forEach(move => {
|
||||
if (move[0] === king.x && move[1] === king.y) {
|
||||
isChecked = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (isChecked)
|
||||
return false;
|
||||
});
|
||||
|
||||
return isChecked;
|
||||
}
|
||||
|
||||
function switchSides() {
|
||||
currentPlayer = currentPlayer === 'b' ? 'w' : 'b';
|
||||
|
||||
if (currentPlayer === 'b') {
|
||||
container.classList.add('black-turn');
|
||||
} else {
|
||||
container.classList.remove('black-turn');
|
||||
|
||||
turn++;
|
||||
}
|
||||
}
|
||||
|
||||
function exportGame() {
|
||||
let exportedGame = '';
|
||||
|
||||
for (let y = 0; y < 8; y++) {
|
||||
let emptyCount = 0;
|
||||
for (let x = 0; x < 8; x++) {
|
||||
const figure = getFigure(x, y);
|
||||
|
||||
if (!!figure) {
|
||||
if (emptyCount > 0) {
|
||||
exportedGame += emptyCount;
|
||||
emptyCount = 0;
|
||||
}
|
||||
|
||||
exportedGame += figure.getExportChar();
|
||||
} else {
|
||||
emptyCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (emptyCount > 0) {
|
||||
exportedGame += emptyCount;
|
||||
}
|
||||
|
||||
if (y !== 7) {
|
||||
exportedGame += '/';
|
||||
}
|
||||
}
|
||||
|
||||
exportedGame += ` ${currentPlayer} `;
|
||||
|
||||
let castling = false;
|
||||
if (castlings.w.short) {
|
||||
exportedGame += 'K';
|
||||
castling = true;
|
||||
}
|
||||
if (castlings.w.long) {
|
||||
exportedGame += 'Q';
|
||||
castling = true;
|
||||
}
|
||||
if (castlings.b.short) {
|
||||
exportedGame += 'k';
|
||||
castling = true;
|
||||
}
|
||||
if (castlings.b.long) {
|
||||
exportedGame += 'q';
|
||||
castling = true;
|
||||
}
|
||||
|
||||
if (!castling) {
|
||||
exportedGame += '-';
|
||||
}
|
||||
|
||||
exportedGame += ` ${!!enpassant ? coordinatesToString(enpassant) : '-'} ${halfTurns} ${turn}`;
|
||||
|
||||
return exportedGame;
|
||||
}
|
||||
|
||||
const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
|
||||
|
||||
function coordinatesToString(coordinates) {
|
||||
return letters[coordinates[0]] + (8 - coordinates[1]);
|
||||
}
|
||||
|
||||
function stringToCoordinates() {
|
||||
|
||||
}
|
||||
|
||||
const figuresTable = {
|
||||
p: Pawn,
|
||||
r: Rook,
|
||||
n: Knight,
|
||||
b: Bishop,
|
||||
q: Queen,
|
||||
k: King,
|
||||
};
|
||||
|
||||
function importGame(string) {
|
||||
const groups = string.split(' ');
|
||||
|
||||
const rows = groups[0].split('/');
|
||||
if (rows.length !== 8)
|
||||
return false;
|
||||
rows.forEach((row, y) => {
|
||||
let len = 0;
|
||||
for (let x = 0; x < row.length; x++) {
|
||||
const char = row.charAt(x);
|
||||
|
||||
if (char.isNumber()) {
|
||||
len += parseInt(char);
|
||||
} else {
|
||||
const figureType = figuresTable[char.toLowerCase()];
|
||||
console.log(char, figureType);
|
||||
const figure = new figureType(x, y, char.isUpperCase() ? 'w' : 'b');
|
||||
figures.push(figure);
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
if(len !== 8) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function isDefiniteTurn() {
|
||||
|
||||
}
|
||||
|
||||
String.prototype.isNumber = function () {
|
||||
return !isNaN(parseInt(this), 10);
|
||||
};
|
||||
|
||||
String.prototype.isUpperCase = function () {
|
||||
return this.toString() === this.toUpperCase();
|
||||
};
|
||||
|
||||
createBoard();
|
||||
// createFigures('w');
|
||||
// createFigures('b');
|
||||
|
||||
importGame('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
|
Reference in New Issue
Block a user