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"
description = "A chess engine written in nim"
license = "Apache-2.0"
srcDir = "src"
srcDir = "nimfish"
binDir = "bin"
installExt = @["nim"]
bin = @["nimfish"]
@ -12,7 +12,7 @@ bin = @["nimfish"]
# Dependencies
requires "nim >= 2.1.1"
requires "nim >= 2.0"
requires "jsony >= 1.1.5"

View File

@ -19,10 +19,12 @@ import std/math
import std/bitops
import src/bitboards
import src/magics
import src/pieces
import src/moves
import nimfishpkg/bitboards
import nimfishpkg/magics
import nimfishpkg/pieces
import nimfishpkg/moves
export bitboards, magics, pieces, moves
type
@ -31,8 +33,9 @@ type
Position* = object
## 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
# to reach this position starting from the
# root of the tree
@ -42,7 +45,7 @@ type
# Used for the 50-move rule
halfMoveClock: int8
# Full move counter. Increments
# every 2 ply
# every 2 ply (half-moves)
fullMoveCount: int8
# En passant target square (see https://en.wikipedia.org/wiki/En_passant)
enPassantSquare*: Square
@ -51,13 +54,16 @@ type
turn: PieceColor
# Positional bitboards for all pieces
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
## A chess board object
# The actual board where pieces live
# (flattened 8x8 matrix)
grid: array[64, Piece]
# The current position
position: Position
@ -135,17 +141,17 @@ func getKingStartingSquare(color: PieceColor): Square {.inline.} =
## for the given color
case color:
of White:
return makeSquare(7, 4)
return "e1".toSquare()
of Black:
return makeSquare(0, 4)
return "e8".toSquare()
else:
discard
func kingSideRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 7) else: makeSquare(0, 7))
func queenSideRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 0) else: makeSquare(0, 0))
func longCastleKing(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 2) else: makeSquare(0, 5))
func shortCastleKing(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 6) else: makeSquare(0, 1))
func kingSideRook(color: PieceColor): Square {.inline.} = (if color == White: "h1".toSquare() else: "h8".toSquare())
func queenSideRook(color: PieceColor): Square {.inline.} = (if color == White: "a8".toSquare() else: "a1".toSquare())
func longCastleKing(color: PieceColor): Square {.inline.} = (if color == White: "c1".toSquare() else: "c8".toSquare())
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 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:
# Castling availability
case c:
# TODO
of '-':
# Neither side can castle anywhere: do nothing,
# as the castling metadata is set to this state
# by default
discard
of 'K':
result.position.castlingAvailable.white.king = true
discard
# result.position.castlingAvailable.white.king = true
of 'Q':
result.position.castlingAvailable.white.queen = true
discard
# result.position.castlingAvailable.white.queen = true
of 'k':
result.position.castlingAvailable.black.king = true
discard
# result.position.castlingAvailable.black.king = true
of 'q':
result.position.castlingAvailable.black.queen = true
discard
# result.position.castlingAvailable.black.queen = true
else:
raise newException(ValueError, &"invalid FEN: unknown symbol '{c}' found in castling availability section")
of 3:
@ -1123,7 +1131,7 @@ proc doMove(self: ChessBoard, move: Move) =
var
halfMoveClock = self.position.halfMoveClock
fullMoveCount = self.position.fullMoveCount
castlingAvailable = self.position.castlingAvailable
castling = self.position.castling
enPassantTarget = nullSquare()
# Needed to detect draw by the 50 move rule
if piece.kind == Pawn or move.isCapture() or move.isEnPassant():
@ -1159,46 +1167,14 @@ proc doMove(self: ChessBoard, move: Move) =
# else:
# discard
# 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
self.position = Position(plyFromRoot: self.position.plyFromRoot + 1,
halfMoveClock: halfMoveClock,
fullMoveCount: fullMoveCount,
turn: self.getSideToMove().opposite,
castlingAvailable: castlingAvailable,
castling: castling,
enPassantSquare: enPassantTarget,
pieces: self.position.pieces
)
@ -1436,19 +1412,20 @@ proc toFEN*(self: ChessBoard): string =
result &= (if self.getSideToMove() == White: "w" else: "b")
result &= " "
# Castling availability
let castleWhite = self.position.castlingAvailable.white
let castleBlack = self.position.castlingAvailable.black
if not (castleBlack.king or castleBlack.queen or castleWhite.king or castleWhite.queen):
result &= "-"
else:
if castleWhite.king:
result &= "K"
if castleWhite.queen:
result &= "Q"
if castleBlack.king:
result &= "k"
if castleBlack.queen:
result &= "q"
result &= "-"
# let castleWhite = self.position.castlingAvailable.white
# let castleBlack = self.position.castlingAvailable.black
# if not (castleBlack.king or castleBlack.queen or castleWhite.king or castleWhite.queen):
# result &= "-"
# else:
# if castleWhite.king:
# result &= "K"
# if castleWhite.queen:
# result &= "Q"
# if castleBlack.king:
# result &= "k"
# if castleBlack.queen:
# result &= "q"
result &= " "
# En passant target
if self.getEnPassantTarget() == nullSquare():

View File

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