diff --git a/Chess/nimfish/nimfishpkg/search.nim b/Chess/nimfish/nimfishpkg/search.nim index 28bb94e..3e4adbe 100644 --- a/Chess/nimfish/nimfishpkg/search.nim +++ b/Chess/nimfish/nimfishpkg/search.nim @@ -127,6 +127,8 @@ proc log(self: SearchManager, depth: int) = elapsedMsec = elapsed.inMilliseconds.uint64 nps = 1000 * (self.nodeCount div max(elapsedMsec, 1)) var logMsg = &"info depth {depth} time {elapsedMsec} nodes {self.nodeCount} nps {nps}" + if not self.transpositionTable.isNil(): + logMsg &= &" hashfull {self.transpositionTable.getFillEstimate()}" if self.bestMoveRoot != nullMove(): logMsg &= &" score cp {self.bestRootScore} pv {self.bestMoveRoot.toAlgebraic()}" echo logMsg @@ -268,8 +270,8 @@ proc search(self: SearchManager, depth, ply: int, alpha, beta: Score): Score {.d var score: Score var fullDepth = true when defined(searchLMR): - if extension == 0 and i >= 3 and not move.isCapture(): - # Late Move Reduction: assume our move orderer did a good job, + if extension == 0 and i >= 5 and not move.isCapture(): + # Late Move Reductions: assume our move orderer did a good job, # so it is not worth it to look at all moves at the same depth equally. # If this move turns out to be better than we expected, we'll re-search # it at full depth diff --git a/Chess/nimfish/nimfishpkg/transpositions.nim b/Chess/nimfish/nimfishpkg/transpositions.nim index 69e0aca..e8f598b 100644 --- a/Chess/nimfish/nimfishpkg/transpositions.nim +++ b/Chess/nimfish/nimfishpkg/transpositions.nim @@ -44,16 +44,41 @@ type bestMove*: Move TTable* = ref object + ## A transposition table data: seq[TTEntry] + when defined(debug): + hits: uint64 + occupancy: uint64 + collisions: uint64 size: uint64 +func size*(self: TTable): uint64 = self.size + +when defined(debug): + func hits*(self: TTable): uint64 = self.hits + func collisions*(self: TTable): uint64 = self.collisions + func occupancy*(self: TTable): uint64 = self.occupancy + + +func getFillEstimate*(self: TTable): uint64 = + # For performance reasons, we estimate the occupancy by + # looking at the first 1000 entries in the table. Why 1000? + # Because the "hashfull" info message is conventionally not a + # percentage, but rather a per...millage? It's in thousandths + # rather than hundredths is the point, don't ask me why + for i in 0..999: + if self.data[i].hash != ZobristKey(0): + inc(result) + + proc newTranspositionTable*(size: uint64): TTable = ## Initializes a new transposition table of ## size bytes new(result) let numEntries = size div sizeof(TTEntry).uint64 result.data = newSeq[TTEntry](numEntries) + result.size = numEntries func getIndex(self: TTable, key: ZobristKey): uint64 = @@ -71,7 +96,15 @@ func getIndex(self: TTable, key: ZobristKey): uint64 = func store*(self: TTable, depth: uint8, score: Score, hash: ZobristKey, bestMove: Move, flag: TTentryFlag) = ## Stores an entry in the transposition table - self.data[self.getIndex(hash)] = TTEntry(flag: flag, score: int16(score), hash: hash, depth: depth, bestMove: bestMove) + when defined(debug): + let idx = self.getIndex(hash) + if self.data[idx].hash != ZobristKey(0): + inc(self.collisions) + else: + inc(self.occupancy) + self.data[idx] = TTEntry(flag: flag, score: int16(score), hash: hash, depth: depth, bestMove: bestMove) + else: + self.data[self.getIndex(hash)] = TTEntry(flag: flag, score: int16(score), hash: hash, depth: depth, bestMove: bestMove) proc get*(self: TTable, hash: ZobristKey, depth: uint8): tuple[success: bool, entry: TTEntry] = @@ -83,6 +116,9 @@ proc get*(self: TTable, hash: ZobristKey, depth: uint8): tuple[success: bool, en ## it's true result.entry = self.data[self.getIndex(hash)] result.success = result.entry.hash == hash and result.entry.depth >= depth + when defined(debug): + if result.success: + inc(self.hits) proc get*(self: TTable, hash: ZobristKey): tuple[success: bool, entry: TTEntry] = @@ -92,4 +128,7 @@ proc get*(self: TTable, hash: ZobristKey): tuple[success: bool, entry: TTEntry] ## or other anomaly: the result should be considered ## invalid unless it's true result.entry = self.data[self.getIndex(hash)] - result.success = result.entry.hash == hash \ No newline at end of file + result.success = result.entry.hash == hash + when defined(debug): + if result.success: + inc(self.hits) \ No newline at end of file diff --git a/Chess/nimfish/nimfishpkg/uci.nim b/Chess/nimfish/nimfishpkg/uci.nim index d309cda..490079e 100644 --- a/Chess/nimfish/nimfishpkg/uci.nim +++ b/Chess/nimfish/nimfishpkg/uci.nim @@ -354,10 +354,10 @@ proc startUCISession* = session.board = newDefaultChessboard() of Go: when defined(useTT): - if session.transpositionTable.isNil(): + if session.transpositionTable.isNil() or session.transpositionTable.size() == 0: + session.transpositionTable = newTranspositionTable(session.hashTableSize * 1024 * 1024) if session.debug: echo &"info string created {session.hashTableSize} MiB TT" - session.transpositionTable = newTranspositionTable(session.hashTableSize * 1024 * 1024) session.searchThread = new Thread[tuple[session: UCISession, command: UCICommand]] createThread(session.searchThread[], bestMove, (session, cmd)) if session.debug: