Fixed package errors and embedded magics into the build
This commit is contained in:
parent
19ad46bbda
commit
fcbe15f275
|
@ -0,0 +1,8 @@
|
|||
# A chess engine written in nim
|
||||
|
||||
For now, that's about it.
|
||||
|
||||
|
||||
# Installation
|
||||
|
||||
Just run `nimble install`
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue