jhlywa / chess.js

A TypeScript chess library for chess move generation/validation, piece placement/movement, and check/checkmate/draw detection
BSD 2-Clause "Simplified" License
3.68k stars 889 forks source link

Force turn #62

Open kleelof opened 10 years ago

kleelof commented 10 years ago

Hello,

Before calling the .moves() function, is it possible to set the turn to black or white?

lee

davecom commented 10 years ago

Hi lee,

Who's turn it is, is determined by the FEN that you originally pass into chess.js. You should modify the FEN if you want it to be the other side's turn. Again checkout the Wikpedia page on FENs for more information about their format which I linked to from the other issue. As far as I know there's no public API for changing the turn since that would be modifying game state in an unsafe way. However, you could dig into the private APIs to manually change the turn if you want. I think it would be much easier to just provide the FEN with the right side's turn in the first place.

Good luck, David

kleelof commented 10 years ago

Hello,

The issue is that I am trying to use the app to build a simple analysis app, so since it is not actually playing, the turn is irrelevant. Anyway, I went ahead and added my own call set_turn(). I realize this would not be useful for most uses, but it would add a new dimension to chess.js if you could make it a permanent addition to the API.

take care, lee

jhlywa commented 10 years ago

This is most likely on oversight on my part. There are a two ways to load positions into chess.js, using FEN (load()) and placing individual pieces on specific squares (put()). FEN requires a side-to-move, so no problems there, but chess.js seem to lack a mechanism to set the side-to-move when placing pieces with put(). As @davecom mentioned, this will hose the game state, so I need to do some code diving to figure out how this should best be implemented.

Thanks for the report.

Azeirah commented 9 years ago

I'm also interested in this behavior, can we get a status update?

jhlywa commented 9 years ago

If you really need this feature you could implement it outside of the chess.js API like so:

/* totally untested ... this will blow your game state/history  */
function set_turn(chess, color) {
    var tokens = chess.fen().split(' ');
    tokens[1] = color;
    chess.load(tokens.join(' '));
}
Azeirah commented 9 years ago

Inserting the following snippet into the generate_moves function after the us and them variables get declared allows users to "force a turn".

    if (typeof options !== 'undefined' && 'orientation' in options) {
      if (us !== options.orientation) {
        var temp = us;
        us       = them;
        them     = temp;
      }
    }

Using it is like this:

chess.moves({square, "a3", orientation: "w"}); // or b, if you want to look from the perspective of b
AlexeiDarmin commented 7 years ago

Improving on @jhlywa's answer and maintaining history:

My use case was I needed to retrieve the other side's potential moves without changing board state.

/* untested, seems to save history so you can continue using .undo() */
let getOpponentMoves = (symGame) => {
  let gamePGN = symGame.pgn()

    let tokens = symGame.fen().split(' ')
    tokens[1] = tokens[1] === 'w' ? 'b' : 'w'
    symGame.load(tokens.join(' '))

    let moves = symGame.moves()

    tokens = symGame.fen().split(' ')
    tokens[1] = tokens[1] === 'w' ? 'b' : 'w'
    symGame.load_pgn(gamePGN)

    return moves
}
codyatwork commented 5 years ago

Is there still a way to do this? Whenever I try the snippet posted load(fen) returns false because the FEN validation fails.

dax006 commented 5 years ago
setTurn: function(newTurn) {
    turn = newTurn;
},

Will lead to some strange behavior. Calling .moves() after it seems to not catch the most recent move, and sometimes pawns appear on empty spaces. I guess it is trying to flip the board but gets confused if the turn() does not match?

Zenith2198 commented 3 years ago

Using @jhlywa's answer and also changing the en passant flag got this working for me! The en passant flag is at index 3 of the FEN, so the function should look like

function swapTurn() {
    let tokens = chess.fen().split(" ");
    tokens[1] = chess.turn() === "b" ? "w" : "b";
    tokens[3] = "-";
    chess.load(tokens.join(" "));
}

Without changing the en passant flag, the FEN can fail to load when white pushes a pawn two spaces and then black skips the turn.