Fixed package errors and embedded magics into the build

This commit is contained in:
Mattia Giambirtone 2024-04-19 15:50:51 +02:00
parent 19ad46bbda
commit fcbe15f275
11 changed files with 70 additions and 81 deletions

8
Chess/README.md Normal file
View File

@ -0,0 +1,8 @@
# A chess engine written in nim
For now, that's about it.
# Installation
Just run `nimble install`

View File

@ -4,7 +4,7 @@ version = "0.1.0"
author = "nocturn9x" author = "nocturn9x"
description = "A chess engine written in nim" description = "A chess engine written in nim"
license = "Apache-2.0" license = "Apache-2.0"
srcDir = "src" srcDir = "nimfish"
binDir = "bin" binDir = "bin"
installExt = @["nim"] installExt = @["nim"]
bin = @["nimfish"] bin = @["nimfish"]
@ -12,7 +12,7 @@ bin = @["nimfish"]
# Dependencies # Dependencies
requires "nim >= 2.1.1" requires "nim >= 2.0"
requires "jsony >= 1.1.5" requires "jsony >= 1.1.5"

View File

@ -19,10 +19,12 @@ import std/math
import std/bitops import std/bitops
import src/bitboards import nimfishpkg/bitboards
import src/magics import nimfishpkg/magics
import src/pieces import nimfishpkg/pieces
import src/moves import nimfishpkg/moves
export bitboards, magics, pieces, moves
type type
@ -31,8 +33,9 @@ type
Position* = object Position* = object
## A chess position ## A chess position
# Did the rooks on either side or the king move?
castlingAvailable: tuple[white, black: tuple[queen, king: bool]] # Castling metadata. Updated on every move
castling: array[64, uint8]
# Number of half-moves that were performed # Number of half-moves that were performed
# to reach this position starting from the # to reach this position starting from the
# root of the tree # root of the tree
@ -42,7 +45,7 @@ type
# Used for the 50-move rule # Used for the 50-move rule
halfMoveClock: int8 halfMoveClock: int8
# Full move counter. Increments # Full move counter. Increments
# every 2 ply # every 2 ply (half-moves)
fullMoveCount: int8 fullMoveCount: int8
# En passant target square (see https://en.wikipedia.org/wiki/En_passant) # En passant target square (see https://en.wikipedia.org/wiki/En_passant)
enPassantSquare*: Square enPassantSquare*: Square
@ -51,13 +54,16 @@ type
turn: PieceColor turn: PieceColor
# Positional bitboards for all pieces # Positional bitboards for all pieces
pieces: tuple[white, black: tuple[king, queens, rooks, bishops, knights, pawns: Bitboard]] pieces: tuple[white, black: tuple[king, queens, rooks, bishops, knights, pawns: Bitboard]]
# Pinned pieces for each side
pins: tuple[white, black: Bitboard]
# Checking pieces
checkers: tuple[white, black: Bitboard]
ChessBoard* = ref object ChessBoard* = ref object
## A chess board object ## A chess board object
# The actual board where pieces live # The actual board where pieces live
# (flattened 8x8 matrix)
grid: array[64, Piece] grid: array[64, Piece]
# The current position # The current position
position: Position position: Position
@ -135,17 +141,17 @@ func getKingStartingSquare(color: PieceColor): Square {.inline.} =
## for the given color ## for the given color
case color: case color:
of White: of White:
return makeSquare(7, 4) return "e1".toSquare()
of Black: of Black:
return makeSquare(0, 4) return "e8".toSquare()
else: else:
discard discard
func kingSideRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 7) else: makeSquare(0, 7)) func kingSideRook(color: PieceColor): Square {.inline.} = (if color == White: "h1".toSquare() else: "h8".toSquare())
func queenSideRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 0) else: makeSquare(0, 0)) func queenSideRook(color: PieceColor): Square {.inline.} = (if color == White: "a8".toSquare() else: "a1".toSquare())
func longCastleKing(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 2) else: makeSquare(0, 5)) func longCastleKing(color: PieceColor): Square {.inline.} = (if color == White: "c1".toSquare() else: "c8".toSquare())
func shortCastleKing(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 6) else: makeSquare(0, 1)) func shortCastleKing(color: PieceColor): Square {.inline.} = (if color == White: "g1".toSquare() else: "g8".toSquare())
func longCastleRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 3) else: makeSquare(7, 5)) func longCastleRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 3) else: makeSquare(7, 5))
func shortCastleRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(0, 0) else: makeSquare(0, 2)) func shortCastleRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(0, 0) else: makeSquare(0, 2))
@ -315,19 +321,21 @@ proc newChessboardFromFEN*(fen: string): ChessBoard =
of 2: of 2:
# Castling availability # Castling availability
case c: case c:
# TODO
of '-': of '-':
# Neither side can castle anywhere: do nothing,
# as the castling metadata is set to this state
# by default
discard discard
of 'K': of 'K':
result.position.castlingAvailable.white.king = true discard
# result.position.castlingAvailable.white.king = true
of 'Q': of 'Q':
result.position.castlingAvailable.white.queen = true discard
# result.position.castlingAvailable.white.queen = true
of 'k': of 'k':
result.position.castlingAvailable.black.king = true discard
# result.position.castlingAvailable.black.king = true
of 'q': of 'q':
result.position.castlingAvailable.black.queen = true discard
# result.position.castlingAvailable.black.queen = true
else: else:
raise newException(ValueError, &"invalid FEN: unknown symbol '{c}' found in castling availability section") raise newException(ValueError, &"invalid FEN: unknown symbol '{c}' found in castling availability section")
of 3: of 3:
@ -1123,7 +1131,7 @@ proc doMove(self: ChessBoard, move: Move) =
var var
halfMoveClock = self.position.halfMoveClock halfMoveClock = self.position.halfMoveClock
fullMoveCount = self.position.fullMoveCount fullMoveCount = self.position.fullMoveCount
castlingAvailable = self.position.castlingAvailable castling = self.position.castling
enPassantTarget = nullSquare() enPassantTarget = nullSquare()
# Needed to detect draw by the 50 move rule # Needed to detect draw by the 50 move rule
if piece.kind == Pawn or move.isCapture() or move.isEnPassant(): if piece.kind == Pawn or move.isCapture() or move.isEnPassant():
@ -1159,46 +1167,14 @@ proc doMove(self: ChessBoard, move: Move) =
# else: # else:
# discard # discard
# Has a rook been captured? # Has a rook been captured?
if move.isCapture():
let captured = self.grid[move.targetSquare]
if captured.kind == Rook:
case captured.color:
of White:
if move.targetSquare == captured.color.queenSideRook():
# Queen side
castlingAvailable.white.queen = false
elif move.targetSquare == captured.color.kingSideRook():
# King side
castlingAvailable.white.king = false
of Black:
if move.targetSquare == captured.color.queenSideRook():
# Queen side
castlingAvailable.black.queen = false
elif move.targetSquare == captured.color.kingSideRook():
# King side
castlingAvailable.black.king = false
else:
# Unreachable
discard
# Has the king moved?
if piece.kind == King or move.isCastling():
# Revoke all castling rights for the moving king
case piece.color:
of White:
castlingAvailable.white.king = false
castlingAvailable.white.queen = false
of Black:
castlingAvailable.black.king = false
castlingAvailable.black.queen = false
else:
discard
# Create new position # Create new position
self.position = Position(plyFromRoot: self.position.plyFromRoot + 1, self.position = Position(plyFromRoot: self.position.plyFromRoot + 1,
halfMoveClock: halfMoveClock, halfMoveClock: halfMoveClock,
fullMoveCount: fullMoveCount, fullMoveCount: fullMoveCount,
turn: self.getSideToMove().opposite, turn: self.getSideToMove().opposite,
castlingAvailable: castlingAvailable, castling: castling,
enPassantSquare: enPassantTarget, enPassantSquare: enPassantTarget,
pieces: self.position.pieces pieces: self.position.pieces
) )
@ -1436,19 +1412,20 @@ proc toFEN*(self: ChessBoard): string =
result &= (if self.getSideToMove() == White: "w" else: "b") result &= (if self.getSideToMove() == White: "w" else: "b")
result &= " " result &= " "
# Castling availability # Castling availability
let castleWhite = self.position.castlingAvailable.white result &= "-"
let castleBlack = self.position.castlingAvailable.black # let castleWhite = self.position.castlingAvailable.white
if not (castleBlack.king or castleBlack.queen or castleWhite.king or castleWhite.queen): # let castleBlack = self.position.castlingAvailable.black
result &= "-" # if not (castleBlack.king or castleBlack.queen or castleWhite.king or castleWhite.queen):
else: # result &= "-"
if castleWhite.king: # else:
result &= "K" # if castleWhite.king:
if castleWhite.queen: # result &= "K"
result &= "Q" # if castleWhite.queen:
if castleBlack.king: # result &= "Q"
result &= "k" # if castleBlack.king:
if castleBlack.queen: # result &= "k"
result &= "q" # if castleBlack.queen:
# result &= "q"
result &= " " result &= " "
# En passant target # En passant target
if self.getEnPassantTarget() == nullSquare(): if self.getEnPassantTarget() == nullSquare():

View File

@ -332,19 +332,23 @@ when isMainModule:
let let
magicsJson = magics.toJSON() magicsJson = magics.toJSON()
movesJson = moves.toJSON() movesJson = moves.toJSON()
var path = joinPath(getCurrentDir(), "src/resources") var currentFile = currentSourcePath()
if path.lastPathPart() == "nimfish": var path = joinPath(currentFile.parentDir(), "resources")
path = joinPath("src", path)
writeFile(joinPath(path, "magics.json"), magicsJson) writeFile(joinPath(path, "magics.json"), magicsJson)
writeFile(joinPath(path, "movesets.json"), movesJson) writeFile(joinPath(path, "movesets.json"), movesJson)
echo &"Dumped data to disk (approx. {round(((len(movesJson) + len(magicsJson)) / 1024) / 1024, 2)} MiB)" echo &"Dumped data to disk (approx. {round(((len(movesJson) + len(magicsJson)) / 1024) / 1024, 2)} MiB)"
else: else:
var path = joinPath(getCurrentDir(), "src/resources") func buildPath: string {.compileTime.} =
if path.lastPathPart() == "nimfish": result = currentSourcePath()
path = joinPath("src", path) result = joinPath(result.parentDir(), "resources")
const path = buildPath()
echo "Loading magic bitboards" echo "Loading magic bitboards"
var magics = readFile(joinPath(path, "magics.json")).fromJson(TableRef[string, array[64, MagicEntry]]) const
var moves = readFile(joinPath(path, "movesets.json")).fromJson(TableRef[string, array[64, seq[Bitboard]]]) magicFile = staticRead(joinPath(path, "magics.json"))
movesFile = staticRead(joinPath(path, "movesets.json"))
var magics = magicFile.fromJson(TableRef[string, array[64, MagicEntry]])
var moves = movesFile.fromJson(TableRef[string, array[64, seq[Bitboard]]])
ROOK_MAGICS = magics["rooks"] ROOK_MAGICS = magics["rooks"]
BISHOP_MAGICS = magics["bishops"] BISHOP_MAGICS = magics["bishops"]
ROOK_MOVES = moves["rooks"] ROOK_MOVES = moves["rooks"]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long