feat(core): add fen parsing and serialization
This commit is contained in:
1 parent
7b7192a1c0
commit
c312e5d2df
1 file changed
+98
@@ -0,0 +1,98 @@
|
||||
package gambit
|
||||
|
||||
object Fen:
|
||||
val startPosition = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
|
||||
|
||||
def parse(fen: String): Position =
|
||||
val parts = fen.trim.split("\\s+")
|
||||
val pos = new Position
|
||||
var rank = 7
|
||||
for row <- parts(0).split("/") do
|
||||
var file = 0
|
||||
for ch <- row do
|
||||
if ch.isDigit then file += (ch - '0')
|
||||
else
|
||||
val piece = charToPiece(ch)
|
||||
val sq = Square.make(file, rank)
|
||||
pos.board(sq) = piece
|
||||
if (piece & 7) == Piece.King then pos.kingSquare(piece >> 3) = sq
|
||||
file += 1
|
||||
rank -= 1
|
||||
|
||||
pos.sideToMove = if parts(1) == "w" then Color.White else Color.Black
|
||||
|
||||
var castle = 0
|
||||
if parts(2) != "-" then
|
||||
for ch <- parts(2) do
|
||||
ch match
|
||||
case 'K' => castle |= Castling.WhiteKing
|
||||
case 'Q' => castle |= Castling.WhiteQueen
|
||||
case 'k' => castle |= Castling.BlackKing
|
||||
case 'q' => castle |= Castling.BlackQueen
|
||||
case _ => ()
|
||||
pos.castling = castle
|
||||
|
||||
pos.epSquare = if parts(3) == "-" then -1 else Square.fromName(parts(3))
|
||||
pos.halfmove = if parts.length > 4 then parts(4).toInt else 0
|
||||
pos.fullmove = if parts.length > 5 then parts(5).toInt else 1
|
||||
pos.hash = pos.computeHash()
|
||||
pos
|
||||
|
||||
def toFen(pos: Position): String =
|
||||
val sb = new StringBuilder
|
||||
var rank = 7
|
||||
while rank >= 0 do
|
||||
var empty = 0
|
||||
var file = 0
|
||||
while file < 8 do
|
||||
val p = pos.board(Square.make(file, rank))
|
||||
if p == Piece.Empty then empty += 1
|
||||
else
|
||||
if empty > 0 then
|
||||
sb.append(empty)
|
||||
empty = 0
|
||||
sb.append(pieceToChar(p))
|
||||
file += 1
|
||||
if empty > 0 then sb.append(empty)
|
||||
if rank > 0 then sb.append('/')
|
||||
rank -= 1
|
||||
|
||||
sb.append(' ')
|
||||
sb.append(if pos.sideToMove == Color.White then 'w' else 'b')
|
||||
sb.append(' ')
|
||||
if pos.castling == 0 then sb.append('-')
|
||||
else
|
||||
if (pos.castling & Castling.WhiteKing) != 0 then sb.append('K')
|
||||
if (pos.castling & Castling.WhiteQueen) != 0 then sb.append('Q')
|
||||
if (pos.castling & Castling.BlackKing) != 0 then sb.append('k')
|
||||
if (pos.castling & Castling.BlackQueen) != 0 then sb.append('q')
|
||||
sb.append(' ')
|
||||
sb.append(if pos.epSquare < 0 then "-" else Square.name(pos.epSquare))
|
||||
sb.append(' ')
|
||||
sb.append(pos.halfmove)
|
||||
sb.append(' ')
|
||||
sb.append(pos.fullmove)
|
||||
sb.toString
|
||||
|
||||
private def charToPiece(ch: Char): Int =
|
||||
val color = if ch.isUpper then Color.White else Color.Black
|
||||
val pieceType = ch.toLower match
|
||||
case 'p' => Piece.Pawn
|
||||
case 'n' => Piece.Knight
|
||||
case 'b' => Piece.Bishop
|
||||
case 'r' => Piece.Rook
|
||||
case 'q' => Piece.Queen
|
||||
case 'k' => Piece.King
|
||||
case _ => Piece.Empty
|
||||
Piece.make(color, pieceType)
|
||||
|
||||
private def pieceToChar(piece: Int): Char =
|
||||
val letter = Piece.typeOf(piece) match
|
||||
case Piece.Pawn => 'p'
|
||||
case Piece.Knight => 'n'
|
||||
case Piece.Bishop => 'b'
|
||||
case Piece.Rook => 'r'
|
||||
case Piece.Queen => 'q'
|
||||
case Piece.King => 'k'
|
||||
case _ => '?'
|
||||
if Piece.colorOf(piece) == Color.White then letter.toUpper else letter
|
||||
Reference in new issue
Block a user