-import { ChessRules, Move, PiPo } from "@/js/base_rules";
-import { randInt } from "@/utils/alea";
+import { ChessRules } from "@/js/base_rules";
+import PiPo from "/utils/PiPo.js";
+import Move from "/utils/Move.js";
import { ArrayFun } from "@/utils/array";
-export class EmergoRules extends ChessRules {
+export default class EmergoRules extends ChessRules {
// Simple encoding: A to L = 1 to 12, from left to right, if white controls.
// Lowercase if black controls.
return null;
}
- static get HasFlags() {
+ get hasFlags() {
return false;
}
-
- static get HasEnpassant() {
+ get hasEnpassant() {
return false;
}
- static get DarkBottomRight() {
- return true;
- }
-
- // board element == file name:
- static board2fen(b) {
+ // board element == piece class ref:
+ board2fen(b) {
return b;
}
- static fen2board(f) {
+ fen2board(f) {
return f;
}
- static IsGoodPosition(position) {
- if (position.length == 0) return false;
- const rows = position.split("/");
- if (rows.length != V.size.x) return false;
- for (let row of rows) {
- let sumElts = 0;
- for (let i = 0; i < row.length; i++) {
- // Add only 0.5 per symbol because 2 per piece
- if (row[i].toLowerCase().match(/^[a-lA-L@]$/)) sumElts += 0.5;
- else {
- const num = parseInt(row[i], 10);
- if (isNaN(num) || num <= 0) return false;
- sumElts += num;
- }
- }
- if (sumElts != V.size.y) return false;
- }
- return true;
- }
-
- static GetBoard(position) {
+ getBoard(position) {
const rows = position.split("/");
- let board = ArrayFun.init(V.size.x, V.size.y, "");
+ let board = ArrayFun.init(this.size.x, this.size.y, "");
for (let i = 0; i < rows.length; i++) {
let j = 0;
for (let indexInRow = 0; indexInRow < rows[i].length; indexInRow++) {
const character = rows[i][indexInRow];
const num = parseInt(character, 10);
- // If num is a number, just shift j:
- if (!isNaN(num)) j += num;
+ if (!isNaN(num))
+ // If num is a number, just shift j:
+ j += num;
else
// Something at position i,j
- board[i][j++] = V.fen2board(character + rows[i][++indexInRow]);
+ board[i][j++] = this.fen2board(character + rows[i][++indexInRow]);
}
}
return board;
}
- getPpath(b) {
- return "Emergo/" + b;
- }
-
getColor(x, y) {
- if (x >= V.size.x) return x == V.size.x ? "w" : "b";
- if (this.board[x][y].charCodeAt(0) < 97) return 'w';
+ if (x >= this.size.x)
+ return x == this.size.x ? "w" : "b";
+ if (this.board[x][y].charCodeAt(0) < 97)
+ return 'w';
return 'b';
}
- getPiece() {
- return V.PAWN; //unused
- }
-
- static IsGoodFen(fen) {
- if (!ChessRules.IsGoodFen(fen)) return false;
- const fenParsed = V.ParseFen(fen);
- // 3) Check reserves
- if (
- !fenParsed.reserve ||
- !fenParsed.reserve.match(/^([0-9]{1,2},?){2,2}$/)
- ) {
- return false;
- }
- return true;
- }
-
- static ParseFen(fen) {
- const fenParts = fen.split(" ");
- return Object.assign(
- ChessRules.ParseFen(fen),
- { reserve: fenParts[3] }
- );
+ getPiece(x, y) {
+ return this.board[x][y];
}
- static get size() {
+ get size() {
return { x: 9, y: 9 };
}
- static GenRandInitFen() {
- return "9/9/9/9/9/9/9/9/9 w 0 12,12";
- }
-
- getFen() {
- return super.getFen() + " " + this.getReserveFen();
+ genRandInitBaseFen() {
+ return { fen: "9/9/9/9/9/9/9/9/9 w 0 12,12", o: {} };
}
- getFenForRepeat() {
- return super.getFenForRepeat() + "_" + this.getReserveFen();
- }
+ static get ReserveArray() {
+ // Piece type doesn't matter
+ return ['@']; //TODO ::
- getReserveFen() {
- return (
- (!this.reserve["w"] ? 0 : this.reserve["w"][V.PAWN]) + "," +
- (!this.reserve["b"] ? 0 : this.reserve["b"][V.PAWN])
- );
- }
- getReservePpath(index, color) {
- return "Emergo/" + (color == 'w' ? 'A' : 'a') + '@';
- }
- static get RESERVE_PIECES() {
- return [V.PAWN]; //only array length matters
}
- setOtherVariables(fen) {
- const reserve =
- V.ParseFen(fen).reserve.split(",").map(x => parseInt(x, 10));
- this.reserve = { w: null, b: null };
- if (reserve[0] > 0) this.reserve['w'] = { [V.PAWN]: reserve[0] };
- if (reserve[1] > 0) this.reserve['b'] = { [V.PAWN]: reserve[1] };
+ setOtherVariables(fenParsed) {
+ super.setOtherVariables(fenParsed);
// Local stack of captures during a turn (squares + directions)
this.captures = [ [] ];
}
atLeastOneCaptureFrom([x, y], color, forbiddenStep) {
- for (let s of V.steps[V.BISHOP]) {
+ for (let s of super.pieces()['b'].both[0].steps) {
if (
!forbiddenStep ||
(s[0] != -forbiddenStep[0] || s[1] != -forbiddenStep[1])
) {
const [i, j] = [x + s[0], y + s[1]];
if (
- V.OnBoard(i + s[0], j + s[1]) &&
- this.board[i][j] != V.EMPTY &&
+ this.onBoard(i + s[0], j + s[1]) &&
+ this.board[i][j] != "" &&
this.getColor(i, j) != color &&
- this.board[i + s[0]][j + s[1]] == V.EMPTY
+ this.board[i + s[0]][j + s[1]] == ""
) {
return true;
}
captures[L-1].square, color, captures[L-1].step)
);
}
- for (let i = 0; i < V.size.x; i++) {
- for (let j=0; j< V.size.y; j++) {
+ for (let i = 0; i < this.size.x; i++) {
+ for (let j=0; j< this.size.y; j++) {
if (
- this.board[i][j] != V.EMPTY &&
+ this.board[i][j] != "" &&
this.getColor(i, j) == color &&
this.atLeastOneCaptureFrom([i, j], color)
) {
res = [i];
maxLength = caps[i].length;
}
- else if (caps[i].length == maxLength) res.push(i);
+ else if (caps[i].length == maxLength)
+ res.push(i);
}
return res;
};
let res = [];
const L = locSteps.length;
const lastStep = (L > 0 ? locSteps[L-1] : null);
- for (let s of V.steps[V.BISHOP]) {
- if (!!lastStep && s[0] == -lastStep[0] && s[1] == -lastStep[1]) continue;
+ for (let s of super.pieces()['b'].both[0].steps) {
+ if (!!lastStep && s[0] == -lastStep[0] && s[1] == -lastStep[1])
+ continue;
const [i, j] = [x + s[0], y + s[1]];
if (
- V.OnBoard(i + s[0], j + s[1]) &&
- this.board[i + s[0]][j + s[1]] == V.EMPTY &&
- this.board[i][j] != V.EMPTY &&
+ this.onBoard(i + s[0], j + s[1]) &&
+ this.board[i + s[0]][j + s[1]] == "" &&
+ this.board[i][j] != "" &&
this.getColor(i, j) != color
) {
const move = this.getBasicMove([x, y], [i + s[0], j + s[1]], [i, j]);
locSteps.push(s);
- V.PlayOnBoard(this.board, move);
+ this.playOnBoard(move);
const nextRes =
this.getLongestCaptures_aux([i + s[0], j + s[1]], color, locSteps);
res.push(1 + nextRes);
locSteps.pop();
- V.UndoOnBoard(this.board, move);
+ this.undoOnBoard(move);
}
}
- if (res.length == 0) return 0;
+ if (res.length == 0)
+ return 0;
return Math.max(...res);
}
let res = [];
const L = locSteps.length;
const lastStep = (L > 0 ? locSteps[L-1] : null);
- for (let s of V.steps[V.BISHOP]) {
- if (!!lastStep && s[0] == -lastStep[0] && s[1] == -lastStep[1]) continue;
+ for (let s of super.pieces()['b'].both[0].steps) {
+ if (!!lastStep && s[0] == -lastStep[0] && s[1] == -lastStep[1])
+ continue;
const [i, j] = [x + s[0], y + s[1]];
if (
- V.OnBoard(i + s[0], j + s[1]) &&
- this.board[i + s[0]][j + s[1]] == V.EMPTY &&
- this.board[i][j] != V.EMPTY &&
+ this.onBoard(i + s[0], j + s[1]) &&
+ this.board[i + s[0]][j + s[1]] == "" &&
+ this.board[i][j] != "" &&
this.getColor(i, j) != color
) {
const move = this.getBasicMove([x, y], [i + s[0], j + s[1]], [i, j]);
locSteps.push(s);
- V.PlayOnBoard(this.board, move);
+ this.playOnBoard(move);
const stepRes =
this.getLongestCaptures_aux([i + s[0], j + s[1]], color, locSteps);
res.push({ step: s, length: 1 + stepRes });
locSteps.pop();
- V.UndoOnBoard(this.board, move);
+ this.undoOnBoard(move);
}
}
return this.maxLengthIndices(res).map(i => res[i]);;
);
}
else {
- for (let i = 0; i < V.size.x; i++) {
- for (let j=0; j < V.size.y; j++) {
+ for (let i = 0; i < this.size.x; i++) {
+ for (let j=0; j < this.size.y; j++) {
if (
- this.board[i][j] != V.EMPTY &&
+ this.board[i][j] != "" &&
this.getColor(i, j) == color
) {
let locSteps = [];
const firstCodes = (color == 'w' ? [65, 97] : [97, 65]);
const cpCapt = this.board[capt[0]][capt[1]];
let count1 = [cp1.charCodeAt(0) - firstCodes[0], -1];
- if (cp1[1] != '@') count1[1] = cp1.charCodeAt(1) - firstCodes[0];
+ if (cp1[1] != '@')
+ count1[1] = cp1.charCodeAt(1) - firstCodes[0];
let countC = [cpCapt.charCodeAt(0) - firstCodes[1], -1];
- if (cpCapt[1] != '@') countC[1] = cpCapt.charCodeAt(1) - firstCodes[1];
+ if (cpCapt[1] != '@')
+ countC[1] = cpCapt.charCodeAt(1) - firstCodes[1];
count1[1]++;
countC[0]--;
let colorChange = false,
colorChange = true;
countC = [countC[1], -1];
}
- else captVanish = true;
+ else
+ captVanish = true;
}
const incPrisoners = String.fromCharCode(firstCodes[0] + count1[1]);
let mv = new Move({
return mv;
}
- getReserveMoves(x) {
- const color = this.turn;
- if (!this.reserve[color] || this.atLeastOneCapture(color)) return [];
+
+// TODO: + style
+ getSquareColorClass(x, y) {
+ return ((x+y) % 2 == 0 ? "dark-square": "light-square");
+ }
+
+
+
+
+ getDropMovesFrom([c, p]) {
+ const color = c;
+ if (!this.reserve[color] || this.atLeastOneCapture(color))
+ return [];
let moves = [];
+ const oppCol = C.GetOppTurn(color);
const shadowPiece =
- this.reserve[V.GetOppCol(color)] == null
- ? this.reserve[color][V.PAWN] - 1
+ !this.reserve[oppCol]
+ ? this.reserve[color]['p'] - 1
: 0;
const appearColor = String.fromCharCode(
(color == 'w' ? 'A' : 'a').charCodeAt(0) + shadowPiece);
new Move({
appear: [ new PiPo({ x: i, y: j, c: appearColor, p: '@' }) ],
vanish: [],
- start: { x: V.size.x + (color == 'w' ? 0 : 1), y: 0 }
+ start: { x: this.size.x + (color == 'w' ? 0 : 1), y: 0 }
})
);
};
- const oppCol = V.GetOppCol(color);
const opponentCanCapture = this.atLeastOneCapture(oppCol);
- for (let i = 0; i < V.size.x; i++) {
- for (let j = i % 2; j < V.size.y; j += 2) {
+ for (let i = 0; i < this.size.x; i++) {
+ for (let j = i % 2; j < this.size.y; j += 2) {
if (
- this.board[i][j] == V.EMPTY &&
+ this.board[i][j] == "" &&
// prevent playing on central square at move 1:
(this.movesCount >= 1 || i != 4 || j != 4)
) {
- if (opponentCanCapture) addMove([i, j]);
+ if (opponentCanCapture)
+ addMove([i, j]);
else {
let canAddMove = true;
- for (let s of V.steps[V.BISHOP]) {
+ for (let s of super.pieces()['b'].both[0].steps) {
if (
- V.OnBoard(i + s[0], j + s[1]) &&
- V.OnBoard(i - s[0], j - s[1]) &&
- this.board[i + s[0]][j + s[1]] != V.EMPTY &&
- this.board[i - s[0]][j - s[1]] == V.EMPTY &&
+ this.onBoard(i + s[0], j + s[1]) &&
+ this.onBoard(i - s[0], j - s[1]) &&
+ this.board[i + s[0]][j + s[1]] != "" &&
+ this.board[i - s[0]][j - s[1]] == "" &&
this.getColor(i + s[0], j + s[1]) == oppCol
) {
canAddMove = false;
break;
}
}
- if (canAddMove) addMove([i, j]);
+ if (canAddMove)
+ addMove([i, j]);
}
}
}
return moves;
}
- getPotentialMovesFrom([x, y], longestCaptures) {
- if (x >= V.size.x) {
- if (longestCaptures.length == 0) return this.getReserveMoves(x);
+ getPossibleMovesFrom([x, y], longestCaptures) {
+ if (x >= this.size.x) {
+ if (longestCaptures.length == 0)
+ return this.getReserveMoves(x);
return [];
}
const color = this.turn;
- if (!!this.reserve[color] && !this.atLeastOneCapture(color)) return [];
+ if (!!this.reserve[color] && !this.atLeastOneCapture(color))
+ return [];
const L0 = this.captures.length;
const captures = this.captures[L0 - 1];
const L = captures.length;
// Just search simple moves:
for (let s of V.steps[V.BISHOP]) {
const [i, j] = [x + s[0], y + s[1]];
- if (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY)
+ if (this.onBoard(i, j) && this.board[i][j] == "")
moves.push(this.getBasicMove([x, y], [i, j]));
}
return moves;
}
- getAllValidMoves() {
- const color = this.turn;
- const longestCaptures = this.getAllLongestCaptures(color);
- let potentialMoves = [];
- for (let i = 0; i < V.size.x; i++) {
- for (let j = 0; j < V.size.y; j++) {
- if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) {
- Array.prototype.push.apply(
- potentialMoves,
- this.getPotentialMovesFrom([i, j], longestCaptures)
- );
- }
- }
- }
- // Add reserve moves
- potentialMoves = potentialMoves.concat(
- this.getReserveMoves(V.size.x + (color == "w" ? 0 : 1))
- );
- return potentialMoves;
- }
-
- getPossibleMovesFrom([x, y]) {
+ getPotentialMovesFrom([x, y]) {
const longestCaptures = this.getAllLongestCaptures(this.getColor(x, y));
- return this.getPotentialMovesFrom([x, y], longestCaptures);
+ return this.getPossibleMovesFrom([x, y], longestCaptures);
}
filterValid(moves) {
return moves;
}
- getCheckSquares() {
- return [];
- }
-
play(move) {
const color = this.turn;
move.turn = color; //for undo
}
}
- undo(move) {
- V.UndoOnBoard(this.board, move);
- if (!move.notTheEnd) {
- this.turn = move.turn;
- this.movesCount--;
- this.captures.pop();
- }
- if (move.vanish.length == 0) {
- const color = (move.appear[0].c == 'A' ? 'w' : 'b');
- const firstCode = (color == 'w' ? 65 : 97);
- const reserveCount = move.appear[0].c.charCodeAt() - firstCode + 1;
- if (!this.reserve[color]) this.reserve[color] = { [V.PAWN]: 0 };
- this.reserve[color][V.PAWN] += reserveCount;
- }
- else if (move.vanish.length == 2) {
- const L0 = this.captures.length;
- let captures = this.captures[L0 - 1];
- captures.pop();
- }
- }
-
atLeastOneMove() {
const color = this.turn;
- if (this.atLeastOneCapture(color)) return true;
- for (let i = 0; i < V.size.x; i++) {
- for (let j = 0; j < V.size.y; j++) {
- if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) {
- const moves = this.getPotentialMovesFrom([i, j], []);
- if (moves.length > 0) return true;
+ if (this.atLeastOneCapture(color))
+ return true;
+ for (let i = 0; i < this.size.x; i++) {
+ for (let j = 0; j < this.size.y; j++) {
+ if (this.board[i][j] != "" && this.getColor(i, j) == color) {
+ const moves = this.getPossibleMovesFrom([i, j], []);
+ if (moves.length > 0)
+ return true;
}
}
}
+
+
+ // TODO: adapt
const reserveMoves =
- this.getReserveMoves(V.size.x + (this.turn == "w" ? 0 : 1));
+ this.getReserveMoves(this.size.x + (this.turn == "w" ? 0 : 1));
return (reserveMoves.length > 0);
}
+
+
getCurrentScore() {
const color = this.turn;
+ const testColorCode = (c) => {
+ return (c <= 90 && color == 'w') || (c >= 97 && color == 'b');
+ };
// If no pieces on board + reserve, I lose
- if (!!this.reserve[color]) return "*";
- let atLeastOnePiece = false;
- outerLoop: for (let i=0; i < V.size.x; i++) {
- for (let j=0; j < V.size.y; j++) {
- if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) {
- atLeastOnePiece = true;
- break outerLoop;
- }
- }
- }
- if (!atLeastOnePiece) return (color == 'w' ? "0-1" : "1-0");
- if (!this.atLeastOneMove()) return "1/2";
+ if (!!this.reserve[color])
+ return "*";
+ const atLeastOnePiece = this.board.some(row => row.some(cell => {
+ return cell != "" && testColorCode(cell.charCodeAt(0));
+ });
+ if (!atLeastOnePiece)
+ return (color == 'w' ? "0-1" : "1-0");
+ if (!this.atLeastOneMove())
+ return "1/2";
return "*";
}
- getComputerMove() {
- // Random mover for now (TODO)
- const color = this.turn;
- let mvArray = [];
- let mv = null;
- while (this.turn == color) {
- const moves = this.getAllValidMoves();
- mv = moves[randInt(moves.length)];
- mvArray.push(mv);
- this.play(mv);
- }
- for (let i = mvArray.length - 1; i >= 0; i--) this.undo(mvArray[i]);
- return (mvArray.length > 1 ? mvArray : mvArray[0]);
- }
-
- getNotation(move) {
- if (move.vanish.length == 0) return "@" + V.CoordsToSquare(move.end);
- const L0 = this.captures.length;
- if (this.captures[L0 - 1].length > 0) return V.CoordsToSquare(move.end);
- return V.CoordsToSquare(move.start) + V.CoordsToSquare(move.end);
- }
-
};