Compare commits

...

2 Commits

12 changed files with 214 additions and 181 deletions

4
.gitignore vendored
View File

@ -3,7 +3,3 @@ nimcache/
nimblecache/ nimblecache/
htmldocs/ htmldocs/
bin bin
Chess/nimfish/nimfishpkg/resources/Pohl.epd
Chess/nimfish/nimfishpkg/resources/*.pgn
# Python
__pycache__

12
Chess/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# ---> Nim
nimcache/
nimblecache/
htmldocs/
bin
nimfish/nimfishpkg/resources/*.epd
nimfish/nimfishpkg/resources/*.pgn
# Python
__pycache__
fast-chess
log.txt
config.json

View File

@ -10,4 +10,4 @@ Just run `nimble install`
# Testing # Testing
Just run `nimble test`: sit back, relax, get yourself a cup of coffee and wait for it to finish :) Just run `nimble test`: sit back, relax, get yourself a cup of coffee and wait for it to finish :)

View File

@ -3,3 +3,4 @@
-d:danger -d:danger
--passL:"-flto" --passL:"-flto"
--passC:"-Ofast -flto -march=native -mtune=native" --passC:"-Ofast -flto -march=native -mtune=native"
--maxLoopIterationsVM:100000000

View File

@ -13,7 +13,6 @@
# limitations under the License. # limitations under the License.
import nimfishpkg/tui import nimfishpkg/tui
import nimfishpkg/misc
import nimfishpkg/movegen import nimfishpkg/movegen
import nimfishpkg/bitboards import nimfishpkg/bitboards
import nimfishpkg/moves import nimfishpkg/moves
@ -24,12 +23,9 @@ import nimfishpkg/position
import nimfishpkg/board import nimfishpkg/board
export tui, misc, movegen, bitboards, moves, pieces, magics, rays, position, board export tui, movegen, bitboards, moves, pieces, magics, rays, position, board
when isMainModule: when isMainModule:
basicTests()
setControlCHook(proc () {.noconv.} = quit(0)) setControlCHook(proc () {.noconv.} = quit(0))
quit(commandLoop()) quit(commandLoop())

View File

@ -27,7 +27,7 @@ import zobrist
export pieces, position, bitboards, moves, magics, rays export pieces, position, bitboards, moves, magics, rays, zobrist
@ -255,17 +255,15 @@ func countPieces*(self: Chessboard, piece: Piece): int {.inline.} =
return self.countPieces(piece.kind, piece.color) return self.countPieces(piece.kind, piece.color)
func getOccupancyFor*(self: Chessboard, color: PieceColor): Bitboard = func getOccupancyFor*(self: Chessboard, color: PieceColor): Bitboard {.inline.} =
## Get the occupancy bitboard for every piece of the given color ## Get the occupancy bitboard for every piece of the given color
result = Bitboard(0) result = self.position.getOccupancyFor(color)
for b in self.position.pieces[color][]:
result = result or b
func getOccupancy*(self: Chessboard): Bitboard {.inline.} = func getOccupancy*(self: Chessboard): Bitboard {.inline.} =
## Get the occupancy bitboard for every piece on ## Get the occupancy bitboard for every piece on
## the chessboard ## the chessboard
result = self.getOccupancyFor(Black) or self.getOccupancyFor(White) result = self.position.getOccupancy()
func getPawnAttacks*(self: Chessboard, square: Square, attacker: PieceColor): Bitboard {.inline.} = func getPawnAttacks*(self: Chessboard, square: Square, attacker: PieceColor): Bitboard {.inline.} =
@ -591,15 +589,15 @@ proc toFEN*(self: Chessboard): string =
proc drawByRepetition*(self: Chessboard): bool = proc drawByRepetition*(self: Chessboard): bool =
## Returns whether the current position is a draw ## Returns whether the current position is a draw
## by repetition ## by repetition
# Naive version. TODO: Improve # TODO: Improve this
var i = self.positions.high() var i = self.positions.high()
var count = 0 var count = 0
while i > 0: while i > 0:
if count == 2:
self.position.repetitionDraw = true
return true
if self.position.zobristKey == self.positions[i].zobristKey: if self.position.zobristKey == self.positions[i].zobristKey:
inc(count) inc(count)
if count == 2:
self.position.repetitionDraw = true
return true
dec(i) dec(i)
@ -620,7 +618,7 @@ proc hash*(self: Chessboard) =
self.position.zobristKey = self.position.zobristKey xor getQueenSideCastlingKey(White) self.position.zobristKey = self.position.zobristKey xor getQueenSideCastlingKey(White)
if self.position.castlingAvailability[Black.int].king: if self.position.castlingAvailability[Black.int].king:
self.position.zobristKey = self.position.zobristKey xor getKingSideCastlingKey(Black) self.position.zobristKey = self.position.zobristKey xor getKingSideCastlingKey(Black)
if self.position.castlingAvailability[Black.int].king: if self.position.castlingAvailability[Black.int].queen:
self.position.zobristKey = self.position.zobristKey xor getQueenSideCastlingKey(Black) self.position.zobristKey = self.position.zobristKey xor getQueenSideCastlingKey(Black)
if self.position.enPassantSquare != nullSquare(): if self.position.enPassantSquare != nullSquare():

View File

@ -1,132 +0,0 @@
# Copyright 2024 Mattia Giambirtone & All Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## Miscellaneous stuff
import board
import std/strformat
import std/strutils
proc testPiece(piece: Piece, kind: PieceKind, color: PieceColor) =
doAssert piece.kind == kind and piece.color == color, &"expected piece of kind {kind} and color {color}, got {piece.kind} / {piece.color} instead"
proc testPieceCount(board: Chessboard, kind: PieceKind, color: PieceColor, count: int) =
let pieces = board.countPieces(kind, color)
doAssert pieces == count, &"expected {count} pieces of kind {kind} and color {color}, got {pieces} instead"
proc testPieceBitboard(bitboard: Bitboard, squares: seq[Square]) =
var i = 0
for square in bitboard:
doAssert squares[i] == square, &"squares[{i}] != bitboard[i]: {squares[i]} != {square}"
inc(i)
if i != squares.len():
doAssert false, &"bitboard.len() ({i}) != squares.len() ({squares.len()})"
const fens = staticRead("../../tests/all.txt").splitLines()
proc basicTests* =
for fen in fens:
doAssert fen == newChessboardFromFEN(fen).toFEN()
var b = newDefaultChessboard()
# Ensure correct number of pieces
testPieceCount(b, Pawn, White, 8)
testPieceCount(b, Pawn, Black, 8)
testPieceCount(b, Knight, White, 2)
testPieceCount(b, Knight, Black, 2)
testPieceCount(b, Bishop, White, 2)
testPieceCount(b, Bishop, Black, 2)
testPieceCount(b, Rook, White, 2)
testPieceCount(b, Rook, Black, 2)
testPieceCount(b, Queen, White, 1)
testPieceCount(b, Queen, Black, 1)
testPieceCount(b, King, White, 1)
testPieceCount(b, King, Black, 1)
# Ensure pieces are in the correct squares. This is testing the FEN
# parser
# Pawns
for loc in ["a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2"]:
testPiece(b.getPiece(loc), Pawn, White)
for loc in ["a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7"]:
testPiece(b.getPiece(loc), Pawn, Black)
# Rooks
testPiece(b.getPiece("a1"), Rook, White)
testPiece(b.getPiece("h1"), Rook, White)
testPiece(b.getPiece("a8"), Rook, Black)
testPiece(b.getPiece("h8"), Rook, Black)
# Knights
testPiece(b.getPiece("b1"), Knight, White)
testPiece(b.getPiece("g1"), Knight, White)
testPiece(b.getPiece("b8"), Knight, Black)
testPiece(b.getPiece("g8"), Knight, Black)
# Bishops
testPiece(b.getPiece("c1"), Bishop, White)
testPiece(b.getPiece("f1"), Bishop, White)
testPiece(b.getPiece("c8"), Bishop, Black)
testPiece(b.getPiece("f8"), Bishop, Black)
# Kings
testPiece(b.getPiece("e1"), King, White)
testPiece(b.getPiece("e8"), King, Black)
# Queens
testPiece(b.getPiece("d1"), Queen, White)
testPiece(b.getPiece("d8"), Queen, Black)
# Ensure our bitboards match with the board
let
whitePawns = b.getBitboard(Pawn, White)
whiteKnights = b.getBitboard(Knight, White)
whiteBishops = b.getBitboard(Bishop, White)
whiteRooks = b.getBitboard(Rook, White)
whiteQueens = b.getBitboard(Queen, White)
whiteKing = b.getBitboard(King, White)
blackPawns = b.getBitboard(Pawn, Black)
blackKnights = b.getBitboard(Knight, Black)
blackBishops = b.getBitboard(Bishop, Black)
blackRooks = b.getBitboard(Rook, Black)
blackQueens = b.getBitboard(Queen, Black)
blackKing = b.getBitboard(King, Black)
whitePawnSquares = @[makeSquare(6'i8, 0'i8), makeSquare(6, 1), makeSquare(6, 2), makeSquare(6, 3), makeSquare(6, 4), makeSquare(6, 5), makeSquare(6, 6), makeSquare(6, 7)]
whiteKnightSquares = @[makeSquare(7'i8, 1'i8), makeSquare(7, 6)]
whiteBishopSquares = @[makeSquare(7'i8, 2'i8), makeSquare(7, 5)]
whiteRookSquares = @[makeSquare(7'i8, 0'i8), makeSquare(7, 7)]
whiteQueenSquares = @[makeSquare(7'i8, 3'i8)]
whiteKingSquares = @[makeSquare(7'i8, 4'i8)]
blackPawnSquares = @[makeSquare(1'i8, 0'i8), makeSquare(1, 1), makeSquare(1, 2), makeSquare(1, 3), makeSquare(1, 4), makeSquare(1, 5), makeSquare(1, 6), makeSquare(1, 7)]
blackKnightSquares = @[makeSquare(0'i8, 1'i8), makeSquare(0, 6)]
blackBishopSquares = @[makeSquare(0'i8, 2'i8), makeSquare(0, 5)]
blackRookSquares = @[makeSquare(0'i8, 0'i8), makeSquare(0, 7)]
blackQueenSquares = @[makeSquare(0'i8, 3'i8)]
blackKingSquares = @[makeSquare(0'i8, 4'i8)]
testPieceBitboard(whitePawns, whitePawnSquares)
testPieceBitboard(whiteKnights, whiteKnightSquares)
testPieceBitboard(whiteBishops, whiteBishopSquares)
testPieceBitboard(whiteRooks, whiteRookSquares)
testPieceBitboard(whiteQueens, whiteQueenSquares)
testPieceBitboard(whiteKing, whiteKingSquares)
testPieceBitboard(blackPawns, blackPawnSquares)
testPieceBitboard(blackKnights, blackKnightSquares)
testPieceBitboard(blackBishops, blackBishopSquares)
testPieceBitboard(blackRooks, blackRookSquares)
testPieceBitboard(blackQueens, blackQueenSquares)
testPieceBitboard(blackKing, blackKingSquares)

View File

@ -14,8 +14,9 @@
## Move generation logic ## Move generation logic
when not defined(danger): import std/strformat
import std/strformat import std/tables
import std/strutils
import bitboards import bitboards
@ -25,10 +26,9 @@ import pieces
import moves import moves
import position import position
import rays import rays
import misc
export bitboards, magics, pieces, moves, position, rays, misc, board export bitboards, magics, pieces, moves, position, rays, board
@ -455,3 +455,142 @@ proc unmakeMove*(self: Chessboard) =
self.position = self.positions.pop() self.position = self.positions.pop()
self.update() self.update()
self.hash() self.hash()
## Testing stuff
proc testPiece(piece: Piece, kind: PieceKind, color: PieceColor) =
doAssert piece.kind == kind and piece.color == color, &"expected piece of kind {kind} and color {color}, got {piece.kind} / {piece.color} instead"
proc testPieceCount(board: Chessboard, kind: PieceKind, color: PieceColor, count: int) =
let pieces = board.countPieces(kind, color)
doAssert pieces == count, &"expected {count} pieces of kind {kind} and color {color}, got {pieces} instead"
proc testPieceBitboard(bitboard: Bitboard, squares: seq[Square]) =
var i = 0
for square in bitboard:
doAssert squares[i] == square, &"squares[{i}] != bitboard[i]: {squares[i]} != {square}"
inc(i)
if i != squares.len():
doAssert false, &"bitboard.len() ({i}) != squares.len() ({squares.len()})"
const testFens = staticRead("../../tests/all.txt").splitLines()
const benchFens = staticRead("../../tests/all.txt").splitLines()
proc basicTests* =
for fen in testFens:
doAssert fen == newChessboardFromFEN(fen).toFEN()
for fen in benchFens:
var
board = newChessboardFromFEN(fen)
hashes = newTable[ZobristKey, Move]()
moves = newMoveList()
board.generateMoves(moves)
for move in moves:
board.makeMove(move)
let
currentFEN = board.toFEN()
pos = board.position
key = pos.zobristKey
board.unmakeMove()
doAssert not hashes.contains(key), &"{fen} has zobrist collisions {move} -> {hashes[key]}"
hashes[key] = move
var board = newDefaultChessboard()
# Ensure correct number of pieces
testPieceCount(board, Pawn, White, 8)
testPieceCount(board, Pawn, Black, 8)
testPieceCount(board, Knight, White, 2)
testPieceCount(board, Knight, Black, 2)
testPieceCount(board, Bishop, White, 2)
testPieceCount(board, Bishop, Black, 2)
testPieceCount(board, Rook, White, 2)
testPieceCount(board, Rook, Black, 2)
testPieceCount(board, Queen, White, 1)
testPieceCount(board, Queen, Black, 1)
testPieceCount(board, King, White, 1)
testPieceCount(board, King, Black, 1)
# Ensure pieces are in the correct squares. This is testing the FEN
# parser
# Pawns
for loc in ["a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2"]:
testPiece(board.getPiece(loc), Pawn, White)
for loc in ["a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7"]:
testPiece(board.getPiece(loc), Pawn, Black)
# Rooks
testPiece(board.getPiece("a1"), Rook, White)
testPiece(board.getPiece("h1"), Rook, White)
testPiece(board.getPiece("a8"), Rook, Black)
testPiece(board.getPiece("h8"), Rook, Black)
# Knights
testPiece(board.getPiece("b1"), Knight, White)
testPiece(board.getPiece("g1"), Knight, White)
testPiece(board.getPiece("b8"), Knight, Black)
testPiece(board.getPiece("g8"), Knight, Black)
# Bishops
testPiece(board.getPiece("c1"), Bishop, White)
testPiece(board.getPiece("f1"), Bishop, White)
testPiece(board.getPiece("c8"), Bishop, Black)
testPiece(board.getPiece("f8"), Bishop, Black)
# Kings
testPiece(board.getPiece("e1"), King, White)
testPiece(board.getPiece("e8"), King, Black)
# Queens
testPiece(board.getPiece("d1"), Queen, White)
testPiece(board.getPiece("d8"), Queen, Black)
# Ensure our bitboards match with the board
let
whitePawns = board.getBitboard(Pawn, White)
whiteKnights = board.getBitboard(Knight, White)
whiteBishops = board.getBitboard(Bishop, White)
whiteRooks = board.getBitboard(Rook, White)
whiteQueens = board.getBitboard(Queen, White)
whiteKing = board.getBitboard(King, White)
blackPawns = board.getBitboard(Pawn, Black)
blackKnights = board.getBitboard(Knight, Black)
blackBishops = board.getBitboard(Bishop, Black)
blackRooks = board.getBitboard(Rook, Black)
blackQueens = board.getBitboard(Queen, Black)
blackKing = board.getBitboard(King, Black)
whitePawnSquares = @[makeSquare(6'i8, 0'i8), makeSquare(6, 1), makeSquare(6, 2), makeSquare(6, 3), makeSquare(6, 4), makeSquare(6, 5), makeSquare(6, 6), makeSquare(6, 7)]
whiteKnightSquares = @[makeSquare(7'i8, 1'i8), makeSquare(7, 6)]
whiteBishopSquares = @[makeSquare(7'i8, 2'i8), makeSquare(7, 5)]
whiteRookSquares = @[makeSquare(7'i8, 0'i8), makeSquare(7, 7)]
whiteQueenSquares = @[makeSquare(7'i8, 3'i8)]
whiteKingSquares = @[makeSquare(7'i8, 4'i8)]
blackPawnSquares = @[makeSquare(1'i8, 0'i8), makeSquare(1, 1), makeSquare(1, 2), makeSquare(1, 3), makeSquare(1, 4), makeSquare(1, 5), makeSquare(1, 6), makeSquare(1, 7)]
blackKnightSquares = @[makeSquare(0'i8, 1'i8), makeSquare(0, 6)]
blackBishopSquares = @[makeSquare(0'i8, 2'i8), makeSquare(0, 5)]
blackRookSquares = @[makeSquare(0'i8, 0'i8), makeSquare(0, 7)]
blackQueenSquares = @[makeSquare(0'i8, 3'i8)]
blackKingSquares = @[makeSquare(0'i8, 4'i8)]
testPieceBitboard(whitePawns, whitePawnSquares)
testPieceBitboard(whiteKnights, whiteKnightSquares)
testPieceBitboard(whiteBishops, whiteBishopSquares)
testPieceBitboard(whiteRooks, whiteRookSquares)
testPieceBitboard(whiteQueens, whiteQueenSquares)
testPieceBitboard(whiteKing, whiteKingSquares)
testPieceBitboard(blackPawns, blackPawnSquares)
testPieceBitboard(blackKnights, blackKnightSquares)
testPieceBitboard(blackBishops, blackBishopSquares)
testPieceBitboard(blackRooks, blackRookSquares)
testPieceBitboard(blackQueens, blackQueenSquares)
testPieceBitboard(blackKing, blackKingSquares)
when isMainModule:
basicTests()

View File

@ -84,6 +84,8 @@ proc toSquare*(s: string): Square {.discardable.} =
proc toAlgebraic*(square: Square): string {.inline.} = proc toAlgebraic*(square: Square): string {.inline.} =
## Converts a square from our internal rank/file ## Converts a square from our internal rank/file
## notation to a square in algebraic notation ## notation to a square in algebraic notation
if square == nullSquare():
return "null"
let let
file = char('a'.uint8 + (square.uint64 and 7)) file = char('a'.uint8 + (square.uint64 and 7))
rank = char('1'.uint8 + ((square.uint64 div 8) xor 7)) rank = char('1'.uint8 + ((square.uint64 div 8) xor 7))

View File

@ -19,7 +19,7 @@ import zobrist
type type
Position* = object Position* = ref object
## A chess position ## A chess position
# Castling availability. This just keeps track # Castling availability. This just keeps track
@ -80,4 +80,17 @@ func getBitboard*(self: Position, kind: PieceKind, color: PieceColor): Bitboard
func getBitboard*(self: Position, piece: Piece): Bitboard = func getBitboard*(self: Position, piece: Piece): Bitboard =
## Returns the positional bitboard for the given piece type ## Returns the positional bitboard for the given piece type
return self.getBitboard(piece.kind, piece.color) return self.getBitboard(piece.kind, piece.color)
func getOccupancyFor*(self: Position, color: PieceColor): Bitboard =
## Get the occupancy bitboard for every piece of the given color
result = Bitboard(0)
for b in self.pieces[color][]:
result = result or b
func getOccupancy*(self: Position): Bitboard {.inline.} =
## Get the occupancy bitboard for every piece on
## the chessboard
result = self.getOccupancyFor(Black) or self.getOccupancyFor(White)

View File

@ -176,9 +176,14 @@ proc qsearch(self: SearchManager, ply: uint8, alpha, beta: Score): Score =
for move in moves: for move in moves:
self.board.doMove(move) self.board.doMove(move)
inc(self.nodeCount) inc(self.nodeCount)
# Find the best move for us (worst move var score: Score
# for our opponent, hence the negative sign) if self.board.position.halfMoveClock >= 100 or self.board.position.repetitionDraw:
var score = -self.qsearch(ply + 1, -beta, -alpha) # Drawing by repetition is *bad*
score = Score(0)
else:
# Find the best move for us (worst move
# for our opponent, hence the negative sign)
score = -self.qsearch(ply + 1, -beta, -alpha)
self.board.unmakeMove() self.board.unmakeMove()
bestScore = max(score, bestScore) bestScore = max(score, bestScore)
if score >= beta: if score >= beta:
@ -198,18 +203,20 @@ proc search(self: SearchManager, depth, ply: int, alpha, beta: Score): Score {.d
## Simple negamax search with alpha-beta pruning ## Simple negamax search with alpha-beta pruning
if self.shouldStop(): if self.shouldStop():
return return
let query = self.transpositionTable.get(self.board.position.zobristKey, depth.uint8) when defined(useTT):
if query.success: let query = self.transpositionTable.get(self.board.position.zobristKey, depth.uint8)
case query.entry.flag: if query.success:
of Exact: case query.entry.flag:
return query.entry.score of Exact:
of LowerBound:
if query.entry.score >= beta:
return query.entry.score
of UpperBound:
if query.entry.score <= alpha:
return query.entry.score return query.entry.score
of LowerBound:
if query.entry.score >= beta:
return query.entry.score
of UpperBound:
if query.entry.score <= alpha:
return query.entry.score
if depth == 0: if depth == 0:
# Quiescent search gain: 264.8 +/- 71.6
return self.qsearch(0, alpha, beta) return self.qsearch(0, alpha, beta)
var moves = newMoveList() var moves = newMoveList()
var depth = depth var depth = depth
@ -231,13 +238,12 @@ proc search(self: SearchManager, depth, ply: int, alpha, beta: Score): Score {.d
if ply == 0 and self.searchMoves.len() > 0 and move notin self.searchMoves: if ply == 0 and self.searchMoves.len() > 0 and move notin self.searchMoves:
continue continue
self.board.doMove(move) self.board.doMove(move)
var extension = self.getSearchExtension(move) # var extension = self.getSearchExtension(move)
let zobrist = self.board.position.zobristKey
inc(self.nodeCount) inc(self.nodeCount)
# Find the best move for us (worst move # Find the best move for us (worst move
# for our opponent, hence the negative sign) # for our opponent, hence the negative sign)
var score: Score var score: Score
var fullDepth = true #[var fullDepth = true
if extension == 0 and i >= 3 and not move.isCapture(): if extension == 0 and i >= 3 and not move.isCapture():
# Late Move Reduction: assume our move orderer did a good job, # Late Move Reduction: assume our move orderer did a good job,
# so it is not worth to look at all moves at the same depth equally. # so it is not worth to look at all moves at the same depth equally.
@ -245,12 +251,12 @@ proc search(self: SearchManager, depth, ply: int, alpha, beta: Score): Score {.d
# it at full depth # it at full depth
const reduction = 1 const reduction = 1
score = -self.search(depth - 1 - reduction, ply + 1, -beta, -alpha) score = -self.search(depth - 1 - reduction, ply + 1, -beta, -alpha)
fullDepth = score > alpha fullDepth = score > alpha]#
if fullDepth:
score = -self.search(depth - 1 + extension, ply + 1, -beta, -alpha)
if self.board.position.halfMoveClock >= 100 or self.board.position.repetitionDraw: if self.board.position.halfMoveClock >= 100 or self.board.position.repetitionDraw:
# Drawing by repetition is *bad* # Drawing by repetition is *bad*
score = Score(0) score = Score(0)
#if fullDepth:
score = -self.search(depth - 1 #[+ extension]#, ply + 1, -beta, -alpha)
self.board.unmakeMove() self.board.unmakeMove()
# When a search is cancelled or times out, we need # When a search is cancelled or times out, we need
# to make sure the entire call stack unwinds back # to make sure the entire call stack unwinds back
@ -259,7 +265,8 @@ proc search(self: SearchManager, depth, ply: int, alpha, beta: Score): Score {.d
return return
bestScore = max(score, bestScore) bestScore = max(score, bestScore)
let nodeType = if score >= beta: LowerBound elif score <= alpha: UpperBound else: Exact let nodeType = if score >= beta: LowerBound elif score <= alpha: UpperBound else: Exact
self.transpositionTable.store(depth.uint8, score, zobrist, nodeType) when defined(useTT):
self.transpositionTable.store(depth.uint8, score, self.board.position.zobristKey, nodeType)
if nodeType == LowerBound: if nodeType == LowerBound:
# score >= beta # score >= beta
# This move was too good for us, opponent will not search it # This move was too good for us, opponent will not search it

View File

@ -271,8 +271,8 @@ proc parseUCICommand(session: UCISession, command: string): UCICommand =
return session.handleUCIGoCommand(cmd) return session.handleUCIGoCommand(cmd)
of "setoption": of "setoption":
result = UCICommand(kind: SetOption) result = UCICommand(kind: SetOption)
inc(current)
while current < cmd.len(): while current < cmd.len():
inc(current)
case cmd[current]: case cmd[current]:
of "name": of "name":
inc(current) inc(current)
@ -282,6 +282,7 @@ proc parseUCICommand(session: UCISession, command: string): UCICommand =
result.value = cmd[current] result.value = cmd[current]
else: else:
discard discard
inc(current)
else: else:
# Unknown UCI commands should be ignored. Attempt # Unknown UCI commands should be ignored. Attempt
@ -333,7 +334,7 @@ proc startUCISession* =
var var
cmd: UCICommand cmd: UCICommand
cmdStr: string cmdStr: string
session = UCISession(hashTableSize: 64) session = UCISession(hashTableSize: 64, board: newDefaultChessboard())
while true: while true:
try: try:
cmdStr = readLine(stdin).strip(leading=true, trailing=true, chars={'\t', ' '}) cmdStr = readLine(stdin).strip(leading=true, trailing=true, chars={'\t', ' '})