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"
|
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"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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():
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue