Releases: lynx-chess/Lynx
v1.7.0
π Search
- Regular search: fail hard -> fail soft (#1039, #1040, #1041)
- QSearch: fail hard -> fail soft (#1052)
- Fail soft TT cutoffs (#1044)
- Remove
pvNode
condition for first move full search (#1045) - History pruning: quiet history (#972)
- Improve queen promotion with capture move ordering (#1061)
- Make
TranspositionTableElement.Key
anushort
instead of ashort
(#1070) - SPSA 2024-10-1 (#1074)
βοΈ Evaluation
- Enemy king related PSQTs (#924)
- Friendly and enemy king distance to passed pawn (#955)
- Passed pawns: bonus for not enemy pieces ahead (#998, #1008)
- Pawn phalanx (#1009, #1010)
- Bishop penalty: same color pawns (#1022)
- Bishop penalty: blocked central pawns (#1029)
- Checks (#1027)
- Mobility: exclude squares attacked by opponent's pawn (#958)
- Add 50 moves rule scaling, down to 50% of the score (#965)
- Improve endgame scaling with pawn count (#928)
- Bucketed passed pawns (#945)
- Index queen mobility bonus by attacks count excluding own pieces (#774)
- Tuning: use some Ethereal FRC data (#916)
- Tuning: tune at 5k epochs (50k epochs -> 10k epochs -> 5k) epochs (#1031)
β Time management
- Use expected moves to go (#996)
β‘ Speedups
- Move
Move
serialization toWriter
thread (#999) - Add a
Board
array toPosition
to track where pieces are indexed by square (#849) - Remove good old
_isFollowingPV
and_isScoringPV
(#1034) - Make
TaperedEvaluationTerm
an integer I (#935) - Add PSQT class to store
PackedPSQT
(#939) - Flatten PSQTs [][][][] (#927)
- Flatten capture history (#870)
- Pin 1 dimension arrays (#953)
- Pin attack-related arrays (#985)
- Reverse killer moves arrays (#861)
- Replace Chebyshev distance calculation with lookup table (double array) (#957)
- Refactor additional evaluations: pass piece side (#963)
- Speedup
InfoCommand.SearchResultInfo
(#984) - Make
SearchResult.Moves
an array and optimize its population (#986) - Refactor
Game.PositionHashHistory
into a private array (#991) - Remove
Position.MakeMoveCalculatingCapturedPiece
, usingPosition.Board
instead (#1021) - Only update PV table on PV nodes (#1042)
π§ Memory usage (!)
- Remove unnecessary, initial TT initializations (#989)
- Allocate TT only once, clearing it afterwards on
ucinewgame
(#990) - Avoid
static readonly
flat array initial allocations for inline arrays (#948) - Use
ArrayPool
to reduce recurrent allocations (#983) - Stop generating
logs/log-β.log
files by default (#1004) - Cache
Move.UCIString
results in aDictionary
(#1001) - Optimize
go
command parsing (#1005) - Remove unused props from
SearchResult
and re-order the ones left (#1006)
π Bug fixes
- Don't prune moves in regular search while being checkmated (#1060)
- Prevent negative checkmate scores from being lower than
EvaluationConstants.MinEval
(#1063)
Non-strength winning changes:
Relevant for testers:
- By default log files are no longer generated under
logs/
dir unless warnings or errors happen (#1004) - Lynx process' memory usage won't skyrocket to twice the expected (TT) value anymore, as it could briefly happen in the past, providing there was such memory available for it.
- Simplify
appsettings.json
(#1075)
Relevant for developers that consume the NuGet package:
- Lynx allocates way less than before when searching, which implies much lower GC pressure.
- You have control now of UCI
info
andbestmove
string allocations if you're usingSearcher
class to interact with the engine, since now the channel doesn't send the information pre-serialized (details below). - API changes:
Channel<string>
->Channel<object>
, you're now expected to invoke.ToString()
on whatever comes from the channel to print it. Alternatively, you can just consume it by checking object types (they are either strings,Lynx.Model.SearchResult
orLynx.UCI.Commands.Engine.BestMoveCommand
) (#999)- Remove
Position(Position, Move)
constructors, now you're forced to useMakeMove
/UnMakeMove
methods (#976) - Remove parameterless
Game
constructor, a fen or a parsing result is always required now (tip:Constants.InitialPositionFEN
can be used) (#980) - Make
Position.UniqueIdentifier
anulong
instead of along
(#1078)
Full Changelog: v1.6.0...v1.7.0
v1.6.0
- π Countermoves (#859)
- π Continuation history - countermove history (1 ply) (#645)
- π Don't always stop search when a mate is found (#827)
- π SPSA 2024-6-27 (#839)
- βοΈ King-bucketed PSQTs (#873 (2) -> #876 (8) -> #879 + #888 (16) -> #893 (24) -> #902 (23))
- βοΈ Escale endgame eval with pawn count (#821, #829)
- βοΈ Give bonus to pieces protected by friendly pawns and penalty to pieces attacked by opponent pawns (#830)
- βοΈ Use some Pedantic data for HCE tuning (#905)
- β‘ Avoid
stackalloc
local initialization when allocating it for movegen (#858) - β‘ Optimize
MoveGenerator.GeneratePieceCaptures()
(#846) - β‘ Micro-optimization in
MoveGenerator.IsAnyPieceMoveValid
(#845)
Non strength-winning changes:
- βοΈ Move eval parameters out of
Configuration
class, making them no longer configurable viaappsettings.json
(#889, #911) - π Make
.ToEPDString()
fully PGN/EPD compliant (#841) - π Avoid node count overflow (#835)
Full Changelog: v1.5.1...v1.6.0
v1.5.1
Full Changelog: v1.5.0...v1.5.1
v1.5.0
- π Add Futility pruning (FP) (#733)
- π LMR: allow when in check (#702)
- π LMR: reduce more if there's a TT move and a capture (#706)
- π Move RFP before NMP (#732)
- π SPSA search parameters tuning (#730, #764)
- βοΈ Remove double pawns penalty [proper SPRT pawn eval] (#746)
- βοΈ Index bishop mobility bonus by attacks count (#758)
- βοΈ Index rook mobility bonus by attacks count exluding own pieces (#768)
- βοΈ Add knight mobility bonus and index it by attacks count excluding own pieces (#775)
- βοΈ Take only pawns into account for king shield (#789)
- βοΈ Add king virtual mobility indexed by mobility count (#785)
- βοΈ Use some Stoofvlees quiet data for eval tuning (#710)
- β‘ Improve search logic (#725)
- β‘ Use optimized method to check if a move was valid (#716)
- β‘ Use a
StringBuilder
to generate UCIinfo
command (#805) - β‘ Remove option to disable TT (#720)
- β‘ Remove manual piece count during static eval (#698)
- β‘ Simplify
TaperedEvaluationTermByRank
(#757) - β‘ Simplify
TaperedEvaluationTermByCount
(#767) - β‘ Simplify Aspiration windows (#802)
- π Fix index out of range exception on max depth (#708)
- π Detect threefold repetition on
pvNode
(#796) - π Fix
Game.MakeMove
behavior on invalid moves (#804)
Non strength-winning changes:
- Add ponder support (#772)
- Generate UCI options for search parameters dynamically (#734)
- Normalize mobility values (#788)
Full Changelog: v1.4.0...v1.5.0
v1.4.0
- π Improve RFP (#652)
- π Avoid doing TT cutoffs on PV nodes (#653)
- π Use TT score as positional eval for pruning (#692)
- β Tweak pawnless endgames evaluation (#693)
- β Tweak time management (#664, #665, #667, #668, #671, #677, #691)
- β‘ Stop checking for two/threefold repetition and 50 moves draws in QSearch (#673)
- β‘ Refactor
Update50movesRule()
method (#678) - β‘ Reimplement repetition detection (#679)
- β‘ Prefetch TT entry in NegaMax search (#681)
- β‘ Remove
Position.StaticEval()
heap allocations (#683) - β‘ Force GC collection at the end of
Engine
constructor and afterucinewgame
(#685) - β‘ Use packed evaluation (#697)
- π Clear history on
newgame
(#649) - π Fix long input
position
commands parsing (#650) - π Fix engine stall when depth over 100 is reached during search (#651)
- π Don't search with fixed depth when cutechess provides 0s to move (#654)
- π Prevent illegal moves when low in time (#657)
- π Error when searching at max depth (#670)
Non strength-winning changes:
- Add
fen
UCI command (#688 - Increase max TT size from 1GB to 8GB (#669)
- π Fix behavior of consecutive
go
commands (#655)
Full Changelog: v1.3.0...v1.4.0
v1.3.0
- π Add basic (quiet) history malus/penalty (#610)
- π Add capture history (#634)
- π Update (quiet) history moves only in beta cutoffs (#608)
- π Stop clearing quiet history (#637)
- π Take quiet history into consideration for LMR (#613)
- β‘ Refactor move encoding methods and stop encoding special move flags individually (#622)
- β‘ Store captured pieces as part of the move (#604)
- β‘ Use jagged arrays (
[][]
) instead of multidimensional ones ([,]
) (#605, #606, #607) - β‘ Simplify triple repetition detection logic, removing some branching (#623)
- β‘ Make
Piece
an integer enum (#603)
Full Changelog: v1.2.0...v1.3.0
v1.2.0
- π Prune SEE bad captures in QSearch (#558)
- π Reduce SEE bad captures in regular search (#564, #571)
- π Use spsa tuned search values (#543, #553)
- βοΈ Add rook mobility to eval (#539)
- 𧬠Improve move generation: hardcode castling moves and a few calculated variables (#541)
- 𧬠Implement SEE and order bad captures after killers but before quiet moves (#554)
- β‘ Reduce TT entry size to 8 bytes (#544)
- β‘ Optimize
go
command parsing (#545) - β‘ Split
MoveGenerator.GenerateAllMoves
andMoveGenerator.GenerateCaptures
to avoid branching (#549) - β‘ Set search thread as high priority (#546)
- β‘ SEE micro-optimizations (#566)
- β‘ Use stack-allocated span for movegen (#551, #596)
- β‘ Optimize
PositionHash
(#582) - β‘ Optimize castling and en-passant moves Zobrist hashing (#577)
- β‘ Replace
EnPassantCaptureSquares
dictionary with equivalent array (#578) - β‘ Optimize FEN parsing (#581)
- β‘ Attempt to initialize
MoveGenerator
andGoCommand
asap (#576) - π Fix engine crash due to a negative calculated time to move (#555)
- π Add support for negative
wtime
andbtime
(#556) - π Enable
InvariantGlobalization
and fix crash in some Linux scenarios (#575)
Non strength-winning changes:
- Add option to run
bench
at different depths (#537)
Full Changelog: v1.1.0...v1.2.0
v1.1.0
- π Add Internal Iterative Reduction (IIR) (#507)
- π Add basic LMP (#512)
- π Improve TT replacement scheme: add required conditions for always replace (#526)
- π Add third killer move (#517, #525)
- π Use new history bonus formula based on Sirius and Berserk one (#527)
- π In case of 'fake' ponder-hit, research from depth 1 (#467)
- β Re-tune eval using some Stash data (#515)
- β‘ Avoid PEXT array initialization when PEXT isn't supported (#516)
Full Changelog: v1.0.1...v1.1.0
v1.0.1
Non strength-winning changes:
-
π Clamp static evaluation within +- checkmate limits, preventing illegal moves (and erratic behavior in general) in positions with too much material on one side (#510).
We're talking about positions here such as
QQQQQQQQ/QQQQQQQQ/QQQQQQQQ/QQQQQQQQ/QQQQQQQQ/QQQQQQQQ/QPPPPPPP/K6k b - - 0 1
, which will never happen in a real game but can be artificially set up (i.e. in lichess), so no strength change is expected in regular engine games.
Full Changelog: v1.0.0...v1.0.1
v1.0.0
Getting out from ZeroVer club now that these two conditions are met:
- Lynx has basically reached feature-parity with BBC, engine outcome of
BitBoard Chess Engine in C
YouTube playlist that helped me the most during the initial phases of Lynx development. - .NET 8 GA has been released and therefore Lynx no longer relies on pre-release SDK or library versions.
- π Rewrite NMP (#479, #482, #492, #493, #494)
- π In case of 'ponder-hit', research last depth (#466)
- π Don't clear TT move if no best move is provided: keep old one II (#478)
- β Use PSQTs tuned without explicit piece values (#425)
- β‘ Incremental move sorting (#477)
- β‘ Avoid checking lack of material in static evaluation when the phase is high enough (#490)
Full Changelog: v0.19.0...v1.0.0