Files
chess-front/fen.js

132 lines
3.8 KiB
JavaScript

import { LETTER_PIECE_NAME_LOOKUP, PIECE_NAME_LETTER_LOOKUP, files } from './constants.js'
const parseCastlingAvailability = castlingAvailability => {
let castlingAvailabilityObj = {whiteKing: false, whiteQueen: false, blackKing: false, blackQueen: false}
if (castlingAvailability !== "-") {
for (const char of castlingAvailability) {
if (char === "K") {
castlingAvailabilityObj.whiteKing = true
} else if (char === "Q") {
castlingAvailabilityObj.whiteQueen = true
} else if (char === "k") {
castlingAvailabilityObj.blackKing = true
} else if (char === "q") {
castlingAvailabilityObj.blackQueen = true
}
}
}
return castlingAvailabilityObj
}
const castlingAvailabilityToFEN = castlingAvailabilityObj => {
let FEN = ""
if (castlingAvailabilityObj.whiteKing) {
FEN += "K"
}
if (castlingAvailabilityObj.whiteQueen) {
FEN += "Q"
}
if (castlingAvailabilityObj.blackKing) {
FEN += "k"
}
if (castlingAvailabilityObj.blackQueen) {
FEN += "q"
}
FEN = FEN || "-"
return FEN
}
const parsePositions = positions => {
let board = {}
const ranks = positions.split('/')
ranks.forEach((tokens, rankIndex) => {
rankIndex = Math.abs(rankIndex - 7)
let rank = rankIndex + 1
Array.from(tokens).forEach((token, fileIndex) => {
let parsed = parseInt(token)
if (isNaN(parsed)) {
let file = files[fileIndex]
board[`${file}${rank}`] = LETTER_PIECE_NAME_LOOKUP[token]
}
})
})
return board
}
const boardToFEN = board => {
let FEN = ""
let blanks = 0
let files = Array.from("abcdefgh")
let ranks = Array.from("12345678").reverse()
ranks.forEach((rank, rankIndex) => {
if (rankIndex) {
if (blanks) {
FEN += blanks
blanks = 0
}
FEN += "/"
}
files.forEach((file, charIndex) => {
let cell = `${file}${rank}`
if (board.hasOwnProperty(cell)) {
if (blanks) {
// it's insane this works, JS casts `blanks` to a String
FEN += blanks
blanks = 0
}
FEN += PIECE_NAME_LETTER_LOOKUP[board[cell]]
} else {
blanks++
}
})
})
return FEN
}
export const toFEN = gameState => {
let {
board,
whoseTurn,
castlingAvailability,
enPassantTargetSquare,
halfMoveClock,
fullMoveNum
} = gameState
enPassantTargetSquare = !enPassantTargetSquare ? "-" : enPassantTargetSquare
return [
boardToFEN(board),
whoseTurn[0],
castlingAvailabilityToFEN(castlingAvailability),
enPassantTargetSquare,
halfMoveClock,
fullMoveNum,
].join(" ")
}
export const getGameStateFromFEN = FEN => {
// https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation
let [
positions,
whoseTurn,
castlingAvailability,
enPassantTargetSquare,
halfMoveClock,
fullMoveNum
] = FEN.split(" ")
whoseTurn = whoseTurn === "w" ? "white" : "black"
enPassantTargetSquare = enPassantTargetSquare === "-" ? null : enPassantTargetSquare
const castlingAvailabilityObj = parseCastlingAvailability(castlingAvailability)
fullMoveNum = parseInt(fullMoveNum)
halfMoveClock = parseInt(halfMoveClock)
return {
board: parsePositions(positions),
whoseTurn,
fullMoveNum,
halfMoveClock,
enPassantTargetSquare,
castlingAvailability: castlingAvailabilityObj,
}
}