const move = moveOrSquare;
const s = move.start,
e = move.end;
- // NOTE: next conditions are first for Crazyhouse, and last for Checkered
- // TODO: Checkered exceptions are too weird and should move in its own file.
if (
- move.vanish.length > 0 &&
Math.abs(s.x - e.x) == 2 &&
s.y == e.y &&
- move.vanish[0].p == V.PAWN &&
- ["w", "b"].includes(move.vanish[0].c)
+ move.appear[0].p == V.PAWN
) {
return {
x: (s.x + e.x) / 2,
const firstRank = color == "w" ? sizeX - 1 : 0;
const startRank = color == "w" ? sizeX - 2 : 1;
const lastRank = color == "w" ? 0 : sizeX - 1;
- const pawnColor = this.getColor(x, y); //can be different for checkered
// NOTE: next condition is generally true (no pawn on last rank)
if (x + shiftX >= 0 && x + shiftX < sizeX) {
for (let piece of finalPieces) {
moves.push(
this.getBasicMove([x, y], [x + shiftX, y], {
- c: pawnColor,
+ c: color,
p: piece
})
);
for (let piece of finalPieces) {
moves.push(
this.getBasicMove([x, y], [x + shiftX, y + shiftY], {
- c: pawnColor,
+ c: color,
p: piece
})
);
// After move is played, update variables + flags
updateVariables(move) {
let piece = undefined;
- // TODO: update variables before move is played, and just use this.turn ?
+ // TODO: update variables before move is played, and just use this.turn?
// (doesn't work in general, think MarseilleChess)
let c = undefined;
if (move.vanish.length >= 1) {
tr(
v-for="g in sortedGames"
@click="$emit('show-game',g)"
- :class="{'my-turn': g.myTurn}"
+ :class="{'my-turn': !!g.myTurn}"
)
td {{ g.vname }}
td {{ player_s(g) }}
},
computed: {
sortedGames: function() {
- // Show in order: games where it's my turn, my running games, my games, other games
+ // Show in order: it's my turn, running games, completed games
let minCreated = Number.MAX_SAFE_INTEGER;
let maxCreated = 0;
- const isMyTurn = (g, myColor) => {
- const rem = g.movesCount % 2;
- return (
- (rem == 0 && myColor == "w") ||
- (rem == 1 && myColor == "b")
- );
- };
- let augmentedGames = this.games
- .filter(g => !this.deleted[g.id])
- .map(g => {
- let priority = 0;
- let myColor = undefined;
- if (
- g.players.some(
- p => p.uid == this.st.user.id || p.sid == this.st.user.sid
- )
- ) {
- priority++;
- myColor =
- g.players[0].uid == this.st.user.id ||
- g.players[0].sid == this.st.user.sid
- ? "w"
- : "b";
- if (g.score == "*") {
- priority++;
- if (g.turn == myColor || isMyTurn(g, myColor)) priority++;
- }
- }
- if (g.created < minCreated) minCreated = g.created;
- if (g.created > maxCreated) maxCreated = g.created;
- return Object.assign({}, g, {
- priority: priority,
- myTurn: priority == 3,
- myColor: myColor
- });
- });
+ this.games.forEach(g => {
+ if (g.created < minCreated) minCreated = g.created;
+ if (g.created > maxCreated) maxCreated = g.created;
+ });
const deltaCreated = maxCreated - minCreated;
- return augmentedGames.sort((g1, g2) => {
+ return this.games.sort((g1, g2) => {
return (
g2.priority - g1.priority + (g2.created - g1.created) / deltaCreated
);
});
- }
+ },
},
methods: {
player_s: function(g) {
let cpArr = arr.map(e => e);
for (let index = 0; index < n; index++) {
const rand = randInt(index, arr.length);
- const temp = cpArr[index];
- cpArr[index] = cpArr[rand];
- cpArr[rand] = temp;
+ [ cpArr[index], cpArr[rand] ] = [ cpArr[rand], cpArr[index] ];
}
return cpArr.slice(0, n);
}
import { ChessRules, PiPo } from "@/base_rules";
export const VariantRules = class AtomicRules extends ChessRules {
+ getEpSquare(moveOrSquare) {
+ if (typeof moveOrSquare !== "object" || move.appear.length > 0)
+ return super.getEpSquare(moveOrSquare);
+ // Capturing move: no en-passant
+ return undefined;
+ }
+
getPotentialMovesFrom([x, y]) {
let moves = super.getPotentialMovesFrom([x, y]);
this.pawnFlags = flags[1];
}
+ getEpSquare(moveOrSquare) {
+ if (typeof moveOrSquare !== "object" || move.appear[0].c != 'c')
+ return super.getEpSquare(moveOrSquare);
+ // Checkered move: no en-passant
+ return undefined;
+ }
+
getCmove(move) {
if (move.appear[0].c == "c" && move.vanish.length == 1)
return { start: move.start, end: move.end };
return moves;
}
+ getPotentialPawnMoves([x, y]) {
+ const color = this.turn;
+ let moves = [];
+ const [sizeX, sizeY] = [V.size.x, V.size.y];
+ const shiftX = color == "w" ? -1 : 1;
+ const startRank = color == "w" ? sizeX - 2 : 1;
+ const lastRank = color == "w" ? 0 : sizeX - 1;
+ const pawnColor = this.getColor(x, y); //can be checkered
+
+ const finalPieces =
+ x + shiftX == lastRank
+ ? [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]
+ : [V.PAWN];
+ if (this.board[x + shiftX][y] == V.EMPTY) {
+ // One square forward
+ for (let piece of finalPieces) {
+ moves.push(
+ this.getBasicMove([x, y], [x + shiftX, y], {
+ c: pawnColor,
+ p: piece
+ })
+ );
+ }
+ if (
+ x == startRank &&
+ this.board[x + 2 * shiftX][y] == V.EMPTY
+ ) {
+ // Two squares jump
+ moves.push(this.getBasicMove([x, y], [x + 2 * shiftX, y]));
+ }
+ }
+ // Captures
+ for (let shiftY of [-1, 1]) {
+ if (
+ y + shiftY >= 0 &&
+ y + shiftY < sizeY &&
+ this.board[x + shiftX][y + shiftY] != V.EMPTY &&
+ this.canTake([x, y], [x + shiftX, y + shiftY])
+ ) {
+ for (let piece of finalPieces) {
+ moves.push(
+ this.getBasicMove([x, y], [x + shiftX, y + shiftY], {
+ c: pawnColor,
+ p: piece
+ })
+ );
+ }
+ }
+ }
+
+ // En passant
+ const Lep = this.epSquares.length;
+ const epSquare = this.epSquares[Lep - 1]; //always at least one element
+ if (
+ !!epSquare &&
+ epSquare.x == x + shiftX &&
+ Math.abs(epSquare.y - y) == 1
+ ) {
+ let enpassantMove = this.getBasicMove([x, y], [epSquare.x, epSquare.y]);
+ enpassantMove.vanish.push({
+ x: x,
+ y: epSquare.y,
+ p: "p",
+ c: this.getColor(x, epSquare.y)
+ });
+ moves.push(enpassantMove);
+ }
+
+ return moves;
+ }
+
canIplay(side, [x, y]) {
return side == this.turn && [side, "c"].includes(this.getColor(x, y));
}
});
}
+ getEpSquare(moveOrSquare) {
+ if (typeof moveOrSquare !== "object" || move.vanish.length > 0)
+ return super.getEpSquare(moveOrSquare);
+ // Landing move: no en-passant
+ return undefined;
+ }
+
static GenRandInitFen(randomness) {
return ChessRules.GenRandInitFen(randomness) + " 0000000000 -";
}
});
}
+ getEpSquare(moveOrSquare) {
+ if (typeof moveOrSquare !== "object" || move.vanish.length > 0)
+ return super.getEpSquare(moveOrSquare);
+ // Landing move: no en-passant
+ return undefined;
+ }
+
static GenRandInitFen(randomness) {
return ChessRules.GenRandInitFen(randomness) + " 0000000000";
}
import { ChessRules, PiPo, Move } from "@/base_rules";
export const VariantRules = class RifleRules extends ChessRules {
+ getEpSquare(moveOrSquare) {
+ if (typeof moveOrSquare !== "object" || move.appear.length > 0)
+ return super.getEpSquare(moveOrSquare);
+ // Capturing move: no en-passant
+ return undefined;
+ }
+
getBasicMove([sx, sy], [ex, ey], tr) {
let mv = new Move({
appear: [],
response.games.map(g => {
const type = this.classifyObject(g);
const vname = this.getVname(g.vid);
- return Object.assign({}, g, { type: type, vname: vname });
+ return Object.assign(
+ {},
+ g,
+ {
+ type: type,
+ vname: vname,
+ priority: g.score == "*" ? 1 : 0 //for display
+ }
+ );
})
);
}
let newGame = game;
newGame.type = this.classifyObject(game);
newGame.vname = this.getVname(game.vid);
+ newGame.priority = 0;
if (!game.score)
- //if new game from Hall
+ // New game from Hall
newGame.score = "*";
+ if (newGame.score == "*") newGame.priority++;
newGame.rids = [game.rid];
delete newGame["rid"];
this.games.push(newGame);
}
case "result": {
let g = this.games.find(g => g.id == data.gid);
- if (!!g) g.score = data.score;
+ if (!!g) {
+ g.score = data.score;
+ g.priority = 0;
+ }
break;
}
case "startgame": {
}
this.send("deletechallenge", { data: c.id });
},
+ // TODO: if several players click same challenge at the same time: problem
clickChallenge: async function(c) {
const myChallenge =
c.from.sid == this.st.user.sid || //live
created: function() {
GameStorage.getAll(true, localGames => {
localGames.forEach(g => g.type = "live");
+ this.decorate(localGames);
this.liveGames = localGames;
});
if (this.st.user.id > 0) {
return !g["deletedBy" + mySide];
});
serverGames.forEach(g => g.type = "corr");
+ this.decorate(serverGames);
this.corrGames = serverGames;
}
}
.classList.add("somethingnew");
}
},
+ // Called at loading to augment games with priority + myTurn infos
+ decorate: function(games) {
+ games.forEach(g => {
+ g.priority = 0;
+ if (g.score == "*") {
+ g.priority++;
+ const myColor =
+ (g.type == "corr" && g.players[0].uid == this.st.user.id) ||
+ (g.type == "live" && g.players[0].sid == this.st.user.sid)
+ ? 'w'
+ : 'b';
+ const rem = g.movesCount % 2;
+ if ((rem == 0 && myColor == 'w') || (rem == 1 && myColor == 'b')) {
+ g.myTurn = true;
+ g.priority++;
+ }
+ }
+ });
+ },
socketMessageListener: function(msg) {
const data = JSON.parse(msg.data);
+ let gamesArrays = {
+ "corr": this.corrGames,
+ "live": this.liveGames
+ };
switch (data.code) {
- // NOTE: no need to increment movesCount: unused if turn is provided
case "notifyturn":
case "notifyscore": {
const info = data.data;
- let games =
- !!parseInt(info.gid)
- ? this.corrGames
- : this.liveGames;
- let g = games.find(g => g.id == info.gid);
+ const type = (!!parseInt(info.gid) ? "corr" : "live");
+ let game = gamesArrays[type].find(g => g.id == info.gid);
// "notifything" --> "thing":
const thing = data.code.substr(6);
- this.$set(g, thing, info[thing]);
- this.tryShowNewsIndicator(g.type);
+ game[thing] = info[thing];
+ if (thing == "score") game.priority = 0;
+ else {
+ game.priority = 3 - game.priority; //toggle turn
+ game.myTurn = !game.myTurn;
+ }
+ this.$forceUpdate();
+ this.tryShowNewsIndicator(type);
break;
}
case "notifynewgame": {
// if unlucky and newgame right after connect:
const v = this.st.variants.find(v => v.id == gameInfo.vid);
const vname = !!v ? v.name : "";
- const type = gameInfo.cadence.indexOf('d') >= 0 ? "corr": "live";
- const game = Object.assign(
+ const type = (gameInfo.cadence.indexOf('d') >= 0 ? "corr": "live");
+ let game = Object.assign(
{
vname: vname,
type: type,
score: "*",
- turn: "w"
+ created: Date.now()
},
gameInfo
);
- // TODO: the new game isn't sorted. Maybe apply a different strategy:
- // 1) Sort all at loading,
- // 2) Insert in place when new games arrive,
- // 3) Change position when score or turn change.
- // And GameList just show list unsorted.
- this[type + "Games"].unshift(game);
+ // Compute priority:
+ game.priority = 1; //at least: my running game
+ if (
+ (type == "corr" && game.players[0].uid == this.st.user.id) ||
+ (type == "live" && game.players[0].sid == this.st.user.sid)
+ ) {
+ game.priority++;
+ game.myTurn = true;
+ }
+ gamesArrays[type].push(game);
+ this.$forceUpdate();
this.tryShowNewsIndicator(type);
break;
}
this.conn.addEventListener("close", this.socketCloseListener);
},
showGame: function(game) {
- // TODO: "isMyTurn" is duplicated (see GameList component). myColor also
- const isMyTurn = (g) => {
- if (g.score != "*") return false;
- const myColor =
- g.players[0].uid == this.st.user.id ||
- g.players[0].sid == this.st.user.sid
- ? "w"
- : "b";
- if (!!g.turn) return g.turn == myColor;
- const rem = g.movesCount % 2;
- return (
- (rem == 0 && myColor == "w") ||
- (rem == 1 && myColor == "b")
- );
- };
- if (game.type == "live" || !isMyTurn(game)) {
+ if (game.type == "live" || !game.myTurn) {
this.$router.push("/game/" + game.id);
return;
}
// It's my turn in this game. Are there others?
let nextIds = "";
- let otherCorrGamesMyTurn = this.corrGames.filter(
- g => g.id != game.id && isMyTurn(g));
+ let otherCorrGamesMyTurn = this.corrGames.filter(g =>
+ g.id != game.id && !!g.myTurn);
if (otherCorrGamesMyTurn.length > 0) {
nextIds += "/?next=[";
otherCorrGamesMyTurn.forEach(g => { nextIds += g.id + ","; });