From 5af363d005adc6656535cd2104ff7b025f366d6b Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Thu, 22 Dec 2016 20:22:27 +0100 Subject: [PATCH 01/71] Bump release to 0.5.0 --- Barbarossa.cabal | 2 +- Main/Barbarossa.hs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Barbarossa.cabal b/Barbarossa.cabal index 40f9575c..1fb83ef3 100644 --- a/Barbarossa.cabal +++ b/Barbarossa.cabal @@ -1,5 +1,5 @@ Name: Barbarossa -Version: 0.4.0 +Version: 0.5.0 Synopsis: UCI chess engine written in Haskell License: BSD3 License-file: LICENSE diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index d9730bd5..26db5f83 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -37,8 +37,8 @@ import Eval.FileParams (makeEvalState) progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" -progVersion = "0.4.0" -progVerSuff = "" +progVersion = "0.5.0" +progVerSuff = "to5" data Options = Options { optConfFile :: Maybe String, -- config file @@ -51,7 +51,7 @@ defaultOptions :: Options defaultOptions = Options { optConfFile = Nothing, optParams = [], - optLogging = LogNever, + optLogging = LogInfo, optAFenFile = Nothing } From f569d9b15d6d438f306250e009e02ca9c8a82f8d Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Thu, 22 Dec 2016 23:56:44 +0100 Subject: [PATCH 02/71] QS: use TT score when cutting TT score is alway from full search and is reliable, so if it contradict the static score, take care and do not prune --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 26db5f83..45c192b5 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "to5" +progVerSuff = "sts" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 84f8dea0..8f2b6c0e 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -34,13 +34,12 @@ useAspirWin = False -- Some fix search parameter scoreGrain, depthForCM, maxDepthExt, minPvDepth :: Int -useTTinPv, readTTinQS :: Bool +useTTinPv :: Bool scoreGrain = 4 -- score granularity depthForCM = 7 -- from this depth inform current move maxDepthExt = 3 -- maximum depth extension useTTinPv = False -- retrieve from TT in PV? minPvDepth = 2 -- from this depth we use alpha beta search -readTTinQS = True -- Parameters for late move reduction: lmrActive :: Bool @@ -1007,24 +1006,20 @@ trimax a b x -- PV Quiescent Search pvQSearch :: Int -> Int -> Int -> Search Int pvQSearch !a !b !c = do - -- TODO: use e as first move if legal + -- TODO: use e as first move if legal & capture -- (hdeep, tp, hsc, e, _) <- reTrieve >> lift ttRead - (hdeep, tp, hsc, _, _) - <- if readTTinQS - then reTrieve >> lift ttRead - else return (-1, undefined, undefined, undefined, undefined) - when (readTTinQS && hdeep < 0) reFail + (hdeep, tp, hsc, _, _) <- reTrieve >> lift ttRead -- tp == 1 => score >= hsc, so if hsc > a then we improved -- tp == 0 => score <= hsc, so if hsc <= asco then we fail low and -- can terminate the search - if readTTinQS && hdeep >= 0 && ( + if hdeep >= 0 && ( tp == 2 -- exact score: always good || tp == 1 && hsc >= b -- we will fail high || tp == 0 && hsc <= a -- we will fail low ) then reSucc 1 >> return (trimax a b hsc) else do - -- TODO: use hsc here too, when possible + when (hdeep < 0) reFail pos <- lift $ getPos if tacticalPos pos then do @@ -1051,7 +1046,8 @@ pvQSearch !a !b !c = do pvQLoop b nc a edges else do let !stp = staticScore pos - if stp >= b + -- what if hsc < b? + if stp >= b && (hdeep < 0 || tp == 1 || hsc >= b) then do when collectFens $ do n <- gets $ sNodes . stats @@ -1059,7 +1055,9 @@ pvQSearch !a !b !c = do return b else do !qsdelta <- lift qsDelta - if stp + qsdelta + qsDeltaMargin < a + let !a1 = a - qsdelta - qsDeltaMargin + -- what if hsc + ... > a? + if stp < a1 && (hdeep < 0 || tp == 0 || hsc <= a1) then do when collectFens $ do n <- gets $ sNodes . stats From c5e307d4983223a134abb01614c1dac0dc8e20d3 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sun, 1 Jan 2017 23:25:39 +0100 Subject: [PATCH 03/71] Rollback QS + more mid material --- Barbarossa.cabal | 9 +++++++-- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 4 ++-- Struct/Status.hs | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Barbarossa.cabal b/Barbarossa.cabal index 1fb83ef3..3d735825 100644 --- a/Barbarossa.cabal +++ b/Barbarossa.cabal @@ -14,6 +14,10 @@ Flag sse42 Description: Enable SSE4.2 support Default: False +Flag ddump + Description: Enable ddumps + Default: True + Executable Barbarossa Main-is: Main/Barbarossa.hs Build-depends: @@ -64,11 +68,12 @@ Executable Barbarossa -fspec-constr-count=24 -funfolding-use-threshold=32 -fno-warn-tabs - -- -ddump-simpl -ddump-to-file -dsuppress-all -dsuppress-uniques - -- -ddump-opt-cmm -ddump-asm CPP-Options: -DSMSTRICT if flag(sse42) GHC-Options: -msse4.2 + if flag(ddump) + GHC-Options: -ddump-simpl -ddump-to-file -dsuppress-all -dsuppress-uniques + -ddump-opt-cmm -ddump-asm -- Executable Evolve -- Main-is: Main/Evolve.hs diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 45c192b5..1bb891a5 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "sts" +progVerSuff = "mmm" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 8f2b6c0e..fc015ba2 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -1047,7 +1047,7 @@ pvQSearch !a !b !c = do else do let !stp = staticScore pos -- what if hsc < b? - if stp >= b && (hdeep < 0 || tp == 1 || hsc >= b) + if stp >= b then do when collectFens $ do n <- gets $ sNodes . stats @@ -1057,7 +1057,7 @@ pvQSearch !a !b !c = do !qsdelta <- lift qsDelta let !a1 = a - qsdelta - qsDeltaMargin -- what if hsc + ... > a? - if stp < a1 && (hdeep < 0 || tp == 0 || hsc <= a1) + if stp < a1 then do when collectFens $ do n <- gets $ sNodes . stats diff --git a/Struct/Status.hs b/Struct/Status.hs index dd8cef84..d9f20a64 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -169,7 +169,7 @@ collectEvalParams (s, v) ep = lookApply s v ep [ instance CollectParams EvalWeights where type CollectFor EvalWeights = EvalWeights npColInit = EvalWeights { - ewMaterialDiff = tme 8 8, + ewMaterialDiff = tme 9 8, ewKingSafe = tme 1 0, ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, From 560a82c251424c1eaf9d95b808eb70e4c1c00f89 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 12:40:54 +0100 Subject: [PATCH 04/71] Eval weights with SGD: 5M pos, shift 0.1 --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 60 +++++++++++++++++++++++----------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 1bb891a5..21fd7d2f 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "mmm" +progVerSuff = "v11a" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index d9f20a64..ffe57e90 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -116,8 +116,8 @@ data EvalWeights instance CollectParams EvalParams where type CollectFor EvalParams = EvalParams npColInit = EvalParams { - epMovingMid = 160, -- after Clop optimisation - epMovingEnd = 130, -- with 3700 games at 15+0.25 s + epMovingMid = 144, -- after Clop optimisation + epMovingEnd = 144, -- with 3700 games at 15+0.25 s epMaterMinor = 1, epMaterRook = 4, epMaterQueen = 13, @@ -169,42 +169,42 @@ collectEvalParams (s, v) ep = lookApply s v ep [ instance CollectParams EvalWeights where type CollectFor EvalWeights = EvalWeights npColInit = EvalWeights { - ewMaterialDiff = tme 9 8, + ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 171 202, - ewRookOpen = tme 219 221, - ewRookConn = tme 96 78, - ewMobilityKnight = tme 50 71, -- Evalo 200 steps: - ewMobilityBishop = tme 57 33, -- length 10, depth 6, batch 128 - ewMobilityRook = tme 28 26, + ewRookHOpen = tme 176 192, + ewRookOpen = tme 224 212, + ewRookConn = tme 103 57, + ewMobilityKnight = tme 50 69, -- Evalo 200 steps: + ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 + ewMobilityRook = tme 27 27, ewMobilityQueen = tme 4 6, - ewCenterPAtts = tme 84 68, - ewCenterNAtts = tme 49 45, - ewCenterBAtts = tme 57 39, - ewCenterRAtts = tme 10 34, - ewCenterQAtts = tme 4 59, - ewCenterKAtts = tme 0 53, + ewCenterPAtts = tme 83 68, + ewCenterNAtts = tme 48 46, + ewCenterBAtts = tme 56 41, + ewCenterRAtts = tme 10 33, + ewCenterQAtts = tme 5 58, + ewCenterKAtts = tme 1 52, ewSpace = tme 1 0, ewAdvAtts = tme 3 16, - ewIsolPawns = tme (-42) (-122), - ewIsolPassed = tme (-60) (-160), - ewBackPawns = tme (-120) (-180), - ewBackPOpen = tme (-35) 0, + ewIsolPawns = tme (-42) (-120), + ewIsolPassed = tme (-63) (-158), + ewBackPawns = tme (-126) (-169), + ewBackPOpen = tme (-27) (-21), ewEnpHanging = tme (-23) (-33), - ewEnpEnPrise = tme (-25) (-21), - ewEnpAttacked = tme (-9) (-13), - ewLastLinePenalty = tme 115 0, - ewBishopPair = tme 363 388, - ewRedundanceRook = tme 0 (-105), - ewRookPawn = tme (-50) (-40), - ewAdvPawn5 = tme 10 130, - ewAdvPawn6 = tme 440 500, - ewPawnBlockP = tme (-124) (-110), - ewPawnBlockO = tme (-23) (-27), - ewPawnBlockA = tme (-14) (-73), + ewEnpEnPrise = tme (-27) (-20), + ewEnpAttacked = tme (-6) (-15), + ewLastLinePenalty = tme 115 (-2), + ewBishopPair = tme 381 330, + ewRedundanceRook = tme (-20) (-76), + ewRookPawn = tme (-48) (-41), + ewAdvPawn5 = tme 5 132, + ewAdvPawn6 = tme 431 413, + ewPawnBlockP = tme (-128) (-105), + ewPawnBlockO = tme (-23) (-25), + ewPawnBlockA = tme (-14) (-72), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From 4d85a18f9a3b66f3e3dffe9f9c5cb6ef4779362f Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 12:53:16 +0100 Subject: [PATCH 05/71] Eval weights: same, second SGD run --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 21fd7d2f..2cdce071 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v11a" +progVerSuff = "v11b" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index ffe57e90..0fc36184 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,9 +174,9 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 176 192, - ewRookOpen = tme 224 212, - ewRookConn = tme 103 57, + ewRookHOpen = tme 175 193, + ewRookOpen = tme 223 213, + ewRookConn = tme 101 66, ewMobilityKnight = tme 50 69, -- Evalo 200 steps: ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 ewMobilityRook = tme 27 27, @@ -185,24 +185,24 @@ instance CollectParams EvalWeights where ewCenterNAtts = tme 48 46, ewCenterBAtts = tme 56 41, ewCenterRAtts = tme 10 33, - ewCenterQAtts = tme 5 58, + ewCenterQAtts = tme 5 57, ewCenterKAtts = tme 1 52, ewSpace = tme 1 0, ewAdvAtts = tme 3 16, ewIsolPawns = tme (-42) (-120), - ewIsolPassed = tme (-63) (-158), - ewBackPawns = tme (-126) (-169), - ewBackPOpen = tme (-27) (-21), - ewEnpHanging = tme (-23) (-33), + ewIsolPassed = tme (-66) (-157), + ewBackPawns = tme (-124) (-172), + ewBackPOpen = tme (-30) (-16), + ewEnpHanging = tme (-23) (-32), ewEnpEnPrise = tme (-27) (-20), - ewEnpAttacked = tme (-6) (-15), - ewLastLinePenalty = tme 115 (-2), - ewBishopPair = tme 381 330, - ewRedundanceRook = tme (-20) (-76), + ewEnpAttacked = tme (-6) (-16), + ewLastLinePenalty = tme 116 (-2), + ewBishopPair = tme 381 332, + ewRedundanceRook = tme (-23) (-76), ewRookPawn = tme (-48) (-41), - ewAdvPawn5 = tme 5 132, - ewAdvPawn6 = tme 431 413, - ewPawnBlockP = tme (-128) (-105), + ewAdvPawn5 = tme 3 132, + ewAdvPawn6 = tme 423 399, + ewPawnBlockP = tme (-129) (-103), ewPawnBlockO = tme (-23) (-25), ewPawnBlockA = tme (-14) (-72), ewPassPawnLev = tme 0 9 From 600c2a6cc0894e007629c7124e6c8ff79cfd9017 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 13:02:28 +0100 Subject: [PATCH 06/71] Eval weights: same, third SGD run --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 2cdce071..947fd47a 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v11b" +progVerSuff = "v11c" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 0fc36184..7d4778de 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -175,8 +175,8 @@ instance CollectParams EvalWeights where ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) ewRookHOpen = tme 175 193, - ewRookOpen = tme 223 213, - ewRookConn = tme 101 66, + ewRookOpen = tme 224 213, + ewRookConn = tme 101 64, ewMobilityKnight = tme 50 69, -- Evalo 200 steps: ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 ewMobilityRook = tme 27 27, @@ -190,19 +190,19 @@ instance CollectParams EvalWeights where ewSpace = tme 1 0, ewAdvAtts = tme 3 16, ewIsolPawns = tme (-42) (-120), - ewIsolPassed = tme (-66) (-157), - ewBackPawns = tme (-124) (-172), - ewBackPOpen = tme (-30) (-16), + ewIsolPassed = tme (-67) (-156), + ewBackPawns = tme (-126) (-170), + ewBackPOpen = tme (-27) (-19), ewEnpHanging = tme (-23) (-32), ewEnpEnPrise = tme (-27) (-20), ewEnpAttacked = tme (-6) (-16), ewLastLinePenalty = tme 116 (-2), - ewBishopPair = tme 381 332, - ewRedundanceRook = tme (-23) (-76), + ewBishopPair = tme 381 331, + ewRedundanceRook = tme (-20) (-79), ewRookPawn = tme (-48) (-41), - ewAdvPawn5 = tme 3 132, - ewAdvPawn6 = tme 423 399, - ewPawnBlockP = tme (-129) (-103), + ewAdvPawn5 = tme 4 132, + ewAdvPawn6 = tme 429 414, + ewPawnBlockP = tme (-130) (-102), ewPawnBlockO = tme (-23) (-25), ewPawnBlockA = tme (-14) (-72), ewPassPawnLev = tme 0 9 From 6b807585518d0c069a1eb2f5d24b2c5e050707f8 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 13:10:18 +0100 Subject: [PATCH 07/71] Eval weights with SGD: 5M pos, shift 0.2 --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 947fd47a..17a74e4a 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v11c" +progVerSuff = "v12a" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 7d4778de..bc4cbd06 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,37 +174,37 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 175 193, - ewRookOpen = tme 224 213, - ewRookConn = tme 101 64, + ewRookHOpen = tme 176 192, + ewRookOpen = tme 224 212, + ewRookConn = tme 103 59, ewMobilityKnight = tme 50 69, -- Evalo 200 steps: ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 ewMobilityRook = tme 27 27, ewMobilityQueen = tme 4 6, ewCenterPAtts = tme 83 68, ewCenterNAtts = tme 48 46, - ewCenterBAtts = tme 56 41, + ewCenterBAtts = tme 56 42, ewCenterRAtts = tme 10 33, - ewCenterQAtts = tme 5 57, + ewCenterQAtts = tme 5 58, ewCenterKAtts = tme 1 52, ewSpace = tme 1 0, ewAdvAtts = tme 3 16, - ewIsolPawns = tme (-42) (-120), - ewIsolPassed = tme (-67) (-156), - ewBackPawns = tme (-126) (-170), - ewBackPOpen = tme (-27) (-19), + ewIsolPawns = tme (-42) (-121), + ewIsolPassed = tme (-68) (-156), + ewBackPawns = tme (-125) (-171), + ewBackPOpen = tme (-28) (-17), ewEnpHanging = tme (-23) (-32), ewEnpEnPrise = tme (-27) (-20), - ewEnpAttacked = tme (-6) (-16), + ewEnpAttacked = tme (-6) (-15), ewLastLinePenalty = tme 116 (-2), - ewBishopPair = tme 381 331, - ewRedundanceRook = tme (-20) (-79), + ewBishopPair = tme 383 325, + ewRedundanceRook = tme (-24) (-73), ewRookPawn = tme (-48) (-41), ewAdvPawn5 = tme 4 132, - ewAdvPawn6 = tme 429 414, - ewPawnBlockP = tme (-130) (-102), + ewAdvPawn6 = tme 418 429, + ewPawnBlockP = tme (-131) (-100), ewPawnBlockO = tme (-23) (-25), - ewPawnBlockA = tme (-14) (-72), + ewPawnBlockA = tme (-14) (-73), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From 971aa0e632b52477447363372ddb321b579c9eb3 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 13:39:24 +0100 Subject: [PATCH 08/71] Eval weights: same, second SGD run --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 17a74e4a..60239205 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v12a" +progVerSuff = "v12b" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index bc4cbd06..b9ee7d65 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,10 +174,10 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 176 192, + ewRookHOpen = tme 175 192, ewRookOpen = tme 224 212, - ewRookConn = tme 103 59, - ewMobilityKnight = tme 50 69, -- Evalo 200 steps: + ewRookConn = tme 100 69, + ewMobilityKnight = tme 51 69, -- Evalo 200 steps: ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 ewMobilityRook = tme 27 27, ewMobilityQueen = tme 4 6, @@ -185,26 +185,26 @@ instance CollectParams EvalWeights where ewCenterNAtts = tme 48 46, ewCenterBAtts = tme 56 42, ewCenterRAtts = tme 10 33, - ewCenterQAtts = tme 5 58, + ewCenterQAtts = tme 5 57, ewCenterKAtts = tme 1 52, ewSpace = tme 1 0, ewAdvAtts = tme 3 16, - ewIsolPawns = tme (-42) (-121), - ewIsolPassed = tme (-68) (-156), - ewBackPawns = tme (-125) (-171), - ewBackPOpen = tme (-28) (-17), + ewIsolPawns = tme (-42) (-120), + ewIsolPassed = tme (-65) (-157), + ewBackPawns = tme (-123) (-172), + ewBackPOpen = tme (-31) (-16), ewEnpHanging = tme (-23) (-32), ewEnpEnPrise = tme (-27) (-20), ewEnpAttacked = tme (-6) (-15), - ewLastLinePenalty = tme 116 (-2), - ewBishopPair = tme 383 325, - ewRedundanceRook = tme (-24) (-73), + ewLastLinePenalty = tme 116 (-3), + ewBishopPair = tme 382 326, + ewRedundanceRook = tme (-17) (-84), ewRookPawn = tme (-48) (-41), ewAdvPawn5 = tme 4 132, - ewAdvPawn6 = tme 418 429, - ewPawnBlockP = tme (-131) (-100), + ewAdvPawn6 = tme 423 412, + ewPawnBlockP = tme (-129) (-104), ewPawnBlockO = tme (-23) (-25), - ewPawnBlockA = tme (-14) (-73), + ewPawnBlockA = tme (-14) (-72), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From 33e0d01319507a77ee04bdcbe050f8fac37f84aa Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 14:20:36 +0100 Subject: [PATCH 09/71] Eval weights: same, third SGD run --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 60239205..06e78a80 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v12b" +progVerSuff = "v12c" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index b9ee7d65..fbb01b82 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,37 +174,37 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 175 192, - ewRookOpen = tme 224 212, - ewRookConn = tme 100 69, - ewMobilityKnight = tme 51 69, -- Evalo 200 steps: + ewRookHOpen = tme 175 193, + ewRookOpen = tme 224 213, + ewRookConn = tme 104 54, + ewMobilityKnight = tme 50 69, -- Evalo 200 steps: ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 ewMobilityRook = tme 27 27, ewMobilityQueen = tme 4 6, ewCenterPAtts = tme 83 68, ewCenterNAtts = tme 48 46, - ewCenterBAtts = tme 56 42, + ewCenterBAtts = tme 56 41, ewCenterRAtts = tme 10 33, - ewCenterQAtts = tme 5 57, + ewCenterQAtts = tme 5 58, ewCenterKAtts = tme 1 52, ewSpace = tme 1 0, ewAdvAtts = tme 3 16, ewIsolPawns = tme (-42) (-120), - ewIsolPassed = tme (-65) (-157), - ewBackPawns = tme (-123) (-172), - ewBackPOpen = tme (-31) (-16), + ewIsolPassed = tme (-67) (-156), + ewBackPawns = tme (-125) (-171), + ewBackPOpen = tme (-28) (-18), ewEnpHanging = tme (-23) (-32), ewEnpEnPrise = tme (-27) (-20), ewEnpAttacked = tme (-6) (-15), - ewLastLinePenalty = tme 116 (-3), - ewBishopPair = tme 382 326, - ewRedundanceRook = tme (-17) (-84), + ewLastLinePenalty = tme 115 (-1), + ewBishopPair = tme 381 332, + ewRedundanceRook = tme (-22) (-74), ewRookPawn = tme (-48) (-41), ewAdvPawn5 = tme 4 132, - ewAdvPawn6 = tme 423 412, - ewPawnBlockP = tme (-129) (-104), + ewAdvPawn6 = tme 429 406, + ewPawnBlockP = tme (-129) (-103), ewPawnBlockO = tme (-23) (-25), - ewPawnBlockA = tme (-14) (-72), + ewPawnBlockA = tme (-14) (-71), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From e0d6d8b29cfd995af9718bb9aab65f0d883a441a Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 15:05:07 +0100 Subject: [PATCH 10/71] Eval weights with SGD: 5M pos, shift 0.4 --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 46 +++++++++++++++++++++++----------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 06e78a80..5dc8240e 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v12c" +progVerSuff = "v14a" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index fbb01b82..07738fe1 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -116,8 +116,8 @@ data EvalWeights instance CollectParams EvalParams where type CollectFor EvalParams = EvalParams npColInit = EvalParams { - epMovingMid = 144, -- after Clop optimisation - epMovingEnd = 144, -- with 3700 games at 15+0.25 s + epMovingMid = 145, -- after Clop optimisation + epMovingEnd = 145, -- with 3700 games at 15+0.25 s epMaterMinor = 1, epMaterRook = 4, epMaterQueen = 13, @@ -174,37 +174,37 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 175 193, - ewRookOpen = tme 224 213, - ewRookConn = tme 104 54, + ewRookHOpen = tme 174 196, + ewRookOpen = tme 223 214, + ewRookConn = tme 104 57, ewMobilityKnight = tme 50 69, -- Evalo 200 steps: - ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 + ewMobilityBishop = tme 57 33, -- length 10, depth 6, batch 128 ewMobilityRook = tme 27 27, ewMobilityQueen = tme 4 6, - ewCenterPAtts = tme 83 68, + ewCenterPAtts = tme 84 68, ewCenterNAtts = tme 48 46, - ewCenterBAtts = tme 56 41, + ewCenterBAtts = tme 56 42, ewCenterRAtts = tme 10 33, ewCenterQAtts = tme 5 58, - ewCenterKAtts = tme 1 52, + ewCenterKAtts = tme 0 52, ewSpace = tme 1 0, ewAdvAtts = tme 3 16, - ewIsolPawns = tme (-42) (-120), - ewIsolPassed = tme (-67) (-156), - ewBackPawns = tme (-125) (-171), - ewBackPOpen = tme (-28) (-18), + ewIsolPawns = tme (-42) (-121), + ewIsolPassed = tme (-64) (-158), + ewBackPawns = tme (-124) (-172), + ewBackPOpen = tme (-29) (-16), ewEnpHanging = tme (-23) (-32), - ewEnpEnPrise = tme (-27) (-20), - ewEnpAttacked = tme (-6) (-15), - ewLastLinePenalty = tme 115 (-1), - ewBishopPair = tme 381 332, - ewRedundanceRook = tme (-22) (-74), - ewRookPawn = tme (-48) (-41), - ewAdvPawn5 = tme 4 132, - ewAdvPawn6 = tme 429 406, - ewPawnBlockP = tme (-129) (-103), + ewEnpEnPrise = tme (-26) (-21), + ewEnpAttacked = tme (-7) (-14), + ewLastLinePenalty = tme 116 (-2), + ewBishopPair = tme 381 331, + ewRedundanceRook = tme (-23) (-73), + ewRookPawn = tme (-49) (-40), + ewAdvPawn5 = tme 6 132, + ewAdvPawn6 = tme 432 431, + ewPawnBlockP = tme (-130) (-102), ewPawnBlockO = tme (-23) (-25), - ewPawnBlockA = tme (-14) (-71), + ewPawnBlockA = tme (-14) (-73), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From 498b7b69caac1eb84ced0106ac23c53646bd31fd Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 15:38:06 +0100 Subject: [PATCH 11/71] Eval weights: same, second SGD run --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 5dc8240e..8e6c7553 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v14a" +progVerSuff = "v14b" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 07738fe1..3d4d86e6 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,37 +174,37 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 174 196, - ewRookOpen = tme 223 214, - ewRookConn = tme 104 57, + ewRookHOpen = tme 175 194, + ewRookOpen = tme 224 213, + ewRookConn = tme 105 54, ewMobilityKnight = tme 50 69, -- Evalo 200 steps: - ewMobilityBishop = tme 57 33, -- length 10, depth 6, batch 128 + ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 ewMobilityRook = tme 27 27, ewMobilityQueen = tme 4 6, - ewCenterPAtts = tme 84 68, - ewCenterNAtts = tme 48 46, + ewCenterPAtts = tme 83 68, + ewCenterNAtts = tme 48 47, ewCenterBAtts = tme 56 42, ewCenterRAtts = tme 10 33, - ewCenterQAtts = tme 5 58, + ewCenterQAtts = tme 4 58, ewCenterKAtts = tme 0 52, ewSpace = tme 1 0, ewAdvAtts = tme 3 16, - ewIsolPawns = tme (-42) (-121), - ewIsolPassed = tme (-64) (-158), - ewBackPawns = tme (-124) (-172), - ewBackPOpen = tme (-29) (-16), + ewIsolPawns = tme (-42) (-120), + ewIsolPassed = tme (-62) (-159), + ewBackPawns = tme (-126) (-170), + ewBackPOpen = tme (-27) (-20), ewEnpHanging = tme (-23) (-32), ewEnpEnPrise = tme (-26) (-21), ewEnpAttacked = tme (-7) (-14), ewLastLinePenalty = tme 116 (-2), - ewBishopPair = tme 381 331, - ewRedundanceRook = tme (-23) (-73), + ewBishopPair = tme 380 335, + ewRedundanceRook = tme (-22) (-74), ewRookPawn = tme (-49) (-40), - ewAdvPawn5 = tme 6 132, - ewAdvPawn6 = tme 432 431, - ewPawnBlockP = tme (-130) (-102), - ewPawnBlockO = tme (-23) (-25), - ewPawnBlockA = tme (-14) (-73), + ewAdvPawn5 = tme 5 133, + ewAdvPawn6 = tme 436 401, + ewPawnBlockP = tme (-127) (-107), + ewPawnBlockO = tme (-23) (-26), + ewPawnBlockA = tme (-13) (-74), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From f2663800459d30ecd3b2177b4b8f909ac358c5ec Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 18:19:00 +0100 Subject: [PATCH 12/71] Eval weights: same, third SGD run --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 8e6c7553..12b9a8bd 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v14b" +progVerSuff = "v14c" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 3d4d86e6..edf034a9 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,15 +174,15 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 175 194, - ewRookOpen = tme 224 213, - ewRookConn = tme 105 54, - ewMobilityKnight = tme 50 69, -- Evalo 200 steps: + ewRookHOpen = tme 175 193, + ewRookOpen = tme 225 212, + ewRookConn = tme 105 53, + ewMobilityKnight = tme 51 69, -- Evalo 200 steps: ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 ewMobilityRook = tme 27 27, ewMobilityQueen = tme 4 6, ewCenterPAtts = tme 83 68, - ewCenterNAtts = tme 48 47, + ewCenterNAtts = tme 48 46, ewCenterBAtts = tme 56 42, ewCenterRAtts = tme 10 33, ewCenterQAtts = tme 4 58, @@ -190,21 +190,21 @@ instance CollectParams EvalWeights where ewSpace = tme 1 0, ewAdvAtts = tme 3 16, ewIsolPawns = tme (-42) (-120), - ewIsolPassed = tme (-62) (-159), - ewBackPawns = tme (-126) (-170), - ewBackPOpen = tme (-27) (-20), + ewIsolPassed = tme (-59) (-161), + ewBackPawns = tme (-124) (-171), + ewBackPOpen = tme (-29) (-18), ewEnpHanging = tme (-23) (-32), ewEnpEnPrise = tme (-26) (-21), ewEnpAttacked = tme (-7) (-14), - ewLastLinePenalty = tme 116 (-2), - ewBishopPair = tme 380 335, - ewRedundanceRook = tme (-22) (-74), + ewLastLinePenalty = tme 115 (-1), + ewBishopPair = tme 381 331, + ewRedundanceRook = tme (-19) (-78), ewRookPawn = tme (-49) (-40), - ewAdvPawn5 = tme 5 133, - ewAdvPawn6 = tme 436 401, - ewPawnBlockP = tme (-127) (-107), + ewAdvPawn5 = tme 4 132, + ewAdvPawn6 = tme 413 419, + ewPawnBlockP = tme (-129) (-103), ewPawnBlockO = tme (-23) (-26), - ewPawnBlockA = tme (-13) (-74), + ewPawnBlockA = tme (-14) (-72), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From fe8bede60ea0b2bf4c5f94a4c89de85e25bcaa25 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 19:49:20 +0100 Subject: [PATCH 13/71] Eval weights with SGD: 5M pos, shift 0.8 --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 62 +++++++++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 12b9a8bd..818ffeff 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v14c" +progVerSuff = "v18a" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index edf034a9..7f2bbbce 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -116,8 +116,8 @@ data EvalWeights instance CollectParams EvalParams where type CollectFor EvalParams = EvalParams npColInit = EvalParams { - epMovingMid = 145, -- after Clop optimisation - epMovingEnd = 145, -- with 3700 games at 15+0.25 s + epMovingMid = 156, -- SGD with shift 0.8 + epMovingEnd = 156, -- with 5 M positions epMaterMinor = 1, epMaterRook = 4, epMaterQueen = 13, @@ -174,37 +174,37 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 175 193, - ewRookOpen = tme 225 212, - ewRookConn = tme 105 53, - ewMobilityKnight = tme 51 69, -- Evalo 200 steps: + ewRookHOpen = tme 176 203, + ewRookOpen = tme 233 210, + ewRookConn = tme 107 51, + ewMobilityKnight = tme 51 68, -- Evalo 200 steps: ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 - ewMobilityRook = tme 27 27, - ewMobilityQueen = tme 4 6, - ewCenterPAtts = tme 83 68, - ewCenterNAtts = tme 48 46, - ewCenterBAtts = tme 56 42, - ewCenterRAtts = tme 10 33, - ewCenterQAtts = tme 4 58, - ewCenterKAtts = tme 0 52, + ewMobilityRook = tme 26 27, + ewMobilityQueen = tme 4 3, + ewCenterPAtts = tme 83 66, + ewCenterNAtts = tme 49 46, + ewCenterBAtts = tme 57 42, + ewCenterRAtts = tme 11 32, + ewCenterQAtts = tme 4 61, + ewCenterKAtts = tme 2 54, ewSpace = tme 1 0, - ewAdvAtts = tme 3 16, - ewIsolPawns = tme (-42) (-120), - ewIsolPassed = tme (-59) (-161), - ewBackPawns = tme (-124) (-171), - ewBackPOpen = tme (-29) (-18), - ewEnpHanging = tme (-23) (-32), - ewEnpEnPrise = tme (-26) (-21), - ewEnpAttacked = tme (-7) (-14), - ewLastLinePenalty = tme 115 (-1), - ewBishopPair = tme 381 331, - ewRedundanceRook = tme (-19) (-78), - ewRookPawn = tme (-49) (-40), - ewAdvPawn5 = tme 4 132, - ewAdvPawn6 = tme 413 419, - ewPawnBlockP = tme (-129) (-103), - ewPawnBlockO = tme (-23) (-26), - ewPawnBlockA = tme (-14) (-72), + ewAdvAtts = tme 2 16, + ewIsolPawns = tme (-41) (-120), + ewIsolPassed = tme (-58) (-169), + ewBackPawns = tme (-125) (-168), + ewBackPOpen = tme (-28) (-22), + ewEnpHanging = tme (-21) (-34), + ewEnpEnPrise = tme (-28) (-26), + ewEnpAttacked = tme (-6) (-7), + ewLastLinePenalty = tme 119 2, + ewBishopPair = tme 392 302, + ewRedundanceRook = tme (-26) (-73), + ewRookPawn = tme (-52) (-41), + ewAdvPawn5 = tme 4 131, + ewAdvPawn6 = tme 400 353, + ewPawnBlockP = tme (-127) (-103), + ewPawnBlockO = tme (-22) (-27), + ewPawnBlockA = tme (-14) (-77), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From d4dec6adb3cd848572d9690d179382b8b76bf893 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 19:56:56 +0100 Subject: [PATCH 14/71] Eval weights: same, second SGD run --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 818ffeff..335405b9 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v18a" +progVerSuff = "v18b" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 7f2bbbce..b8aec6e4 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,15 +174,15 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 176 203, - ewRookOpen = tme 233 210, - ewRookConn = tme 107 51, + ewRookHOpen = tme 175 205, + ewRookOpen = tme 232 212, + ewRookConn = tme 106 52, ewMobilityKnight = tme 51 68, -- Evalo 200 steps: ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 ewMobilityRook = tme 26 27, ewMobilityQueen = tme 4 3, - ewCenterPAtts = tme 83 66, - ewCenterNAtts = tme 49 46, + ewCenterPAtts = tme 84 66, + ewCenterNAtts = tme 49 45, ewCenterBAtts = tme 57 42, ewCenterRAtts = tme 11 32, ewCenterQAtts = tme 4 61, @@ -190,21 +190,21 @@ instance CollectParams EvalWeights where ewSpace = tme 1 0, ewAdvAtts = tme 2 16, ewIsolPawns = tme (-41) (-120), - ewIsolPassed = tme (-58) (-169), - ewBackPawns = tme (-125) (-168), - ewBackPOpen = tme (-28) (-22), + ewIsolPassed = tme (-65) (-165), + ewBackPawns = tme (-124) (-169), + ewBackPOpen = tme (-29) (-21), ewEnpHanging = tme (-21) (-34), ewEnpEnPrise = tme (-28) (-26), ewEnpAttacked = tme (-6) (-7), - ewLastLinePenalty = tme 119 2, - ewBishopPair = tme 392 302, - ewRedundanceRook = tme (-26) (-73), + ewLastLinePenalty = tme 118 4, + ewBishopPair = tme 389 314, + ewRedundanceRook = tme (-23) (-79), ewRookPawn = tme (-52) (-41), - ewAdvPawn5 = tme 4 131, - ewAdvPawn6 = tme 400 353, - ewPawnBlockP = tme (-127) (-103), - ewPawnBlockO = tme (-22) (-27), - ewPawnBlockA = tme (-14) (-77), + ewAdvPawn5 = tme 5 131, + ewAdvPawn6 = tme 401 380, + ewPawnBlockP = tme (-127) (-102), + ewPawnBlockO = tme (-22) (-26), + ewPawnBlockA = tme (-14) (-76), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From a1b88148b0e7f02cba5b6ae107a986c53aa04ece Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 4 Jan 2017 20:37:58 +0100 Subject: [PATCH 15/71] Eval weights: same, third SGD run --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 335405b9..1dec669c 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "v18b" +progVerSuff = "v18c" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index b8aec6e4..71c4422f 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,37 +174,37 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) - ewRookHOpen = tme 175 205, - ewRookOpen = tme 232 212, - ewRookConn = tme 106 52, + ewRookHOpen = tme 178 200, + ewRookOpen = tme 234 207, + ewRookConn = tme 104 59, ewMobilityKnight = tme 51 68, -- Evalo 200 steps: ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 - ewMobilityRook = tme 26 27, + ewMobilityRook = tme 26 28, ewMobilityQueen = tme 4 3, ewCenterPAtts = tme 84 66, - ewCenterNAtts = tme 49 45, + ewCenterNAtts = tme 49 46, ewCenterBAtts = tme 57 42, - ewCenterRAtts = tme 11 32, + ewCenterRAtts = tme 11 33, ewCenterQAtts = tme 4 61, ewCenterKAtts = tme 2 54, ewSpace = tme 1 0, ewAdvAtts = tme 2 16, ewIsolPawns = tme (-41) (-120), - ewIsolPassed = tme (-65) (-165), - ewBackPawns = tme (-124) (-169), - ewBackPOpen = tme (-29) (-21), + ewIsolPassed = tme (-57) (-169), + ewBackPawns = tme (-126) (-168), + ewBackPOpen = tme (-26) (-22), ewEnpHanging = tme (-21) (-34), ewEnpEnPrise = tme (-28) (-26), ewEnpAttacked = tme (-6) (-7), - ewLastLinePenalty = tme 118 4, - ewBishopPair = tme 389 314, - ewRedundanceRook = tme (-23) (-79), + ewLastLinePenalty = tme 119 3, + ewBishopPair = tme 387 321, + ewRedundanceRook = tme (-32) (-67), ewRookPawn = tme (-52) (-41), - ewAdvPawn5 = tme 5 131, - ewAdvPawn6 = tme 401 380, - ewPawnBlockP = tme (-127) (-102), + ewAdvPawn5 = tme 4 131, + ewAdvPawn6 = tme 396 370, + ewPawnBlockP = tme (-128) (-100), ewPawnBlockO = tme (-22) (-26), - ewPawnBlockA = tme (-14) (-76), + ewPawnBlockA = tme (-14) (-77), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From 9fa5682c7e341966bc9096428581df496492274f Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sun, 8 Jan 2017 17:45:41 +0100 Subject: [PATCH 16/71] Search max depth extension: 5 --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 26db5f83..0b1c5d2a 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "to5" +progVerSuff = "me5" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 84f8dea0..e06dfd1d 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -37,7 +37,7 @@ scoreGrain, depthForCM, maxDepthExt, minPvDepth :: Int useTTinPv, readTTinQS :: Bool scoreGrain = 4 -- score granularity depthForCM = 7 -- from this depth inform current move -maxDepthExt = 3 -- maximum depth extension +maxDepthExt = 5 -- maximum depth extension useTTinPv = False -- retrieve from TT in PV? minPvDepth = 2 -- from this depth we use alpha beta search readTTinQS = True @@ -762,7 +762,7 @@ resetSpc nst = nst { spcno = movno nst } reserveExtension :: Int -> Int -> Search Int reserveExtension !uex !exd - | uex >= maxDepthExt || exd == 0 = return 0 + | exd == 0 || uex >= maxDepthExt = return 0 | otherwise = do modify $ \s -> s { usedext = usedext s + exd } return exd From 1817420ddcbb59c1a0a4318b8321fb12e8604845 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Tue, 10 Jan 2017 01:38:23 +0100 Subject: [PATCH 17/71] Null move search: inactive when stm has no piece --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 7 ++++++- Search/Albeta.hs | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 0b1c5d2a..1435f5b9 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "me5" +progVerSuff = "zz" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index f6d01427..3dca6a9c 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -8,7 +8,7 @@ module Moves.Base ( posToState, getPos, posNewSearch, doRealMove, doMove, undoMove, genMoves, genTactMoves, canPruneMove, - tacticalPos, isMoveLegal, isKillCand, isTKillCand, + tacticalPos, zugZwang, isMoveLegal, isKillCand, isTKillCand, betaCut, doNullMove, ttRead, ttStore, curNodes, chooseMove, isTimeout, informCtx, mateScore, scoreDiff, qsDelta, draftStats, @@ -31,6 +31,7 @@ import Struct.Context import Struct.Status import Hash.TransTab import Moves.Board +import Moves.BitBoard (less) import Eval.BasicEval import Eval.Eval import Moves.ShowMe @@ -244,6 +245,10 @@ undoMove = modify $ \s -> s { stack = tail $ stack s } tacticalPos :: MyPos -> Bool tacticalPos = (/= 0) . check +{-# INLINE zugZwang #-} +zugZwang :: MyPos -> Bool +zugZwang p = me p `less` (kings p .|. pawns p) == 0 + {-# INLINE isMoveLegal #-} isMoveLegal :: MyPos -> Move -> Bool isMoveLegal = legalMove diff --git a/Search/Albeta.hs b/Search/Albeta.hs index e06dfd1d..c1bb9456 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -615,7 +615,7 @@ data NullMoveResult = NoNullMove | NullMoveHigh | NullMoveLow | NullMoveThreat P nullMoveFailsHigh :: MyPos -> NodeState -> Int -> Int -> Int -> Search NullMoveResult nullMoveFailsHigh pos nst b d lastnull - | lastnull < 1 || tacticalPos pos -- go smooth into QS + | lastnull < 1 || tacticalPos pos || zugZwang pos -- go smooth into QS || crtnt nst == AllNode = return NoNullMove -- no null move in all nodes | otherwise = do let v = staticScore pos From 163dd998cac9660bce47219134f1010516eb9b03 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 14 Jan 2017 13:24:46 +0100 Subject: [PATCH 18/71] Eval: weak pawns attacks --- Eval/Eval.hs | 8 +++++++- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index ed99d913..b4fdbb3f 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -675,7 +675,10 @@ instance EvalItem EnPrise where -- - if he has only one attack, we are somehow restricted to defend or move that piece -- In 2 we have a more complicated analysis, which maybe is not worth to do enPrise :: MyPos -> EvalWeights -> MidEnd -> MidEnd -enPrise p ew mide = mad (mad (mad mide (ewEnpHanging ew) ha) (ewEnpEnPrise ew) ep) (ewEnpAttacked ew) at +enPrise p ew mide = mad (mad (mad (mad mide (ewEnpHanging ew) ha) + (ewEnpEnPrise ew) ep) + (ewEnpAttacked ew) at) + (ewWepAttacked ew) wp where !meP = me p .&. pawns p -- my pieces !meM = me p .&. (knights p .|. bishops p) !meR = me p .&. rooks p @@ -696,6 +699,9 @@ enPrise p ew mide = mad (mad (mad mide (ewEnpHanging ew) ha) (ewEnpEnPrise ew) e !ha = popCount haP + 3 * popCount haM + 5 * popCount haR + 9 * popCount haQ !ep = 3 * popCount epM + 5 * popCount epR + 9 * popCount epQ !at = popCount atP + 3 * popCount atM + 5 * popCount atR + 9 * popCount atQ + !wp1 = popCount$ (meP `less` myPAttacs p) .&. yoAttacs p -- my weak attacked pawns + !wp2 = popCount$ (yo p .&. pawns p `less` yoPAttacs p) .&. myAttacs p -- your weak attacked pawns + !wp = wp2 - wp1 ------ Last Line ------ data LastLine = LastLine diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 1435f5b9..111041f8 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "zz" +progVerSuff = "wpa" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index dd8cef84..5a7daa56 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -101,6 +101,7 @@ data EvalWeights ewEnpHanging :: !MidEnd, ewEnpEnPrise :: !MidEnd, ewEnpAttacked :: !MidEnd, + ewWepAttacked :: !MidEnd, ewLastLinePenalty :: !MidEnd, ewBishopPair :: !MidEnd, ewRedundanceRook :: !MidEnd, @@ -196,6 +197,7 @@ instance CollectParams EvalWeights where ewEnpHanging = tme (-23) (-33), ewEnpEnPrise = tme (-25) (-21), ewEnpAttacked = tme (-9) (-13), + ewWepAttacked = tme 48 64, ewLastLinePenalty = tme 115 0, ewBishopPair = tme 363 388, ewRedundanceRook = tme 0 (-105), @@ -264,6 +266,8 @@ collectEvalWeights (s, v) ew = lookApply s v ew [ ("end.enpEnPrise", setEndEnpEnPrise), ("mid.enpAttacked", setMidEnpAttacked), ("end.enpAttacked", setEndEnpAttacked), + ("mid.wepAttacked", setMidWepAttacked), + ("end.wepAttacked", setEndWepAttacked), ("mid.lastLinePenalty", setMidLastLinePenalty), ("end.lastLinePenalty", setEndLastLinePenalty), ("mid.bishopPair", setMidBishopPair), @@ -337,6 +341,8 @@ collectEvalWeights (s, v) ew = lookApply s v ew [ setEndEnpEnPrise v' ew' = ew' { ewEnpEnPrise = (ewEnpEnPrise ew') { end = round v' }} setMidEnpAttacked v' ew' = ew' { ewEnpAttacked = (ewEnpAttacked ew') { mid = round v' }} setEndEnpAttacked v' ew' = ew' { ewEnpAttacked = (ewEnpAttacked ew') { end = round v' }} + setMidWepAttacked v' ew' = ew' { ewWepAttacked = (ewWepAttacked ew') { mid = round v' }} + setEndWepAttacked v' ew' = ew' { ewWepAttacked = (ewWepAttacked ew') { end = round v' }} setMidLastLinePenalty v' ew' = ew' { ewLastLinePenalty = (ewLastLinePenalty ew') { mid = round v' }} setEndLastLinePenalty v' ew' = ew' { ewLastLinePenalty = (ewLastLinePenalty ew') { end = round v' }} setMidBishopPair v' ew' = ew' { ewBishopPair = (ewBishopPair ew') { mid = round v' }} From d9d72a7d0d6fc9b495cc3d70c428e0bf1f5a6436 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 21 Jan 2017 01:34:13 +0100 Subject: [PATCH 19/71] Time management based on logistic regression --- Main/Barbarossa.hs | 230 +++++++++++++++++++++++++-------------------- Moves/Base.hs | 23 +---- Search/Albeta.hs | 65 ++++++------- Struct/Context.hs | 13 +-- Struct/Status.hs | 2 +- Uci/UciGlue.hs | 4 +- 6 files changed, 164 insertions(+), 173 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 1435f5b9..038b2066 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -10,12 +10,13 @@ import Control.Concurrent import Control.Exception import Data.Array.Unboxed import Data.Foldable (foldrM) -import Data.List (intersperse, delete) +import Data.List (intersperse) import Data.Maybe import Data.Typeable import System.Console.GetOpt import System.Environment (getArgs) import System.IO +import System.Random import System.Time import Struct.Struct @@ -38,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "zz" +progVerSuff = "sig" data Options = Options { optConfFile :: Maybe String, -- config file @@ -110,7 +111,7 @@ initContext opts = do forGui = Nothing, srchStrtMs = 0, myColor = White, - prvMvInfo = Nothing + totBmCh = 0, lastChDr = 0 } ctxVar <- newMVar chg let context = Ctx { @@ -360,12 +361,9 @@ doGo cmds = do else if Ponder `elem` cmds then ctxLog DebugUci "Just ponder: ignored" else do - let (tim, tpm, mtg) = getTimeParams cmds lastsc $ myColor chg + let (tim, tpm, mtg) = getTimeParams cmds $ myColor chg md = 20 -- max search depth dpt = fromMaybe md (findDepth cmds) - lastsc = case forGui chg of - Just InfoB { infoScore = sc } -> sc - _ -> 0 startWorking tim tpm mtg dpt data Agreg = Agreg { @@ -403,16 +401,14 @@ aggregateError agr refsc sc = agr { agrCumErr = agrCumErr agr + fromIntegral (dif * dif), agrFenOk = agrFenOk agr + 1 } where dif = sc - refsc -getTimeParams :: [GoCmds] -> Int -> Color -> (Int, Int, Int) -getTimeParams cs _ c -- unused: lastsc - = if tpm == 0 && tim == 0 - then (0, 0, 0) - else (tim, tpm, mtg) +getTimeParams :: [GoCmds] -> Color -> (Int, Int, Int) +getTimeParams cs c + | tpm == 0 && tim == 0 = (0, 0, 0) + | otherwise = (tim, tpm, mtg) where tpm = fromMaybe 0 $ findTInc c cs tim = fromMaybe 0 $ findTime c cs mtg = fromMaybe 0 $ findMovesToGo cs - -- These parameters should be optimised (i.e.: first made options) remTimeFracIni, remTimeFracFin, remTimeFracDev :: Double remTimeFracIni = 0.15 -- fraction of remaining time which we can consume at once - initial value @@ -423,13 +419,13 @@ timeReserved :: Int timeReserved = 70 -- milliseconds reserved for move communication -- This function calculates the normal time for the next search loop, --- the maximum of that (whch cannot be exceeded) +-- the maximum of that (which cannot be exceeded) -- and if we are in time troubles or not compTime :: Int -> Int -> Int -> Int -> (Int, Int, Bool) -compTime tim tpm fixmtg lastsc +compTime tim tpm fixmtg cursc | tim == 0 && tpm == 0 = ( 0, 0, False) | otherwise = (ctm, tmx, ttroub) - where mtg = if fixmtg > 0 then fixmtg else estimateMovesToGo lastsc + where mtg = if fixmtg > 0 then fixmtg else estimateMovesToGo cursc ctn = tpm + tim `div` mtg (ctm, short) = if tim > 0 && tim < 2000 || tim == 0 && tpm < 700 then (300, True) @@ -444,7 +440,7 @@ compTime tim tpm fixmtg lastsc ttroub = short || over estMvsToGo :: Array Int Int -estMvsToGo = listArray (0, 8) [30, 28, 24, 18, 12, 10, 8, 6, 3] +estMvsToGo = listArray (0, 8) [50, 38, 24, 18, 12, 10, 8, 6, 3] estimateMovesToGo :: Int -> Int estimateMovesToGo sc = estMvsToGo ! mvidx @@ -462,9 +458,8 @@ startWorking tim tpm mtg dpt = do ctxLog DebugUci $ "Start at " ++ show currms ++ " to search: " ++ show tim ++ " / " ++ show tpm ++ " / " ++ show mtg ++ " - maximal " ++ show dpt ++ " plys" - modifyChanging $ \c -> c { working = True, srchStrtMs = currms, - prvMvInfo = Nothing, - crtStatus = posNewSearch (crtStatus c) } + modifyChanging $ \c -> c { working = True, srchStrtMs = currms, totBmCh = 0, + lastChDr = 0, crtStatus = posNewSearch (crtStatus c) } tid <- newThread (startSearchThread tim tpm mtg dpt) modifyChanging (\c -> c { compThread = Just tid }) return () @@ -498,106 +493,133 @@ ctxCatch a f = do -- Search with the given depth searchTheTree :: Int -> Int -> Int -> Int -> Int -> Int -> Maybe Int -> [Move] -> [Move] -> CtxIO Int -searchTheTree tief mtief timx tim tpm mtg lsc lpv rmvs = do +searchTheTree draft mdraft timx tim tpm mtg lsc lpv rmvs = do + ctxLog LogInfo $ "searchTheTree starts draft " ++ show draft ctx <- ask chg <- readChanging ctxLog LogInfo $ "Time = " ++ show tim ++ " Timx = " ++ show timx - (path, sc, rmvsf, timint, stfin) <- bestMoveCont tief timx (crtStatus chg) lsc lpv rmvs - case length path of _ -> return () -- because of lazyness! - storeBestMove path sc -- write back in status - modifyChanging (\c -> c { crtStatus = stfin }) + (path, sc, rmvsf, timint, stfin, ch) <- bestMoveCont draft timx (crtStatus chg) lsc lpv rmvs + -- case length path of _ -> return () -- because of lazyness! + let totch = totBmCh chg + ch + ldCh | ch > 0 = draft + | otherwise = lastChDr chg + modifyChanging $ \c -> c { crtStatus = stfin, totBmCh = totch, lastChDr = ldCh, + forGui = Just $ InfoB { infoPv = path, infoScore = sc }} currms <- lift $ currMilli (startSecond ctx) - let (ms', mx, urg) = compTime tim tpm mtg sc - ms <- if urg || null path then return ms' else correctTime tief (reduceBegin (realPly chg) ms') sc path - let strtms = srchStrtMs chg - delta = strtms + ms - currms - ms2 = ms `div` 2 - onlyone = ms > 0 && length rmvsf == 1 && tief >= 4 -- only in normal play - halfover = ms > 0 && delta <= ms2 -- time is half over - depthmax = tief >= mtief -- or maximal depth - mes = "Depth " ++ show tief ++ " Score " ++ show sc ++ " in ms " - ++ show currms ++ " remaining " ++ show delta - ++ " path " ++ show path + let (ms, mx, _) = compTime tim tpm mtg sc -- urg not used + reds = case lsc of + Just osc -> timeProlongation osc sc + _ -> 1 + redp = reduceBegin $ realPly chg + start = srchStrtMs chg + used = currms - start + over = used >= mx + onlyone = ms > 0 && length rmvsf == 1 && draft >= 4 -- only in normal play + draftmax = draft >= mdraft -- or maximal draft + mes = "Draft " ++ show draft ++ " Score " ++ show sc ++ " path " ++ show path + ++ " ms " ++ show ms ++ " used " ++ show used ctxLog LogInfo mes - ctxLog LogInfo $ "compTime: " ++ show ms' ++ " / " ++ show mx - if depthmax || timint || halfover || onlyone + ctxLog LogInfo $ "Time factors (reds/redp): " ++ show reds ++ " / " ++ show redp + (justStop, mxr) <- stopByChance (reds * redp) ms used mx draft ch totch ldCh + ctxLog LogInfo $ "compTime (ms/mx/mxr): " ++ show ms ++ " / " ++ show mx ++ " / " ++ show mxr + if draftmax || timint || over || onlyone || justStop then do - when depthmax $ ctxLog LogInfo "in searchTheTree: max depth reached" + ctxLog LogInfo $ "searchTheTree terminated in first if: " + ++ show draftmax ++ "/" + ++ show timint ++ "/" + ++ show over ++ "/" + ++ show onlyone ++ "/" + ++ show justStop giveBestMove path return sc else do + ctxLog LogInfo $ "searchTheTree finishes draft " ++ show draft chg' <- readChanging if working chg' - then if mx == 0 -- no time constraint - then searchTheTree (tief + 1) mtief 0 tim tpm mtg (Just sc) path rmvsf - else searchTheTree (tief + 1) mtief (strtms + mx) tim tpm mtg (Just sc) path rmvsf + then if mx == 0 -- no time constraint (take original maximum) + then searchTheTree (draft + 1) mdraft 0 tim tpm mtg (Just sc) path rmvsf + else searchTheTree (draft + 1) mdraft (start + mxr) tim tpm mtg (Just sc) path rmvsf else do ctxLog DebugUci "in searchTheTree: not working" giveBestMove path -- was stopped return sc --- We assume here that we always have at least the first move of the PV (our best) --- If not (which is a fatal error) we will get an exception (head of empty list) --- which will be catched somewhere else and reported --- This is changed now in an attemption to catch the head exception: if the path --- is empty, this function will not be called -correctTime :: Int -> Int -> Int -> [Move] -> CtxIO Int -correctTime draft ms sc path = do - tp <- asks tipars - chg <- readChanging - (ti, func) <- case prvMvInfo chg of - Nothing -> do - -- We are obviously in the first draft - just insert the first infos, use normal time - let pmi = PrevMvInfo { pmiBestSc = sc, pmiChanged = 0, pmiBMSoFar = [bm] } - bm = head path - func = \c -> c { prvMvInfo = Just pmi } - return (ms, func) - Just (PrevMvInfo { pmiBestSc = osc, pmiChanged = ok, pmiBMSoFar = obsf }) -> do - -- We have previous moves, update and calculate time factor - let pmi = PrevMvInfo { pmiBestSc = sc, pmiChanged = k, pmiBMSoFar = bsf } - (k, bsf, cha) = - case path of - bm:_ -> case obsf of - om:_ -> if bm == om -- same best move? - then (ok, obsf, False) - else (ok + 1, bm : delete bm obsf, True) - [] -> (ok + 1, [bm], True) - [] -> (ok, obsf, False) -- this cant happen! - func = \c -> c { prvMvInfo = Just pmi } - ms' = timeFactor tp cha draft ms osc sc k bsf - ctxLog LogInfo $ "timeFactor: " ++ show cha - ++ " / " ++ show draft - ++ " / " ++ show ms - ++ " / " ++ show osc - ++ " / " ++ show sc - ++ " / " ++ show k - ++ " / " ++ show bsf - return (ms', func) - modifyChanging func - return ti - --- Concept is: have an initial factor and 3 auxiliary: one for draft (when last best move --- changed), one for score change and one for number of changes and different best moves so far --- Add all together and limit by a max factor --- Then multiply the given time by that factor -timeFactor :: TimeParams -> Bool -> Int -> Int -> Int -> Int -> Int -> [Move] -> Int -timeFactor tp cha draft tim osc sc chgs mvs = round $ fromIntegral tim * min (tpMaxFact tp) finf - where finf = tpIniFact tp + drf + scf + chf - drf = if cha then tpDrScale tp * fromIntegral (draft * draft) -- draft factor - else 0 - scf = let scdiff = osc - sc - in tpScScale tp * fromIntegral (scdiff * scdiff * draft) -- score change factor - chf = tpChScale tp * fromIntegral (chgs * length mvs * draft) -- change factor - -reduceBegin :: Maybe Int -> Int -> Int -reduceBegin mi ms | Just i <- mi, - i < 10 = (ms * i) `div` 10 - | otherwise = ms - -storeBestMove :: [Move] -> Int -> CtxIO () -storeBestMove mvs sc = do - let s = InfoB { infoPv = mvs, infoScore = sc } - modifyChanging (\c -> c { forGui = Just s }) +-- The time management changes a bit like this: +-- We calculate ther normal and maximum time to use for this move, as before +-- But now, instead of giving some time correction based on number of changes in best move, +-- we calculate a probability that next draft will change the best move based on: +-- - last draft +-- - number of changes in last draft +-- - total number of changes in this search +-- - last draft with changes +-- Than based on this probability and on wanted time versus already spent time +-- we decide if we start the next draft or not +stopByChance :: Double -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> CtxIO (Bool, Int) +stopByChance red ms used mx draft ch totch ldCh + | used >= msr = return (True, mx) + | otherwise = do + let dmax = maxDepthAtThisRate draft used msr + ctxLog LogInfo $ "stopByChance: dmax = " ++ show dmax ++ ", draft = " ++ show draft + if dmax <= draft + then return (True, mx) + else do + let p = probChange (fromIntegral draft) (fromIntegral ch) (fromIntegral totch) (fromIntegral ldCh) + mxf = fromIntegral mx + mxr = round $ (mxf + mxf * p) / 2 + if dmax > draft + 1 + then return (False, mxr) -- we have more than 1 draft to go + else do -- this would be the last draft so far + ctxLog LogInfo $ "stopByChance: p = " ++ show p + r <- liftIO $ getStdRandom (randomR (0::Double, 1)) + if r < p then return (False, mxr) else return (True, mxr) + where msr = round $ red * fromIntegral ms + +maxDepthAtThisRate :: Int -> Int -> Int -> Int +maxDepthAtThisRate d used ms + | d == 1 = floor dmax1 + | otherwise = floor dmax + where branchingFactor = 1.5 :: Double + logs = 1 / log branchingFactor + bfd = branchingFactor ** fromIntegral d + msf = fromIntegral ms + usedf = fromIntegral (used+1) + dmax = (log (bfd * msf - msf + usedf) - log usedf) * logs + dmax1 = (log (msf + usedf) - log usedf) * logs + +-- This is just a prediction using logistic regression on the 4 parameters +-- The parameters were found outside and have reached 77% prediction rate +probChange :: Double -> Double -> Double -> Double -> Double +probChange d c ct dc = 1 / (1 + exp (-z)) + -- where w0 = -0.47326189 -- these got 77% + -- w1 = -0.24871493 + -- w2 = 0.18633039 + -- w3 = 0.07070459 + -- w4 = 0.1175941 + -- where w0 = -0.46828955 -- these got 80% + -- w1 = -0.24585093 + -- w2 = 0.19289682 + -- w3 = 0.09635968 + -- w4 = 0.10235857 + where w0 = -1.80799248 -- these got 91% with scales + w1 = -0.59439615 / 20 + w2 = 0.3024311 / 10 + w3 = 0.4347557 / 20 + w4 = -0.34551297 / 20 + z = w0 + w1 * d + w2 * c + w3 * ct + w4 * dc + +reduceBegin :: Maybe Int -> Double +reduceBegin mi | Just i <- mi, + i < 10 = fromIntegral i / 10 + | otherwise = 1 + +timeProlongation :: Int -> Int -> Double +timeProlongation osc sc + | sc >= osc - tpMargin = 1 + | otherwise = 1 + log ((oscf - scf) / fm) + where oscf = fromIntegral osc + scf = fromIntegral sc + tpMargin = 8 + fm = fromIntegral tpMargin giveBestMove :: [Move] -> CtxIO () giveBestMove mvs = do diff --git a/Moves/Base.hs b/Moves/Base.hs index 3dca6a9c..e58a881c 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -9,7 +9,7 @@ module Moves.Base ( posToState, getPos, posNewSearch, doRealMove, doMove, undoMove, genMoves, genTactMoves, canPruneMove, tacticalPos, zugZwang, isMoveLegal, isKillCand, isTKillCand, - betaCut, doNullMove, ttRead, ttStore, curNodes, chooseMove, isTimeout, informCtx, + betaCut, doNullMove, ttRead, ttStore, curNodes, isTimeout, informCtx, mateScore, scoreDiff, qsDelta, draftStats, finNode, @@ -22,7 +22,6 @@ import Data.Int import Control.Monad.State import Control.Monad.Reader (ask) -- import Numeric -import System.Random import Moves.BaseTypes import Search.AlbetaTypes @@ -370,26 +369,6 @@ scoreDiff = do (p1:p2:_) -> return $! negate (staticScore p1 + staticScore p2) _ -> return 0 --- Choose between almost equal (root) moves -chooseMove :: Bool -> [(Int, [Move])] -> Game (Int, [Move]) -chooseMove True pvs = return $ if null pvs then error "Empty choose!" else head pvs -chooseMove _ pvs = case pvs of - p1 : [] -> return p1 - p1 : ps -> do - let equal = p1 : takeWhile inrange ps - minscore = fst p1 - scoreDiffEqual - inrange x = fst x >= minscore - len = length equal - logMes $ "Choose from: " ++ show pvs - logMes $ "Choose length: " ++ show len - logMes $ "Choose equals: " ++ show equal - if len == 1 - then return p1 - else do - r <- liftIO $ getStdRandom (randomR (0, len - 1)) - return $! equal !! r - [] -> return (0, []) -- just for Wall - logMes :: String -> Game () logMes s = lift $ talkToContext . LogMes $ s diff --git a/Search/Albeta.hs b/Search/Albeta.hs index c1bb9456..e4229677 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -11,8 +11,7 @@ import Data.Array.Base (unsafeAt) import Data.Array.Unboxed import Data.Bits import Data.Int -import Data.List (delete, sortBy) -import Data.Ord (comparing) +import Data.List (delete) import Data.Maybe (fromMaybe) import Search.CStateMonad @@ -121,8 +120,7 @@ beta0 = maxBound - 2000 data Pvsl = Pvsl { pvPath :: Path, -- pv path - pvNodes :: !Int64, -- number of nodes in the current search - pvGood :: !Bool -- beta cut or alpha improvement + pvNodes :: !Int64 -- number of nodes in the current search } deriving Show data Killer = NoKiller | OneKiller !Move | TwoKillers !Move !Move deriving (Eq, Show) @@ -158,6 +156,7 @@ data NodeState movno :: !Int, -- current move number spcno :: !Int, -- last move number of a special move albe :: !Bool, -- in alpha/beta search (for small depths) + rbmch :: !Int, -- number of changes in root best move cursc :: Path, -- current alpha value (now plus path & depth) killer :: Killer, -- the current killer moves cpos :: MyPos, -- current position for this node @@ -223,7 +222,7 @@ pvsInit = PVState { ronly = pvro00, stats = ssts0, absdp = 0, usedext = 0, abort futme = futIniVal, futyo = futIniVal, lmrhi = lmrInitLim, lmrlv = lmrInitLv, lmrrs = 0 } nst0 :: NodeState -nst0 = NSt { crtnt = PVNode, nxtnt = PVNode, cursc = pathFromScore "Zero" 0, +nst0 = NSt { crtnt = PVNode, nxtnt = PVNode, cursc = pathFromScore "Zero" 0, rbmch = 0, movno = 1, spcno = 1, killer = NoKiller, albe = False, cpos = initPos, pvsl = [] } -- we start with spcno = 1 as we consider the first move as special -- to avoid in any way reducing the tt move @@ -234,7 +233,7 @@ resetNSt !sc !kill nst = nst { cursc = sc, movno = 1, spcno = 1, killer = kill } pvro00 :: PVReadOnly pvro00 = PVReadOnly { draft = 0, albest = False, timeli = False, abmili = 0 } -alphaBeta :: ABControl -> Game (Int, [Move], [Move], Bool) +alphaBeta :: ABControl -> Game (Int, [Move], [Move], Bool, Int) alphaBeta abc = do let !d = maxdepth abc rmvs = Alt $ rootmvs abc @@ -254,7 +253,7 @@ alphaBeta abc = do -- ++ " alpha = " ++ show alpha1 -- ++ " beta = " ++ show beta1 -- aspirWin alpha1 beta1 d lpv rmvs aspTries - r1@((s1, es1, _), pvsf) + r1@((s1, es1, _, _), pvsf) <- runCState (searchReduced alpha1 beta1) pvs0 if abort pvsf || (s1 > alpha1 && s1 < beta1 && not (nullSeq es1)) then return r1 @@ -267,9 +266,9 @@ alphaBeta abc = do -- when aborted, return the last found good move -- we have to trust that abort is never done in draft 1! case fst r of - (s, Seq path, Alt rmvs') -> if null path - then return (fromMaybe 0 $ lastscore abc, lastpv abc, [], timint) - else return (s, path, rmvs', timint) + (s, Seq path, Alt rmvs', ch) -> if null path + then return (fromMaybe 0 $ lastscore abc, lastpv abc, [], timint, 0) + else return (s, path, rmvs', timint, ch) {-- aspirWin :: Int -> Int -> Int -> Seq Move -> Alt Move -> Int -> m (Int, Seq Move, Alt Move) @@ -288,7 +287,7 @@ aspirWin a b d lpv rmvs t = do -- Root PV Search pvRootSearch :: Int -> Int -> Int -> Seq Move -> Alt Move -> Bool - -> Search (Int, Seq Move, Alt Move) + -> Search (Int, Seq Move, Alt Move, Int) pvRootSearch a b d lastpath rmvs aspir = do pos <- lift getPos edges <- if null (unalt rmvs) -- only when d==1, but we could have lastpath from the previous real move @@ -300,35 +299,30 @@ pvRootSearch a b d lastpath rmvs aspir = do nstf <- pvLoop (pvInnerRoot b d) nsti edges abrt <- gets abort reportStats - let sc | d > 1 = pathScore (cursc nstf) - | p:_ <- pvsl nstf = pathScore $ pvPath p - | otherwise = a + let (sc, pm) | d > 1 = (pathScore (cursc nstf), pathMoves (cursc nstf)) + | ms:_ <- pvsl nstf = (pathScore $ pvPath ms, pathMoves (pvPath ms)) + | otherwise = (a, emptySeq) + p = unseq pm -- Root is pv node, cannot fail low, except when aspiration fails! if sc <= a -- failed low or timeout when searching PV then do unless (abrt || aspir) $ lift $ informStr "Failed low at root??" - return (a, emptySeq, edges) -- just to permit aspiration to retry + return (a, emptySeq, edges, rbmch nstf) -- just to permit aspiration to retry else do -- lift $ mapM_ (\m -> informStr $ "Root move: " ++ show m) (pvsl nstf) - albest' <- gets (albest . ronly) - (s, p) <- if sc >= b || abrt - then return (sc, unseq $ pathMoves (cursc nstf)) - else lift $ chooseMove albest' - $ sortBy (comparing fstdesc) - $ map pvslToPair - $ filter pvGood $ pvsl nstf - when (d < depthForCM) $ informBest s d p + when (d < depthForCM) $ informBest sc d p let (best':_) = p allrmvs = if sc >= b then unalt edges else map pvslToMove (pvsl nstf) xrmvs = Alt $ best' : delete best' allrmvs -- best on top - return (s, Seq p, xrmvs) - where fstdesc (a', _) = -a' + return (sc, Seq p, xrmvs, rbmch nstf) +{-- pvslToPair :: Pvsl -> (Int, [Move]) pvslToPair (Pvsl { pvPath = p }) = (score, pv) where pv = unseq $ pathMoves p sc = pathScore p score = scoreToExtern sc $ length pv +--} pvslToMove :: Pvsl -> Move pvslToMove (Pvsl { pvPath = Path { pathMoves = Seq (m:_)}}) = m @@ -417,20 +411,21 @@ checkFailOrPVRoot xstats b d e s nst = timeToAbort (True, nst) $ do !nodes0 = sNodes xstats + sRSuc xstats !nodes1 = sNodes (stats sst) + sRSuc (stats sst) !nodes' = nodes1 - nodes0 - pvg = Pvsl s nodes' True -- the good - pvb = Pvsl s nodes' False -- the bad + pvg = Pvsl s nodes' -- the good de = max d $ pathDepth s if d == 1 then do let typ = 2 lift $ ttStore de typ (pathScore s) e nodes' - let xpvslg = if pathScore s > a - then insertToPvs d pvg (pvsl nst) -- the good - else insertToPvs d pvb (pvsl nst) -- the bad (when aspiration) - return (False, nst {movno = mn + 1, pvsl = xpvslg }) + -- lift $ logmes $ "checkFail: d = 1, mv = " ++ show e + let xpvslg = insertToPvs d pvg (pvsl nst) -- the good + rch | pathScore s > a = rbmch nst + 1 + | otherwise = rbmch nst + return (False, nst {movno = mn + 1, pvsl = xpvslg, rbmch = rch }) else if pathScore s <= a then do -- failed low - let xpvslb = insertToPvs d pvb (pvsl nst) -- the bad + -- lift $ logmes $ "checkFail: d = " ++ show d ++ ", mv = " ++ show e ++ ", s <= a" + let xpvslb = insertToPvs d pvg (pvsl nst) -- the bad nst1 = nst { movno = mn + 1, pvsl = xpvslb, killer = newKiller d s nst } return (False, nst1) else if pathScore s >= b @@ -440,9 +435,10 @@ checkFailOrPVRoot xstats b d e s nst = timeToAbort (True, nst) $ do let typ = 1 -- beta cut (score is lower limit) with move e ttStore de typ b e nodes' betaCut True (absdp sst) e + -- lift $ logmes $ "checkFail: d = " ++ show d ++ ", mv = " ++ show e ++ ", s >= b" let xpvslg = insertToPvs d pvg (pvsl nst) -- the good csc = s { pathScore = b } - nst1 = nst { cursc = csc, pvsl = xpvslg } + nst1 = nst { cursc = csc, pvsl = xpvslg, rbmch = rbmch nst + 1 } return (True, nst1) else do -- means: > a && < b let sc = pathScore s @@ -452,9 +448,10 @@ checkFailOrPVRoot xstats b d e s nst = timeToAbort (True, nst) $ do let typ = 2 -- best move so far (score is exact) ttStore de typ sc e nodes' betaCut True (absdp sst) e -- not really cut, but good move + -- lift $ logmes $ "checkFail: d = " ++ show d ++ ", mv = " ++ show e ++ ", s > a" let xpvslg = insertToPvs d pvg (pvsl nst) -- the good nst1 = nst { cursc = s, nxtnt = nextNodeType (nxtnt nst), - movno = mn + 1, pvsl = xpvslg } + movno = mn + 1, pvsl = xpvslg, rbmch = rbmch nst + 1 } return (False, nst1) insertToPvs :: Int -> Pvsl -> [Pvsl] -> [Pvsl] diff --git a/Struct/Context.hs b/Struct/Context.hs index 385b5d6a..f797c6c1 100644 --- a/Struct/Context.hs +++ b/Struct/Context.hs @@ -56,14 +56,6 @@ data Context = Ctx { change :: MVar Changing -- the changing context } --- Information about previuos best move and changes --- to be used in time management -data PrevMvInfo = PrevMvInfo { - pmiBestSc :: Int, -- score of best move - pmiChanged :: Int, -- number of changes in best move - pmiBMSoFar :: [Move] -- all best moves seen so far - } - -- Time management parameters data TimeParams = TimeParams { tpIniFact, tpMaxFact, @@ -106,13 +98,14 @@ data Changing = Chg { forGui :: Maybe InfoToGui, -- info for gui srchStrtMs :: Int, -- search start time (milliseconds) myColor :: Color, -- our play color - prvMvInfo :: Maybe PrevMvInfo -- not in the first draft + totBmCh :: Int, -- all BM changes in this search + lastChDr :: Int -- last draft which changed root BM } type CtxIO = ReaderT Context IO -- Result of a search -type IterResult = ([Move], Int, [Move], Bool, MyState) +type IterResult = ([Move], Int, [Move], Bool, MyState, Int) readChanging :: CtxIO Changing readChanging = do diff --git a/Struct/Status.hs b/Struct/Status.hs index dd8cef84..1ca02739 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -20,7 +20,7 @@ data MyState = MyState { stack :: [MyPos], -- stack of played positions hash :: Cache, -- transposition table hist :: History, -- history table - mstats :: SStats, -- per move search search statistics + mstats :: SStats, -- per move search statistics gstats :: SStats, -- global search statistics evalst :: EvalState -- eval status (parameter & statistics) } diff --git a/Uci/UciGlue.hs b/Uci/UciGlue.hs index b9e9c7d6..ec6a8877 100644 --- a/Uci/UciGlue.hs +++ b/Uci/UciGlue.hs @@ -33,9 +33,9 @@ bestMoveCont tiefe sttime stati lastsc lpv rmvs = do best = False, stoptime = sttime } - ((sc, path, rmvsf, timint), statf) <- SM.runCState (alphaBeta abc) stati + ((sc, path, rmvsf, timint, ch), statf) <- SM.runCState (alphaBeta abc) stati -- when (sc == 0) $ return () let n = sNodes $ mstats statf informGui sc tiefe n path ctxLog LogInfo $ "score " ++ show sc ++ " path " ++ show path - return (path, sc, rmvsf, timint, statf) + return (path, sc, rmvsf, timint, statf, ch) From 730fa49121f4f0da0344575e9831c62c1ec7cc00 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 21 Jan 2017 13:21:34 +0100 Subject: [PATCH 20/71] Time management: consider last move score Search longer when score drops Draft extension when score drops more than a margin --- Main/Barbarossa.hs | 43 +++++++++++++++++++++++++++++-------------- Moves/Base.hs | 2 -- Struct/Context.hs | 3 ++- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 038b2066..9fc9a4c3 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -111,7 +111,7 @@ initContext opts = do forGui = Nothing, srchStrtMs = 0, myColor = White, - totBmCh = 0, lastChDr = 0 + totBmCh = 0, lastChDr = 0, lmvScore = Nothing } ctxVar <- newMVar chg let context = Ctx { @@ -418,6 +418,9 @@ remTimeFracDev = remTimeFracFin - remTimeFracIni timeReserved :: Int timeReserved = 70 -- milliseconds reserved for move communication +extendScoreMargin :: Int +extendScoreMargin = 40 + -- This function calculates the normal time for the next search loop, -- the maximum of that (which cannot be exceeded) -- and if we are in time troubles or not @@ -507,7 +510,12 @@ searchTheTree draft mdraft timx tim tpm mtg lsc lpv rmvs = do forGui = Just $ InfoB { infoPv = path, infoScore = sc }} currms <- lift $ currMilli (startSecond ctx) let (ms, mx, _) = compTime tim tpm mtg sc -- urg not used - reds = case lsc of + exte = maybe False id $ do + los <- lsc + gls <- lmvScore chg + return $ sc < los - extendScoreMargin + || sc < gls - extendScoreMargin + reds = case lmvScore chg of Just osc -> timeProlongation osc sc _ -> 1 redp = reduceBegin $ realPly chg @@ -520,7 +528,7 @@ searchTheTree draft mdraft timx tim tpm mtg lsc lpv rmvs = do ++ " ms " ++ show ms ++ " used " ++ show used ctxLog LogInfo mes ctxLog LogInfo $ "Time factors (reds/redp): " ++ show reds ++ " / " ++ show redp - (justStop, mxr) <- stopByChance (reds * redp) ms used mx draft ch totch ldCh + (justStop, mxr) <- stopByChance (reds * redp) exte ms used mx draft ch totch ldCh ctxLog LogInfo $ "compTime (ms/mx/mxr): " ++ show ms ++ " / " ++ show mx ++ " / " ++ show mxr if draftmax || timint || over || onlyone || justStop then do @@ -530,6 +538,8 @@ searchTheTree draft mdraft timx tim tpm mtg lsc lpv rmvs = do ++ show over ++ "/" ++ show onlyone ++ "/" ++ show justStop + -- Store last score for this move + modifyChanging $ \c -> c { lmvScore = Just sc } giveBestMove path return sc else do @@ -544,31 +554,36 @@ searchTheTree draft mdraft timx tim tpm mtg lsc lpv rmvs = do giveBestMove path -- was stopped return sc --- The time management changes a bit like this: +-- The time management changes like this: -- We calculate ther normal and maximum time to use for this move, as before --- But now, instead of giving some time correction based on number of changes in best move, --- we calculate a probability that next draft will change the best move based on: +-- we correct the time per move with some factor (ply in game, score drop) +-- we calculate what would be the max draft we could reach at this rate +-- if we reached the max draft - stop the search +-- else we calculate a probability that next draft will change the best move based on: -- - last draft -- - number of changes in last draft -- - total number of changes in this search -- - last draft with changes --- Than based on this probability and on wanted time versus already spent time --- we decide if we start the next draft or not -stopByChance :: Double -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> CtxIO (Bool, Int) -stopByChance red ms used mx draft ch totch ldCh +-- Than based on this probability we limit the interrup time for next search (in case it starts) +-- if max draft is greater than next draft we start next search +-- if max draft = next draft we decide probabilistically if we start the next draft or not +stopByChance :: Double -> Bool -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> CtxIO (Bool, Int) +stopByChance red extend ms used mx draft ch totch ldCh + | extend = return (False, mx) | used >= msr = return (True, mx) | otherwise = do let dmax = maxDepthAtThisRate draft used msr - ctxLog LogInfo $ "stopByChance: dmax = " ++ show dmax ++ ", draft = " ++ show draft - if dmax <= draft + ctxLog LogInfo $ "stopByChance: draft = " ++ show draft ++ " dmax = " ++ show dmax + if dmax < draft then return (True, mx) else do + -- We need the probability to limit the interrupt time at least: let p = probChange (fromIntegral draft) (fromIntegral ch) (fromIntegral totch) (fromIntegral ldCh) mxf = fromIntegral mx - mxr = round $ (mxf + mxf * p) / 2 + mxr = min mx $ round $ red * (mxf + mxf * p) / 2 if dmax > draft + 1 then return (False, mxr) -- we have more than 1 draft to go - else do -- this would be the last draft so far + else do ctxLog LogInfo $ "stopByChance: p = " ++ show p r <- liftIO $ getStdRandom (randomR (0::Double, 1)) if r < p then return (False, mxr) else return (True, mxr) diff --git a/Moves/Base.hs b/Moves/Base.hs index e58a881c..df5096bd 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -44,8 +44,6 @@ nearmate i = i >= mateScore - 255 || i <= -mateScore + 255 -- Some options and parameters: -- debug :: Bool -- debug = False -scoreDiffEqual :: Int -scoreDiffEqual = 4 -- under this score difference moves are considered to be equal (choose random) printEvalInt :: Int64 printEvalInt = 2 `shiftL` 12 - 1 -- if /= 0: print eval info every so many nodes diff --git a/Struct/Context.hs b/Struct/Context.hs index f797c6c1..ed438fa0 100644 --- a/Struct/Context.hs +++ b/Struct/Context.hs @@ -99,7 +99,8 @@ data Changing = Chg { srchStrtMs :: Int, -- search start time (milliseconds) myColor :: Color, -- our play color totBmCh :: Int, -- all BM changes in this search - lastChDr :: Int -- last draft which changed root BM + lastChDr :: Int, -- last draft which changed root BM + lmvScore :: Maybe Int -- last move score } type CtxIO = ReaderT Context IO From 47f6cf931e43aa3969ec3fd7956299502ace4465 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 21 Jan 2017 22:56:28 +0100 Subject: [PATCH 21/71] Small but important corrections & additions Correct return from abort: do not change tables! Implement ucinewgame: reset some variables Moves to go: less when repetitions Correct score when mate found --- Main/Barbarossa.hs | 125 +++++++++++++++------------- Moves/Base.hs | 9 +- Search/Albeta.hs | 188 +++++++++++++++++++----------------------- Search/AlbetaTypes.hs | 4 +- Uci/UCI.hs | 8 +- 5 files changed, 168 insertions(+), 166 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 9fc9a4c3..46ae1832 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -208,7 +208,7 @@ theWriter inter wchan lchan mustlog refs = forever $ do when mustlog $ logging lchan refs "Output" s -- The informer is getting structured data --- and formats it to a string which is set to the writer +-- and formats it to a string which is sent to the writer -- It ignores messages which come while we are not searching startInformer :: CtxIO () startInformer = do @@ -314,7 +314,7 @@ notImplemented :: String -> CtxIO () notImplemented s = ctxLog LogWarning $ "not implemented: " ++ s doUciNewGame :: CtxIO () -doUciNewGame = notImplemented "doUciNewGame" +doUciNewGame = modifyChanging $ \c -> c { totBmCh = 0, lastChDr = 0, lmvScore = Nothing } doPosition :: Pos -> [Move] -> CtxIO () doPosition fen mvs = do @@ -326,12 +326,14 @@ doPosition fen mvs = do hi <- liftIO newHist let es = evalst $ crtStatus chg (mi, ns) <- newState fen mvs (hash . crtStatus $ chg) hi es - modifyChanging (\c -> c { crtStatus = ns, realPly = mi, myColor = myCol }) + -- reset the last move score when we begin new game: + let lsc = case mi of + Just x -> if x == 1 || x == 2 then Nothing else lmvScore chg + Nothing -> lmvScore chg + modifyChanging $ \c -> c { crtStatus = ns, realPly = mi, myColor = myCol, lmvScore = lsc } where newState fpos ms c h es = foldM execMove (stateFromFen fpos c h es) ms execMove (mi, s) m = do - let mj = case mi of - Nothing -> Nothing - Just i -> Just (i+1) + let mj = ((+) 1) <$> mi -- increment real ply s' <- execCState (doRealMove m) s return (mj, s') fenColor = movingColor fen @@ -362,9 +364,10 @@ doGo cmds = do then ctxLog DebugUci "Just ponder: ignored" else do let (tim, tpm, mtg) = getTimeParams cmds $ myColor chg + rept = countRepetitions $ crtStatus chg md = 20 -- max search depth dpt = fromMaybe md (findDepth cmds) - startWorking tim tpm mtg dpt + startWorking tim tpm mtg dpt rept data Agreg = Agreg { agrCumErr :: !Integer, -- accumulated error @@ -393,7 +396,7 @@ perFenLine dpt fenLine agr = do ctxLog LogInfo $ "Ref.Score " ++ refsc ++ " fen " ++ fen doPosition (Pos fen) [] modifyChanging $ \c -> c { working = True } - sc <- searchTheTree 1 dpt 0 0 0 0 Nothing [] [] + sc <- searchTheTree 1 dpt 0 0 0 0 0 Nothing [] [] return $ aggregateError agr rsc sc aggregateError :: Agreg -> Int -> Int -> Agreg @@ -419,17 +422,20 @@ timeReserved :: Int timeReserved = 70 -- milliseconds reserved for move communication extendScoreMargin :: Int -extendScoreMargin = 40 +extendScoreMargin = 24 -- This function calculates the normal time for the next search loop, -- the maximum of that (which cannot be exceeded) -- and if we are in time troubles or not -compTime :: Int -> Int -> Int -> Int -> (Int, Int, Bool) -compTime tim tpm fixmtg cursc +compTime :: Int -> Int -> Int -> Int -> Int -> (Int, Int, Bool) +compTime tim tpm fixmtg cursc rept | tim == 0 && tpm == 0 = ( 0, 0, False) | otherwise = (ctm, tmx, ttroub) where mtg = if fixmtg > 0 then fixmtg else estimateMovesToGo cursc - ctn = tpm + tim `div` mtg + mtr | rept >= 2 = 3 -- consider repetitions + | mtg == 0 = 1 + | otherwise = mtg + ctn = tpm + tim `div` mtr (ctm, short) = if tim > 0 && tim < 2000 || tim == 0 && tpm < 700 then (300, True) else (ctn, False) @@ -443,7 +449,7 @@ compTime tim tpm fixmtg cursc ttroub = short || over estMvsToGo :: Array Int Int -estMvsToGo = listArray (0, 8) [50, 38, 24, 18, 12, 10, 8, 6, 3] +estMvsToGo = listArray (0, 8) [50, 36, 24, 15, 10, 7, 5, 3, 2] estimateMovesToGo :: Int -> Int estimateMovesToGo sc = estMvsToGo ! mvidx @@ -454,8 +460,8 @@ newThread a = do ctx <- ask liftIO $ forkIO $ runReaderT a ctx -startWorking :: Int -> Int -> Int -> Int -> CtxIO () -startWorking tim tpm mtg dpt = do +startWorking :: Int -> Int -> Int -> Int -> Int -> CtxIO () +startWorking tim tpm mtg dpt rept = do ctx <- ask currms <- lift $ currMilli (startSecond ctx) ctxLog DebugUci $ "Start at " ++ show currms @@ -463,7 +469,7 @@ startWorking tim tpm mtg dpt = do ++ " - maximal " ++ show dpt ++ " plys" modifyChanging $ \c -> c { working = True, srchStrtMs = currms, totBmCh = 0, lastChDr = 0, crtStatus = posNewSearch (crtStatus c) } - tid <- newThread (startSearchThread tim tpm mtg dpt) + tid <- newThread (startSearchThread tim tpm mtg dpt rept) modifyChanging (\c -> c { compThread = Just tid }) return () @@ -471,9 +477,9 @@ startWorking tim tpm mtg dpt = do -- in the search thread (here in giveBestMove) -- This is not good, then it can lead to race conditions. We should -- find another scheme, for example with STM -startSearchThread :: Int -> Int -> Int -> Int -> CtxIO () -startSearchThread tim tpm mtg dpt = - ctxCatch (void $ searchTheTree 1 dpt 0 tim tpm mtg Nothing [] []) +startSearchThread :: Int -> Int -> Int -> Int -> Int -> CtxIO () +startSearchThread tim tpm mtg dpt rept = + ctxCatch (void $ searchTheTree 1 dpt 0 tim tpm mtg rept Nothing [] []) $ \e -> do chg <- readChanging let mes = "searchTheTree terminated by exception: " ++ show e @@ -495,8 +501,8 @@ ctxCatch a f = do (\e -> runReaderT (f e) ctx) -- Search with the given depth -searchTheTree :: Int -> Int -> Int -> Int -> Int -> Int -> Maybe Int -> [Move] -> [Move] -> CtxIO Int -searchTheTree draft mdraft timx tim tpm mtg lsc lpv rmvs = do +searchTheTree :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Maybe Int -> [Move] -> [Move] -> CtxIO Int +searchTheTree draft mdraft timx tim tpm mtg rept lsc lpv rmvs = do ctxLog LogInfo $ "searchTheTree starts draft " ++ show draft ctx <- ask chg <- readChanging @@ -509,7 +515,7 @@ searchTheTree draft mdraft timx tim tpm mtg lsc lpv rmvs = do modifyChanging $ \c -> c { crtStatus = stfin, totBmCh = totch, lastChDr = ldCh, forGui = Just $ InfoB { infoPv = path, infoScore = sc }} currms <- lift $ currMilli (startSecond ctx) - let (ms, mx, _) = compTime tim tpm mtg sc -- urg not used + let (ms, mx, _) = compTime tim tpm mtg sc rept -- urg not used exte = maybe False id $ do los <- lsc gls <- lmvScore chg @@ -531,28 +537,28 @@ searchTheTree draft mdraft timx tim tpm mtg lsc lpv rmvs = do (justStop, mxr) <- stopByChance (reds * redp) exte ms used mx draft ch totch ldCh ctxLog LogInfo $ "compTime (ms/mx/mxr): " ++ show ms ++ " / " ++ show mx ++ " / " ++ show mxr if draftmax || timint || over || onlyone || justStop - then do - ctxLog LogInfo $ "searchTheTree terminated in first if: " - ++ show draftmax ++ "/" - ++ show timint ++ "/" - ++ show over ++ "/" - ++ show onlyone ++ "/" - ++ show justStop - -- Store last score for this move - modifyChanging $ \c -> c { lmvScore = Just sc } - giveBestMove path - return sc - else do - ctxLog LogInfo $ "searchTheTree finishes draft " ++ show draft - chg' <- readChanging - if working chg' - then if mx == 0 -- no time constraint (take original maximum) - then searchTheTree (draft + 1) mdraft 0 tim tpm mtg (Just sc) path rmvsf - else searchTheTree (draft + 1) mdraft (start + mxr) tim tpm mtg (Just sc) path rmvsf - else do - ctxLog DebugUci "in searchTheTree: not working" - giveBestMove path -- was stopped - return sc + then do + ctxLog LogInfo $ "searchTheTree terminated in first if: " + ++ show draftmax ++ "/" + ++ show timint ++ "/" + ++ show over ++ "/" + ++ show onlyone ++ "/" + ++ show justStop + -- Store last score for this move + modifyChanging $ \c -> c { lmvScore = Just sc } + giveBestMove path + return sc + else do + ctxLog LogInfo $ "searchTheTree finishes draft " ++ show draft + chg' <- readChanging + if working chg' + then if mx == 0 -- no time constraint (take original maximum) + then searchTheTree (draft + 1) mdraft 0 tim tpm mtg rept (Just sc) path rmvsf + else searchTheTree (draft + 1) mdraft (start + mxr) tim tpm mtg rept (Just sc) path rmvsf + else do + ctxLog DebugUci "in searchTheTree: not working" + giveBestMove path -- was stopped + return sc -- The time management changes like this: -- We calculate ther normal and maximum time to use for this move, as before @@ -639,8 +645,7 @@ timeProlongation osc sc giveBestMove :: [Move] -> CtxIO () giveBestMove mvs = do -- ctxLog "Info" $ "The moves: " ++ show mvs - modifyChanging $ \c -> c { - working = False, compThread = Nothing, forGui = Nothing } + modifyChanging $ \c -> c { working = False, compThread = Nothing, forGui = Nothing } if null mvs then answer $ infos "empty pv" else answer $ bestMove (head mvs) Nothing @@ -669,7 +674,7 @@ beforeProgExit = return () doStop :: CtxIO () doStop = do chg <- readChanging - modifyChanging (\c -> c { working = False, compThread = Nothing }) + modifyChanging $ \c -> c { working = False, compThread = Nothing } case compThread chg of Just tid -> do -- when extern $ liftIO $ threadDelay 100000 -- warte 0.1 Sec. @@ -711,18 +716,28 @@ bestMove m mp = s -- sel.depth nicht implementiert formInfo :: InfoToGui -> String formInfo itg = "info" - -- ++ " score cp " ++ show isc - ++ formScore isc + ++ formScore esc ++ " depth " ++ show (infoDepth itg) -- ++ " seldepth " ++ show idp ++ " time " ++ show (infoTime itg) ++ " nodes " ++ show (infoNodes itg) ++ nps' - ++ " pv" ++ concatMap (\m -> ' ' : toString m) (infoPv itg) + ++ " pv" ++ concatMap (\m -> ' ' : toString m) pv where nps' = case infoTime itg of 0 -> "" x -> " nps " ++ show (infoNodes itg `div` fromIntegral x * 1000) - isc = infoScore itg + esc = scoreToExtern (infoScore itg) (length pv) + pv = infoPv itg + +data ExternScore = Score Int | Mate Int + +-- The internal score is weird for found mates (always mate) +-- Turn it to nicer score by considering path lenght to mate +scoreToExtern :: Int -> Int -> ExternScore +scoreToExtern sc le + | sc == mateScore = Mate $ (le + 1) `div` 2 + | sc == -mateScore = Mate $ negate $ le `div` 2 + | otherwise = Score sc -- formInfoB :: InfoToGui -> String -- formInfoB itg = "info" @@ -731,11 +746,9 @@ formInfo itg = "info" -- ++ " pv" ++ concatMap (\m -> ' ' : toString m) (infoPv itg) -- where isc = infoScore itg -formScore :: Int -> String -formScore i - | i >= mateScore - 255 = " score mate " ++ show ((mateScore - i + 1) `div` 2) - | i <= (-mateScore) + 255 = " score mate " ++ show ((-mateScore - i) `div` 2) - | otherwise = " score cp " ++ show i +formScore :: ExternScore -> String +formScore (Score s) = " score cp " ++ show s +formScore (Mate n) = " score mate " ++ show n -- sel.depth nicht implementiert -- formInfo2 :: InfoToGui -> String diff --git a/Moves/Base.hs b/Moves/Base.hs index df5096bd..23489601 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -12,13 +12,14 @@ module Moves.Base ( betaCut, doNullMove, ttRead, ttStore, curNodes, isTimeout, informCtx, mateScore, scoreDiff, qsDelta, draftStats, - finNode, + finNode, countRepetitions, showMyPos, logMes, nearmate ) where import Data.Bits import Data.Int +import Data.List (nub) import Control.Monad.State import Control.Monad.Reader (ask) -- import Numeric @@ -232,6 +233,12 @@ checkRemisRules p = do (_:_:_) -> return True _ -> return False +-- If we have a few repetitions in the last moves, then we will reduce moves to go +-- so the time management can allocate more time for next moves +countRepetitions :: MyState -> Int +countRepetitions s = 6 - uniq + where uniq = length $ nub $ map zobkey $ take 6 $ stack s + {-# INLINE undoMove #-} undoMove :: Game () undoMove = modify $ \s -> s { stack = tail $ stack s } diff --git a/Search/Albeta.hs b/Search/Albeta.hs index e4229677..19f8635b 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -310,31 +310,16 @@ pvRootSearch a b d lastpath rmvs aspir = do return (a, emptySeq, edges, rbmch nstf) -- just to permit aspiration to retry else do -- lift $ mapM_ (\m -> informStr $ "Root move: " ++ show m) (pvsl nstf) - when (d < depthForCM) $ informBest sc d p + when (d < depthForCM) $ informPV sc d p let (best':_) = p allrmvs = if sc >= b then unalt edges else map pvslToMove (pvsl nstf) xrmvs = Alt $ best' : delete best' allrmvs -- best on top return (sc, Seq p, xrmvs, rbmch nstf) -{-- -pvslToPair :: Pvsl -> (Int, [Move]) -pvslToPair (Pvsl { pvPath = p }) = (score, pv) - where pv = unseq $ pathMoves p - sc = pathScore p - score = scoreToExtern sc $ length pv ---} - pvslToMove :: Pvsl -> Move pvslToMove (Pvsl { pvPath = Path { pathMoves = Seq (m:_)}}) = m pvslToMove _ = undefined -- just for Wall --- The internal score is weird for found mates (always mate) --- Turn it to nicer score by considering path lenght to mate -scoreToExtern :: Int -> Int -> Int -scoreToExtern !sc le - | nearmate sc = if sc > 0 then sc - le else sc + le - | otherwise = sc - legalResult :: DoResult -> Bool legalResult Illegal = False legalResult _ = True @@ -402,9 +387,8 @@ pvInnerRootExten b d !exd nst = do let nst' = nst { crtnt = PVNode, nxtnt = PVNode } pnextlev <$> pvSearch nst' (-b) (-a) d1 -checkFailOrPVRoot :: SStats -> Int -> Int -> Move -> Path - -> NodeState -> Search (Bool, NodeState) -checkFailOrPVRoot xstats b d e s nst = timeToAbort (True, nst) $ do +checkFailOrPVRoot :: SStats -> Int -> Int -> Move -> Path -> NodeState -> Search (Bool, NodeState) +checkFailOrPVRoot xstats b d e s nst = do sst <- get let !mn = movno nst a = pathScore $ cursc nst @@ -413,46 +397,44 @@ checkFailOrPVRoot xstats b d e s nst = timeToAbort (True, nst) $ do !nodes' = nodes1 - nodes0 pvg = Pvsl s nodes' -- the good de = max d $ pathDepth s - if d == 1 + if d == 1 -- we shouln't get abort here... then do let typ = 2 lift $ ttStore de typ (pathScore s) e nodes' - -- lift $ logmes $ "checkFail: d = 1, mv = " ++ show e let xpvslg = insertToPvs d pvg (pvsl nst) -- the good rch | pathScore s > a = rbmch nst + 1 | otherwise = rbmch nst return (False, nst {movno = mn + 1, pvsl = xpvslg, rbmch = rch }) - else if pathScore s <= a - then do -- failed low - -- lift $ logmes $ "checkFail: d = " ++ show d ++ ", mv = " ++ show e ++ ", s <= a" - let xpvslb = insertToPvs d pvg (pvsl nst) -- the bad - nst1 = nst { movno = mn + 1, pvsl = xpvslb, killer = newKiller d s nst } - return (False, nst1) - else if pathScore s >= b - then do - -- what when a root move fails high? We are in aspiration - lift $ do - let typ = 1 -- beta cut (score is lower limit) with move e - ttStore de typ b e nodes' - betaCut True (absdp sst) e - -- lift $ logmes $ "checkFail: d = " ++ show d ++ ", mv = " ++ show e ++ ", s >= b" - let xpvslg = insertToPvs d pvg (pvsl nst) -- the good - csc = s { pathScore = b } - nst1 = nst { cursc = csc, pvsl = xpvslg, rbmch = rbmch nst + 1 } - return (True, nst1) - else do -- means: > a && < b - let sc = pathScore s - pa = unseq $ pathMoves s - informBest (scoreToExtern sc $ length pa) (draft $ ronly sst) pa - lift $ do - let typ = 2 -- best move so far (score is exact) - ttStore de typ sc e nodes' - betaCut True (absdp sst) e -- not really cut, but good move - -- lift $ logmes $ "checkFail: d = " ++ show d ++ ", mv = " ++ show e ++ ", s > a" - let xpvslg = insertToPvs d pvg (pvsl nst) -- the good - nst1 = nst { cursc = s, nxtnt = nextNodeType (nxtnt nst), - movno = mn + 1, pvsl = xpvslg, rbmch = rbmch nst + 1 } - return (False, nst1) + else if abort sst + then return (True, nst) + else if pathScore s <= a + then do -- failed low + let xpvslb = insertToPvs d pvg (pvsl nst) -- the bad + nst1 = nst { movno = mn + 1, pvsl = xpvslb, killer = newKiller d s nst } + return (False, nst1) + else if pathScore s >= b + then do + -- what when a root move fails high? We are in aspiration + lift $ do + let typ = 1 -- beta cut (score is lower limit) with move e + ttStore de typ b e nodes' + betaCut True (absdp sst) e + let xpvslg = insertToPvs d pvg (pvsl nst) -- the good + csc = s { pathScore = b } + nst1 = nst { cursc = csc, pvsl = xpvslg, rbmch = rbmch nst + 1 } + return (True, nst1) + else do -- means: > a && < b + let sc = pathScore s + pa = unseq $ pathMoves s + informPV sc (draft $ ronly sst) pa + lift $ do + let typ = 2 -- best move so far (score is exact) + ttStore de typ sc e nodes' + betaCut True (absdp sst) e -- not really cut, but good move + let xpvslg = insertToPvs d pvg (pvsl nst) -- the good + nst1 = nst { cursc = s, nxtnt = nextNodeType (nxtnt nst), + movno = mn + 1, pvsl = xpvslg, rbmch = rbmch nst + 1 } + return (False, nst1) insertToPvs :: Int -> Pvsl -> [Pvsl] -> [Pvsl] insertToPvs _ p [] = [p] @@ -838,32 +820,34 @@ checkFailOrPVLoop :: SStats -> Int -> Int -> Move -> Path checkFailOrPVLoop xstats b d e s nst = do sst <- get let mn = movno nst - if pathScore s <= pathScore (cursc nst) - then do - let nst1 = nst { movno = mn+1, killer = newKiller d s nst } - return (False, nst1) - else do - let nodes0 = sNodes xstats - nodes1 = sNodes $ stats sst - nodes' = nodes1 - nodes0 - !de = max d $ pathDepth s - if pathScore s >= b - then do - lift $ do - let typ = 1 -- best move is e and is beta cut (score is lower limit) - ttStore de typ b e nodes' - betaCut True (absdp sst) e -- anounce a beta move (for example, update history) - incBeta mn - let csc = s { pathScore = b } - nst1 = nst { cursc = csc } - return (True, nst1) - else do -- means: > a && < b - lift $ do - let typ = 2 -- score is exact - ttStore de typ (pathScore s) e nodes' - betaCut True (absdp sst) e -- not really a cut, but good move here - let nst1 = nst { cursc = s, nxtnt = nextNodeType (nxtnt nst), movno = mn+1 } - return (False, nst1) + if abort sst + then return (True, nst) + else if pathScore s <= pathScore (cursc nst) + then do + let nst1 = nst { movno = mn+1, killer = newKiller d s nst } + return (False, nst1) + else do + let nodes0 = sNodes xstats + nodes1 = sNodes $ stats sst + nodes' = nodes1 - nodes0 + !de = max d $ pathDepth s + if pathScore s >= b + then do + lift $ do + let typ = 1 -- best move is e and is beta cut (score is lower limit) + ttStore de typ b e nodes' + betaCut True (absdp sst) e -- anounce a beta move (for example, update history) + incBeta mn + let csc = s { pathScore = b } + nst1 = nst { cursc = csc } + return (True, nst1) + else do -- means: > a && < b + lift $ do + let typ = 2 -- score is exact + ttStore de typ (pathScore s) e nodes' + betaCut True (absdp sst) e -- not really a cut, but good move here + let nst1 = nst { cursc = s, nxtnt = nextNodeType (nxtnt nst), movno = mn+1 } + return (False, nst1) -- For zero window checkFailOrPVLoopZ :: SStats -> Int -> Int -> Move -> Path @@ -871,23 +855,25 @@ checkFailOrPVLoopZ :: SStats -> Int -> Int -> Move -> Path checkFailOrPVLoopZ xstats b d e s nst = do sst <- get let mn = movno nst - if pathScore s < b -- failed low - then do - let nst1 = nst { movno = mn+1, killer = newKiller d s nst } - return (False, nst1) - else do -- here is s >= b: failed high - let nodes0 = sNodes xstats - nodes1 = sNodes $ stats sst - nodes' = nodes1 - nodes0 - !de = max d $ pathDepth s - lift $ do - let typ = 1 -- best move is e and is beta cut (score is lower limit) - ttStore de typ b e nodes' - betaCut True (absdp sst) e -- anounce a beta move (for example, update history) - incBeta mn - let csc = s { pathScore = b } - nst1 = nst { cursc = csc } - return (True, nst1) + if abort sst + then return (True, nst) + else if pathScore s < b -- failed low + then do + let nst1 = nst { movno = mn+1, killer = newKiller d s nst } + return (False, nst1) + else do -- here is s >= b: failed high + let nodes0 = sNodes xstats + nodes1 = sNodes $ stats sst + nodes' = nodes1 - nodes0 + !de = max d $ pathDepth s + lift $ do + let typ = 1 -- best move is e and is beta cut (score is lower limit) + ttStore de typ b e nodes' + betaCut True (absdp sst) e -- anounce a beta move (for example, update history) + incBeta mn + let csc = s { pathScore = b } + nst1 = nst { cursc = csc } + return (True, nst1) newKiller :: Int -> Path -> NodeState -> Killer newKiller d s nst @@ -1238,10 +1224,6 @@ killerToList (OneKiller e) = [e] killerToList (TwoKillers e1 e2) = [e1, e2] --- Communication to the outside - some convenience functions --- - -informBM :: Int -> Int -> Int64 -> [Move] -> Game () -informBM a b c d = informCtx (BestMv a b c d) - informCM :: Move -> Int -> Game () informCM a b = informCtx (CurrMv a b) @@ -1251,7 +1233,7 @@ informStr s = informCtx (InfoStr s) logmes :: String -> Game () logmes s = informCtx (LogMes s) -informBest :: Int -> Int -> [Move] -> Search () -informBest s d es = do - n <- lift curNodes - lift $ informBM s d n es +informPV :: Int -> Int -> [Move] -> Search () +informPV s d es = lift $ do + n <- curNodes + informCtx (BestMv s d n es) diff --git a/Search/AlbetaTypes.hs b/Search/AlbetaTypes.hs index 498edcb8..49d9c6f2 100644 --- a/Search/AlbetaTypes.hs +++ b/Search/AlbetaTypes.hs @@ -61,8 +61,8 @@ nulDebug = False formatStats :: SStats -> [String] formatStats sst = [ - "Nodes: " ++ show (sNodes sst) ++ ", in QS: " ++ show (sNodesQS sst) - ++ " (QS%: " ++ show (100 * sNodesQS sst `div` sNodes sst) ++ ")", + "Nodes: " ++ show (sNodes sst) ++ ", in QS: " ++ show (sNodesQS sst) ++ " (QS%: " + ++ show (if sNodes sst == 0 then 0 else 100 * sNodesQS sst `div` sNodes sst) ++ ")", "Retrieve: " ++ show (sRetr sst) ++ ", not found: " ++ show (sRFal sst) ++ ", found usable: " ++ show (sRFnd sst) ++ ", found not usable: " ++ show (sRetr sst - (sRFal sst + sRFnd sst)) diff --git a/Uci/UCI.hs b/Uci/UCI.hs index 2b743172..41a40be7 100644 --- a/Uci/UCI.hs +++ b/Uci/UCI.hs @@ -42,7 +42,7 @@ data GoCmds | MovesToGo Int | Depth Int | Nodes Int - | Mate Int + | FindMate Int | MoveTime Int | Infinite deriving (Eq, Show) @@ -209,7 +209,7 @@ parseGoCmd = P.choice $ map P.try [ parseMovesToGo, parseDepth, parseNodes, - parseMate, + parseFindMate, parseMoveTime, parseInfinite, parseSearchMoves @@ -249,8 +249,8 @@ parseDepth = parseWithInt "depth" Depth parseNodes :: Parser GoCmds parseNodes = parseWithInt "nodes" Nodes -parseMate :: Parser GoCmds -parseMate = parseWithInt "mate" Mate +parseFindMate :: Parser GoCmds +parseFindMate = parseWithInt "mate" FindMate parseMoveTime :: Parser GoCmds parseMoveTime = parseWithInt "movetime" MoveTime From b53648fd22006b07f967929dc545f1b15f268682 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Fri, 3 Feb 2017 22:08:11 +0100 Subject: [PATCH 22/71] Rollback max extensions, correct repetitions Plus a few other small corrections --- Main/Barbarossa.hs | 35 ++++++++++++++++------------------- Moves/Base.hs | 5 +++-- Search/Albeta.hs | 2 +- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 46ae1832..b4de7a7a 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "sig" +progVerSuff = "sic" data Options = Options { optConfFile :: Maybe String, -- config file @@ -365,8 +365,8 @@ doGo cmds = do else do let (tim, tpm, mtg) = getTimeParams cmds $ myColor chg rept = countRepetitions $ crtStatus chg - md = 20 -- max search depth - dpt = fromMaybe md (findDepth cmds) + md = 20 -- max search depth + dpt = fromMaybe md (findDepth cmds) startWorking tim tpm mtg dpt rept data Agreg = Agreg { @@ -427,26 +427,22 @@ extendScoreMargin = 24 -- This function calculates the normal time for the next search loop, -- the maximum of that (which cannot be exceeded) -- and if we are in time troubles or not -compTime :: Int -> Int -> Int -> Int -> Int -> (Int, Int, Bool) +compTime :: Int -> Int -> Int -> Int -> Int -> (Int, Int) compTime tim tpm fixmtg cursc rept - | tim == 0 && tpm == 0 = ( 0, 0, False) - | otherwise = (ctm, tmx, ttroub) + | tim == 0 && tpm == 0 = ( 0, 0) + | otherwise = (ctm, tmx) where mtg = if fixmtg > 0 then fixmtg else estimateMovesToGo cursc mtr | rept >= 2 = 3 -- consider repetitions | mtg == 0 = 1 | otherwise = mtg ctn = tpm + tim `div` mtr - (ctm, short) = if tim > 0 && tim < 2000 || tim == 0 && tpm < 700 - then (300, True) - else (ctn, False) + ctm = if tim > 0 && tim < 2000 || tim == 0 && tpm < 700 then 300 else ctn frtim = fromIntegral $ max 0 $ tim - ctm -- rest time after this move fctm = fromIntegral ctm :: Double rtimprc = fctm / max frtim fctm rtimfrc = remTimeFracIni + remTimeFracDev * rtimprc tmxt = round $ fctm + rtimfrc * frtim - maxx = max 0 $ tim - timeReserved - (tmx, over) = if maxx < tmxt then (maxx, True) else (tmxt, False) - ttroub = short || over + tmx = min tmxt $ max 0 $ tim - timeReserved estMvsToGo :: Array Int Int estMvsToGo = listArray (0, 8) [50, 36, 24, 15, 10, 7, 5, 3, 2] @@ -508,14 +504,13 @@ searchTheTree draft mdraft timx tim tpm mtg rept lsc lpv rmvs = do chg <- readChanging ctxLog LogInfo $ "Time = " ++ show tim ++ " Timx = " ++ show timx (path, sc, rmvsf, timint, stfin, ch) <- bestMoveCont draft timx (crtStatus chg) lsc lpv rmvs - -- case length path of _ -> return () -- because of lazyness! let totch = totBmCh chg + ch ldCh | ch > 0 = draft | otherwise = lastChDr chg modifyChanging $ \c -> c { crtStatus = stfin, totBmCh = totch, lastChDr = ldCh, forGui = Just $ InfoB { infoPv = path, infoScore = sc }} currms <- lift $ currMilli (startSecond ctx) - let (ms, mx, _) = compTime tim tpm mtg sc rept -- urg not used + let (ms, mx) = compTime tim tpm mtg sc rept exte = maybe False id $ do los <- lsc gls <- lmvScore chg @@ -561,7 +556,7 @@ searchTheTree draft mdraft timx tim tpm mtg rept lsc lpv rmvs = do return sc -- The time management changes like this: --- We calculate ther normal and maximum time to use for this move, as before +-- We calculate the normal and maximum time to use for this move, as before -- we correct the time per move with some factor (ply in game, score drop) -- we calculate what would be the max draft we could reach at this rate -- if we reached the max draft - stop the search @@ -570,7 +565,7 @@ searchTheTree draft mdraft timx tim tpm mtg rept lsc lpv rmvs = do -- - number of changes in last draft -- - total number of changes in this search -- - last draft with changes --- Than based on this probability we limit the interrup time for next search (in case it starts) +-- Than based on this probability we limit the interrupt time for next search (in case it starts) -- if max draft is greater than next draft we start next search -- if max draft = next draft we decide probabilistically if we start the next draft or not stopByChance :: Double -> Bool -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> CtxIO (Bool, Int) @@ -629,9 +624,11 @@ probChange d c ct dc = 1 / (1 + exp (-z)) z = w0 + w1 * d + w2 * c + w3 * ct + w4 * dc reduceBegin :: Maybe Int -> Double -reduceBegin mi | Just i <- mi, - i < 10 = fromIntegral i / 10 - | otherwise = 1 +reduceBegin mi | Just i <- mi = reduce i + | otherwise = 1 + where reduce i | i < 6 = 0.5 + | i < 10 = fromIntegral i / 10 + | otherwise = 1 timeProlongation :: Int -> Int -> Double timeProlongation osc sc diff --git a/Moves/Base.hs b/Moves/Base.hs index 23489601..df12415d 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -236,8 +236,9 @@ checkRemisRules p = do -- If we have a few repetitions in the last moves, then we will reduce moves to go -- so the time management can allocate more time for next moves countRepetitions :: MyState -> Int -countRepetitions s = 6 - uniq - where uniq = length $ nub $ map zobkey $ take 6 $ stack s +countRepetitions s = length f6 - uniq + where uniq = length $ nub $ map zobkey f6 + f6 = take 6 $ stack s {-# INLINE undoMove #-} undoMove :: Game () diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 19f8635b..f555ef2a 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -36,7 +36,7 @@ scoreGrain, depthForCM, maxDepthExt, minPvDepth :: Int useTTinPv, readTTinQS :: Bool scoreGrain = 4 -- score granularity depthForCM = 7 -- from this depth inform current move -maxDepthExt = 5 -- maximum depth extension +maxDepthExt = 3 -- maximum depth extension useTTinPv = False -- retrieve from TT in PV? minPvDepth = 2 -- from this depth we use alpha beta search readTTinQS = True From 2a296fc448b64e1a054c46fba21713f5bc8c95cb Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sun, 5 Feb 2017 19:27:41 +0100 Subject: [PATCH 23/71] Different corrections Interrupt: more consequent (less side effects) Mate score correction Time menagement: a bit shorter + repetition draw --- Barbarossa.cabal | 4 +- Main/Barbarossa.hs | 82 +++++++------ Search/Albeta.hs | 269 +++++++++++++++++++----------------------- Search/AlbetaTypes.hs | 4 +- Uci/UCI.hs | 4 +- 5 files changed, 174 insertions(+), 189 deletions(-) diff --git a/Barbarossa.cabal b/Barbarossa.cabal index 1fb83ef3..666b4404 100644 --- a/Barbarossa.cabal +++ b/Barbarossa.cabal @@ -64,8 +64,8 @@ Executable Barbarossa -fspec-constr-count=24 -funfolding-use-threshold=32 -fno-warn-tabs - -- -ddump-simpl -ddump-to-file -dsuppress-all -dsuppress-uniques - -- -ddump-opt-cmm -ddump-asm + -ddump-simpl -ddump-to-file -dsuppress-all -dsuppress-uniques + -ddump-opt-cmm -ddump-asm CPP-Options: -DSMSTRICT if flag(sse42) GHC-Options: -msse4.2 diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 111041f8..4ee0fe4d 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -33,12 +33,12 @@ import Search.CStateMonad (execCState) import Search.AlbetaTypes import Eval.FileParams (makeEvalState) --- Name, authos, version and suffix: +-- Name, author, version and suffix: progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "wpa" +progVerSuff = "wpai" data Options = Options { optConfFile :: Maybe String, -- config file @@ -412,7 +412,6 @@ getTimeParams cs _ c -- unused: lastsc tim = fromMaybe 0 $ findTime c cs mtg = fromMaybe 0 $ findMovesToGo cs - -- These parameters should be optimised (i.e.: first made options) remTimeFracIni, remTimeFracFin, remTimeFracDev :: Double remTimeFracIni = 0.15 -- fraction of remaining time which we can consume at once - initial value @@ -420,18 +419,21 @@ remTimeFracFin = 0.5 -- same at final (when remaining time is near zero) remTimeFracDev = remTimeFracFin - remTimeFracIni timeReserved :: Int -timeReserved = 70 -- milliseconds reserved for move communication +timeReserved = 100 -- milliseconds reserved for move communication -- This function calculates the normal time for the next search loop, --- the maximum of that (whch cannot be exceeded) +-- the maximum of that (which cannot be exceeded) -- and if we are in time troubles or not -compTime :: Int -> Int -> Int -> Int -> (Int, Int, Bool) -compTime tim tpm fixmtg lastsc +compTime :: Int -> Int -> Int -> Int -> Bool -> (Int, Int, Bool) +compTime tim tpm fixmtg cursc isdraw | tim == 0 && tpm == 0 = ( 0, 0, False) | otherwise = (ctm, tmx, ttroub) - where mtg = if fixmtg > 0 then fixmtg else estimateMovesToGo lastsc - ctn = tpm + tim `div` mtg - (ctm, short) = if tim > 0 && tim < 2000 || tim == 0 && tpm < 700 + where mtg = if fixmtg > 0 then fixmtg else estimateMovesToGo cursc + mtr | isdraw = 1 -- repetition draw + | mtg == 0 = 1 + | otherwise = mtg + ctn = tpm + tim `div` mtr + (ctm, short) = if tim > 0 && tim < 1000 || tim == 0 && tpm < 700 then (300, True) else (ctn, False) frtim = fromIntegral $ max 0 $ tim - ctm -- rest time after this move @@ -444,7 +446,7 @@ compTime tim tpm fixmtg lastsc ttroub = short || over estMvsToGo :: Array Int Int -estMvsToGo = listArray (0, 8) [30, 28, 24, 18, 12, 10, 8, 6, 3] +estMvsToGo = listArray (0, 8) [35, 28, 24, 18, 12, 8, 4, 3, 2] estimateMovesToGo :: Int -> Int estimateMovesToGo sc = estMvsToGo ! mvidx @@ -498,24 +500,26 @@ ctxCatch a f = do -- Search with the given depth searchTheTree :: Int -> Int -> Int -> Int -> Int -> Int -> Maybe Int -> [Move] -> [Move] -> CtxIO Int -searchTheTree tief mtief timx tim tpm mtg lsc lpv rmvs = do +searchTheTree draft mdraft timx tim tpm mtg lsc lpv rmvs = do ctx <- ask chg <- readChanging ctxLog LogInfo $ "Time = " ++ show tim ++ " Timx = " ++ show timx - (path, sc, rmvsf, timint, stfin) <- bestMoveCont tief timx (crtStatus chg) lsc lpv rmvs - case length path of _ -> return () -- because of lazyness! + (path, sc, rmvsf, timint, stfin) <- bestMoveCont draft timx (crtStatus chg) lsc lpv rmvs storeBestMove path sc -- write back in status modifyChanging (\c -> c { crtStatus = stfin }) currms <- lift $ currMilli (startSecond ctx) - let (ms', mx, urg) = compTime tim tpm mtg sc - ms <- if urg || null path then return ms' else correctTime tief (reduceBegin (realPly chg) ms') sc path + let isDraw = draft >= 6 && length (take 3 path) < 3 && sc == 0 + (ms', mx, urg) = compTime tim tpm mtg sc isDraw + ms <- if urg || null path + then return ms' + else correctTime draft (reduceBegin (realPly chg) ms') sc path let strtms = srchStrtMs chg delta = strtms + ms - currms ms2 = ms `div` 2 - onlyone = ms > 0 && length rmvsf == 1 && tief >= 4 -- only in normal play + onlyone = ms > 0 && length rmvsf == 1 && draft >= 4 -- only in normal play halfover = ms > 0 && delta <= ms2 -- time is half over - depthmax = tief >= mtief -- or maximal depth - mes = "Depth " ++ show tief ++ " Score " ++ show sc ++ " in ms " + depthmax = draft >= mdraft -- or maximal depth + mes = "Depth " ++ show draft ++ " Score " ++ show sc ++ " in ms " ++ show currms ++ " remaining " ++ show delta ++ " path " ++ show path ctxLog LogInfo mes @@ -528,13 +532,13 @@ searchTheTree tief mtief timx tim tpm mtg lsc lpv rmvs = do else do chg' <- readChanging if working chg' - then if mx == 0 -- no time constraint - then searchTheTree (tief + 1) mtief 0 tim tpm mtg (Just sc) path rmvsf - else searchTheTree (tief + 1) mtief (strtms + mx) tim tpm mtg (Just sc) path rmvsf - else do - ctxLog DebugUci "in searchTheTree: not working" - giveBestMove path -- was stopped - return sc + then if mx == 0 -- no time constraint + then searchTheTree (draft+1) mdraft 0 tim tpm mtg (Just sc) path rmvsf + else searchTheTree (draft+1) mdraft (strtms+mx) tim tpm mtg (Just sc) path rmvsf + else do + ctxLog DebugUci "in searchTheTree: not working" + giveBestMove path -- was stopped + return sc -- We assume here that we always have at least the first move of the PV (our best) -- If not (which is a fatal error) we will get an exception (head of empty list) @@ -674,18 +678,28 @@ bestMove m mp = s -- sel.depth nicht implementiert formInfo :: InfoToGui -> String formInfo itg = "info" - -- ++ " score cp " ++ show isc - ++ formScore isc + ++ formScore esc ++ " depth " ++ show (infoDepth itg) -- ++ " seldepth " ++ show idp ++ " time " ++ show (infoTime itg) ++ " nodes " ++ show (infoNodes itg) ++ nps' - ++ " pv" ++ concatMap (\m -> ' ' : toString m) (infoPv itg) + ++ " pv" ++ concatMap (\m -> ' ' : toString m) pv where nps' = case infoTime itg of 0 -> "" x -> " nps " ++ show (infoNodes itg `div` fromIntegral x * 1000) - isc = infoScore itg + esc = scoreToExtern (infoScore itg) (length pv) + pv = infoPv itg + +data ExternScore = Score Int | Mate Int + +-- The external score is weird for found mates (always mate) +-- Turn it to nice score by considering path length to mate +scoreToExtern :: Int -> Int -> ExternScore +scoreToExtern sc le + | sc == mateScore = Mate $ (le + 1) `div` 2 + | sc == -mateScore = Mate $ negate $ le `div` 2 + | otherwise = Score sc -- formInfoB :: InfoToGui -> String -- formInfoB itg = "info" @@ -694,11 +708,9 @@ formInfo itg = "info" -- ++ " pv" ++ concatMap (\m -> ' ' : toString m) (infoPv itg) -- where isc = infoScore itg -formScore :: Int -> String -formScore i - | i >= mateScore - 255 = " score mate " ++ show ((mateScore - i + 1) `div` 2) - | i <= (-mateScore) + 255 = " score mate " ++ show ((-mateScore - i) `div` 2) - | otherwise = " score cp " ++ show i +formScore :: ExternScore -> String +formScore (Score s) = " score cp " ++ show s +formScore (Mate n) = " score mate " ++ show n -- sel.depth nicht implementiert -- formInfo2 :: InfoToGui -> String diff --git a/Search/Albeta.hs b/Search/Albeta.hs index c1bb9456..43ac17e7 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -23,7 +23,7 @@ import Moves.Base import Moves.Fen (initPos) absurd :: String -> Game () -absurd s = logmes $ "o/\\o: " ++ s -- used for messages when assertions fail +absurd s = logmes $ "Absurd: " ++ s -- used for messages when assertions fail collectFens :: Bool collectFens = True @@ -309,7 +309,6 @@ pvRootSearch a b d lastpath rmvs aspir = do unless (abrt || aspir) $ lift $ informStr "Failed low at root??" return (a, emptySeq, edges) -- just to permit aspiration to retry else do - -- lift $ mapM_ (\m -> informStr $ "Root move: " ++ show m) (pvsl nstf) albest' <- gets (albest . ronly) (s, p) <- if sc >= b || abrt then return (sc, unseq $ pathMoves (cursc nstf)) @@ -317,7 +316,7 @@ pvRootSearch a b d lastpath rmvs aspir = do $ sortBy (comparing fstdesc) $ map pvslToPair $ filter pvGood $ pvsl nstf - when (d < depthForCM) $ informBest s d p + when (d < depthForCM) $ informPV s d p let (best':_) = p allrmvs = if sc >= b then unalt edges else map pvslToMove (pvsl nstf) xrmvs = Alt $ best' : delete best' allrmvs -- best on top @@ -325,22 +324,14 @@ pvRootSearch a b d lastpath rmvs aspir = do where fstdesc (a', _) = -a' pvslToPair :: Pvsl -> (Int, [Move]) -pvslToPair (Pvsl { pvPath = p }) = (score, pv) +pvslToPair (Pvsl { pvPath = p }) = (sc, pv) where pv = unseq $ pathMoves p sc = pathScore p - score = scoreToExtern sc $ length pv pvslToMove :: Pvsl -> Move pvslToMove (Pvsl { pvPath = Path { pathMoves = Seq (m:_)}}) = m pvslToMove _ = undefined -- just for Wall --- The internal score is weird for found mates (always mate) --- Turn it to nicer score by considering path lenght to mate -scoreToExtern :: Int -> Int -> Int -scoreToExtern !sc le - | nearmate sc = if sc > 0 then sc - le else sc + le - | otherwise = sc - legalResult :: DoResult -> Bool legalResult Illegal = False legalResult _ = True @@ -380,7 +371,6 @@ pvInnerRoot b d nst e = timeToAbort (True, nst) $ do checkFailOrPVRoot (stats old) b d e s' nst else return (False, nst) --- pvInnerRootExten :: Path -> Int -> Bool -> Int -> NodeState -> Search (Path, Int) pvInnerRootExten :: Int -> Int -> Int -> NodeState -> Search Path pvInnerRootExten b d !exd nst = do old <- get @@ -397,20 +387,20 @@ pvInnerRootExten b d !exd nst = do -- no futility pruning & no LMR for root moves! -- Here we expect to fail low s1 <- pnextlev <$> pvZeroW nst (-a) d1 nulMoves True - checkFailHard "pvZeroW" a b (pathScore s1) - abrt <- gets abort - if abrt || pathScore s1 <= a -- we failed low as expected - then return s1 - else do - -- Here we didn't fail low and need re-search - -- As we don't reduce (beeing in a PV node), re-search is full window - lift $ logmes $ "Research: a = " ++ show a ++ ", s1 = " ++ show s1 - let nst' = nst { crtnt = PVNode, nxtnt = PVNode } - pnextlev <$> pvSearch nst' (-b) (-a) d1 + whenAbort s1 $ do + checkFailHard "pvZeroW" a b (pathScore s1) + if pathScore s1 <= a -- we failed low as expected + then return s1 + else do + -- Here we didn't fail low and need re-search + -- As we don't reduce (beeing in a PV node), re-search is full window + lift $ logmes $ "Research: a = " ++ show a ++ ", s1 = " ++ show s1 + let nst' = nst { crtnt = PVNode, nxtnt = PVNode } + pnextlev <$> pvSearch nst' (-b) (-a) d1 checkFailOrPVRoot :: SStats -> Int -> Int -> Move -> Path -> NodeState -> Search (Bool, NodeState) -checkFailOrPVRoot xstats b d e s nst = timeToAbort (True, nst) $ do +checkFailOrPVRoot xstats b d e s nst = whenAbort (True, nst) $ do sst <- get let !mn = movno nst a = pathScore $ cursc nst @@ -447,7 +437,7 @@ checkFailOrPVRoot xstats b d e s nst = timeToAbort (True, nst) $ do else do -- means: > a && < b let sc = pathScore s pa = unseq $ pathMoves s - informBest (scoreToExtern sc $ length pa) (draft $ ronly sst) pa + informPV sc (draft $ ronly sst) pa lift $ do let typ = 2 -- best move so far (score is exact) ttStore de typ sc e nodes' @@ -491,7 +481,6 @@ pvSearch nst !a !b !d = do when (not $ inPv || ab) $ lift $ absurd $ "pvSearch: not inPv, not ab, nst = " ++ show nst -- Check first for a TT entry of the position to search (hdeep, tp, hsc, e, nodes') <- reTrieve >> lift ttRead - when (hdeep < 0) reFail -- tp == 1 => score >= hsc, so if hsc >= asco then we improved, -- but can we use hsc in PV? This score is not exact! -- Idea: return only if better than beta, else search for exact score @@ -511,6 +500,7 @@ pvSearch nst !a !b !d = do lift $ betaCut True adp e reSucc nodes' >> return ttpath else do + when (hdeep < 0) reFail -- Here: when ab we should do null move search pos <- lift getPos -- Use the found TT move as best move @@ -527,25 +517,23 @@ pvSearch nst !a !b !d = do let !nsti = resetNSt (pathFromScore "low limit" a) NoKiller nst' nstf <- pvSLoop b d prune nsti edges let s = cursc nstf - -- After pvSLoop ... we expect always that s >= a - this must be checked if it is so - -- then it makes sense below to take bestPath when failed low (s == a) - abrt' <- gets abort - if abrt' || pathScore s > a - then checkFailHard "pvSLoop improve" a b (pathScore s) >> return s - else if movno nstf > 1 - then do - -- here we failed low - let de = max d $ pathDepth s - nodes1 <- gets (sNodes . stats) - -- store as upper score, and as move, the first one generated - lift $ do - let typ = 0 - !deltan = nodes1 - nodes0 - mv = head $ unalt edges -- not null - we are on "else" of noMove - ttStore de typ a mv deltan - checkFailHard "pvSLoop low" a b (pathScore s) - return s - else return $ trimaxPath a b $ if tacticalPos pos then matedPath else staleMate + whenAbort s $ do + if pathScore s > a + then checkFailHard "pvSLoop improve" a b (pathScore s) >> return s + else if movno nstf > 1 + then do + -- here we failed low + let de = max d $ pathDepth s + nodes1 <- gets (sNodes . stats) + -- store as upper score, and as move, the first one generated + lift $ do + let typ = 0 + !deltan = nodes1 - nodes0 + mv = head $ unalt edges -- not null - we are on "else" of noMove + ttStore de typ a mv deltan + checkFailHard "pvSLoop low" a b (pathScore s) + return s + else return $ trimaxPath a b $ if tacticalPos pos then matedPath else staleMate -- PV Zero Window pvZeroW :: NodeState -> Int -> Int -> Int -> Bool -> Search Path @@ -557,7 +545,6 @@ pvZeroW !_ !b !d !_ _ | d <= 0 = do pvZeroW !nst !b !d !lastnull redu = do -- Check if we have it in TT (hdeep, tp, hsc, e, nodes') <- reTrieve >> lift ttRead - when (hdeep < 0) reFail if hdeep >= d && (tp == 2 || tp == 1 && hsc >= b || tp == 0 && hsc < b) then do let ttpath = Path { pathScore = trimax bGrain b hsc, pathDepth = hdeep, @@ -568,47 +555,47 @@ pvZeroW !nst !b !d !lastnull redu = do lift $ betaCut True adp e reSucc nodes' >> return ttpath else do + when (hdeep < 0) reFail pos <- lift getPos nmhigh <- nullMoveFailsHigh pos nst b d lastnull - abrt <- gets abort - if abrt - then return $ pathFromScore "Aborted" b -- when aborted: it doesn't matter - else case nmhigh of - NullMoveHigh -> return $ pathFromScore "NullMoveHigh" b - _ -> do - -- Use the TT move as best move - let mttmv = if hdeep > 0 then Just e else Nothing - nst' = nst { cpos = pos } - edges <- genAndSort nst' mttmv bGrain b d - if noMove edges - then return $ trimaxPath bGrain b $ if tacticalPos pos then matedPath else staleMate - else do - !nodes0 <- gets (sNodes . stats) - -- futility pruning: - prune <- isPruneFutil d bGrain False (staticScore pos) - -- Loop thru the moves - let kill1 = case nmhigh of - NullMoveThreat s -> newTKiller pos d s - _ -> NoKiller - !nsti = resetNSt (pathFromScore "low limit" bGrain) kill1 nst' - nstf <- pvZLoop b d prune redu nsti edges - let s = cursc nstf - checkFailHard "pvZLoop" bGrain b (pathScore s) - -- Here we expect bGrain <= s < b -- this must be checked - if pathScore s >= b - then return s -- failed high - else if movno nstf > 1 -- we failed low - then do - let !de = max d $ pathDepth s - !nodes1 <- gets (sNodes . stats) - -- store as upper score, and as move the first one (generated) - lift $ do - let typ = 0 - !deltan = nodes1 - nodes0 - mv = head $ unalt edges -- not null, we are in "else" of noMove - ttStore de typ bGrain mv deltan - return s - else return $ trimaxPath bGrain b $ if tacticalPos pos then matedPath else staleMate + whenAbort (pathFromScore "Aborted" b) $ do + case nmhigh of + NullMoveHigh -> return $ pathFromScore "NullMoveHigh" b + _ -> do + -- Use the TT move as best move + let mttmv = if hdeep > 0 then Just e else Nothing + nst' = nst { cpos = pos } + edges <- genAndSort nst' mttmv bGrain b d + if noMove edges + then return $ trimaxPath bGrain b $ if tacticalPos pos then matedPath else staleMate + else do + !nodes0 <- gets (sNodes . stats) + -- futility pruning: + prune <- isPruneFutil d bGrain False (staticScore pos) + -- Loop thru the moves + let kill1 = case nmhigh of + NullMoveThreat s -> newTKiller pos d s + _ -> NoKiller + !nsti = resetNSt (pathFromScore "low limit" bGrain) kill1 nst' + nstf <- pvZLoop b d prune redu nsti edges + let s = cursc nstf + whenAbort s $ do + checkFailHard "pvZLoop" bGrain b (pathScore s) + -- Here we expect bGrain <= s < b -- this must be checked + if pathScore s >= b + then return s -- failed high + else if movno nstf > 1 -- we failed low + then do + let !de = max d $ pathDepth s + !nodes1 <- gets (sNodes . stats) + -- store as upper score, and as move the first one (generated) + lift $ do + let typ = 0 + !deltan = nodes1 - nodes0 + mv = head $ unalt edges -- not null, we are in "else" of noMove + ttStore de typ bGrain mv deltan + return s + else return $ trimaxPath bGrain b $ if tacticalPos pos then matedPath else staleMate where !bGrain = b - scoreGrain data NullMoveResult = NoNullMove | NullMoveHigh | NullMoveLow | NullMoveThreat Path @@ -783,13 +770,13 @@ pvInnerLoopExten b d !exd nst = do -- Here we must be in a Cut node (will fail low) -- and we should have: crtnt = CutNode, nxtnt = AllNode s1 <- pnextlev <$> pvZeroW nst (-a) d1 nulMoves True - abrt <- gets abort - if abrt || pathScore s1 <= a - then return s1 -- failed low (as expected) or aborted - else do - -- we didn't fail low and need re-search: full window - let nst1 = nst { crtnt = PVNode, nxtnt = PVNode } - pnextlev <$> pvSearch nst1 (-b) (-a) d1 + whenAbort s1 $ do + if pathScore s1 <= a + then return s1 -- failed low (as expected) or aborted + else do + -- we didn't fail low and need re-search: full window + let nst1 = nst { crtnt = PVNode, nxtnt = PVNode } + pnextlev <$> pvSearch nst1 (-b) (-a) d1 -- For zero window pvInnerLoopExtenZ :: Int -> Int -> Bool -> Int -> NodeState -> Bool -> Search Path @@ -822,23 +809,25 @@ pvInnerLoopExtenZ b d spec !exd nst redu = do when (pathScore sr < b && pathScore s1 >= b) $ do incReMi -- LMR missed the point when collectFens $ lift $ finNode "LMRM" 0 - if pathScore sr < b - then do - moreLMR True 1 -- more LMR - return sr -- failed low (as expected) - else do - -- was reduced and didn't fail low: re-search with full depth - incReSe nodre -- so many nodes we wasted by reducing this time - moreLMR False d' -- less LMR - -- Now we expect to fail high, i.e. exchange the crt/nxt node type - let nst1 = nst { crtnt = nxtnt nst, nxtnt = crtnt nst } - sf <- pnextlev <$> pvZeroW nst1 onemB d1 nulMoves True - when (pathScore sf >= b) $ moreLMR False d1 - return sf + whenAbort sr $ do + if pathScore sr < b + then do + moreLMR True 1 -- more LMR + return sr -- failed low (as expected) + else do + -- was reduced and didn't fail low: re-search with full depth + incReSe nodre -- so many nodes we wasted by reducing this time + moreLMR False d' -- less LMR + -- Now we expect to fail high, i.e. exchange the crt/nxt node type + let nst1 = nst { crtnt = nxtnt nst, nxtnt = crtnt nst } + sf <- pnextlev <$> pvZeroW nst1 onemB d1 nulMoves True + whenAbort sf $ do + when (pathScore sf >= b) $ moreLMR False d1 + return sf checkFailOrPVLoop :: SStats -> Int -> Int -> Move -> Path -> NodeState -> Search (Bool, NodeState) -checkFailOrPVLoop xstats b d e s nst = do +checkFailOrPVLoop xstats b d e s nst = whenAbort (True, nst) $ do sst <- get let mn = movno nst if pathScore s <= pathScore (cursc nst) @@ -871,7 +860,7 @@ checkFailOrPVLoop xstats b d e s nst = do -- For zero window checkFailOrPVLoopZ :: SStats -> Int -> Int -> Move -> Path -> NodeState -> Search (Bool, NodeState) -checkFailOrPVLoopZ xstats b d e s nst = do +checkFailOrPVLoopZ xstats b d e s nst = whenAbort (True, nst) $ do sst <- get let mn = movno nst if pathScore s < b -- failed low @@ -1013,17 +1002,17 @@ pvQSearch !a !b !c = do <- if readTTinQS then reTrieve >> lift ttRead else return (-1, undefined, undefined, undefined, undefined) - when (readTTinQS && hdeep < 0) reFail -- tp == 1 => score >= hsc, so if hsc > a then we improved -- tp == 0 => score <= hsc, so if hsc <= asco then we fail low and -- can terminate the search - if readTTinQS && hdeep >= 0 && ( + if hdeep >= 0 && ( tp == 2 -- exact score: always good || tp == 1 && hsc >= b -- we will fail high || tp == 0 && hsc <= a -- we will fail low ) then reSucc 1 >> return (trimax a b hsc) else do + when (readTTinQS && hdeep < 0) reFail -- TODO: use hsc here too, when possible pos <- lift $ getPos if tacticalPos pos @@ -1031,16 +1020,10 @@ pvQSearch !a !b !c = do (es1, es2) <- lift $ genMoves 0 let edges = Alt $ es1 ++ es2 if noMove edges - then do - when collectFens $ do - n <- gets $ sNodes . stats - lift $ finNode "MATE" n - return $! trimax a b (-mateScore) + then return $! trimax a b (-mateScore) else if c >= qsMaxChess then do - when collectFens $ do - n <- gets $ sNodes . stats - lift $ finNode "ENDL" n + when collectFens $ finWithNodes "ENDL" return $! trimax a b inEndlessCheck else do -- for check extensions in case of very few moves (1 or 2): @@ -1053,25 +1036,19 @@ pvQSearch !a !b !c = do let !stp = staticScore pos if stp >= b then do - when collectFens $ do - n <- gets $ sNodes . stats - lift $ finNode "BETA" n + when collectFens $ finWithNodes "BETA" return b else do !qsdelta <- lift qsDelta if stp + qsdelta + qsDeltaMargin < a then do - when collectFens $ do - n <- gets $ sNodes . stats - lift $ finNode "DELT" n + when collectFens $ finWithNodes "DELT" return a else do edges <- liftM Alt $ lift genTactMoves if noMove edges then do -- no more captures - when collectFens $ do - n <- gets $ sNodes . stats - lift $ finNode "NOCA" n + when collectFens $ finWithNodes "NOCA" return $! trimax a b stp else if stp > a then pvQLoop b c stp edges @@ -1095,11 +1072,7 @@ pvQInnerLoop !b c !a e = timeToAbort (True, b) $ do newNodeQS !sc <- case r of Final sc -> return (-sc) - _ -> do - modify $ \s -> s { absdp = absdp s + 1 } - !sc <- pvQSearch (-b) (-a) c - modify $ \s -> s { absdp = absdp s - 1 } -- no usedext here - return (-sc) + _ -> negate <$> pvQSearch (-b) (-a) c lift undoMove if sc >= b then return (True, b) @@ -1108,6 +1081,12 @@ pvQInnerLoop !b c !a e = timeToAbort (True, b) $ do else return (False, a) else return (False, a) +{-# INLINE finWithNodes #-} +finWithNodes :: String -> Search () +finWithNodes s = do + n <- gets $ sNodes . stats + lift $ finNode s n + {-# INLINE bestMoveFromIID #-} bestMoveFromIID :: NodeState -> Int -> Int -> Int -> Search [Move] bestMoveFromIID nst a b d @@ -1143,6 +1122,12 @@ timeToAbort a act = do else act where timeNodes = 4 * 1024 - 1 -- check time every so many nodes +{-# INLINE whenAbort #-} +whenAbort :: a -> Search a -> Search a +whenAbort a act = do + !abrt <- gets abort + if abrt then return a else act + {-# INLINE reportStats #-} reportStats :: Search () reportStats = do @@ -1160,15 +1145,6 @@ reportStats = do modStat :: (SStats -> SStats) -> Search () modStat f = modify $ \s -> case f (stats s) of st -> s { stats = st } -{-- -modRetStat :: (SStats -> SStats) -> (SStats -> Int) -> Search Int -modRetStat f g = do - s <- get - let ss = f $ stats s - put s { stats = ss } - return $! g ss ---} - incNodes :: Int -> SStats -> SStats incNodes 1 s = incNodesQS s -- d can't be < 0 here incNodes _ s = case sNodes s + 1 of n1 -> s { sNodes = n1 } @@ -1219,6 +1195,7 @@ incReBe n = modStat $ \s -> s { sReBe = sReBe s + n } incReMi :: Search () incReMi = modStat $ \s -> s { sReMi = sReMi s + 1 } +{-# SPECIALIZE bestFirst :: [Move] -> [Move] -> ([Move], [Move]) -> [Move] #-} bestFirst :: Eq e => [e] -> [e] -> ([e], [e]) -> [e] bestFirst path kl (es1, es2) | null path = es1 ++ kl ++ delall es2 kl @@ -1241,10 +1218,6 @@ killerToList (OneKiller e) = [e] killerToList (TwoKillers e1 e2) = [e1, e2] --- Communication to the outside - some convenience functions --- - -informBM :: Int -> Int -> Int64 -> [Move] -> Game () -informBM a b c d = informCtx (BestMv a b c d) - informCM :: Move -> Int -> Game () informCM a b = informCtx (CurrMv a b) @@ -1254,7 +1227,7 @@ informStr s = informCtx (InfoStr s) logmes :: String -> Game () logmes s = informCtx (LogMes s) -informBest :: Int -> Int -> [Move] -> Search () -informBest s d es = do - n <- lift curNodes - lift $ informBM s d n es +informPV :: Int -> Int -> [Move] -> Search () +informPV s d es = lift $ do + n <- curNodes + informCtx (BestMv s d n es) diff --git a/Search/AlbetaTypes.hs b/Search/AlbetaTypes.hs index 498edcb8..49d9c6f2 100644 --- a/Search/AlbetaTypes.hs +++ b/Search/AlbetaTypes.hs @@ -61,8 +61,8 @@ nulDebug = False formatStats :: SStats -> [String] formatStats sst = [ - "Nodes: " ++ show (sNodes sst) ++ ", in QS: " ++ show (sNodesQS sst) - ++ " (QS%: " ++ show (100 * sNodesQS sst `div` sNodes sst) ++ ")", + "Nodes: " ++ show (sNodes sst) ++ ", in QS: " ++ show (sNodesQS sst) ++ " (QS%: " + ++ show (if sNodes sst == 0 then 0 else 100 * sNodesQS sst `div` sNodes sst) ++ ")", "Retrieve: " ++ show (sRetr sst) ++ ", not found: " ++ show (sRFal sst) ++ ", found usable: " ++ show (sRFnd sst) ++ ", found not usable: " ++ show (sRetr sst - (sRFal sst + sRFnd sst)) diff --git a/Uci/UCI.hs b/Uci/UCI.hs index 2b743172..bc8ffc01 100644 --- a/Uci/UCI.hs +++ b/Uci/UCI.hs @@ -42,7 +42,7 @@ data GoCmds | MovesToGo Int | Depth Int | Nodes Int - | Mate Int + | FindMate Int | MoveTime Int | Infinite deriving (Eq, Show) @@ -250,7 +250,7 @@ parseNodes :: Parser GoCmds parseNodes = parseWithInt "nodes" Nodes parseMate :: Parser GoCmds -parseMate = parseWithInt "mate" Mate +parseMate = parseWithInt "mate" FindMate parseMoveTime :: Parser GoCmds parseMoveTime = parseWithInt "movetime" MoveTime From 27242c18ae69a61fe00c5072a547646bc638174f Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Tue, 21 Feb 2017 09:20:22 +0100 Subject: [PATCH 24/71] Correct number of total changes, new weights Weights were calculated only with samples for draft >= 8 and class_balanced logistic regression --- Main/Barbarossa.hs | 33 +++++++++++++++------------------ Search/Albeta.hs | 10 ++++++---- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index b4de7a7a..062e009e 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "sic" +progVerSuff = "sicv" data Options = Options { optConfFile :: Maybe String, -- config file @@ -507,6 +507,8 @@ searchTheTree draft mdraft timx tim tpm mtg rept lsc lpv rmvs = do let totch = totBmCh chg + ch ldCh | ch > 0 = draft | otherwise = lastChDr chg + when (ch > 0) $ + ctxLog LogInfo $ "Changes in draft " ++ show draft ++ ": " ++ show ch ++ " / " ++ show totch modifyChanging $ \c -> c { crtStatus = stfin, totBmCh = totch, lastChDr = ldCh, forGui = Just $ InfoB { infoPv = path, infoScore = sc }} currms <- lift $ currMilli (startSecond ctx) @@ -579,12 +581,16 @@ stopByChance red extend ms used mx draft ch totch ldCh then return (True, mx) else do -- We need the probability to limit the interrupt time at least: - let p = probChange (fromIntegral draft) (fromIntegral ch) (fromIntegral totch) (fromIntegral ldCh) + let imbalance = 1 + p = imbalance * probChange (fromIntegral draft) (fromIntegral ch) + (fromIntegral totch) (fromIntegral ldCh) mxf = fromIntegral mx mxr = min mx $ round $ red * (mxf + mxf * p) / 2 if dmax > draft + 1 then return (False, mxr) -- we have more than 1 draft to go else do + ctxLog LogInfo $ "stopByChance: d/ch/tch/ldch = " + ++ show draft ++ " / " ++ show ch ++ " / " ++ show totch ++ " / " ++ show ldCh ctxLog LogInfo $ "stopByChance: p = " ++ show p r <- liftIO $ getStdRandom (randomR (0::Double, 1)) if r < p then return (False, mxr) else return (True, mxr) @@ -603,24 +609,15 @@ maxDepthAtThisRate d used ms dmax1 = (log (msf + usedf) - log usedf) * logs -- This is just a prediction using logistic regression on the 4 parameters --- The parameters were found outside and have reached 77% prediction rate +-- The parameters were found outside and have reached 68,7% prediction rate +-- 600k samples, class_weight balanced, scaled, L2, C=100 probChange :: Double -> Double -> Double -> Double -> Double probChange d c ct dc = 1 / (1 + exp (-z)) - -- where w0 = -0.47326189 -- these got 77% - -- w1 = -0.24871493 - -- w2 = 0.18633039 - -- w3 = 0.07070459 - -- w4 = 0.1175941 - -- where w0 = -0.46828955 -- these got 80% - -- w1 = -0.24585093 - -- w2 = 0.19289682 - -- w3 = 0.09635968 - -- w4 = 0.10235857 - where w0 = -1.80799248 -- these got 91% with scales - w1 = -0.59439615 / 20 - w2 = 0.3024311 / 10 - w3 = 0.4347557 / 20 - w4 = -0.34551297 / 20 + where w0 = 1.701 + w1 = -4.977 / 19 + w2 = 3.269 / 6 + w3 = 0.723 / 18 + w4 = 2.729 / 19 z = w0 + w1 * d + w2 * c + w3 * ct + w4 * dc reduceBegin :: Maybe Int -> Double diff --git a/Search/Albeta.hs b/Search/Albeta.hs index f555ef2a..62b76d57 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -222,7 +222,7 @@ pvsInit = PVState { ronly = pvro00, stats = ssts0, absdp = 0, usedext = 0, abort futme = futIniVal, futyo = futIniVal, lmrhi = lmrInitLim, lmrlv = lmrInitLv, lmrrs = 0 } nst0 :: NodeState -nst0 = NSt { crtnt = PVNode, nxtnt = PVNode, cursc = pathFromScore "Zero" 0, rbmch = 0, +nst0 = NSt { crtnt = PVNode, nxtnt = PVNode, cursc = pathFromScore "Zero" 0, rbmch = -1, movno = 1, spcno = 1, killer = NoKiller, albe = False, cpos = initPos, pvsl = [] } -- we start with spcno = 1 as we consider the first move as special -- to avoid in any way reducing the tt move @@ -402,9 +402,11 @@ checkFailOrPVRoot xstats b d e s nst = do let typ = 2 lift $ ttStore de typ (pathScore s) e nodes' let xpvslg = insertToPvs d pvg (pvsl nst) -- the good - rch | pathScore s > a = rbmch nst + 1 - | otherwise = rbmch nst - return (False, nst {movno = mn + 1, pvsl = xpvslg, rbmch = rch }) + -- Do not count the changes in draft 1 (they were wrong anyway, + -- as we do not update cursc here and search all root moves) + -- rch | pathScore s > a = rbmch nst + 1 + -- | otherwise = rbmch nst + return (False, nst {movno = mn + 1, pvsl = xpvslg }) else if abort sst then return (True, nst) else if pathScore s <= a From 06aec1b581aa90fe549df57143226332b0f6d816 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Thu, 16 Mar 2017 17:57:27 +0100 Subject: [PATCH 25/71] New eval term: king on pawn(s) Inspired from Stockfish King opennes & king placement are together as they need almost the same elements --- Eval/Eval.hs | 96 ++++++++++++++++++---------------------------- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 12 ++++++ 3 files changed, 51 insertions(+), 59 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index b4fdbb3f..798358e6 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -36,8 +36,7 @@ evalItems = [ EvIt Material, -- material balance (i.e. white - black material EvIt Redundance, -- bishop pair and rook redundance EvIt RookPawn, -- the rook pawns are about 15% less valuable EvIt KingSafe, -- king safety - EvIt KingOpen, -- malus for king openness - EvIt KingPlace, -- bonus when king is near some fields + EvIt KingPlace, -- bonus when king is near some fields, opennes EvIt LastLine, -- malus for pieces on last line (except rooks and king) EvIt Mobility, -- pieces mobility EvIt Center, -- attacs of center squares @@ -286,37 +285,7 @@ materDiff p ew mide = mad mide (ewMaterialDiff ew) md where !md | moving p == White = mater p | otherwise = - mater p ------- King openness ------ -data KingOpen = KingOpen - -instance EvalItem KingOpen where - evalItem _ _ ew p _ mide = kingOpen p ew mide - --- Openness can be tought only with pawns (like we take) or all pieces -kingOpen :: MyPos -> EvalWeights -> MidEnd -> MidEnd -kingOpen p ew mide = mad mide (ewKingOpen ew) ko - where !ko = adv - own - moprooks = popCount $ rooks p .&. yo p - mopqueens = popCount $ queens p .&. yo p - mwb = popCount $ bAttacs paw msq `less` paw - -- mwr = popCount $ rAttacs paw msq `less` (paw .|. lastrs) - mwr = popCount $ rAttacs paw msq `less` paw - yoprooks = popCount $ rooks p .&. me p - yopqueens = popCount $ queens p .&. me p - ywb = popCount $ bAttacs paw ysq `less` paw - -- ywr = popCount $ rAttacs paw ysq `less` (paw .|. lastrs) - ywr = popCount $ rAttacs paw ysq `less` paw - paw = pawns p - msq = kingSquare (kings p) $ me p - ysq = kingSquare (kings p) $ yo p - comb !oR !oQ !wb !wr = let r = oR * wr - q = oQ * (wb + wr) - in r + q*q - own = comb moprooks mopqueens mwb mwr - adv = comb yoprooks yopqueens ywb ywr - -- lastrs = 0xFF000000000000FF -- approx: take out last row which cant be covered by pawns - ------- King placement ------ +------ King placement and opennes ------ data KingPlace = KingPlace instance EvalItem KingPlace where @@ -325,8 +294,14 @@ instance EvalItem KingPlace where -- Depending on which pieces are on the board we have some preferences -- where the king should be placed. For example, in the opening and middle game it should -- be in some corner, in endgame it should be near some (passed) pawn(s) +-- We calculate the king opennes here, as we have all we need +-- We also give a bonus for a king beeing near pawn(s) kingPlace :: EvalParams -> MyPos -> EvalWeights -> MidEnd -> MidEnd -kingPlace ep p ew mide = made (madm mide (ewKingPlaceCent ew) kcd) (ewKingPlacePwns ew) kpd +kingPlace ep p ew mide = made (madm (mad (mad (mad mide (ewKingPawn2 ew) kpa2) + (ewKingPawn1 ew) kpa1) + (ewKingOpen ew) ko) + (ewKingPlaceCent ew) kcd) + (ewKingPlacePwns ew) kpd where !kcd = (mpl - ypl) `unsafeShiftR` epMaterBonusScale ep !kpd = (mpi - ypi) `unsafeShiftR` epPawnBonusScale ep !mks = kingSquare (kings p) $ me p @@ -344,12 +319,10 @@ kingPlace ep p ew mide = made (madm mide (ewKingPlaceCent ew) kcd) (ewKingPlaceP , kingPawnsBonus mks ypassed mpassed , kingPawnsBonus yks ypassed mpassed ) - !mro = rooks p .&. me p - !mrooks = popCount mro + !mrooks = popCount $ rooks p .&. me p !mqueens = popCount $ queens p .&. me p !mminor = popCount $ (bishops p .|. knights p) .&. me p - !yro = rooks p .&. yo p - !yrooks = popCount yro + !yrooks = popCount $ rooks p .&. yo p !yqueens = popCount $ queens p .&. yo p !yminor = popCount $ (bishops p .|. knights p) .&. yo p !mpawns = pawns p .&. me p @@ -358,6 +331,27 @@ kingPlace ep p ew mide = made (madm mide (ewKingPlaceCent ew) kcd) (ewKingPlaceP !ypassed = passed p .&. yo p materFun m r q = (m * epMaterMinor ep + r * epMaterRook ep + q * epMaterQueen ep) `unsafeShiftR` epMaterScale ep + !ko = adv - own + mwb = popCount $ bAttacs paw mks `less` paw + mwr = popCount $ rAttacs paw mks `less` paw + ywb = popCount $ bAttacs paw yks `less` paw + ywr = popCount $ rAttacs paw yks `less` paw + paw = pawns p + comb !oR !oQ !wb !wr = let r = oR * wr + q = oQ * (wb + wr) + in r + q*q + own = comb yrooks yqueens mwb mwr + adv = comb mrooks mqueens ywb ywr + pmkpa = popCount (myKAttacs p .&. paw) + pykpa = popCount (yoKAttacs p .&. paw) + !kpa1 = mkpa1 - ykpa1 + !kpa2 = mkpa2 - ykpa2 + (mkpa1, mkpa2) | pmkpa == 0 = (0, 0) + | pmkpa == 1 = (1, 0) + | otherwise = (0, 1) + (ykpa1, ykpa2) | pykpa == 0 = (0, 0) + | pykpa == 1 = (1, 0) + | otherwise = (0, 1) promoW, promoB :: Square -> Square promoW s = 56 + (s .&. 7) @@ -400,10 +394,6 @@ kingMaterBonus c !myp !mat !ksq bb = 57 bg = 62 bh = 63 - -- roWA = row1 .&. (fileA .|. fileB .|. fileC) - -- roWH = row1 .&. (fileG .|. fileH) - -- roBA = row8 .&. (fileA .|. fileB .|. fileC) - -- roBH = row8 .&. (fileG .|. fileH) shWA2 = row2 .&. (fileA .|. fileB .|. fileC) shWA3 = row3 .&. (fileA .|. fileB .|. fileC) shWH2 = row2 .&. (fileF .|. fileG .|. fileH) @@ -468,7 +458,7 @@ data Mobility = Mobility -- "safe" moves instance EvalItem Mobility where evalItem _ _ ew p _ mide = mobDiff p ew mide --- Here we do not calculate pawn mobility (which, calculated as attacs, is useless) +-- Here we do not calculate pawn mobility (which, calculated as attacks, is useless) mobDiff :: MyPos -> EvalWeights -> MidEnd -> MidEnd mobDiff p ew mide = mad (mad (mad (mad mide (ewMobilityKnight ew) n) (ewMobilityBishop ew) b) (ewMobilityRook ew) r) (ewMobilityQueen ew) q where !myN = popCount $ myNAttacs p `less` (me p .|. yoPAttacs p) @@ -556,9 +546,6 @@ spaceBlack !mpawns !matts !ypatts !yatts = sv !sv = spaceVals `unsafeAt` spa -- Non linear space values: --- span2r: 200 --- span3r: 300 --- span4r: 400 spaceVals :: UArray Int Int spaceVals = listArray (0, 24) $ map f [1..25] where f x = round $ spf * (sqrt x - 1) @@ -940,27 +927,20 @@ pawnEndGame p !mescds = map snd $ filter fst mpsqs -- my escaped passed pawns ypsqs = map escYo $ bbToSquares yfpbb -- your pp squares & distances to promotion !yescds = map snd $ filter fst ypsqs -- your escaped passed pawns - -- mesc = not . null $ mescds - -- yesc = not . null $ yescds - dpr | mim < miy = promoBonus - distMalus mim - | mim > miy + 1 = -promoBonus + distMalus miy - | otherwise = withQueens -- Here: this is more complex, e.g. if check while promoting - -- or direct after promotion + queen capture? - -- (mim, msq) = minimumBy (comparing snd) mescds -- who is promoting first? - -- (miy, ysq) = minimumBy (comparing snd) yescds + dpr | mim < miy = myrace + | mim > miy + 1 = yorace + | otherwise = withQueens -- Here: this is more complex, e.g. if check while promoting + -- or direct after promotion + queen capture? mim = fst $ minimumBy (comparing snd) mescds -- who is promoting first? miy = fst $ minimumBy (comparing snd) yescds myrace = promoBonus - distMalus mim yorace = -promoBonus + distMalus miy promoBonus = 1000 -- i.e. almost a queen (here the unit is 1 cp) distMalus x = unsafeShiftL x 3 -- to bring at least 8 cp per move until promotion - -- We try to estimate static what will be after promotions of both queens + -- We try to estimate staticaly what will be after promotions of both queens -- This will be another specialized evaluation function... -- But now we consider only the material difference (which consists only of pawns) withQueens = maDiff - -- This one is for prunning: so match we can win at most - -- yoPawnCount = popCount $ pawns p .&. yo p - -- speg = simplePawnEndGame p -- just to see how it works... escMeWhite :: Square -> Square -> (Bool, (Square, Int)) escMeWhite !ksq !psq = (esc, (psq, dis)) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index f083a72d..b5b8b229 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -38,7 +38,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "wpv" +progVerSuff = "kon" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index ce7824ca..7ae9b835 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -79,6 +79,8 @@ data EvalWeights ewKingOpen :: !MidEnd, ewKingPlaceCent :: !MidEnd, ewKingPlacePwns :: !MidEnd, + ewKingPawn1 :: !MidEnd, + ewKingPawn2 :: !MidEnd, ewRookHOpen :: !MidEnd, ewRookOpen :: !MidEnd, ewRookConn :: !MidEnd, @@ -175,6 +177,8 @@ instance CollectParams EvalWeights where ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) + ewKingPawn1 = tme 8 48, + ewKingPawn2 = tme 12 64, ewRookHOpen = tme 178 200, ewRookOpen = tme 234 207, ewRookConn = tme 104 59, @@ -222,6 +226,10 @@ collectEvalWeights (s, v) ew = lookApply s v ew [ ("end.kingPlaceCent", setEndKingPlaceCent), ("mid.kingPlacePwns", setMidKingPlacePwns), ("end.kingPlacePwns", setEndKingPlacePwns), + ("mid.kingPawn1", setMidKingPawn1), + ("end.kingPawn1", setEndKingPawn1), + ("mid.kingPawn2", setMidKingPawn2), + ("end.kingPawn2", setEndKingPawn2), ("mid.rookHOpen", setMidRookHOpen), ("end.rookHOpen", setEndRookHOpen), ("mid.rookOpen", setMidRookOpen), @@ -297,6 +305,10 @@ collectEvalWeights (s, v) ew = lookApply s v ew [ setEndKingPlaceCent v' ew' = ew' { ewKingPlaceCent = (ewKingPlaceCent ew') { end = round v' }} setMidKingPlacePwns v' ew' = ew' { ewKingPlacePwns = (ewKingPlacePwns ew') { mid = round v' }} setEndKingPlacePwns v' ew' = ew' { ewKingPlacePwns = (ewKingPlacePwns ew') { end = round v' }} + setMidKingPawn1 v' ew' = ew' { ewKingPawn1 = (ewKingPawn1 ew') { mid = round v' }} + setEndKingPawn1 v' ew' = ew' { ewKingPawn1 = (ewKingPawn1 ew') { end = round v' }} + setMidKingPawn2 v' ew' = ew' { ewKingPawn2 = (ewKingPawn2 ew') { mid = round v' }} + setEndKingPawn2 v' ew' = ew' { ewKingPawn2 = (ewKingPawn2 ew') { end = round v' }} setMidRookHOpen v' ew' = ew' { ewRookHOpen = (ewRookHOpen ew') { mid = round v' }} setEndRookHOpen v' ew' = ew' { ewRookHOpen = (ewRookHOpen ew') { end = round v' }} setMidRookOpen v' ew' = ew' { ewRookOpen = (ewRookOpen ew') { mid = round v' }} From 754e6f93513de341341173bf4d4118cca2fa0cbd Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 8 Apr 2017 14:02:29 +0200 Subject: [PATCH 26/71] LMR even for extended moves --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index f42c9c8d..8c89c3bd 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "kont" +progVerSuff = "lmre" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 5b73a71d..f565ea7d 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -41,8 +41,6 @@ useTTinPv = False -- retrieve from TT in PV? minPvDepth = 2 -- from this depth we use alpha beta search -- Parameters for late move reduction: -lmrActive :: Bool -lmrActive = True lmrInitLv, lmrInitLim, lmrLevMin, lmrLevMax :: Int lmrInitLv = 8 lmrInitLim = 8500 @@ -773,7 +771,7 @@ pvInnerLoopExtenZ b d spec !exd nst redu = do -- late move reduction let !d1 = d + exd' - 1 -- this is the normal (unreduced) depth for next search !d' = if redu - then reduceLmr d1 (nearmate b) spec exd (lmrlv old) (movno nst - spcno nst) + then reduceLmr (nearmate b) spec d1 (lmrlv old) (movno nst - spcno nst) else d1 let !onemB = scoreGrain - b if not redu || d' == d1 @@ -903,10 +901,10 @@ genAndSort nst mttmv a b d = do -- With a variable lmrlev the reduction should stay in a region -- where the number of researches has an acceptable level {-# INLINE reduceLmr #-} -reduceLmr :: Int -> Bool -> Bool -> Int -> Int -> Int -> Int -reduceLmr !d nearmatea !spec !exd lmrlev w - | not lmrActive || spec || exd > 0 || d <= 1 || nearmatea = d - | otherwise = max 1 $ d - lmrArr!(lmrlev, w) +reduceLmr :: Bool -> Bool -> Int -> Int -> Int -> Int +reduceLmr nearmatea spec d lmrlev w + | spec || d <= 1 || nearmatea = d + | otherwise = max 1 $ d - lmrArr!(lmrlev, w) -- Adjust the LMR related parameters in the state moreLMR :: Bool -> Int -> Search () From 71827b935bb091d19f7e78eaf0298d51f978b10e Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 29 Apr 2017 21:21:26 +0200 Subject: [PATCH 27/71] Add SelfPlay, correct node statistics --- Barbarossa-NB.tex | 2 +- Barbarossa.cabal | 60 ++++- Hash/TransTab.hs | 6 +- Main/Barbarossa.hs | 13 +- Main/SelfPlay.hs | 614 +++++++++++++++++++++++++++++++++++++++++++++ Moves/Base.hs | 3 +- Moves/Fen.hs | 4 +- Search/Albeta.hs | 17 +- Struct/Status.hs | 1 - 9 files changed, 702 insertions(+), 18 deletions(-) create mode 100644 Main/SelfPlay.hs diff --git a/Barbarossa-NB.tex b/Barbarossa-NB.tex index a1de6bd8..715056c4 100644 --- a/Barbarossa-NB.tex +++ b/Barbarossa-NB.tex @@ -19,7 +19,7 @@ searched nodes per second) is still far behind comparable engines written in C or C++. Nevertheless Barbarossa can compete with many engines - as it can be seen on the CCRL rating lists, where is it currently listed with a strength -of about 2200 ELO. +of more than 2300 ELO (the last release version, see below). Barbarossa uses a few techniques which are well known in the computer chess scene: \begin{compactitem} diff --git a/Barbarossa.cabal b/Barbarossa.cabal index cd9cb992..e5a36df5 100644 --- a/Barbarossa.cabal +++ b/Barbarossa.cabal @@ -68,8 +68,64 @@ Executable Barbarossa -fspec-constr-count=24 -funfolding-use-threshold=32 -fno-warn-tabs - -- -ddump-simpl -ddump-to-file -dsuppress-all -dsuppress-uniques - -- -ddump-opt-cmm -ddump-asm + CPP-Options: -DSMSTRICT + if flag(sse42) + GHC-Options: -msse4.2 + if flag(ddump) + GHC-Options: -ddump-simpl -ddump-to-file -dsuppress-all -dsuppress-uniques + -ddump-opt-cmm -ddump-asm + +Executable SelfPlay + Main-is: Main/SelfPlay.hs + Build-depends: + base >= 4.5, + array, + old-time, + containers, + filepath, + mtl, + parsec, + vector, + vector-algorithms, + random, + directory, + transformers, + QuickCheck, + text + Other-modules: + Eval.BasicEval, + Eval.Eval, + Eval.FileParams, + Hash.TransTab, + Hash.Zobrist, + Moves.Base, + Moves.BaseTypes, + Moves.BitBoard, + Moves.Board, + Moves.Fen, + Moves.GenMagics, + Moves.History, + Moves.Magics, + Moves.Moves, + Moves.Notation, + Moves.Pattern, + Moves.ShowMe, + Search.Albeta, + Search.AlbetaTypes, + Search.CStateMonad, + Struct.Config, + Struct.Context, + Struct.Status, + Struct.Struct, + Uci.UCI, + Uci.UciGlue + GHC-Options: -O2 -Wall + -funbox-strict-fields + -threaded + -rtsopts -with-rtsopts=-N3 + -fspec-constr-count=24 + -funfolding-use-threshold=32 + -fno-warn-tabs CPP-Options: -DSMSTRICT if flag(sse42) GHC-Options: -msse4.2 diff --git a/Hash/TransTab.hs b/Hash/TransTab.hs index 5635e43b..17c5a7b0 100644 --- a/Hash/TransTab.hs +++ b/Hash/TransTab.hs @@ -3,7 +3,7 @@ {-# LANGUAGE MagicHash #-} {-# LANGUAGE CPP #-} module Hash.TransTab ( - Cache, newCache, retrieveEntry, readCache, writeCache, newGener, + Cache, newCache, freeCache, retrieveEntry, readCache, writeCache, newGener, -- checkProp ) where @@ -12,6 +12,7 @@ import Data.Bits import Data.Int import Data.Word import Foreign.Marshal.Array +import Foreign.Marshal.Alloc (free) import Foreign.Storable import Foreign.Ptr import Data.Text.Unsafe (inlinePerformIO) @@ -110,6 +111,9 @@ newCache mb = do return Cache { mem = memc, lomask = lom, mimask = mim, zemask = complement mim, gener = 0 } where cellMask = complement part3Mask -- for speed we keep both masks +freeCache :: Cache -> IO () +freeCache = free . mem + generInc, generMsk :: Word64 generInc = 0x0100000000000000 -- 1 in first byte generMsk = 0xFF00000000000000 -- to mask all except generation diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 8c89c3bd..a1cf597f 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "lmre" +progVerSuff = "self" data Options = Options { optConfFile :: Maybe String, -- config file @@ -237,9 +237,10 @@ theReader = do ctxLog DebugUci $ "Input: " ++ line let euci = parseUciStr line stop <- case euci of - Left _ -> do + Left erm -> do ctxLog LogWarning $ "Input: " ++ line - ctxLog LogWarning $ "Parse: " ++ show euci + ctxLog LogWarning $ "Parse: " ++ show erm + answer $ infos $ "Parse: " ++ show erm return False Right uci -> interpret uci unless stop theReader @@ -524,14 +525,16 @@ searchTheTree draft mdraft timx tim tpm mtg rept lsc lpv rmvs = do redp = reduceBegin $ realPly chg start = srchStrtMs chg used = currms - start - over = used >= mx + over = mx > 0 && used >= mx onlyone = ms > 0 && length rmvsf == 1 && draft >= 4 -- only in normal play draftmax = draft >= mdraft -- or maximal draft mes = "Draft " ++ show draft ++ " Score " ++ show sc ++ " path " ++ show path ++ " ms " ++ show ms ++ " used " ++ show used ctxLog LogInfo mes ctxLog LogInfo $ "Time factors (reds/redp): " ++ show reds ++ " / " ++ show redp - (justStop, mxr) <- stopByChance (reds * redp) exte ms used mx draft ch totch ldCh + (justStop, mxr) <- if mx > 0 + then stopByChance (reds * redp) exte ms used mx draft ch totch ldCh + else return (False, 0) ctxLog LogInfo $ "compTime (ms/mx/mxr): " ++ show ms ++ " / " ++ show mx ++ " / " ++ show mxr if draftmax || timint || over || onlyone || justStop then do diff --git a/Main/SelfPlay.hs b/Main/SelfPlay.hs new file mode 100644 index 00000000..22fb7d13 --- /dev/null +++ b/Main/SelfPlay.hs @@ -0,0 +1,614 @@ +{-# LANGUAGE PatternGuards #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE MultiWayIf #-} + +module Main where +import Control.Monad.Reader +-- import Control.Monad.State +import Control.Concurrent +import Control.Exception +-- import Data.Bits (popCount, (.|.)) +import Data.List (intersperse) +-- import Data.Monoid +-- import Network +import Foreign hiding (void) +import System.Console.GetOpt +import System.Directory +import System.Environment (getArgs) +import System.FilePath +import System.IO +import System.Time + +import Struct.Struct +import Struct.Status +import Struct.Context +import Struct.Config +import Hash.TransTab +import Search.AlbetaTypes (ssts0) +import Moves.Base +import Moves.Fen +import Moves.Notation +import Moves.History +import Search.CStateMonad (execCState) +import Eval.FileParams (makeEvalState) +-- import Eval.Eval -- not yet needed +import Uci.UciGlue + +debug :: Bool +debug = False + +data Options = Options { + optPlayer1 :: Maybe String, -- player 1 config file + optPlayer2 :: Maybe String, -- player 2 config file + optConfFile :: Maybe String, -- config file + optParams :: [String], -- list of eval parameter assignements + optNThreads :: Int, -- number of threads - not used for self play now + optDepth :: Int, -- search depth for self play + optNSkip :: Maybe Int, -- number of fens to skip (Nothing = none) + optNFens :: Maybe Int, -- number of fens (Nothing = all) + optMatch :: Maybe String, -- match between configs in the given directory + optAFenFile :: FilePath, -- fen file with start positions + optFOutFile :: FilePath -- output file for filter option + } + +defaultOptions :: Options +defaultOptions = Options { + optPlayer1 = Nothing, + optPlayer2 = Nothing, + optConfFile = Nothing, + optParams = [], + optNThreads = 1, + optDepth = 1, + optNSkip = Nothing, + optNFens = Nothing, + optMatch = Nothing, + optAFenFile = "alle.epd", + optFOutFile = "vect.txt" + } + +setPlayer1 :: String -> Options -> Options +setPlayer1 cf opt = opt { optPlayer1 = Just cf } + +setPlayer2 :: String -> Options -> Options +setPlayer2 cf opt = opt { optPlayer2 = Just cf } + +setConfFile :: String -> Options -> Options +setConfFile cf opt = opt { optConfFile = Just cf } + +addParam :: String -> Options -> Options +addParam pa opt = opt { optParams = pa : optParams opt } + +addNThrds :: String -> Options -> Options +addNThrds ns opt = opt { optNThreads = read ns } + +addDepth :: String -> Options -> Options +addDepth ns opt = opt { optDepth = read ns } + +addNSkip :: String -> Options -> Options +addNSkip ns opt = opt { optNSkip = Just $ read ns } + +addNFens :: String -> Options -> Options +addNFens ns opt = opt { optNFens = Just $ read ns } + +addMatch :: String -> Options -> Options +addMatch ns opt = opt { optMatch = Just ns } + +addIFile :: FilePath -> Options -> Options +addIFile fi opt = opt { optAFenFile = fi } + +addOFile :: FilePath -> Options -> Options +addOFile fi opt = opt { optFOutFile = fi } + +options :: [OptDescr (Options -> Options)] +options = [ + Option "a" ["player1"] (ReqArg setPlayer1 "STRING") "Configuration file for player 1", + Option "b" ["player2"] (ReqArg setPlayer2 "STRING") "Configuration file for player 2", + Option "c" ["config"] (ReqArg setConfFile "STRING") "Configuration file", + Option "p" ["param"] (ReqArg addParam "STRING") "Eval/search/time params: name=value,...", + Option "m" ["match"] (ReqArg addMatch "STRING") "Start match between 2 configs in the given directory", + Option "i" ["input"] (ReqArg addIFile "STRING") "Input (fen) file", + Option "o" ["output"] (ReqArg addOFile "STRING") "Output file", + Option "d" ["depth"] (ReqArg addDepth "STRING") "Search depth", + Option "t" ["threads"] (ReqArg addNThrds "STRING") "Number of threads", + Option "s" ["skip"] (ReqArg addNSkip "STRING") "Number of fens to skip", + Option "f" ["fens"] (ReqArg addNFens "STRING") "Number of fens to play" + ] + +theOptions :: IO (Options, [String]) +theOptions = do + args <- getArgs + case getOpt Permute options args of + (o, n, []) -> return (foldr ($) defaultOptions o, n) + (_, _, es) -> ioError (userError (concat es ++ usageInfo header options)) + where header = "Usage: " ++ idName + ++ " [-c CONF] [-m DIR [-a CFILE1] -b CFILE2] [-t THREADS] [-i FENFILE [-s SKIP][-f FENS]] [-o OUTFILE] [-d DEPTH]" + idName = "SelfPlay" + +initContext :: Options -> IO Context +initContext opts = do + clktm <- getClockTime + lchan <- newChan + wchan <- newChan + ichan <- newChan + ha <- newCache 1 -- it will take the minimum number of entries + hi <- newHist + let paramList = stringToParams $ concat $ intersperse "," $ optParams opts + (parc, evs) <- makeEvalState (optConfFile opts) paramList "progver" "progsuf" + let chg = Chg { + working = False, + compThread = Nothing, + crtStatus = posToState initPos ha hi evs, + realPly = Nothing, + forGui = Nothing, + srchStrtMs = 0, + myColor = White, + totBmCh = 0, lastChDr = 0, lmvScore = Nothing + } + ctxVar <- newMVar chg + let context = Ctx { + logger = lchan, + writer = wchan, + inform = ichan, + strttm = clktm, + change = ctxVar, + loglev = if debug then DebugSearch else LogNever, + evpid = parc, + tipars = npSetParm (colParams paramList :: CollectFor TimeParams) + } + return context + +main :: IO () +main = do + (opts, _) <- theOptions + ctx <- initContext opts + case optMatch opts of + Nothing -> runReaderT (filterFile opts) ctx + Just dir -> do + wdl <- runReaderT (matchFile opts dir) ctx + putStrLn $ "End result: " ++ show wdl + +filterFile :: Options -> CtxIO () +filterFile opts = do + ctx <- ask + let logFileName = "selfplay-" ++ show (startSecond ctx) ++ ".log" + startLogger logFileName + startInformer + lift $ do + putStrLn $ "Vectorizing " ++ optAFenFile opts + putStrLn $ "Play depth " ++ show (optDepth opts) + putStrLn $ "Results to " ++ optFOutFile opts + -- putStrLn $ "Marker: " ++ show markerEval + hi <- liftIO $ openFile (optAFenFile opts) ReadMode + ho <- liftIO $ openFile (optFOutFile opts) WriteMode + case optNSkip opts of + Just m -> loopCount (skipLines hi m) () + Nothing -> return () + -- loopCount (oracleAndFeats (optDepth opts) hi ho (optNFens opts)) () + loopCount (balancedPos hi ho (optNFens opts)) () + liftIO $ do + hClose ho + hClose hi + +matchFile :: Options -> String -> CtxIO (Int, Int, Int) +matchFile opts dir = do + ctx <- ask + let logFileName = "selfplay-" ++ show (startSecond ctx) ++ ".log" + startLogger logFileName + startInformer + liftIO $ do + putStrLn $ "Playing games from " ++ optAFenFile opts + putStrLn $ "Play depth " ++ show (optDepth opts) + putStrLn $ "Results to " ++ optFOutFile opts + let mids = (,) <$> optPlayer1 opts <*> optPlayer2 opts + case mids of + Nothing -> do + liftIO $ putStrLn "For a match we need 2 configs as players" + return (0, 0, 0) + Just (id1, id2) -> do + ctxLog LogInfo $ "Players from directory " ++ dir + ctxLog LogInfo $ "Player 1 " ++ id1 + ctxLog LogInfo $ "Player 2 " ++ id2 + (hi, ho) <- liftIO $ do + hi <- openFile (optAFenFile opts) ReadMode + ho <- openFile (optFOutFile opts) WriteMode + return (hi, ho) + case optNSkip opts of + Just m -> do + ispos <- skipWithIndex (optAFenFile opts) hi m + when (not ispos) $ loopCount (skipLines hi m) () + Nothing -> return () + (eval1, eval2) <- liftIO $ do + setCurrentDirectory dir + (_, eval1) <- liftIO $ makeEvalState (Just id1) [] "progver" "progsuf" + (_, eval2) <- liftIO $ makeEvalState (Just id2) [] "progver" "progsuf" + return (eval1, eval2) + let act = playEveryGame (optDepth opts) hi ho (optNFens opts) (id1, eval1) (id2, eval2) + wdl <- loopCount act (0, 0, 0) + liftIO $ do + hClose ho + hClose hi + return wdl + +-- If the fen file has an index, use it to skip to the wanted line +-- The index must be created with binary IndexTxt from Bartest +skipWithIndex :: MonadIO m => String -> Handle -> Int -> m Bool +skipWithIndex fn h k = liftIO $ do + let fni = replaceExtension fn "idx" + fniex <- doesFileExist fni + if fniex + then do + withBinaryFile fni ReadMode $ \ih -> + allocaBytes 4 $ \ptr -> do + when debug $ putStrLn $ "Skip to index entry " ++ show k + hSeek ih AbsoluteSeek (fromIntegral k * 4) + rb <- hGetBuf ih ptr 4 + if rb < 4 + then error "Unexpected EOF in index file" + else do + wo <- peek ptr :: IO Word32 + when debug $ putStrLn $ "Skip to file byte " ++ show wo + hSeek h AbsoluteSeek (fromIntegral wo) + return True + else return False + +loopCount :: Monad m => (Int -> a -> m (Bool, a)) -> a -> m a +loopCount act = go 1 + where go !k a = do + (r, b) <- act k a + if r then go (k+1) b else return b + +skipLines :: MonadIO m => Handle -> Int -> Int -> () -> m (Bool, ()) +skipLines hi m k () = do + end <- if k <= m then liftIO $ hIsEOF hi else return True + if end + then return (False, ()) + else do + _ <- liftIO $ hGetLine hi + when (k `mod` 100000 == 0) $ liftIO $ do + putStrLn $ "Positions skipped: " ++ show k + hFlush stdout + return (True, ()) + +-- We want positions which are not very imbalanced (after 1 ply search) +balancedPos :: Handle -> Handle -> Maybe Int -> Int -> () -> CtxIO (Bool, ()) +balancedPos hi ho mn k () = do + end <- case mn of + Nothing -> lift $ hIsEOF hi + Just n -> if k <= n then lift $ hIsEOF hi else return True + if end + then return (False, ()) + else do + fen <- lift $ hGetLine hi + when debug $ lift $ do + putStrLn $ "Fen: " ++ fen + hFlush stdout + when (k `mod` 100000 == 0) $ do + ctx <- ask + currms <- lift $ currMilli (startSecond ctx) + lift $ do + putStrLn $ "Positions completed: " ++ show k ++ " (" + ++ show (k `div` currms) ++ " positions per ms)" + hFlush stdout + let pos = posFromFen fen + chg <- readChanging + let crts = crtStatus chg + sini = posToState pos (hash crts) (hist crts) (evalst crts) + modifyChanging $ \c -> c { crtStatus = sini } + (msc, path) <- iterativeDeepening 1 + case msc of + Nothing -> return () + Just sc -> if null path + then return () + else when (abs sc <= 150) $ lift $ hPutStrLn ho fen + return (True, ()) + +oracleAndFeats :: Int -> Handle -> Handle -> Maybe Int -> Int -> () -> CtxIO (Bool, ()) +oracleAndFeats depth hi _ho mn k () = do -- not functional yet + end <- case mn of + Nothing -> lift $ hIsEOF hi + Just n -> if k <= n then lift $ hIsEOF hi else return True + if end + then return (False, ()) + else do + fen <- lift $ hGetLine hi + when debug $ lift $ do + putStrLn $ "Fen: " ++ fen + hFlush stdout + when (k `mod` 10 == 0) $ do + ctx <- ask + currms <- lift $ currMilli (startSecond ctx) + lift $ do + putStrLn $ "Positions completed: " ++ show k ++ " (" + ++ show (currms `div` k) ++ " ms per position)" + hFlush stdout + let pos = posFromFen fen + msc <- autoPlayToEnd depth pos + when debug $ lift $ do + putStrLn $ "Rez of auto play: " ++ show msc + hFlush stdout +-- This part can't work now as we do not have featsEval +{- + case msc of + Just sc' -> do + let (ph, fts) = featsEval pos + sc | moving pos == White = sc' -- score autoPlayToEnd is from White p.o.v. + | otherwise = -sc' + lift $ hPutStrLn ho $ show ph ++ " " ++ show sc ++ " " ++ show fts + Nothing -> return () +-} + return (True, ()) + +playEveryGame :: Int -> Handle -> Handle -> Maybe Int + -> (String, EvalState) -- "player" 1 + -> (String, EvalState) -- "player" 2 + -> Int + -> (Int, Int, Int) + -> CtxIO (Bool, (Int, Int, Int)) +playEveryGame depth hi _ho mn (id1, eval1) (id2, eval2) k wdl = do + end <- case mn of + Nothing -> lift $ hIsEOF hi + Just n -> if k <= n then lift $ hIsEOF hi else return True + if end + then return (False, wdl) + else do + fen <- lift $ hGetLine hi + when debug $ lift $ do + putStrLn $ "Fen: " ++ fen + hFlush stdout + when (k `mod` 10 == 0) $ do + ctx <- ask + currms <- lift $ currMilli (startSecond ctx) + lift $ do + putStrLn $ "Positions completed: " ++ show k ++ " (" + ++ show (currms `div` k) ++ " ms per position)" + hFlush stdout + let pos = posFromFen fen + gr1 <- playGame depth pos (id1, eval1) (id2, eval2) + gr2 <- playGame depth pos (id2, eval2) (id1, eval1) + let wdl1 = scoreGameResult id1 gr1 -- game result from + wdl2 = scoreGameResult id1 gr2 -- POV of id1 + wdla = addGameScores wdl wdl1 + wdlb = addGameScores wdla wdl2 + when debug $ lift $ do + putStrLn $ "Rez of auto play: " ++ show gr1 ++ " / " ++ show gr2 + putStrLn $ "Score so far: " ++ show wdlb + hFlush stdout + -- lift $ hPutStrLn ho $ show ph ++ " " ++ show sc ++ " " ++ show fts + return (True, wdlb) + +-- The logger will be startet anyway, but will open a file +-- only when it has to write the first message +-- When it cannot open that file, it should at least consume the messages +-- so that the channel does not get stuck +data LoggerState = LoggerFile String + | LoggerHandle Handle + | LoggerError + +startLogger :: String -> CtxIO () +startLogger file = do + ctx <- ask + void $ liftIO $ forkIO $ catch (theLogger (logger ctx) (LoggerFile file)) collectError + ctxLog LogInfo "Logger started" + +theLogger :: Chan String -> LoggerState -> IO () +theLogger lchan lst = do + s <- readChan lchan + case lst of + LoggerError -> theLogger lchan lst + LoggerFile f -> handle collectError $ do + h <- openFile f AppendMode + hPutStrLn h s + hFlush h + theLogger lchan (LoggerHandle h) + LoggerHandle h -> do + hPutStrLn h s + hFlush h + theLogger lchan lst + +-- The informer is getting structured data +-- Because we do not have a Gui here, we discard the messages +startInformer :: CtxIO () +startInformer = do + ctx <- ask + void $ newThread (theInformer (inform ctx)) + return () + +theInformer :: Chan InfoToGui -> CtxIO () +theInformer ichan = forever $ void $ liftIO $ readChan ichan + +newThread :: CtxIO () -> CtxIO ThreadId +newThread a = do + ctx <- ask + liftIO $ forkIO $ runReaderT a ctx + +-- We play the position to the end using fixed depth for now +-- which means, this function can be used only to optimize eval weights but not +-- time or search parameters +-- The result score is from White p.o.v.: +-- 0: remis +-- +1: white wins +-- -1: black wins +autoPlayToEnd :: Int -> MyPos -> CtxIO (Maybe Int) +autoPlayToEnd d pos = do + chg <- readChanging + let crts = crtStatus chg + sini = posToState pos (hash crts) (hist crts) (evalst crts) + modifyChanging $ \c -> c { crtStatus = sini } + go (0::Int) + where go i = do + -- Search to depth: + (msc, path) <- iterativeDeepening d + if null path + then do + when (i>0) $ ctxLog LogError $ "Empty path when playing" + return Nothing -- should not happen when i > 0 + else case msc of + Nothing -> do + when (i>0) $ ctxLog LogError $ "No score when playing" + return Nothing + Just sc -> do + let j = i+1 + m = head path + ctxLog LogInfo $ "Real move " ++ show j ++ ": " ++ show m + chg <- readChanging + sfin' <- execCState (doRealMove m) (crtStatus chg) + let p = head $ stack sfin' + if sc == 19999 -- mate in 1 + then if tacticalPos p + then do + let r = if moving p == White then -1 else 1 + ctxLog LogInfo $ "Mate (" ++ show r ++ ")" + return $ Just r + else do + ctxLog LogError $ "Mate announced, not in check!" + return Nothing + else if remis50Moves p + then do + ctxLog LogInfo $ "Remis 50 moves" + return $ Just 0 + else do + hi <- liftIO newHist + let sfin = sfin' { hist = hi } + modifyChanging $ \s -> s { crtStatus = sfin } + go j + +-- Play the given position to the end using fixed depth with 2 configurations +-- This function can be used only to optimize eval weights but not time or search parameters +-- The result score is from White p.o.v.: +-- 0: remis +-- +1: white wins +-- -1: black wins +playGame :: Int -> MyPos -> (String, EvalState) -> (String, EvalState) -> CtxIO GameResult +playGame d pos (ide1, eval1) (ide2, eval2) = do + ctxLog LogInfo $ "Setup new game between " ++ ide1 ++ " and " ++ ide2 + chg <- readChanging + let crts = crtStatus chg + (hash1, hash2, hist0) <- liftIO $ do + freeCache $ hash crts + -- Alloc only one history, as this will be anyway re-allocated for every move + (,,) <$> newCache 1 <*> newCache 1 <*> newHist + let state1 = posToState pos hash1 hist0 eval1 + state2 = posToState pos hash2 hist0 eval2 + color1 = moving pos + color2 = other color1 + -- Maybe set realPly? (what is this good for if not for time management?) + chg1 = chg { crtStatus = state1, forGui = Nothing, srchStrtMs = 0, + myColor = color1, totBmCh = 0, lastChDr = 0, lmvScore = Nothing } + chg2 = chg { crtStatus = state2, forGui = Nothing, srchStrtMs = 0, + myColor = color2, totBmCh = 0, lastChDr = 0, lmvScore = Nothing } + ctxLog LogInfo $ "Color for " ++ ide1 ++ ": " ++ show color1 + ctxLog LogInfo $ "Starting position: " ++ posToFen pos + go (0::Int) (ide1, chg1) (ide2, chg2) + where go i (id1, chg1) (id2, chg2) = do + start <- asks startSecond + currms <- lift $ currMilli start + let j = i + 1 + -- Prepare for chg1 to search: + modifyChanging $ const chg1 { forGui = Nothing, srchStrtMs = currms, + totBmCh = 0, lastChDr = 0 } + ctxLog LogInfo $ "Real ply " ++ show j ++ " engine " ++ id1 + -- Search to depth: + (msc, path) <- iterativeDeepening d + ctxLog LogInfo $ "Real ply " ++ show j ++ " returns " ++ show msc ++ " / " ++ show path + if null path + then do + ctxLog LogError $ "Empty path when playing" + return $ GameAborted "Empty path when playing" + else case msc of + Nothing -> do + ctxLog LogError $ "No score when playing" + return $ GameAborted "No score when playing" + Just sc -> do + let m = head path + ctxLog LogInfo $ "Real move " ++ show j ++ " from " ++ id1 ++ ": " ++ show m + chg1f <- readChanging + s1fin <- execCState (doRealMove m) (crtStatus chg1f) + s2ini <- execCState (doRealMove m) (crtStatus chg2) + let p = head $ stack s1fin + -- Using length path here could be a problem + -- in case of a TT cut which is on path + if | sc == mateScore && length path == 1 -- mate in 1 + -> if tacticalPos p + then do + ctxLog LogInfo $ "Mate (" ++ id1 ++ " wins)" + return $ GameWin id1 "Mate" + else do + ctxLog LogError $ "Mate announced, but not in check!" + return $ GameAborted "Mate announced, but not in check" + | remis50Moves p -> do + ctxLog LogInfo $ "Remis 50 moves" + return $ GameRemis "Remis 50 moves rule" + | remis3Repetitions p $ stack s1fin -> do + ctxLog LogInfo $ "Remis 3 repetitions" + return $ GameRemis "Remis 3 repetitions rule" + | sc == 0 && length path == 1 -> do -- this should be patt + ctxLog LogInfo $ "Remis (patt)" + return $ GameRemis "Remis (patt)" + | noMatingMaterial p -> do + ctxLog LogInfo $ "Remis no mating material" + return $ GameRemis "Remis no mating material" + | otherwise -> do + hi <- liftIO newHist + let state2 = s2ini { hist = hi, mstats = ssts0 } + chg1n = chg1f { crtStatus = s1fin } + chg2n = chg2 { crtStatus = state2 } + go j (id2, chg2n) (id1, chg1n) + +iterativeDeepening :: Int -> CtxIO (Maybe Int, [Move]) +iterativeDeepening depth = do + --when debug $ lift $ do + -- putStrLn $ "In iter deep: " ++ show depth + -- hFlush stdout + chg <- readChanging + go 1 (crtStatus chg) Nothing [] [] + where go d _ lsc lpv _ | d > depth = return (lsc, lpv) + go d sini lsc lpv rmvs = do + --when debug $ lift $ do + -- putStrLn $ "In iter deep go: " ++ show d + -- hFlush stdout + (path, sc, rmvsf, _timint, sfin, _) <- bestMoveCont d 0 sini lsc lpv rmvs + if null path + then return (Just sc, path) + else go (d+1) sfin (Just sc) path rmvsf + +-- Append error info to error file: +collectError :: SomeException -> IO () +collectError e = handle cannot $ do + let efname = "Barbarossa_collected_errors.txt" + TOD tm _ <- getClockTime + ef <- openFile efname AppendMode + hPutStrLn ef $ show tm ++ " selfplay: " ++ show e + hClose ef + where cannot :: IOException -> IO () + cannot _ = return () + +data GameResult = GameAborted String + | GameWin String String + | GameRemis String + deriving Show + +scoreGameResult :: String -> GameResult -> (Int, Int, Int) +scoreGameResult player (GameWin plwin _) + | player == plwin = (1, 0, 0) + | otherwise = (0, 0, 1) +scoreGameResult _ (GameRemis _) = (0, 1, 0) +scoreGameResult _ _ = (0, 0, 0) + +addGameScores :: (Int, Int, Int) -> (Int, Int, Int) -> (Int, Int, Int) +addGameScores (w1, d1, l1) (w2, d2, l2) = (w1+w2, d1+d2, l1+l2) + +remis3Repetitions :: MyPos -> [MyPos] -> Bool +remis3Repetitions p ps + | _:_:_:_ <- filter (== zobkey p) + $ map zobkey $ takeWhile isReversible ps = True + | otherwise = False + +noMatingMaterial :: MyPos -> Bool +noMatingMaterial p + | occup p == kings p .|. knights p = True -- one side should have only king + | occup p == kings p .|. bishops p + && popCount (occup p) == 3 = True + | otherwise = False diff --git a/Moves/Base.hs b/Moves/Base.hs index df12415d..6b9b0d3c 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -70,7 +70,6 @@ posToState p c h e = MyState { hash = c, hist = h, mstats = ssts0, - gstats = ssts0, evalst = e } where stsc = evalState (posEval p) e @@ -82,7 +81,7 @@ posNewSearch p = p { hash = newGener (hash p) } draftStats :: SStats -> Game () draftStats dst = do s <- get - put s { mstats = addStats (mstats s) dst, gstats = addStats (gstats s) dst } + put s { mstats = addStats (mstats s) dst } -- Loosing captures after non-captures? loosingLast :: Bool diff --git a/Moves/Fen.hs b/Moves/Fen.hs index 621ac4b0..b86d12ea 100644 --- a/Moves/Fen.hs +++ b/Moves/Fen.hs @@ -81,8 +81,8 @@ fenFromString fen = zipWith ($) fenfuncs fentails getFenMv = headOrDefault "w" getFenCast = headOrDefault "-" getFenEp = headOrDefault "-" - getFenHalf = headOrDefault "-" - getFenMvNo = headOrDefault "-" + getFenHalf = headOrDefault "0" + getFenMvNo = headOrDefault "0" updatePos :: MyPos -> MyPos updatePos !p = p { diff --git a/Search/Albeta.hs b/Search/Albeta.hs index f565ea7d..33041912 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -224,6 +224,12 @@ nst0 = NSt { crtnt = PVNode, nxtnt = PVNode, cursc = pathFromScore "Zero" 0, rbm -- we start with spcno = 1 as we consider the first move as special -- to avoid in any way reducing the tt move +resetStats :: Search SStats +resetStats = do + st <- get + put st { stats = ssts0 } + return $ stats st + resetNSt :: Path -> Killer -> NodeState -> NodeState resetNSt !sc !kill nst = nst { cursc = sc, movno = 1, spcno = 1, killer = kill } @@ -307,7 +313,7 @@ pvRootSearch a b d lastpath rmvs aspir = do return (a, emptySeq, edges, rbmch nstf) -- just to permit aspiration to retry else do -- lift $ mapM_ (\m -> informStr $ "Root move: " ++ show m) (pvsl nstf) - when (d < depthForCM) $ informPV sc d p + -- when (d < depthForCM) $ informPV sc d p let (best':_) = p allrmvs = if sc >= b then unalt edges else map pvslToMove (pvsl nstf) xrmvs = Alt $ best' : delete best' allrmvs -- best on top @@ -1213,6 +1219,9 @@ logmes :: String -> Game () logmes s = informCtx (LogMes s) informPV :: Int -> Int -> [Move] -> Search () -informPV s d es = lift $ do - n <- curNodes - informCtx (BestMv s d n es) +informPV s d es = do + dst <- resetStats + lift $ do + draftStats dst + n <- curNodes + informCtx (BestMv s d n es) diff --git a/Struct/Status.hs b/Struct/Status.hs index 1fe2e116..fb5c29ce 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -21,7 +21,6 @@ data MyState = MyState { hash :: Cache, -- transposition table hist :: History, -- history table mstats :: SStats, -- per move search statistics - gstats :: SStats, -- global search statistics evalst :: EvalState -- eval status (parameter & statistics) } From 7f945342cd7856e62cae3d71898cf6941901b9b6 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 10 May 2017 00:34:30 +0200 Subject: [PATCH 28/71] Mobility change: Stockfish style --- Eval/Eval.hs | 40 +++++++++++++++++++++++++--------------- Main/Barbarossa.hs | 2 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index 798358e6..cb6e2afe 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -456,23 +456,33 @@ perRook allp myp rsq (ho, op) data Mobility = Mobility -- "safe" moves instance EvalItem Mobility where - evalItem _ _ ew p _ mide = mobDiff p ew mide + evalItem _ _ ew p _ mide + | moving p == White = mobDiff p r23 r67 pbw pbb ew mide + | otherwise = mobDiff p r67 r23 pbb pbw ew mide + where r23 = row2 .|. row3 + r67 = row6 .|. row7 + pbw = occup p `unsafeShiftR` 8 + pbb = occup p `unsafeShiftL` 8 -- Here we do not calculate pawn mobility (which, calculated as attacks, is useless) -mobDiff :: MyPos -> EvalWeights -> MidEnd -> MidEnd -mobDiff p ew mide = mad (mad (mad (mad mide (ewMobilityKnight ew) n) (ewMobilityBishop ew) b) (ewMobilityRook ew) r) (ewMobilityQueen ew) q - where !myN = popCount $ myNAttacs p `less` (me p .|. yoPAttacs p) - !myB = popCount $ myBAttacs p `less` (me p .|. yoPAttacs p) - !myR = popCount $ myRAttacs p `less` (me p .|. yoA1) - !myQ = popCount $ myQAttacs p `less` (me p .|. yoA2) - !yoA1 = yoPAttacs p .|. yoNAttacs p .|. yoBAttacs p - !yoA2 = yoA1 .|. yoRAttacs p - !yoN = popCount $ yoNAttacs p `less` (yo p .|. myPAttacs p) - !yoB = popCount $ yoBAttacs p `less` (yo p .|. myPAttacs p) - !yoR = popCount $ yoRAttacs p `less` (yo p .|. myA1) - !yoQ = popCount $ yoQAttacs p `less` (yo p .|. myA2) - !myA1 = myPAttacs p .|. myNAttacs p .|. myBAttacs p - !myA2 = myA1 .|. myRAttacs p +-- Mobility inspired by Stockfish, with mobility aria +mobDiff :: MyPos -> BBoard -> BBoard -> BBoard -> BBoard -> EvalWeights -> MidEnd -> MidEnd +mobDiff p mylr yolr mypb yopb ew mide = mad (mad (mad (mad mide (ewMobilityKnight ew) n) + (ewMobilityBishop ew) b) + (ewMobilityRook ew) r) + (ewMobilityQueen ew) q + where !myPMA = me p .&. pawns p .&. (mylr .|. mypb) + !yoPMA = yo p .&. pawns p .&. (yolr .|. yopb) + !myMA = complement $ myPMA .|. (kings p .&. me p) .|. yoPAttacs p + !yoMA = complement $ yoPMA .|. (kings p .&. yo p) .|. myPAttacs p + !myN = popCount $ myNAttacs p .&. myMA + !myB = popCount $ myBAttacs p .&. myMA + !myR = popCount $ myRAttacs p .&. myMA + !myQ = popCount $ myQAttacs p .&. myMA + !yoN = popCount $ yoNAttacs p .&. yoMA + !yoB = popCount $ yoBAttacs p .&. yoMA + !yoR = popCount $ yoRAttacs p .&. yoMA + !yoQ = popCount $ yoQAttacs p .&. yoMA !n = myN - yoN !b = myB - yoB !r = myR - yoR diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index a1cf597f..77cb692e 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "self" +progVerSuff = "moa" data Options = Options { optConfFile :: Maybe String, -- config file From 4e42803a361fe55201768fb216604470bbd5cdbe Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sun, 14 May 2017 19:36:41 +0200 Subject: [PATCH 29/71] Eval new term: bishop pawns --- Eval/Eval.hs | 11 ++++++++++- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 6 ++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index 798358e6..73edfd6a 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -714,7 +714,9 @@ instance EvalItem Redundance where -- This function is optimised evalRedundance :: MyPos -> EvalWeights -> MidEnd -> MidEnd -evalRedundance p ew mide = mad (mad mide (ewBishopPair ew) bp) (ewRedundanceRook ew) rr +evalRedundance p ew mide = mad (mad (mad mide (ewBishopPawns ew) pa) + (ewBishopPair ew) bp) + (ewRedundanceRook ew) rr where !wbl = bishops p .&. me p .&. lightSquares !wbd = bishops p .&. me p .&. darkSquares !bbl = bishops p .&. yo p .&. lightSquares @@ -727,6 +729,13 @@ evalRedundance p ew mide = mad (mad mide (ewBishopPair ew) bp) (ewRedundanceRook !wrr = popCount wro `unsafeShiftR` 1 -- tricky here: 2, 3 are the same... !brr = popCount bro `unsafeShiftR` 1 -- and here !rr = wrr - brr + !mpa | (wbl == 0) == (wbd == 0) = 0 + | wbl == 0 = popCount (me p .&. pawns p .&. darkSquares) + | otherwise = popCount (me p .&. pawns p .&. lightSquares) + !ypa | (bbl == 0) == (bbd == 0) = 0 + | bbl == 0 = popCount (yo p .&. pawns p .&. darkSquares) + | otherwise = popCount (yo p .&. pawns p .&. lightSquares) + !pa = mpa - ypa {-- ------ Knight & Rook correction according to own pawns ------ diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index a1cf597f..c7a89a00 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "self" +progVerSuff = "bpa" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index fb5c29ce..95fb1cf8 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -105,6 +105,7 @@ data EvalWeights ewWepAttacked :: !MidEnd, ewLastLinePenalty :: !MidEnd, ewBishopPair :: !MidEnd, + ewBishopPawns :: !MidEnd, ewRedundanceRook :: !MidEnd, ewRookPawn :: !MidEnd, ewAdvPawn6 :: !MidEnd, @@ -203,6 +204,7 @@ instance CollectParams EvalWeights where ewWepAttacked = tme 48 64, ewLastLinePenalty = tme 119 3, ewBishopPair = tme 387 321, + ewBishopPawns = tme (-24) (-64), ewRedundanceRook = tme (-32) (-67), ewRookPawn = tme (-52) (-41), ewAdvPawn5 = tme 4 131, @@ -279,6 +281,8 @@ collectEvalWeights (s, v) ew = lookApply s v ew [ ("end.lastLinePenalty", setEndLastLinePenalty), ("mid.bishopPair", setMidBishopPair), ("end.bishopPair", setEndBishopPair), + ("mid.bishopPawns", setMidBishopPawns), + ("end.bishopPawns", setEndBishopPawns), ("mid.redundanceRook", setMidRedundanceRook), ("end.redundanceRook", setEndRedundanceRook), ("mid.rookPawn", setMidRookPawn), @@ -358,6 +362,8 @@ collectEvalWeights (s, v) ew = lookApply s v ew [ setEndLastLinePenalty v' ew' = ew' { ewLastLinePenalty = (ewLastLinePenalty ew') { end = round v' }} setMidBishopPair v' ew' = ew' { ewBishopPair = (ewBishopPair ew') { mid = round v' }} setEndBishopPair v' ew' = ew' { ewBishopPair = (ewBishopPair ew') { end = round v' }} + setMidBishopPawns v' ew' = ew' { ewBishopPawns = (ewBishopPawns ew') { mid = round v' }} + setEndBishopPawns v' ew' = ew' { ewBishopPawns = (ewBishopPawns ew') { end = round v' }} setMidRedundanceRook v' ew' = ew' { ewRedundanceRook = (ewRedundanceRook ew') { mid = round v' }} setEndRedundanceRook v' ew' = ew' { ewRedundanceRook = (ewRedundanceRook ew') { end = round v' }} setMidRookPawn v' ew' = ew' { ewRookPawn = (ewRookPawn ew') { mid = round v' }} From 96b1807e350ba0e29375dda5eaa261d030e24340 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Tue, 16 May 2017 17:25:05 +0200 Subject: [PATCH 30/71] Bishop pawns: all pawns, balanced --- Eval/Eval.hs | 21 ++++++++++++--------- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 8 ++++---- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index 73edfd6a..78f772b0 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -721,21 +721,24 @@ evalRedundance p ew mide = mad (mad (mad mide (ewBishopPawns ew) pa) !wbd = bishops p .&. me p .&. darkSquares !bbl = bishops p .&. yo p .&. lightSquares !bbd = bishops p .&. yo p .&. darkSquares - !bpw = popCount wbl .&. popCount wbd -- tricky here: exact 1 and 1 is ok - !bpb = popCount bbl .&. popCount bbd -- and here + !bpwl = popCount wbl + !bpwd = popCount wbd + !bpw = bpwl .&. bpwd -- tricky here: exact 1 and 1 is ok + !bpbl = popCount bbl + !bpbd = popCount bbd + !bpb = bpbl .&. bpbd -- and here !bp = bpw - bpb + !mpal = bpwl * (popCount (pawns p .&. lightSquares) - pawnEven) + !mpad = bpwd * (popCount (pawns p .&. darkSquares) - pawnEven) + !ypal = bpbl * (popCount (pawns p .&. lightSquares) - pawnEven) + !ypad = bpbd * (popCount (pawns p .&. darkSquares) - pawnEven) + !pa = mpal + mpad - ypal - ypad !wro = rooks p .&. me p !bro = rooks p .&. yo p !wrr = popCount wro `unsafeShiftR` 1 -- tricky here: 2, 3 are the same... !brr = popCount bro `unsafeShiftR` 1 -- and here !rr = wrr - brr - !mpa | (wbl == 0) == (wbd == 0) = 0 - | wbl == 0 = popCount (me p .&. pawns p .&. darkSquares) - | otherwise = popCount (me p .&. pawns p .&. lightSquares) - !ypa | (bbl == 0) == (bbd == 0) = 0 - | bbl == 0 = popCount (yo p .&. pawns p .&. darkSquares) - | otherwise = popCount (yo p .&. pawns p .&. lightSquares) - !pa = mpa - ypa + pawnEven = 6 {-- ------ Knight & Rook correction according to own pawns ------ diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index c7a89a00..b7d74b3e 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "bpa" +progVerSuff = "bpa2" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 95fb1cf8..a5967be7 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -182,13 +182,13 @@ instance CollectParams EvalWeights where ewRookHOpen = tme 178 200, ewRookOpen = tme 234 207, ewRookConn = tme 104 59, - ewMobilityKnight = tme 51 68, -- Evalo 200 steps: - ewMobilityBishop = tme 57 32, -- length 10, depth 6, batch 128 + ewMobilityKnight = tme 51 68, -- Evalo 200 steps: length 10, depth 6, batch 128 + ewMobilityBishop = tme 58 32, -- adjusted bc bishop pawns ewMobilityRook = tme 26 28, ewMobilityQueen = tme 4 3, ewCenterPAtts = tme 84 66, ewCenterNAtts = tme 49 46, - ewCenterBAtts = tme 57 42, + ewCenterBAtts = tme 58 42, -- adjusted bc bishop pawns ewCenterRAtts = tme 11 33, ewCenterQAtts = tme 4 61, ewCenterKAtts = tme 2 54, @@ -203,7 +203,7 @@ instance CollectParams EvalWeights where ewEnpAttacked = tme (-6) (-7), ewWepAttacked = tme 48 64, ewLastLinePenalty = tme 119 3, - ewBishopPair = tme 387 321, + ewBishopPair = tme 390 320, ewBishopPawns = tme (-24) (-64), ewRedundanceRook = tme (-32) (-67), ewRookPawn = tme (-52) (-41), From 3f55b84c5c357327a7fb1b4f4e3a482c94c1f56b Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Fri, 19 May 2017 02:07:02 +0200 Subject: [PATCH 31/71] Small changes for clarity & speed (hopefully) - gen moves especially for QS - do move especially for QS Plus some comments deleted --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 89 ++++++++++++++++++++-------------------------- Search/Albeta.hs | 17 ++++----- 3 files changed, 47 insertions(+), 61 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 77cb692e..628a5a85 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "moa" +progVerSuff = "sma" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index 6b9b0d3c..13f9f5d8 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -7,9 +7,10 @@ module Moves.Base ( posToState, getPos, posNewSearch, - doRealMove, doMove, undoMove, genMoves, genTactMoves, canPruneMove, + doRealMove, doMove, doQSMove, doNullMove, undoMove, + genMoves, genTactMoves, genEscapeMoves, canPruneMove, tacticalPos, zugZwang, isMoveLegal, isKillCand, isTKillCand, - betaCut, doNullMove, ttRead, ttStore, curNodes, isTimeout, informCtx, + betaCut, ttRead, ttStore, curNodes, isTimeout, informCtx, mateScore, scoreDiff, qsDelta, draftStats, finNode, countRepetitions, @@ -43,17 +44,14 @@ nearmate :: Int -> Bool nearmate i = i >= mateScore - 255 || i <= -mateScore + 255 -- Some options and parameters: --- debug :: Bool --- debug = False - printEvalInt :: Int64 printEvalInt = 2 `shiftL` 12 - 1 -- if /= 0: print eval info every so many nodes mateScore :: Int mateScore = 20000 -curNodes :: Game Int64 {-# INLINE curNodes #-} +curNodes :: Game Int64 curNodes = gets (sNodes . mstats) {-# INLINE getPos #-} @@ -83,36 +81,34 @@ draftStats dst = do s <- get put s { mstats = addStats (mstats s) dst } --- Loosing captures after non-captures? -loosingLast :: Bool -loosingLast = True - genMoves :: Int -> Game ([Move], [Move]) genMoves d = do p <- getPos - if isCheck p $ moving p + if inCheck p then return (genMoveFCheck p, []) else do h <- gets hist let l0 = genMoveCast p l1 = genMovePromo p (l2w, l2l) = genMoveCaptWL p - l3' = genMoveNCapt p - l3 = histSortMoves d h l3' - return $! if loosingLast - then (l1 ++ l2w, l0 ++ l3 ++ l2l) - else (l1 ++ l2w ++ l2l, l0 ++ l3) + l3 = histSortMoves d h $ genMoveNCapt p + -- Loosing captures after non-captures + return (l1 ++ l2w, l0 ++ l3 ++ l2l) --- Generate only tactical moves, i.e. promotions, captures & check escapes +-- Generate only tactical moves, i.e. promotions & captures +-- Needed only in QS, when we know we are not in check genTactMoves :: Game [Move] genTactMoves = do p <- getPos - if isCheck p $ moving p - then return $ genMoveFCheck p - else do - let l1 = genMovePromo p - l2w = fst $ genMoveCaptWL p - return $ l1 ++ l2w + let l1 = genMovePromo p + l2w = fst $ genMoveCaptWL p + return $ l1 ++ l2w + +-- Generate only escape moves: needed only in QS when we know we have to escape +genEscapeMoves :: Game [Move] +genEscapeMoves = do + p <- getPos + return $ genMoveFCheck p {-- checkGenMoves :: MyPos -> [Move] -> [Move] @@ -137,11 +133,6 @@ checkGenMove p m@(Move w) ++ showHex w (" in pos\n" ++ showMyPos p) --} --- massert :: String -> Game Bool -> Game () --- massert s mb = do --- b <- mb --- if b then return () else error s - showMyPos :: MyPos -> String showMyPos p = showTab (black p) (slide p) (kkrq p) (diag p) ++ "================ " ++ mc ++ "\n" where mc = if moving p == White then "w" else "b" @@ -182,9 +173,9 @@ doRealMove m = do put s { stack = p' : stack s } return $ Exten 0 False --- Move from a node to a descendent - the search version -doMove :: Move -> Bool -> Game DoResult -doMove m qs = do +-- Move from a node to a descendent - the normal search version +doMove :: Move -> Game DoResult +doMove m = do s <- get let (pc:_) = stack s -- we never saw an empty stack error until now -- Moving a non-existent piece? @@ -205,13 +196,29 @@ doMove m qs = do then return Illegal else do put s { stack = p : stack s } - remis <- if qs then return False else checkRemisRules p + remis <- checkRemisRules p if remis then return $ Final 0 else do let dext = if inCheck p then 1 else 0 return $! Exten dext $ moveIsCaptPromo pc m +-- Move from a node to a descendent - the QS search version +-- Here we do only a restricted check for illegal moves +-- It does not check for remis, so it can't return Final +-- It does not check for extensions a.s.o. +doQSMove :: Move -> Game DoResult +doQSMove m = do + s <- get + let (pc:_) = stack s -- we never saw an empty stack error until now + sts = evalState (posEval p) (evalst s) + p = doFromToMove m pc { staticScore = sts } + if not $ checkOk p + then return Illegal + else do + put s { stack = p : stack s } + return $ Exten 0 False + doNullMove :: Game () doNullMove = do s <- get @@ -270,14 +277,6 @@ isKillCand p mm ym isTKillCand :: MyPos -> Move -> Bool isTKillCand p mm = not $ moveIsCapture p mm --- Static evaluation function --- This does not detect mate or stale mate, it only returns the calculated --- static score from a position which has already to be valid --- Mate/stale mate has to be detected by search! --- {-# INLINE staticVal #-} --- staticVal :: Game Int --- staticVal = staticScore <$> getPos - {-# INLINE finNode #-} finNode :: String -> Int64 -> Game () finNode str nodes = @@ -293,16 +292,6 @@ finNode str nodes = -- ++ concatMap (\(n, v) -> " " ++ n ++ "=" ++ show v) -- (("score", staticScore p) : weightPairs (staticFeats p)) -{-- -materVal :: Game Int -materVal = do - t <- getPos - let !m = mater t - return $! case moving t of - White -> m - _ -> -m ---} - {-# INLINE qsDelta #-} qsDelta :: Game Int qsDelta = do diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 33041912..717b4292 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -337,7 +337,7 @@ pvInnerRoot :: Int -- current beta -> Search (Bool, NodeState) pvInnerRoot b d nst e = timeToAbort (True, nst) $ do -- do the move - exd <- lift $ doMove e False + exd <- lift $ doMove e if legalResult exd then do old <- get @@ -667,7 +667,7 @@ pvInnerLoop b d prune nst e = timeToAbort (True, nst) $ do return (False, nst1) else do old <- get - exd <- lift $ doMove e False -- do the move + exd <- lift $ doMove e -- do the move if legalResult exd then do newNode d @@ -705,7 +705,7 @@ pvInnerLoopZ b d prune nst e redu = timeToAbort (True, nst) $ do return (False, nst1) else do old <- get - exd <- lift $ doMove e False -- do the move + exd <- lift $ doMove e -- do the move -- even the legality could be checked before, maybe much cheaper if legalResult exd then do @@ -1005,8 +1005,7 @@ pvQSearch !a !b !c = do pos <- lift $ getPos if tacticalPos pos then do - (es1, es2) <- lift $ genMoves 0 - let edges = Alt $ es1 ++ es2 + edges <- Alt <$> lift genEscapeMoves if noMove edges then return $! trimax a b (-mateScore) else if c >= qsMaxChess @@ -1036,7 +1035,7 @@ pvQSearch !a !b !c = do when collectFens $ finWithNodes "DELT" return a else do - edges <- liftM Alt $ lift genTactMoves + edges <- Alt <$> lift genTactMoves if noMove edges then do -- no more captures when collectFens $ finWithNodes "NOCA" @@ -1057,13 +1056,11 @@ pvQLoop b c = go pvQInnerLoop :: Int -> Int -> Int -> Move -> Search (Bool, Int) pvQInnerLoop !b c !a e = timeToAbort (True, b) $ do - r <- lift $ doMove e True + r <- lift $ doQSMove e if legalResult r then do newNodeQS - !sc <- case r of - Final sc -> return (-sc) - _ -> negate <$> pvQSearch (-b) (-a) c + !sc <- negate <$> pvQSearch (-b) (-a) c lift undoMove if sc >= b then return (True, b) From 3ebbea9975d213ff5bd8091385a0d13310793c47 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 27 May 2017 23:54:38 +0200 Subject: [PATCH 32/71] Null move only for depth >= 2 Sven Schule says, null move is waste of time at depth 1 --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 35 ++++++++++++++++------------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 55a41980..a5ab30d6 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "smab" +progVerSuff = "nm2" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 717b4292..38d054a4 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -82,8 +82,6 @@ qsMaxChess :: Int qsMaxChess = 2 -- max number of chess for a quiet search path -- Parameters for null move pruning -nulMoves :: Int -nulMoves = 1 -- how many null moves in sequence are allowed (one or two) nulMargin, nulSubmrg, nulTrig :: Int nulMargin = 1 -- margin to search the null move (over beta) (in scoreGrain units!) nulSubmrg = 2 -- improved margin (in scoreGrain units!) @@ -377,7 +375,7 @@ pvInnerRootExten b d !exd nst = do else do -- no futility pruning & no LMR for root moves! -- Here we expect to fail low - s1 <- pnextlev <$> pvZeroW nst (-a) d1 nulMoves True + s1 <- pnextlev <$> pvZeroW nst (-a) d1 True whenAbort s1 $ do checkFailHard "pvZeroW" a b (pathScore s1) if pathScore s1 <= a -- we failed low as expected @@ -527,13 +525,13 @@ pvSearch nst !a !b !d = do else return $ trimaxPath a b $ if tacticalPos pos then matedPath else staleMate -- PV Zero Window -pvZeroW :: NodeState -> Int -> Int -> Int -> Bool -> Search Path -pvZeroW !_ !b !d !_ _ | d <= 0 = do +pvZeroW :: NodeState -> Int -> Int -> Bool -> Search Path +pvZeroW !_ !b !d _ | d <= 0 = do v <- pvQSearch bGrain b 0 checkFailHard "QS" bGrain b v return $ pathFromScore ("pvQSearch 21:" ++ show v) v where !bGrain = b - scoreGrain -pvZeroW !nst !b !d !lastnull redu = do +pvZeroW !nst !b !d redu = do -- Check if we have it in TT (hdeep, tp, hsc, e, nodes') <- reTrieve >> lift ttRead if hdeep >= d && (tp == 2 || tp == 1 && hsc >= b || tp == 0 && hsc < b) @@ -548,7 +546,7 @@ pvZeroW !nst !b !d !lastnull redu = do else do when (hdeep < 0) reFail pos <- lift getPos - nmhigh <- nullMoveFailsHigh pos nst b d lastnull + nmhigh <- nullMoveFailsHigh pos nst b d whenAbort (pathFromScore "Aborted" b) $ do case nmhigh of NullMoveHigh -> return $ pathFromScore "NullMoveHigh" b @@ -591,9 +589,9 @@ pvZeroW !nst !b !d !lastnull redu = do data NullMoveResult = NoNullMove | NullMoveHigh | NullMoveLow | NullMoveThreat Path -nullMoveFailsHigh :: MyPos -> NodeState -> Int -> Int -> Int -> Search NullMoveResult -nullMoveFailsHigh pos nst b d lastnull - | lastnull < 1 || tacticalPos pos || zugZwang pos -- go smooth into QS +nullMoveFailsHigh :: MyPos -> NodeState -> Int -> Int -> Search NullMoveResult +nullMoveFailsHigh pos nst b d + | d < 2 || tacticalPos pos || zugZwang pos -- no null move at d < 2 || crtnt nst == AllNode = return NoNullMove -- no null move in all nodes | otherwise = do let v = staticScore pos @@ -606,8 +604,8 @@ nullMoveFailsHigh pos nst b d lastnull xchangeFutil let nst' = deepNSt nst val <- if v > b + bigDiff - then fmap pnextlev $ pvZeroW nst' (-nma) d2 lastnull1 True - else fmap pnextlev $ pvZeroW nst' (-nma) d1 lastnull1 True + then fmap pnextlev $ pvZeroW nst' (-nma) d2 True + else fmap pnextlev $ pvZeroW nst' (-nma) d1 True lift undoMove -- undo null move xchangeFutil if pathScore val >= nmb @@ -625,7 +623,6 @@ nullMoveFailsHigh pos nst b d lastnull d2 = nmDArr2 `unsafeAt` d -- this is for bigger differences nmb = if nulSubAct then b - (nulSubmrg * scoreGrain) else b nma = nmb - (nulMargin * scoreGrain) - lastnull1 = lastnull - 1 bigDiff = 500 -- if we are very far ahead -- This is now more than reduction 3 for depth over 9 @@ -760,7 +757,7 @@ pvInnerLoopExten b d !exd nst = do else do -- Here we must be in a Cut node (will fail low) -- and we should have: crtnt = CutNode, nxtnt = AllNode - s1 <- pnextlev <$> pvZeroW nst (-a) d1 nulMoves True + s1 <- pnextlev <$> pvZeroW nst (-a) d1 True whenAbort s1 $ do if pathScore s1 <= a then return s1 -- failed low (as expected) or aborted @@ -783,15 +780,15 @@ pvInnerLoopExtenZ b d spec !exd nst redu = do if not redu || d' == d1 then do moreLMR True 1 -- more LMR - pnextlev <$> pvZeroW nst onemB d' nulMoves redu + pnextlev <$> pvZeroW nst onemB d' redu else do incRedu nds0 <- gets $ sNodes . stats - !sr <- pnextlev <$> pvZeroW nst onemB d' nulMoves True + !sr <- pnextlev <$> pvZeroW nst onemB d' True nds1 <- gets $ sNodes . stats let nodre = nds1 - nds0 !s1 <- if lmrDebug - then pnextlev <$> pvZeroW nst onemB d1 nulMoves False + then pnextlev <$> pvZeroW nst onemB d1 False else return sr nds2 <- gets $ sNodes . stats let nodnr = nds2 - nds1 @@ -811,7 +808,7 @@ pvInnerLoopExtenZ b d spec !exd nst redu = do moreLMR False d' -- less LMR -- Now we expect to fail high, i.e. exchange the crt/nxt node type let nst1 = nst { crtnt = nxtnt nst, nxtnt = crtnt nst } - sf <- pnextlev <$> pvZeroW nst1 onemB d1 nulMoves True + sf <- pnextlev <$> pvZeroW nst1 onemB d1 True whenAbort sf $ do when (pathScore sf >= b) $ moreLMR False d1 return sf @@ -1082,7 +1079,7 @@ bestMoveFromIID nst a b d = do s <- pvSearch nst a b d' return $! unseq $ pathMoves s | nt == CutNode && (d >= minIIDCut || (d >= minIIDCutNK && killer nst == NoKiller)) - = do s <- pvZeroW nst b d' nulMoves False + = do s <- pvZeroW nst b d' False return $! unseq $ pathMoves s | otherwise = return [] where d' = min maxIIDDepth (iidNewDepth d) From 2ecb27f77087a38900bec2e57aef24a55064c8d6 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Tue, 16 May 2017 13:34:06 +0200 Subject: [PATCH 33/71] Bishop value, SEE piece value changes --- Eval/BasicEval.hs | 24 +++++++++--------------- Main/Barbarossa.hs | 2 +- Moves/Board.hs | 19 ++++++++----------- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/Eval/BasicEval.hs b/Eval/BasicEval.hs index 57a9ab6f..565eddf8 100644 --- a/Eval/BasicEval.hs +++ b/Eval/BasicEval.hs @@ -1,22 +1,13 @@ module Eval.BasicEval ( - matPiece + matPiece, seeValue ) where --- import Data.Array.Unboxed --- import Data.Array.Base --- import GHC.Arr (unsafeIndex) - import Struct.Struct -{-- -matvals :: UArray Piece Int -matvals = listArray (Pawn, King) [ 100, 325, 325, 500, 975, 20000 ] ---} - matPiece1 :: Piece -> Int matPiece1 Pawn = 100 matPiece1 Knight = 360 -matPiece1 Bishop = 361 +matPiece1 Bishop = 360 matPiece1 Rook = 565 matPiece1 Queen = 1100 matPiece1 King = 20000 @@ -29,7 +20,10 @@ fun Black = negate matPiece :: Color -> Piece -> Int matPiece c = fun c . matPiece1 -{- -matPiece White = unsafeAt matvals . unsafeIndex (Pawn, King) -matPiece Black = negate . unsafeAt matvals . unsafeIndex (Pawn, King) --} +seeValue :: Piece -> Int +seeValue Pawn = 1 +seeValue Knight = 3 +seeValue Bishop = 3 +seeValue Rook = 5 +seeValue Queen = 10 +seeValue King = 200 diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index a5ab30d6..73db2ce3 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "nm2" +progVerSuff = "sseq" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Board.hs b/Moves/Board.hs index 19eda38d..df709542 100644 --- a/Moves/Board.hs +++ b/Moves/Board.hs @@ -627,12 +627,12 @@ findLKA0 pt ksq psq -- Choose the cheapest of a set of pieces chooseAttacker :: MyPos -> BBoard -> (BBoard, Int) chooseAttacker pos !frompieces - | p /= 0 = p1 `seq` (p1, value Pawn) - | n /= 0 = n1 `seq` (n1, value Knight) - | b /= 0 = b1 `seq` (b1, value Bishop) - | r /= 0 = r1 `seq` (r1, value Rook) - | q /= 0 = q1 `seq` (q1, value Queen) - | k /= 0 = k1 `seq` (k1, value King) + | p /= 0 = p1 `seq` (p1, seeValue Pawn) + | n /= 0 = n1 `seq` (n1, seeValue Knight) + | b /= 0 = b1 `seq` (b1, seeValue Bishop) + | r /= 0 = r1 `seq` (r1, seeValue Rook) + | q /= 0 = q1 `seq` (q1, seeValue Queen) + | k /= 0 = k1 `seq` (k1, seeValue King) | otherwise = (0, 0) where p = frompieces .&. pawns pos n = frompieces .&. knights pos @@ -699,9 +699,6 @@ xrayAttacs pos sq = sa1 /= sa0 unimax :: Int -> [Int] -> Int unimax = foldl' (\a g -> min g (-a)) -value :: Piece -> Int -value = matPiece White - usePosXRay :: Bool usePosXRay = False @@ -800,7 +797,7 @@ perCaptFieldWL pos mypc advdefence sq mvlst where !myAttRec = theAttacs pos sq myattacs = mypc .&. atAtt myAttRec Busy _ pcto = tabla pos sq - valto = value pcto + valto = seeValue pcto hanging = not (advdefence `testBit` sq) prAgrsqs = bbToSquares prPawns reAgrsqs = bbToSquares reAtts @@ -827,7 +824,7 @@ perCaptWL !pos !attacks promo vict !gain0 !sq !sqfa (wsqs, lsqs) where ss = moveToLMove attc vict $ moveAddPiece attc $ moveFromTo sqfa sq approx = approximateEasyCapts && gain0 >= v0 Busy _ attc = tabla pos sqfa - v0 = value attc + v0 = seeValue attc adv = seeMoveValue pos attacks sqfa sq v0 -- Captures of hanging pieces are always winning From 3aada9443c34e54fd577be503a31df216064bc42 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 28 Jun 2017 12:43:03 +0200 Subject: [PATCH 34/71] Correct draft statistics --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 12 +++--------- Search/Albeta.hs | 11 ++--------- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 73db2ce3..e82535d6 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "sseq" +progVerSuff = "cst" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index 13f9f5d8..99c78902 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -51,8 +51,8 @@ mateScore :: Int mateScore = 20000 {-# INLINE curNodes #-} -curNodes :: Game Int64 -curNodes = gets (sNodes . mstats) +curNodes :: Int64 -> Game Int64 +curNodes n = (n + ) <$> gets (sNodes . mstats) {-# INLINE getPos #-} getPos :: Game MyPos @@ -284,13 +284,7 @@ finNode str nodes = s <- get let (p:_) = stack s -- we never saw an empty stack error until now fen = posToFen p - -- mv = case tail $ words fen of - -- mv':_ -> mv' - -- _ -> error "Wrong fen in finNode" - logMes $ str ++ " Fen: " ++ fen - -- logMes $ "Eval info " ++ mv ++ ":" - -- ++ concatMap (\(n, v) -> " " ++ n ++ "=" ++ show v) - -- (("score", staticScore p) : weightPairs (staticFeats p)) + logMes $ str ++ " Score: " ++ show (staticScore p) ++ " Fen: " ++ fen {-# INLINE qsDelta #-} qsDelta :: Game Int diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 38d054a4..12ed8209 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -222,12 +222,6 @@ nst0 = NSt { crtnt = PVNode, nxtnt = PVNode, cursc = pathFromScore "Zero" 0, rbm -- we start with spcno = 1 as we consider the first move as special -- to avoid in any way reducing the tt move -resetStats :: Search SStats -resetStats = do - st <- get - put st { stats = ssts0 } - return $ stats st - resetNSt :: Path -> Killer -> NodeState -> NodeState resetNSt !sc !kill nst = nst { cursc = sc, movno = 1, spcno = 1, killer = kill } @@ -1214,8 +1208,7 @@ logmes s = informCtx (LogMes s) informPV :: Int -> Int -> [Move] -> Search () informPV s d es = do - dst <- resetStats + ss <- gets stats lift $ do - draftStats dst - n <- curNodes + n <- curNodes $ sNodes ss informCtx (BestMv s d n es) From 3d570e2fae337b527663e1a0c899c6a975bf155d Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 6 Sep 2017 01:12:41 +0200 Subject: [PATCH 35/71] Eval: half values for most params --- Eval/Eval.hs | 2 +- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 58 +++++++++++++++++++++++----------------------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index 5a76cda3..dff9990a 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -559,7 +559,7 @@ spaceBlack !mpawns !matts !ypatts !yatts = sv spaceVals :: UArray Int Int spaceVals = listArray (0, 24) $ map f [1..25] where f x = round $ spf * (sqrt x - 1) - spf = 300 :: Double + spf = 200 :: Double -------- Attacks to adverse squares ---------- data Advers = Advers diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index e82535d6..b4cc8e3d 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "cst" +progVerSuff = "sol" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index a5967be7..6b7c2944 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,44 +174,44 @@ instance CollectParams EvalWeights where npColInit = EvalWeights { ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, - ewKingOpen = tme 5 0, + ewKingOpen = tme 3 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) ewKingPawn1 = tme 8 48, ewKingPawn2 = tme 12 64, - ewRookHOpen = tme 178 200, - ewRookOpen = tme 234 207, - ewRookConn = tme 104 59, - ewMobilityKnight = tme 51 68, -- Evalo 200 steps: length 10, depth 6, batch 128 - ewMobilityBishop = tme 58 32, -- adjusted bc bishop pawns - ewMobilityRook = tme 26 28, - ewMobilityQueen = tme 4 3, - ewCenterPAtts = tme 84 66, - ewCenterNAtts = tme 49 46, - ewCenterBAtts = tme 58 42, -- adjusted bc bishop pawns - ewCenterRAtts = tme 11 33, - ewCenterQAtts = tme 4 61, + ewRookHOpen = tme 89 100, + ewRookOpen = tme 117 104, + ewRookConn = tme 52 30, + ewMobilityKnight = tme 25 34, -- Evalo 200 steps: length 10, depth 6, batch 128 + ewMobilityBishop = tme 29 16, -- adjusted bc bishop pawns + ewMobilityRook = tme 13 14, + ewMobilityQueen = tme 2 2, + ewCenterPAtts = tme 42 33, + ewCenterNAtts = tme 25 23, + ewCenterBAtts = tme 29 21, -- adjusted bc bishop pawns + ewCenterRAtts = tme 6 17, + ewCenterQAtts = tme 2 30, ewCenterKAtts = tme 2 54, ewSpace = tme 1 0, - ewAdvAtts = tme 2 16, - ewIsolPawns = tme (-41) (-120), - ewIsolPassed = tme (-57) (-169), - ewBackPawns = tme (-126) (-168), - ewBackPOpen = tme (-26) (-22), - ewEnpHanging = tme (-21) (-34), + ewAdvAtts = tme 1 8, + ewIsolPawns = tme (-21) (-60), + ewIsolPassed = tme (-27) (-85), + ewBackPawns = tme (-63) (-84), + ewBackPOpen = tme (-13) (-11), + ewEnpHanging = tme (-22) (-34), ewEnpEnPrise = tme (-28) (-26), ewEnpAttacked = tme (-6) (-7), - ewWepAttacked = tme 48 64, - ewLastLinePenalty = tme 119 3, + ewWepAttacked = tme 48 64, + ewLastLinePenalty = tme 60 2, ewBishopPair = tme 390 320, - ewBishopPawns = tme (-24) (-64), - ewRedundanceRook = tme (-32) (-67), - ewRookPawn = tme (-52) (-41), - ewAdvPawn5 = tme 4 131, - ewAdvPawn6 = tme 396 370, - ewPawnBlockP = tme (-128) (-100), - ewPawnBlockO = tme (-22) (-26), - ewPawnBlockA = tme (-14) (-77), + ewBishopPawns = tme (-12) (-32), + ewRedundanceRook = tme (-16) (-33), + ewRookPawn = tme (-26) (-21), + ewAdvPawn5 = tme 2 66, + ewAdvPawn6 = tme 200 185, + ewPawnBlockP = tme (-64) (-50), + ewPawnBlockO = tme (-11) (-13), + ewPawnBlockA = tme (-7) (-38), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From 415e4cb779cc983bf985b1b8cc869b8319a1a2bb Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 6 Sep 2017 20:59:52 +0200 Subject: [PATCH 36/71] Eval: only 10% less for some params Half was too much. Parameters for king placement, oppenness and safety, as well as related to material (including attacks and bishop pair) stay unchanged --- Eval/Eval.hs | 2 +- Struct/Status.hs | 56 ++++++++++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index dff9990a..17b088c2 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -559,7 +559,7 @@ spaceBlack !mpawns !matts !ypatts !yatts = sv spaceVals :: UArray Int Int spaceVals = listArray (0, 24) $ map f [1..25] where f x = round $ spf * (sqrt x - 1) - spf = 200 :: Double + spf = 270 :: Double -------- Attacks to adverse squares ---------- data Advers = Advers diff --git a/Struct/Status.hs b/Struct/Status.hs index 6b7c2944..740ac63b 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,44 +174,44 @@ instance CollectParams EvalWeights where npColInit = EvalWeights { ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, - ewKingOpen = tme 3 0, + ewKingOpen = tme 5 0, ewKingPlaceCent = tme 6 0, ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) ewKingPawn1 = tme 8 48, ewKingPawn2 = tme 12 64, - ewRookHOpen = tme 89 100, - ewRookOpen = tme 117 104, - ewRookConn = tme 52 30, - ewMobilityKnight = tme 25 34, -- Evalo 200 steps: length 10, depth 6, batch 128 - ewMobilityBishop = tme 29 16, -- adjusted bc bishop pawns - ewMobilityRook = tme 13 14, - ewMobilityQueen = tme 2 2, - ewCenterPAtts = tme 42 33, - ewCenterNAtts = tme 25 23, - ewCenterBAtts = tme 29 21, -- adjusted bc bishop pawns - ewCenterRAtts = tme 6 17, - ewCenterQAtts = tme 2 30, + ewRookHOpen = tme 160 180, + ewRookOpen = tme 211 186, + ewRookConn = tme 94 53, + ewMobilityKnight = tme 46 61, + ewMobilityBishop = tme 52 29, + ewMobilityRook = tme 23 25, + ewMobilityQueen = tme 4 3, + ewCenterPAtts = tme 76 59, + ewCenterNAtts = tme 44 41, + ewCenterBAtts = tme 52 38, + ewCenterRAtts = tme 10 30, + ewCenterQAtts = tme 4 55, ewCenterKAtts = tme 2 54, ewSpace = tme 1 0, - ewAdvAtts = tme 1 8, - ewIsolPawns = tme (-21) (-60), - ewIsolPassed = tme (-27) (-85), - ewBackPawns = tme (-63) (-84), - ewBackPOpen = tme (-13) (-11), - ewEnpHanging = tme (-22) (-34), + ewAdvAtts = tme 2 14, + ewIsolPawns = tme (-37) (-108), + ewIsolPassed = tme (-51) (-152), + ewBackPawns = tme (-113) (-151), + ewBackPOpen = tme (-23) (-20), + ewEnpHanging = tme (-21) (-34), ewEnpEnPrise = tme (-28) (-26), ewEnpAttacked = tme (-6) (-7), ewWepAttacked = tme 48 64, - ewLastLinePenalty = tme 60 2, + ewLastLinePenalty = tme 107 3, ewBishopPair = tme 390 320, - ewBishopPawns = tme (-12) (-32), - ewRedundanceRook = tme (-16) (-33), - ewRookPawn = tme (-26) (-21), - ewAdvPawn5 = tme 2 66, - ewAdvPawn6 = tme 200 185, - ewPawnBlockP = tme (-64) (-50), - ewPawnBlockO = tme (-11) (-13), - ewPawnBlockA = tme (-7) (-38), + ewBishopPawns = tme (-22) (-58), + ewRedundanceRook = tme (-29) (-61), + ewRookPawn = tme (-47) (-37), + ewAdvPawn5 = tme 4 118, + ewAdvPawn6 = tme 356 333, + ewPawnBlockP = tme (-115) (-90), + ewPawnBlockO = tme (-20) (-23), + ewPawnBlockA = tme (-13) (-70), ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights From ac49156476ca46b737788fbc6e80dc54ef645bee Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Thu, 14 Sep 2017 03:02:54 +0200 Subject: [PATCH 37/71] Eval items: no class, just direct functions Also small optimization in doQSMove --- Eval/Eval.hs | 204 ++++++++++++++------------------------------- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 14 ++-- Search/Albeta.hs | 2 +- 4 files changed, 70 insertions(+), 152 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index 17b088c2..991e76da 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -11,7 +11,6 @@ module Eval.Eval ( import Data.Array.Base (unsafeAt) import Data.Bits import Data.List (minimumBy) -import Control.Monad.State.Lazy import Data.Array.Unboxed import Data.Ord (comparing) @@ -22,35 +21,6 @@ import Moves.Moves import Moves.BitBoard import Moves.Pattern -class EvalItem a where - evalItem :: Int -> EvalParams -> EvalWeights -> MyPos -> a -> MidEnd -> MidEnd - -data AnyEvalItem = forall a . EvalItem a => EvIt a - --- This is the list of evaluated characteristics of a positions --- Every item can have one or more parameters which have a name, a default value --- and a range of values (values are kept for learning purposes as doubles, --- but for the evaluation itself one copy of integer parameter values is also kept) -evalItems :: [AnyEvalItem] -evalItems = [ EvIt Material, -- material balance (i.e. white - black material - EvIt Redundance, -- bishop pair and rook redundance - EvIt RookPawn, -- the rook pawns are about 15% less valuable - EvIt KingSafe, -- king safety - EvIt KingPlace, -- bonus when king is near some fields, opennes - EvIt LastLine, -- malus for pieces on last line (except rooks and king) - EvIt Mobility, -- pieces mobility - EvIt Center, -- attacs of center squares - EvIt Space, -- space in own courtyard not attacked by enemy - EvIt Advers, -- attacs of adverse squares - EvIt RookPlc, -- rooks points for placements - EvIt EnPrise, -- when not quiescent - pieces en prise - EvIt PaBlo, -- pawn blocking - EvIt Izolan, -- isolated pawns - EvIt Backward, -- backward pawns - EvIt AdvPawns, -- advanced pawns - EvIt PassPawns -- pass pawns - ] - ------------------------------------------------------------------ -- Parameters of this module ------------ granCoarse, granCoarse2, granCoarseM, shift2Cp :: Int @@ -69,16 +39,15 @@ initEvalState sds = EvalState { matesc :: Int matesc = 20000 - 255 -- warning, this is also defined in Base.hs!! -posEval :: MyPos -> State EvalState Int -posEval !p = do - sti <- get - let sce = evalDispatch p sti - !scl = min matesc $ max (-matesc) sce - !scc = if granCoarse > 0 then (scl + granCoarse2) .&. granCoarseM else scl - return scc +{-# INLINE posEval #-} +posEval :: MyPos -> EvalState -> Int +posEval p !sti = scc + where !sce = evalDispatch p sti + !scl = min matesc $ max (-matesc) sce + !scc = if granCoarse > 0 then (scl + granCoarse2) .&. granCoarseM else scl evalDispatch :: MyPos -> EvalState -> Int -evalDispatch p sti +evalDispatch p !sti | pawns p == 0 = evalNoPawns p sti | pawns p .&. me p == 0 || pawns p .&. yo p == 0 = evalSideNoPawns p sti @@ -86,16 +55,29 @@ evalDispatch p sti Just r <- pawnEndGame p = r | otherwise = normalEval p sti -itemEval :: Int -> EvalParams -> EvalWeights -> MyPos -> AnyEvalItem -> MidEnd -> MidEnd -itemEval gph ep ew p (EvIt a) = evalItem gph ep ew p a - normalEval :: MyPos -> EvalState -> Int normalEval p !sti = sc - where feat = foldr (itemEval gph ep ew p) (MidEnd 0 0) evalItems - ep = esEParams sti - ew = esEWeights sti - gph = gamePhase p - !sc = ((mid feat + epMovingMid ep) * gph + (end feat + epMovingEnd ep) * (256 - gph)) + where ep = esEParams sti + ew = esEWeights sti + !gph = gamePhase p + !mide1 = materDiff p ew (MidEnd 0 0) + !mide2 = evalRedundance p ew mide1 + !mide3 = evalRookPawn p ew mide2 + !mide4 = kingSafe p ew mide3 + !mide5 = kingPlace ep p ew mide4 + !mide6 = lastline p ew mide5 + !mide7 = mobiLity p ew mide6 + !mide8 = centerDiff p ew mide7 + !mide9 = spaceDiff p ew mide8 + !midea = adversDiff p ew mide9 + !mideb = evalRookPlc p ew midea + !midec = enPrise p ew mideb + !mided = pawnBl p ew midec + !midee = isolDiff p ew mided + !midef = backDiff p ew midee + !mideg = advPawns p ew midef + !mideh = passPawns gph ep p ew mideg + !sc = ((mid mideh + epMovingMid ep) * gph + (end mideh + epMovingEnd ep) * (256 - gph)) `unsafeShiftR` (shift2Cp + 8) gamePhase :: MyPos -> Int @@ -107,7 +89,7 @@ gamePhase p = g !g = qs * 39 + rs * 20 + (bs + ns) * 12 -- opening: 254, end: 0 evalSideNoPawns :: MyPos -> EvalState -> Int -evalSideNoPawns p sti +evalSideNoPawns p !sti | npwin && insufficient = 0 | npwin && lessRook p = nsc `div` 4 | otherwise = nsc @@ -121,7 +103,7 @@ evalSideNoPawns p sti -- These evaluation function distiguishes between some known finals with no pawns evalNoPawns :: MyPos -> EvalState -> Int -evalNoPawns p sti = sc +evalNoPawns p !sti = sc where !sc | onlykings = 0 | kmk || knnk = 0 -- one minor or two knights | kbbk = mateKBBK p kaloneyo -- 2 bishops @@ -161,7 +143,7 @@ winBonus :: Int winBonus = 200 -- when it's known win mateKBBK :: MyPos -> Bool -> Int -mateKBBK = mateScore centerDistance +mateKBBK = scoreToMate centerDistance -- It seems that with 2 bishops or 1 major it's the same -- rule to go to mate @@ -169,12 +151,12 @@ mateKMajxK :: MyPos -> Bool -> Int mateKMajxK = mateKBBK mateKBNK :: MyPos -> Bool -> Int -mateKBNK p = mateScore (bnMateDistance wbish) p +mateKBNK p = scoreToMate (bnMateDistance wbish) p where wbish = bishops p .&. lightSquares /= 0 -{-# INLINE mateScore #-} -mateScore :: (Square -> Int) -> MyPos -> Bool -> Int -mateScore f p mywin = msc +{-# INLINE scoreToMate #-} +scoreToMate :: (Square -> Int) -> MyPos -> Bool -> Int +scoreToMate f p mywin = msc where !kadv = if mywin then ky else km !km = kingSquare (kings p) (me p) !ky = kingSquare (kings p) (yo p) @@ -212,17 +194,13 @@ bnMateDistance wbish sq = min (squareDistance sq ocor1) (squareDistance sq ocor2 -- and only at the end we negate the score if black side is asked ---------------------------------------------------------------------------- ------ King Safety ------ -data KingSafe = KingSafe - -instance EvalItem KingSafe where - evalItem _ _ ew p _ mide = kingSafe p ew mide -- Rewrite of king safety taking into account number and quality -- of pieces attacking king neighbour squares -- This function is almost optimised, it could perhaps be faster -- if we eliminate the lists kingSafe :: MyPos -> EvalWeights -> MidEnd -> MidEnd -kingSafe !p !ew !mide = madm mide (ewKingSafe ew) ksafe +kingSafe p !ew !mide = madm mide (ewKingSafe ew) ksafe where !ksafe = ksSide (yo p) (yoKAttacs p) (myPAttacs p) (myNAttacs p) (myBAttacs p) (myRAttacs p) (myQAttacs p) (myKAttacs p) (myAttacs p) - ksSide (me p) (myKAttacs p) (yoPAttacs p) (yoNAttacs p) (yoBAttacs p) (yoRAttacs p) (yoQAttacs p) (yoKAttacs p) (yoAttacs p) @@ -275,21 +253,13 @@ kingSquare kingsb colorp = head $ bbToSquares $ kingsb .&. colorp {-# INLINE kingSquare #-} ------ Material ------ -data Material = Material - -instance EvalItem Material where - evalItem _ _ ew p _ mide = materDiff p ew mide materDiff :: MyPos -> EvalWeights -> MidEnd -> MidEnd -materDiff p ew mide = mad mide (ewMaterialDiff ew) md +materDiff p !ew mide = mad mide (ewMaterialDiff ew) md where !md | moving p == White = mater p | otherwise = - mater p ------ King placement and opennes ------ -data KingPlace = KingPlace - -instance EvalItem KingPlace where - evalItem _ ep ew p _ mide = kingPlace ep p ew mide -- Depending on which pieces are on the board we have some preferences -- where the king should be placed. For example, in the opening and middle game it should @@ -297,7 +267,7 @@ instance EvalItem KingPlace where -- We calculate the king opennes here, as we have all we need -- We also give a bonus for a king beeing near pawn(s) kingPlace :: EvalParams -> MyPos -> EvalWeights -> MidEnd -> MidEnd -kingPlace ep p ew mide = made (madm (mad (mad (mad mide (ewKingPawn2 ew) kpa2) +kingPlace ep p !ew mide = made (madm (mad (mad (mad mide (ewKingPawn2 ew) kpa2) (ewKingPawn1 ew) kpa1) (ewKingOpen ew) ko) (ewKingPlaceCent ew) kcd) @@ -420,13 +390,9 @@ matKCArr :: UArray Int Int -- 0 5 10 matKCArr = listArray (0, 63) $ [0, 0, 0, 1, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12] ++ repeat 12 ------ Rookm placement points ------ -data RookPlc = RookPlc - -instance EvalItem RookPlc where - evalItem _ _ ew p _ mide = evalRookPlc p ew mide evalRookPlc :: MyPos -> EvalWeights -> MidEnd -> MidEnd -evalRookPlc p ew mide = mad (mad (mad mide (ewRookHOpen ew) ho) (ewRookOpen ew) op) (ewRookConn ew) rc +evalRookPlc p !ew mide = mad (mad (mad mide (ewRookHOpen ew) ho) (ewRookOpen ew) op) (ewRookConn ew) rc where !mRs = rooks p .&. me p !mPs = pawns p .&. me p (mho, mop) = foldr (perRook (pawns p) mPs) (0, 0) $ bbToSquares mRs @@ -453,16 +419,15 @@ perRook allp myp rsq (ho, op) rcolls = listArray (0, 7) [ fileA, fileB, fileC, fileD, fileE, fileF, fileG, fileH ] ------ Mobility ------ -data Mobility = Mobility -- "safe" moves -instance EvalItem Mobility where - evalItem _ _ ew p _ mide - | moving p == White = mobDiff p r23 r67 pbw pbb ew mide - | otherwise = mobDiff p r67 r23 pbb pbw ew mide - where r23 = row2 .|. row3 - r67 = row6 .|. row7 - pbw = occup p `unsafeShiftR` 8 - pbb = occup p `unsafeShiftL` 8 +mobiLity :: MyPos -> EvalWeights -> MidEnd -> MidEnd +mobiLity p ew mide + | moving p == White = mobDiff p r23 r67 pbw pbb ew mide + | otherwise = mobDiff p r67 r23 pbb pbw ew mide + where r23 = row2 .|. row3 + r67 = row6 .|. row7 + pbw = occup p `unsafeShiftR` 8 + pbb = occup p `unsafeShiftL` 8 -- Here we do not calculate pawn mobility (which, calculated as attacks, is useless) -- Mobility inspired by Stockfish, with mobility aria @@ -489,14 +454,10 @@ mobDiff p mylr yolr mypb yopb ew mide = mad (mad (mad (mad mide (ewMobilityKnigh !q = myQ - yoQ ------ Center control ------ -data Center = Center - -instance EvalItem Center where - evalItem _ _ ew p _ mide = centerDiff p ew mide -- This function is already optimised centerDiff :: MyPos -> EvalWeights -> MidEnd -> MidEnd -centerDiff p ew mide = mad (mad (mad (mad (mad (mad mide (ewCenterPAtts ew) pd) (ewCenterNAtts ew) nd) (ewCenterBAtts ew) bd) (ewCenterRAtts ew) rd) (ewCenterQAtts ew) qd) (ewCenterKAtts ew) kd +centerDiff p !ew mide = mad (mad (mad (mad (mad (mad mide (ewCenterPAtts ew) pd) (ewCenterNAtts ew) nd) (ewCenterBAtts ew) bd) (ewCenterRAtts ew) rd) (ewCenterQAtts ew) qd) (ewCenterKAtts ew) kd where !mpa = popCount $ myPAttacs p .&. center !ypa = popCount $ yoPAttacs p .&. center !pd = mpa - ypa @@ -519,13 +480,9 @@ centerDiff p ew mide = mad (mad (mad (mad (mad (mad mide (ewCenterPAtts ew) pd) -------- Space for own pieces in our courtyard ----------- -- This is implemented exactly like in Stockfish, only the weights are a bit different -data Space = Space - -instance EvalItem Space where - evalItem _ _ ew p _ mide = spaceDiff p ew mide spaceDiff :: MyPos -> EvalWeights -> MidEnd -> MidEnd -spaceDiff p ew mide = mad mide (ewSpace ew) sd +spaceDiff p !ew mide = mad mide (ewSpace ew) sd where !sd = ms - ys (ms, ys) | moving p == White = ( @@ -562,13 +519,9 @@ spaceVals = listArray (0, 24) $ map f [1..25] spf = 270 :: Double -------- Attacks to adverse squares ---------- -data Advers = Advers - -instance EvalItem Advers where - evalItem _ _ ew p _ mide = adversDiff p ew mide adversDiff :: MyPos -> EvalWeights -> MidEnd -> MidEnd -adversDiff p ew mide = mad mide (ewAdvAtts ew) ad +adversDiff p !ew mide = mad mide (ewAdvAtts ew) ad where !ad = md - yd !md = popCount $ myAttacs p .&. yoH !yd = popCount $ yoAttacs p .&. myH @@ -578,13 +531,9 @@ adversDiff p ew mide = mad mide (ewAdvAtts ew) ad ah58 = 0xFFFFFFFF00000000 -------- Isolated pawns -------- -data Izolan = Izolan - -instance EvalItem Izolan where - evalItem _ _ ew p _ mide = isolDiff p ew mide isolDiff :: MyPos -> EvalWeights -> MidEnd -> MidEnd -isolDiff p ew mide = mad (mad mide (ewIsolPawns ew) nd) (ewIsolPassed ew) pd +isolDiff p !ew mide = mad (mad mide (ewIsolPawns ew) nd) (ewIsolPassed ew) pd where (!myr, !myp) = isol (pawns p .&. me p) (passed p) (!yor, !yop) = isol (pawns p .&. yo p) (passed p) !nd = myr - yor @@ -602,13 +551,9 @@ isol ps pp = (ris, pis) !pis = popCount $ myp `less` myc -------- Backward pawns -------- -data Backward = Backward - -instance EvalItem Backward where - evalItem _ _ ew p _ mide = backDiff p ew mide backDiff :: MyPos -> EvalWeights -> MidEnd -> MidEnd -backDiff p ew mide +backDiff p !ew mide | moving p == White = let wp = pawns p .&. me p bp = pawns p .&. yo p @@ -657,10 +602,6 @@ frontAttacksBlack !b = fa -- by 3712 games at 15+0.25 sec against pass3v, Clop forecast: 82 +- 40 ELO -- enpHanging and enpEnPrise again optimised (only mean) with Clop by running 16300 -- games at 15+0.25 sec against pass3w, resulting in a Clop forecast of 63 +- 19 ELO -data EnPrise = EnPrise - -instance EvalItem EnPrise where - evalItem _ _ ew p _ mide = enPrise p ew mide -- Here we should only take at least the opponent attacks! When we evaluate, -- we are in one on this situations: @@ -672,7 +613,7 @@ instance EvalItem EnPrise where -- - if he has only one attack, we are somehow restricted to defend or move that piece -- In 2 we have a more complicated analysis, which maybe is not worth to do enPrise :: MyPos -> EvalWeights -> MidEnd -> MidEnd -enPrise p ew mide = mad (mad (mad (mad mide (ewEnpHanging ew) ha) +enPrise p !ew mide = mad (mad (mad (mad mide (ewEnpHanging ew) ha) (ewEnpEnPrise ew) ep) (ewEnpAttacked ew) at) (ewWepAttacked ew) wp @@ -701,15 +642,11 @@ enPrise p ew mide = mad (mad (mad (mad mide (ewEnpHanging ew) ha) !wp = wp2 - wp1 ------ Last Line ------ -data LastLine = LastLine - -instance EvalItem LastLine where - evalItem _ _ ew p _ mide = lastline p ew mide -- Only for minor figures (queen is free to stay where it wants) -- Negative at the end: so that it falls stronger lastline :: MyPos -> EvalWeights -> MidEnd -> MidEnd -lastline p ew mide = madm mide (ewLastLinePenalty ew) cdiff +lastline p !ew mide = madm mide (ewLastLinePenalty ew) cdiff where !whl = popCount $ me p .&. cb !bll = popCount $ yo p .&. cb !cb = (knights p .|. bishops p) .&. lali @@ -717,14 +654,10 @@ lastline p ew mide = madm mide (ewLastLinePenalty ew) cdiff !cdiff = bll - whl ------ Redundance: bishop pair and rook redundance ------ -data Redundance = Redundance - -instance EvalItem Redundance where - evalItem _ _ ew p _ mide = evalRedundance p ew mide -- This function is optimised evalRedundance :: MyPos -> EvalWeights -> MidEnd -> MidEnd -evalRedundance p ew mide = mad (mad (mad mide (ewBishopPawns ew) pa) +evalRedundance p !ew mide = mad (mad (mad mide (ewBishopPawns ew) pa) (ewBishopPair ew) bp) (ewRedundanceRook ew) rr where !wbl = bishops p .&. me p .&. lightSquares @@ -771,26 +704,18 @@ evalNRCorrection p = [md] --} ------ Rook pawn weakness ------ -data RookPawn = RookPawn - -instance EvalItem RookPawn where - evalItem _ _ ew p _ mide = evalRookPawn p ew mide -- This function is already optimised evalRookPawn :: MyPos -> EvalWeights -> MidEnd -> MidEnd -evalRookPawn p ew mide = mad mide (ewRookPawn ew) rps +evalRookPawn p !ew mide = mad mide (ewRookPawn ew) rps where !wrp = popCount $ pawns p .&. me p .&. rookFiles !brp = popCount $ pawns p .&. yo p .&. rookFiles !rps = wrp - brp ------ Blocked pawns ------ -data PaBlo = PaBlo - -instance EvalItem PaBlo where - evalItem _ _ ew p _ mide = pawnBl p ew mide pawnBl :: MyPos -> EvalWeights -> MidEnd -> MidEnd -pawnBl p ew mide +pawnBl p !ew mide | moving p == White = let (wp, wo, wa) = pawnBloWhite mer mef yof (bp, bo, ba) = pawnBloBlack yor yof mef in mad (mad (mad mide (ewPawnBlockP ew) (wp-bp)) (ewPawnBlockO ew) (wo-bo)) (ewPawnBlockA ew) (wa-ba) @@ -819,17 +744,14 @@ pawnBloBlack !pa !op !tp = cntPaBlo p1 pa op tp where !p1 = pa `unsafeShiftR` 8 ------ Pass pawns ------ -data PassPawns = PassPawns -- passPawnLev after optimization with Clop -- 4686 games at 15+0.25 games pass3o against itself (mean) -- Clop forecast: 60+-25 elo -instance EvalItem PassPawns where - evalItem gph ep ew p _ mide = passPawns gph ep p ew mide -- Every passed pawn will be evaluated separately passPawns :: Int -> EvalParams -> MyPos -> EvalWeights -> MidEnd -> MidEnd -passPawns gph ep p ew mide = mad mide (ewPassPawnLev ew) dpp +passPawns !gph ep p !ew mide = mad mide (ewPassPawnLev ew) dpp where !mppbb = passed p .&. me p !yppbb = passed p .&. yo p !myc = moving p @@ -844,7 +766,7 @@ passPawns gph ep p ew mide = mad mide (ewPassPawnLev ew) dpp -- - how many squares ahead are controlled by own/opponent pieces? -- - does it has a rook behind? perPassedPawn :: Int -> EvalParams -> MyPos -> Color -> Square -> Int -perPassedPawn gph ep p c sq +perPassedPawn !gph ep p c sq | attacked && not defended && c /= moving p = epPassMin ep -- but if we have more than one like that? | otherwise = perPassedPawnOk gph ep p c sq sqbb moi toi moia toia @@ -856,7 +778,7 @@ perPassedPawn gph ep p c sq !attacked = toia .&. sqbb /= 0 perPassedPawnOk :: Int -> EvalParams -> MyPos -> Color -> Square -> BBoard -> BBoard -> BBoard -> BBoard -> BBoard -> Int -perPassedPawnOk gph ep p c sq sqbb moi toi moia toia = val +perPassedPawnOk !gph ep p c sq sqbb moi toi moia toia = val where (!way, !behind, !asq) | c == White = (shadowUp sqbb, shadowDown sqbb, sq+8) | otherwise = (shadowDown sqbb, shadowUp sqbb, sq-8) @@ -898,13 +820,9 @@ kdDist = (kdDistArr `unsafeAt`) . (7+) ------ Advanced pawns, on 6th & 7th rows (not passed) ------ -data AdvPawns = AdvPawns - -instance EvalItem AdvPawns where - evalItem _ _ ew p _ mide = advPawns p ew mide advPawns :: MyPos -> EvalWeights -> MidEnd -> MidEnd -advPawns p ew mide = mad (mad mide (ewAdvPawn5 ew) ap5) (ewAdvPawn6 ew) ap6 +advPawns p !ew mide = mad (mad mide (ewAdvPawn5 ew) ap5) (ewAdvPawn6 ew) ap6 where !apbb = pawns p `less` passed p !mapbb = apbb .&. me p !yapbb = apbb .&. yo p diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index b4cc8e3d..8885f7ee 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "sol" +progVerSuff = "sop" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index 99c78902..59af5b62 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -70,7 +70,7 @@ posToState p c h e = MyState { mstats = ssts0, evalst = e } - where stsc = evalState (posEval p) e + where stsc = posEval p e p'' = p { staticScore = stsc } posNewSearch :: MyState -> MyState @@ -182,7 +182,7 @@ doMove m = do il = occup pc `uBitClear` fromSquare m -- Capturing one king? kc = kings pc `uBitSet` toSquare m - sts = evalState (posEval p) (evalst s) + sts = posEval p (evalst s) p = doFromToMove m pc { staticScore = sts } if (il || kc) then do @@ -207,23 +207,23 @@ doMove m = do -- Here we do only a restricted check for illegal moves -- It does not check for remis, so it can't return Final -- It does not check for extensions a.s.o. -doQSMove :: Move -> Game DoResult +doQSMove :: Move -> Game Bool doQSMove m = do s <- get let (pc:_) = stack s -- we never saw an empty stack error until now - sts = evalState (posEval p) (evalst s) + sts = posEval p (evalst s) p = doFromToMove m pc { staticScore = sts } if not $ checkOk p - then return Illegal + then return False else do put s { stack = p : stack s } - return $ Exten 0 False + return True doNullMove :: Game () doNullMove = do s <- get let (pc:_) = stack s -- we never saw an empty stack error until now - sts = evalState (posEval p) (evalst s) + sts = posEval p (evalst s) p = reverseMoving pc { staticScore = sts } put s { stack = p : stack s } diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 12ed8209..947045fb 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -1048,7 +1048,7 @@ pvQLoop b c = go pvQInnerLoop :: Int -> Int -> Int -> Move -> Search (Bool, Int) pvQInnerLoop !b c !a e = timeToAbort (True, b) $ do r <- lift $ doQSMove e - if legalResult r + if r then do newNodeQS !sc <- negate <$> pvQSearch (-b) (-a) c From 8dbf9cefae91c289869a243e2ffce312801660c2 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sun, 24 Sep 2017 19:37:27 +0200 Subject: [PATCH 38/71] King safety sharper formula --- Eval/Eval.hs | 32 +++++++++++++++++--------------- Main/Barbarossa.hs | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index 991e76da..ac24a7a8 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -210,16 +210,18 @@ data Flc = Flc !Int !Int fadd :: Flc -> Flc -> Flc fadd (Flc f1 q1) (Flc f2 q2) = Flc (f1+f2) (q1+q2) -fmul :: Flc -> Int -fmul (Flc f q) = f * q - ksSide :: BBoard -> BBoard -> BBoard -> BBoard -> BBoard -> BBoard -> BBoard -> BBoard -> BBoard -> Int ksSide !yop !yok !myp !myn !myb !myr !myq !myk !mya | myq == 0 = 0 | otherwise = mattacs - where !freey = popCount $ yok `less` (mya .|. yop) - qual a p = let c = popCount $ yok .&. a - in Flc (flaCoef `unsafeAt` c) (c * p) + where qual a p + | yoka == 0 = Flc 0 0 + | c == 1 = Flc 1 p + | c == 2 = Flc 1 (p `unsafeShiftL` 1) + | c == 3 = Flc 1 (p `unsafeShiftL` 2) + | otherwise = Flc 1 (p `unsafeShiftL` 3) + where !yoka = yok .&. a + c = popCount yoka -- qualWeights = [1, 2, 2, 4, 8, 2] !qp = qual myp 1 !qn = qual myn 2 @@ -227,15 +229,15 @@ ksSide !yop !yok !myp !myn !myb !myr !myq !myk !mya !qr = qual myr 4 !qq = qual myq 8 !qk = qual myk 2 - !ixm = fmul (fadd qp $ fadd qn $ fadd qb $ fadd qr $ fadd qq qk) `unsafeShiftR` 2 - + 8 + ksShift - freey - !mattacs = attCoef `unsafeAt` ixm - ksShift = 5 - --- We want to eliminate "if yok .&. a /= 0 ..." --- by using an array -flaCoef :: UArray Int Int -flaCoef = listArray (0, 8) [ 0, 1, 1, 1, 1, 1, 1, 1, 1 ] + !(Flc c q) = fadd qp $ fadd qn $ fadd qb $ fadd qr $ fadd qq qk + !mattacs + | c == 0 = 0 + | otherwise = attCoef `unsafeAt` ixt + where !freey = popCount $ yok `less` (mya .|. yop) + !conce = popCount $ yok .&. mya + !ixm = c * q `unsafeShiftR` 2 + !ixt = ixm + ksShift + 8 - freey + c - conce + ksShift = 5 -- We take the maximum of 240 because: -- Quali max: 8 * (1 + 2 + 2 + 4 + 8 + 2) < 160 diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 8885f7ee..32f47412 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "sop" +progVerSuff = "sok" data Options = Options { optConfFile :: Maybe String, -- config file From eb9f95822389764de6b10600b8ccd9bd65f32625 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 18 Oct 2017 22:13:40 +0200 Subject: [PATCH 39/71] Eval: simplify king safety, king placement change --- Eval/Eval.hs | 74 ++++++++++++++++++++++------------------------ Main/Barbarossa.hs | 2 +- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index ac24a7a8..21b01799 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -189,16 +189,9 @@ bnMateDistance wbish sq = min (squareDistance sq ocor1) (squareDistance sq ocor2 ---------------------------------------------------------------------------- -- Here we have the implementation of the evaluation items --- They do not return a score, but a vector of fulfillments of some criteria --- With version 0.55 we compute everything from white point of view --- and only at the end we negate the score if black side is asked ---------------------------------------------------------------------------- ------- King Safety ------ --- Rewrite of king safety taking into account number and quality --- of pieces attacking king neighbour squares --- This function is almost optimised, it could perhaps be faster --- if we eliminate the lists +------ King Safety ------ kingSafe :: MyPos -> EvalWeights -> MidEnd -> MidEnd kingSafe p !ew !mide = madm mide (ewKingSafe ew) ksafe where !ksafe = ksSide (yo p) (yoKAttacs p) (myPAttacs p) (myNAttacs p) (myBAttacs p) (myRAttacs p) (myQAttacs p) (myKAttacs p) (myAttacs p) @@ -216,12 +209,12 @@ ksSide !yop !yok !myp !myn !myb !myr !myq !myk !mya | otherwise = mattacs where qual a p | yoka == 0 = Flc 0 0 - | c == 1 = Flc 1 p - | c == 2 = Flc 1 (p `unsafeShiftL` 1) - | c == 3 = Flc 1 (p `unsafeShiftL` 2) + | y == 1 = Flc 1 p + | y == 2 = Flc 1 (p `unsafeShiftL` 1) + | y == 3 = Flc 1 (p `unsafeShiftL` 2) | otherwise = Flc 1 (p `unsafeShiftL` 3) where !yoka = yok .&. a - c = popCount yoka + y = popCount yoka -- qualWeights = [1, 2, 2, 4, 8, 2] !qp = qual myp 1 !qn = qual myn 2 @@ -233,22 +226,26 @@ ksSide !yop !yok !myp !myn !myb !myr !myq !myk !mya !mattacs | c == 0 = 0 | otherwise = attCoef `unsafeAt` ixt - where !freey = popCount $ yok `less` (mya .|. yop) - !conce = popCount $ yok .&. mya + -- where !freey = popCount $ yok `less` (mya .|. yop) + -- !conce = popCount $ yok .&. mya + -- This is equivalent to: + where !freco = popCount $ yok `less` (yop `less` mya) !ixm = c * q `unsafeShiftR` 2 - !ixt = ixm + ksShift + 8 - freey + c - conce - ksShift = 5 + !ixt = ixm + c + ksShift - freco + ksShift = 13 --- We take the maximum of 240 because: --- Quali max: 8 * (1 + 2 + 2 + 4 + 8 + 2) < 160 +-- We take the maximum of 272 because: +-- Quali max: 8 * (1 + 2 + 2 + 4 + 8 + 2) = 168 -- Flag max: 6 --- 6 * 160 / 4 = 240 --- Here the beginning of -8 is actually wrong, which comes to the same --- as increasing the importance of king safety +-- 6 * 168 / 4 + 6 + 13 = 272 attCoef :: UArray Int Int -attCoef = listArray (0, 248) $ take 8 (repeat 0) ++ [ f x | x <- [0..63] ] ++ repeat (f 63) - where f :: Int -> Int - f x = let y = fromIntegral x :: Double in round $ (2.92968750 - 0.03051758*y)*y*y +attCoef = listArray (0, 272) $ take zeros (repeat 0) ++ [ f x | x <- [0..63] ] ++ repeat (f 63) + where -- Without the scaling, f will take max value of 4000 for 63 + f :: Int -> Int + f x = let y = fromIntegral x :: Double + in round $ maxks * (2.92968750 - 0.03051758*y)*y*y / 4000 + zeros = 8 + maxks = 3800 kingSquare :: BBoard -> BBoard -> Square kingSquare kingsb colorp = head $ bbToSquares $ kingsb .&. colorp @@ -281,13 +278,13 @@ kingPlace ep p !ew mide = made (madm (mad (mad (mad mide (ewKingPawn2 ew) kpa2) !mkm = materFun yminor yrooks yqueens !ykm = materFun mminor mrooks mqueens (!mpl, !ypl, !mpi, !ypi) - | moving p == White = ( kingMaterBonus White mpawns mkm mks - , kingMaterBonus Black ypawns ykm yks + | moving p == White = ( kingMaterBonus yqueens White mpawns mkm mks + , kingMaterBonus mqueens Black ypawns ykm yks , kingPawnsBonus mks mpassed ypassed , kingPawnsBonus yks mpassed ypassed ) - | otherwise = ( kingMaterBonus Black mpawns mkm mks - , kingMaterBonus White ypawns ykm yks + | otherwise = ( kingMaterBonus yqueens Black mpawns mkm mks + , kingMaterBonus mqueens White ypawns ykm yks , kingPawnsBonus mks ypassed mpassed , kingPawnsBonus yks ypassed mpassed ) @@ -343,8 +340,13 @@ kingPawnsBonus !ksq !wpass !bpass = bonus -- This is a bonus for the king beeing near one corner -- It's bigger when the enemy has more material (only pieces) -- and when that corner has a pawn shelter -kingMaterBonus :: Color -> BBoard -> Int -> Square -> Int -kingMaterBonus c !myp !mat !ksq +kingMaterBonus :: Int -> Color -> BBoard -> Int -> Square -> Int +kingMaterBonus !qs c !myp !mat !ksq + | qs == 0 = 0 + | otherwise = kMatBonus c myp mat ksq + +kMatBonus :: Color -> BBoard -> Int -> Square -> Int +kMatBonus c !myp !mat !ksq | c == White = matFactor mat * prxw | otherwise = matFactor mat * prxb where !prxw = prxWA + prxWH @@ -391,7 +393,7 @@ pawnBonus = unsafeAt pawnBonusArr matKCArr :: UArray Int Int -- 0 5 10 matKCArr = listArray (0, 63) $ [0, 0, 0, 1, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12] ++ repeat 12 ------- Rookm placement points ------ +------ Rook placement points ------ evalRookPlc :: MyPos -> EvalWeights -> MidEnd -> MidEnd evalRookPlc p !ew mide = mad (mad (mad mide (ewRookHOpen ew) ho) (ewRookOpen ew) op) (ewRookConn ew) rc @@ -431,7 +433,7 @@ mobiLity p ew mide pbw = occup p `unsafeShiftR` 8 pbb = occup p `unsafeShiftL` 8 --- Here we do not calculate pawn mobility (which, calculated as attacks, is useless) +-- No pawn mobility (which, calculated as attacks, is useless) -- Mobility inspired by Stockfish, with mobility aria mobDiff :: MyPos -> BBoard -> BBoard -> BBoard -> BBoard -> EvalWeights -> MidEnd -> MidEnd mobDiff p mylr yolr mypb yopb ew mide = mad (mad (mad (mad mide (ewMobilityKnight ew) n) @@ -481,7 +483,6 @@ centerDiff p !ew mide = mad (mad (mad (mad (mad (mad mide (ewCenterPAtts ew) pd) center = 0x0000003C3C000000 -------- Space for own pieces in our courtyard ----------- --- This is implemented exactly like in Stockfish, only the weights are a bit different spaceDiff :: MyPos -> EvalWeights -> MidEnd -> MidEnd spaceDiff p !ew mide = mad mide (ewSpace ew) sd @@ -646,7 +647,6 @@ enPrise p !ew mide = mad (mad (mad (mad mide (ewEnpHanging ew) ha) ------ Last Line ------ -- Only for minor figures (queen is free to stay where it wants) --- Negative at the end: so that it falls stronger lastline :: MyPos -> EvalWeights -> MidEnd -> MidEnd lastline p !ew mide = madm mide (ewLastLinePenalty ew) cdiff where !whl = popCount $ me p .&. cb @@ -745,12 +745,8 @@ pawnBloBlack :: BBoard -> BBoard -> BBoard -> (Int, Int, Int) pawnBloBlack !pa !op !tp = cntPaBlo p1 pa op tp where !p1 = pa `unsafeShiftR` 8 ------- Pass pawns ------ +------ Passed pawns ------ --- passPawnLev after optimization with Clop --- 4686 games at 15+0.25 games pass3o against itself (mean) --- Clop forecast: 60+-25 elo - -- Every passed pawn will be evaluated separately passPawns :: Int -> EvalParams -> MyPos -> EvalWeights -> MidEnd -> MidEnd passPawns !gph ep p !ew mide = mad mide (ewPassPawnLev ew) dpp diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 32f47412..2540704b 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "sok" +progVerSuff = "soku" data Options = Options { optConfFile :: Maybe String, -- config file From 98d0b739f2d0dfb54d8812360235e518441e143d Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Tue, 21 Nov 2017 10:27:06 +0100 Subject: [PATCH 40/71] Changes regarding SelfPlay config error handling Errors in config files will be reported (fatal) instead of beeing ignored --- Eval/FileParams.hs | 10 +++++++--- Main/SelfPlay.hs | 9 ++++++--- Struct/Config.hs | 15 +++++++++------ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Eval/FileParams.hs b/Eval/FileParams.hs index ebbcf9b2..d0767235 100644 --- a/Eval/FileParams.hs +++ b/Eval/FileParams.hs @@ -13,11 +13,12 @@ import Eval.Eval (initEvalState) -- Opens a parameter file for eval, read it and create an eval state makeEvalState :: Maybe FilePath -> [(String, Double)] -> String -> String -> IO (FilePath, EvalState) -makeEvalState argfile assigns pver psuff = +makeEvalState argfile assigns pver psuff = do + -- putStrLn $ "makeEvalState: " ++ show argfile case argfile of Just afn -> do -- config file as argument fex <- doesFileExist afn - if fex then filState afn afn assigns else defState + if fex then filState afn afn assigns else error $ "makeEvalState: no such file: " ++ afn Nothing -> go $ configFileNames pver psuff where defState = return ("", initEvalState assigns) go [] = defState @@ -33,7 +34,10 @@ filState fn ident ass = do fileToState :: FilePath -> [(String, Double)] -> IO EvalState fileToState fn ass = do fCont <- readFile fn - return $ initEvalState $ ass ++ fileToParams fCont + -- putStrLn $ "This is the file " ++ fn ++ ":" ++ fCont + let ies = initEvalState $ ass ++ fileToParams fCont + -- putStrLn $ "This is state: " ++ show ies + return ies -- This produces a list of config file names depending on -- program version and programm version suffix diff --git a/Main/SelfPlay.hs b/Main/SelfPlay.hs index 22fb7d13..c857178f 100644 --- a/Main/SelfPlay.hs +++ b/Main/SelfPlay.hs @@ -194,6 +194,7 @@ filterFile opts = do matchFile :: Options -> String -> CtxIO (Int, Int, Int) matchFile opts dir = do + liftIO $ setCurrentDirectory dir ctx <- ask let logFileName = "selfplay-" ++ show (startSecond ctx) ++ ".log" startLogger logFileName @@ -221,10 +222,12 @@ matchFile opts dir = do when (not ispos) $ loopCount (skipLines hi m) () Nothing -> return () (eval1, eval2) <- liftIO $ do - setCurrentDirectory dir - (_, eval1) <- liftIO $ makeEvalState (Just id1) [] "progver" "progsuf" - (_, eval2) <- liftIO $ makeEvalState (Just id2) [] "progver" "progsuf" + (_, eval1) <- makeEvalState (Just id1) [] "progver" "progsuf" + (_, eval2) <- makeEvalState (Just id2) [] "progver" "progsuf" return (eval1, eval2) + when debug $ do + ctxLog LogInfo $ "Player 1 config: " ++ show eval1 + ctxLog LogInfo $ "Player 2 config: " ++ show eval2 let act = playEveryGame (optDepth opts) hi ho (optNFens opts) (id1, eval1) (id2, eval2) wdl <- loopCount act (0, 0, 0) liftIO $ do diff --git a/Struct/Config.hs b/Struct/Config.hs index b7d0543a..b5a2b1e1 100644 --- a/Struct/Config.hs +++ b/Struct/Config.hs @@ -20,13 +20,16 @@ colParams :: CollectParams p => [(String, Double)] -> p colParams = foldr npColParm npColInit readParam :: String -> Maybe (String, Double) -readParam s = let (ns, vs) = span (/= '=') s - in case vs of - ('=' : rs) -> case reads (strip rs) of - (v, ""):[] -> Just (strip ns, v) - _ -> Nothing -- did not read - _ -> Nothing -- did not contain '=' +readParam s + = let (ns, vs) = span (/= '=') s + in case vs of + ('=' : rs) -> case reads (strip rs) of + (v, ""):[] -> Just (strip ns, v) + _ -> error $ err1 rs + _ -> error $ err2 vs where strip = filter (not . isSpace) + err1 x = "readParam: cannot read " ++ strip x ++ " as a double" + err2 x = "readParam: line does not contain '=': " ++ x type Setter a = Double -> a -> a From b050a65e40eb41e65b6006bad822d7fc180ab526 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Tue, 21 Nov 2017 16:04:57 +0100 Subject: [PATCH 41/71] Eval weights after 300 steps DSPSA --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 64 +++++++++++++++++++++++----------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 2540704b..f8d8077f 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "soku" +progVerSuff = "dspsa0" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 740ac63b..84f7944e 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,45 +174,45 @@ instance CollectParams EvalWeights where npColInit = EvalWeights { ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, - ewKingOpen = tme 5 0, - ewKingPlaceCent = tme 6 0, - ewKingPlacePwns = tme 0 6, -- max after ~12k Clop games (ELO +23 +- 12) + ewKingOpen = tme 4 0, + ewKingPlaceCent = tme 7 0, + ewKingPlacePwns = tme 1 5, ewKingPawn1 = tme 8 48, - ewKingPawn2 = tme 12 64, - ewRookHOpen = tme 160 180, - ewRookOpen = tme 211 186, + ewKingPawn2 = tme 11 64, + ewRookHOpen = tme 160 179, + ewRookOpen = tme 211 185, ewRookConn = tme 94 53, - ewMobilityKnight = tme 46 61, - ewMobilityBishop = tme 52 29, - ewMobilityRook = tme 23 25, + ewMobilityKnight = tme 45 61, + ewMobilityBishop = tme 52 27, + ewMobilityRook = tme 23 24, ewMobilityQueen = tme 4 3, ewCenterPAtts = tme 76 59, - ewCenterNAtts = tme 44 41, - ewCenterBAtts = tme 52 38, - ewCenterRAtts = tme 10 30, - ewCenterQAtts = tme 4 55, - ewCenterKAtts = tme 2 54, + ewCenterNAtts = tme 44 40, + ewCenterBAtts = tme 53 39, + ewCenterRAtts = tme 9 30, + ewCenterQAtts = tme 4 56, + ewCenterKAtts = tme 1 54, ewSpace = tme 1 0, - ewAdvAtts = tme 2 14, - ewIsolPawns = tme (-37) (-108), - ewIsolPassed = tme (-51) (-152), - ewBackPawns = tme (-113) (-151), - ewBackPOpen = tme (-23) (-20), - ewEnpHanging = tme (-21) (-34), - ewEnpEnPrise = tme (-28) (-26), - ewEnpAttacked = tme (-6) (-7), + ewAdvAtts = tme 2 13, + ewIsolPawns = tme (-36) (-107), + ewIsolPassed = tme (-52) (-151), + ewBackPawns = tme (-112) (-152), + ewBackPOpen = tme (-22) (-19), + ewEnpHanging = tme (-21) (-36), + ewEnpEnPrise = tme (-27) (-27), + ewEnpAttacked = tme (-7) (-7), ewWepAttacked = tme 48 64, - ewLastLinePenalty = tme 107 3, - ewBishopPair = tme 390 320, - ewBishopPawns = tme (-22) (-58), + ewLastLinePenalty = tme 106 3, + ewBishopPair = tme 389 321, + ewBishopPawns = tme (-21) (-58), ewRedundanceRook = tme (-29) (-61), - ewRookPawn = tme (-47) (-37), - ewAdvPawn5 = tme 4 118, - ewAdvPawn6 = tme 356 333, - ewPawnBlockP = tme (-115) (-90), - ewPawnBlockO = tme (-20) (-23), - ewPawnBlockA = tme (-13) (-70), - ewPassPawnLev = tme 0 9 + ewRookPawn = tme (-48) (-36), + ewAdvPawn5 = tme 5 117, + ewAdvPawn6 = tme 358 335, + ewPawnBlockP = tme (-115) (-91), + ewPawnBlockO = tme (-20) (-21), + ewPawnBlockA = tme (-14) (-70), + ewPassPawnLev = tme (-1) 10 } npColParm = collectEvalWeights npSetParm = id From a8c48702c6e6d23d2d5adea3240df499d2c6e773 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Tue, 21 Nov 2017 16:45:49 +0100 Subject: [PATCH 42/71] Correct error when no parameter option --- Main/Barbarossa.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index f8d8077f..c4f614db 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -101,7 +101,9 @@ initContext opts = do ichan <- newChan ha <- newCache 1 -- it will take the minimum number of entries hi <- newHist - let paramList = stringToParams $ concat $ intersperse "," $ optParams opts + let paramList + | null $ optParams opts = [] + | otherwise = stringToParams $ concat $ intersperse "," $ optParams opts (parc, evs) <- makeEvalState (optConfFile opts) paramList progVersion progVerSuff let chg = Chg { working = False, From ea3fd5f84b99efd527671221210d6ce09bf4d852 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Tue, 21 Nov 2017 16:45:49 +0100 Subject: [PATCH 43/71] Correct error when no parameter option --- Main/Barbarossa.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 2540704b..7209fb5e 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -101,7 +101,9 @@ initContext opts = do ichan <- newChan ha <- newCache 1 -- it will take the minimum number of entries hi <- newHist - let paramList = stringToParams $ concat $ intersperse "," $ optParams opts + let paramList + | null $ optParams opts = [] + | otherwise = stringToParams $ concat $ intersperse "," $ optParams opts (parc, evs) <- makeEvalState (optConfFile opts) paramList progVersion progVerSuff let chg = Chg { working = False, From 5854250732d117c8ed617eb57ad97c5379c05828 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 22 Nov 2017 00:00:23 +0100 Subject: [PATCH 44/71] Eval weights after 300 steps DSPSA 100 double games against soku per point, depth 2 --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 72 +++++++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index c4f614db..858a34a5 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "dspsa0" +progVerSuff = "dspsa1" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 84f7944e..9ee33fa0 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,45 +174,45 @@ instance CollectParams EvalWeights where npColInit = EvalWeights { ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, - ewKingOpen = tme 4 0, - ewKingPlaceCent = tme 7 0, - ewKingPlacePwns = tme 1 5, - ewKingPawn1 = tme 8 48, - ewKingPawn2 = tme 11 64, - ewRookHOpen = tme 160 179, - ewRookOpen = tme 211 185, - ewRookConn = tme 94 53, - ewMobilityKnight = tme 45 61, + ewKingOpen = tme 3 1, + ewKingPlaceCent = tme 5 6, + ewKingPlacePwns = tme (-3) 4, + ewKingPawn1 = tme 4 50, + ewKingPawn2 = tme 15 67, + ewRookHOpen = tme 160 180, + ewRookOpen = tme 212 186, + ewRookConn = tme 93 52, + ewMobilityKnight = tme 48 61, ewMobilityBishop = tme 52 27, - ewMobilityRook = tme 23 24, - ewMobilityQueen = tme 4 3, - ewCenterPAtts = tme 76 59, - ewCenterNAtts = tme 44 40, - ewCenterBAtts = tme 53 39, - ewCenterRAtts = tme 9 30, - ewCenterQAtts = tme 4 56, - ewCenterKAtts = tme 1 54, + ewMobilityRook = tme 21 27, + ewMobilityQueen = tme 9 3, + ewCenterPAtts = tme 81 62, + ewCenterNAtts = tme 45 41, + ewCenterBAtts = tme 53 36, + ewCenterRAtts = tme 15 33, + ewCenterQAtts = tme 6 55, + ewCenterKAtts = tme 2 51, ewSpace = tme 1 0, - ewAdvAtts = tme 2 13, - ewIsolPawns = tme (-36) (-107), - ewIsolPassed = tme (-52) (-151), - ewBackPawns = tme (-112) (-152), - ewBackPOpen = tme (-22) (-19), + ewAdvAtts = tme 2 14, + ewIsolPawns = tme (-36) (-109), + ewIsolPassed = tme (-48) (-153), + ewBackPawns = tme (-110) (-148), + ewBackPOpen = tme (-25) (-22), ewEnpHanging = tme (-21) (-36), - ewEnpEnPrise = tme (-27) (-27), - ewEnpAttacked = tme (-7) (-7), - ewWepAttacked = tme 48 64, - ewLastLinePenalty = tme 106 3, - ewBishopPair = tme 389 321, - ewBishopPawns = tme (-21) (-58), - ewRedundanceRook = tme (-29) (-61), - ewRookPawn = tme (-48) (-36), - ewAdvPawn5 = tme 5 117, - ewAdvPawn6 = tme 358 335, - ewPawnBlockP = tme (-115) (-91), - ewPawnBlockO = tme (-20) (-21), - ewPawnBlockA = tme (-14) (-70), - ewPassPawnLev = tme (-1) 10 + ewEnpEnPrise = tme (-25) (-25), + ewEnpAttacked = tme (-6) (-5), + ewWepAttacked = tme 51 62, + ewLastLinePenalty = tme 110 3, + ewBishopPair = tme 390 320, + ewBishopPawns = tme (-23) (-60), + ewRedundanceRook = tme (-35) (-62), + ewRookPawn = tme (-47) (-40), + ewAdvPawn5 = tme 6 117, + ewAdvPawn6 = tme 356 334, + ewPawnBlockP = tme (-113) (-88), + ewPawnBlockO = tme (-19) (-25), + ewPawnBlockA = tme (-11) (-69), + ewPassPawnLev = tme 0 8 } npColParm = collectEvalWeights npSetParm = id From e141e76a813d06fa2f55577e6be3df47ebdbb54c Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 22 Nov 2017 09:13:42 +0100 Subject: [PATCH 45/71] Eval weights after 1000 steps DSPSA Depth 5, 1 game, difference method after Stockfish --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 76 +++++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 858a34a5..7714f0ad 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "dspsa1" +progVerSuff = "dspsa2" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 9ee33fa0..2ed93aa5 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,45 +174,45 @@ instance CollectParams EvalWeights where npColInit = EvalWeights { ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, - ewKingOpen = tme 3 1, - ewKingPlaceCent = tme 5 6, - ewKingPlacePwns = tme (-3) 4, - ewKingPawn1 = tme 4 50, - ewKingPawn2 = tme 15 67, - ewRookHOpen = tme 160 180, - ewRookOpen = tme 212 186, - ewRookConn = tme 93 52, - ewMobilityKnight = tme 48 61, - ewMobilityBishop = tme 52 27, - ewMobilityRook = tme 21 27, - ewMobilityQueen = tme 9 3, - ewCenterPAtts = tme 81 62, - ewCenterNAtts = tme 45 41, - ewCenterBAtts = tme 53 36, - ewCenterRAtts = tme 15 33, - ewCenterQAtts = tme 6 55, - ewCenterKAtts = tme 2 51, + ewKingOpen = tme 5 1, + ewKingPlaceCent = tme 7 0, + ewKingPlacePwns = tme 1 7, + ewKingPawn1 = tme 8 48, + ewKingPawn2 = tme 12 66, + ewRookHOpen = tme 159 179, + ewRookOpen = tme 212 187, + ewRookConn = tme 93 53, + ewMobilityKnight = tme 47 61, + ewMobilityBishop = tme 53 29, + ewMobilityRook = tme 23 24, + ewMobilityQueen = tme 4 5, + ewCenterPAtts = tme 76 60, + ewCenterNAtts = tme 46 42, + ewCenterBAtts = tme 52 40, + ewCenterRAtts = tme 10 30, + ewCenterQAtts = tme 3 57, + ewCenterKAtts = tme 2 54, ewSpace = tme 1 0, - ewAdvAtts = tme 2 14, - ewIsolPawns = tme (-36) (-109), - ewIsolPassed = tme (-48) (-153), - ewBackPawns = tme (-110) (-148), - ewBackPOpen = tme (-25) (-22), - ewEnpHanging = tme (-21) (-36), - ewEnpEnPrise = tme (-25) (-25), - ewEnpAttacked = tme (-6) (-5), - ewWepAttacked = tme 51 62, - ewLastLinePenalty = tme 110 3, - ewBishopPair = tme 390 320, - ewBishopPawns = tme (-23) (-60), - ewRedundanceRook = tme (-35) (-62), - ewRookPawn = tme (-47) (-40), - ewAdvPawn5 = tme 6 117, - ewAdvPawn6 = tme 356 334, - ewPawnBlockP = tme (-113) (-88), - ewPawnBlockO = tme (-19) (-25), - ewPawnBlockA = tme (-11) (-69), - ewPassPawnLev = tme 0 8 + ewAdvAtts = tme 3 14, + ewIsolPawns = tme (-38) (-108), + ewIsolPassed = tme (-50) (-152), + ewBackPawns = tme (-114) (-151), + ewBackPOpen = tme (-22) (-21), + ewEnpHanging = tme (-20) (-33), + ewEnpEnPrise = tme (-26) (-27), + ewEnpAttacked = tme (-6) (-6), + ewWepAttacked = tme 49 64, + ewLastLinePenalty = tme 106 3, + ewBishopPair = tme 391 320, + ewBishopPawns = tme (-21) (-58), + ewRedundanceRook = tme (-30) (-61), + ewRookPawn = tme (-46) (-38), + ewAdvPawn5 = tme 5 118, + ewAdvPawn6 = tme 357 333, + ewPawnBlockP = tme (-114) (-91), + ewPawnBlockO = tme (-20) (-22), + ewPawnBlockA = tme (-13) (-72), + ewPassPawnLev = tme 1 7 } npColParm = collectEvalWeights npSetParm = id From 36c06e10e5460c1c83bf436f74918ff688632a57 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 22 Nov 2017 11:49:59 +0100 Subject: [PATCH 46/71] Eval weights after 2000 steps DSPSA Depth 5, 2 games, difference method (Stockfish) 2 weights are manually modified (king opennes, passed pawn level) --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 74 +++++++++++++++++++++++----------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 7714f0ad..7700514d 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "dspsa2" +progVerSuff = "dspsa3" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 2ed93aa5..e6886d35 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,45 +174,45 @@ instance CollectParams EvalWeights where npColInit = EvalWeights { ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, - ewKingOpen = tme 5 1, - ewKingPlaceCent = tme 7 0, - ewKingPlacePwns = tme 1 7, - ewKingPawn1 = tme 8 48, - ewKingPawn2 = tme 12 66, - ewRookHOpen = tme 159 179, - ewRookOpen = tme 212 187, - ewRookConn = tme 93 53, - ewMobilityKnight = tme 47 61, - ewMobilityBishop = tme 53 29, - ewMobilityRook = tme 23 24, - ewMobilityQueen = tme 4 5, - ewCenterPAtts = tme 76 60, - ewCenterNAtts = tme 46 42, - ewCenterBAtts = tme 52 40, - ewCenterRAtts = tme 10 30, - ewCenterQAtts = tme 3 57, + ewKingOpen = tme 5 0, -- instead of 4 0 + ewKingPlaceCent = tme 5 1, + ewKingPlacePwns = tme (-1) 4, + ewKingPawn1 = tme 7 47, + ewKingPawn2 = tme 12 62, + ewRookHOpen = tme 159 181, + ewRookOpen = tme 214 184, + ewRookConn = tme 92 51, + ewMobilityKnight = tme 46 62, + ewMobilityBishop = tme 53 31, + ewMobilityRook = tme 22 22, + ewMobilityQueen = tme 7 5, + ewCenterPAtts = tme 76 59, + ewCenterNAtts = tme 44 40, + ewCenterBAtts = tme 51 40, + ewCenterRAtts = tme 10 32, + ewCenterQAtts = tme 2 51, ewCenterKAtts = tme 2 54, ewSpace = tme 1 0, - ewAdvAtts = tme 3 14, - ewIsolPawns = tme (-38) (-108), - ewIsolPassed = tme (-50) (-152), - ewBackPawns = tme (-114) (-151), - ewBackPOpen = tme (-22) (-21), - ewEnpHanging = tme (-20) (-33), - ewEnpEnPrise = tme (-26) (-27), - ewEnpAttacked = tme (-6) (-6), - ewWepAttacked = tme 49 64, - ewLastLinePenalty = tme 106 3, - ewBishopPair = tme 391 320, - ewBishopPawns = tme (-21) (-58), - ewRedundanceRook = tme (-30) (-61), - ewRookPawn = tme (-46) (-38), - ewAdvPawn5 = tme 5 118, - ewAdvPawn6 = tme 357 333, - ewPawnBlockP = tme (-114) (-91), - ewPawnBlockO = tme (-20) (-22), - ewPawnBlockA = tme (-13) (-72), - ewPassPawnLev = tme 1 7 + ewAdvAtts = tme 4 13, + ewIsolPawns = tme (-37) (-106), + ewIsolPassed = tme (-51) (-151), + ewBackPawns = tme (-112) (-149), + ewBackPOpen = tme (-23) (-20), + ewEnpHanging = tme (-24) (-31), + ewEnpEnPrise = tme (-29) (-26), + ewEnpAttacked = tme (-7) (-6), + ewWepAttacked = tme 50 63, + ewLastLinePenalty = tme 106 4, + ewBishopPair = tme 391 321, + ewBishopPawns = tme (-20) (-60), + ewRedundanceRook = tme (-29) (-58), + ewRookPawn = tme (-47) (-35), + ewAdvPawn5 = tme 6 120, + ewAdvPawn6 = tme 356 336, + ewPawnBlockP = tme (-116) (-90), + ewPawnBlockO = tme (-21) (-24), + ewPawnBlockA = tme (-13) (-69), + ewPassPawnLev = tme 2 7 -- instead of 2 6 } npColParm = collectEvalWeights npSetParm = id From 69f233a84e1a2f07f5ce5d197944585fbf596ccc Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 22 Nov 2017 19:24:30 +0100 Subject: [PATCH 47/71] Eval weights after 4000 steps DSPSA Depth 4, 2 games, difference method (Stockfish) --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 72 +++++++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 7700514d..c24850d6 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "dspsa3" +progVerSuff = "dspsa4" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index e6886d35..ea92d915 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,45 +174,45 @@ instance CollectParams EvalWeights where npColInit = EvalWeights { ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, - ewKingOpen = tme 5 0, -- instead of 4 0 - ewKingPlaceCent = tme 5 1, - ewKingPlacePwns = tme (-1) 4, - ewKingPawn1 = tme 7 47, - ewKingPawn2 = tme 12 62, - ewRookHOpen = tme 159 181, - ewRookOpen = tme 214 184, - ewRookConn = tme 92 51, - ewMobilityKnight = tme 46 62, - ewMobilityBishop = tme 53 31, - ewMobilityRook = tme 22 22, - ewMobilityQueen = tme 7 5, + ewKingOpen = tme 4 0, + ewKingPlaceCent = tme 6 0, + ewKingPlacePwns = tme 0 6, + ewKingPawn1 = tme 8 49, + ewKingPawn2 = tme 12 64, + ewRookHOpen = tme 160 180, + ewRookOpen = tme 211 186, + ewRookConn = tme 94 52, + ewMobilityKnight = tme 46 61, + ewMobilityBishop = tme 53 29, + ewMobilityRook = tme 23 24, + ewMobilityQueen = tme 4 2, ewCenterPAtts = tme 76 59, - ewCenterNAtts = tme 44 40, - ewCenterBAtts = tme 51 40, - ewCenterRAtts = tme 10 32, - ewCenterQAtts = tme 2 51, - ewCenterKAtts = tme 2 54, + ewCenterNAtts = tme 44 42, + ewCenterBAtts = tme 52 38, + ewCenterRAtts = tme 10 30, + ewCenterQAtts = tme 4 55, + ewCenterKAtts = tme 2 55, ewSpace = tme 1 0, - ewAdvAtts = tme 4 13, - ewIsolPawns = tme (-37) (-106), - ewIsolPassed = tme (-51) (-151), - ewBackPawns = tme (-112) (-149), - ewBackPOpen = tme (-23) (-20), - ewEnpHanging = tme (-24) (-31), - ewEnpEnPrise = tme (-29) (-26), - ewEnpAttacked = tme (-7) (-6), - ewWepAttacked = tme 50 63, - ewLastLinePenalty = tme 106 4, - ewBishopPair = tme 391 321, - ewBishopPawns = tme (-20) (-60), - ewRedundanceRook = tme (-29) (-58), - ewRookPawn = tme (-47) (-35), - ewAdvPawn5 = tme 6 120, - ewAdvPawn6 = tme 356 336, - ewPawnBlockP = tme (-116) (-90), - ewPawnBlockO = tme (-21) (-24), + ewAdvAtts = tme 2 14, + ewIsolPawns = tme (-37) (-108), + ewIsolPassed = tme (-50) (-152), + ewBackPawns = tme (-113) (-151), + ewBackPOpen = tme (-24) (-20), + ewEnpHanging = tme (-21) (-35), + ewEnpEnPrise = tme (-28) (-26), + ewEnpAttacked = tme (-6) (-7), + ewWepAttacked = tme 48 63, + ewLastLinePenalty = tme 108 3, + ewBishopPair = tme 390 320, + ewBishopPawns = tme (-23) (-57), + ewRedundanceRook = tme (-29) (-61), + ewRookPawn = tme (-47) (-37), + ewAdvPawn5 = tme 4 118, + ewAdvPawn6 = tme 357 332, + ewPawnBlockP = tme (-115) (-90), + ewPawnBlockO = tme (-20) (-23), ewPawnBlockA = tme (-13) (-69), - ewPassPawnLev = tme 2 7 -- instead of 2 6 + ewPassPawnLev = tme 0 9 } npColParm = collectEvalWeights npSetParm = id From abc3fb0b17150db57e1604859c141b033375a8f2 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Fri, 24 Nov 2017 12:45:58 +0100 Subject: [PATCH 48/71] Eval weights after 10000 steps with DSPSA Depth 4, 2 games, difference method --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 70 +++++++++++++++++++++++----------------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index c24850d6..ab27d8a9 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "dspsa4" +progVerSuff = "dspsa5" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index ea92d915..fc431a8f 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -175,44 +175,44 @@ instance CollectParams EvalWeights where ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, ewKingOpen = tme 4 0, - ewKingPlaceCent = tme 6 0, - ewKingPlacePwns = tme 0 6, - ewKingPawn1 = tme 8 49, + ewKingPlaceCent = tme 6 2, + ewKingPlacePwns = tme 0 4, + ewKingPawn1 = tme 7 49, ewKingPawn2 = tme 12 64, - ewRookHOpen = tme 160 180, - ewRookOpen = tme 211 186, - ewRookConn = tme 94 52, - ewMobilityKnight = tme 46 61, - ewMobilityBishop = tme 53 29, + ewRookHOpen = tme 158 183, + ewRookOpen = tme 212 185, + ewRookConn = tme 96 54, + ewMobilityKnight = tme 45 60, + ewMobilityBishop = tme 51 30, ewMobilityRook = tme 23 24, - ewMobilityQueen = tme 4 2, - ewCenterPAtts = tme 76 59, - ewCenterNAtts = tme 44 42, - ewCenterBAtts = tme 52 38, - ewCenterRAtts = tme 10 30, - ewCenterQAtts = tme 4 55, - ewCenterKAtts = tme 2 55, + ewMobilityQueen = tme 5 4, + ewCenterPAtts = tme 77 56, + ewCenterNAtts = tme 43 39, + ewCenterBAtts = tme 49 36, + ewCenterRAtts = tme 8 29, + ewCenterQAtts = tme 7 55, + ewCenterKAtts = tme 4 55, ewSpace = tme 1 0, - ewAdvAtts = tme 2 14, - ewIsolPawns = tme (-37) (-108), - ewIsolPassed = tme (-50) (-152), - ewBackPawns = tme (-113) (-151), - ewBackPOpen = tme (-24) (-20), - ewEnpHanging = tme (-21) (-35), - ewEnpEnPrise = tme (-28) (-26), - ewEnpAttacked = tme (-6) (-7), - ewWepAttacked = tme 48 63, - ewLastLinePenalty = tme 108 3, - ewBishopPair = tme 390 320, - ewBishopPawns = tme (-23) (-57), - ewRedundanceRook = tme (-29) (-61), - ewRookPawn = tme (-47) (-37), - ewAdvPawn5 = tme 4 118, - ewAdvPawn6 = tme 357 332, - ewPawnBlockP = tme (-115) (-90), - ewPawnBlockO = tme (-20) (-23), - ewPawnBlockA = tme (-13) (-69), - ewPassPawnLev = tme 0 9 + ewAdvAtts = tme 4 13, + ewIsolPawns = tme (-38) (-109), + ewIsolPassed = tme (-48) (-154), + ewBackPawns = tme (-112) (-150), + ewBackPOpen = tme (-24) (-19), + ewEnpHanging = tme (-20) (-35), + ewEnpEnPrise = tme (-28) (-28), + ewEnpAttacked = tme (-9) (-8), + ewWepAttacked = tme 47 64, + ewLastLinePenalty = tme 108 8, + ewBishopPair = tme 388 318, + ewBishopPawns = tme (-24) (-59), + ewRedundanceRook = tme (-30) (-61), + ewRookPawn = tme (-48) (-38), + ewAdvPawn5 = tme 5 116, + ewAdvPawn6 = tme 355 334, + ewPawnBlockP = tme (-115) (-91), + ewPawnBlockO = tme (-22) (-26), + ewPawnBlockA = tme (-14) (-71), + ewPassPawnLev = tme (-1) 9 } npColParm = collectEvalWeights npSetParm = id From 7ccf01a1c8a5496a8640f448d808b21d88b1c3c2 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 25 Nov 2017 17:44:02 +0100 Subject: [PATCH 49/71] Eval weights after 5000 steps DSPSA Depth 4, 2 games, differential, with Adadelta-like method --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 74 +++++++++++++++++++++++----------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index ab27d8a9..dc3df6c8 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "dspsa5" +progVerSuff = "dspsa6" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index fc431a8f..5e34df51 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -174,45 +174,45 @@ instance CollectParams EvalWeights where npColInit = EvalWeights { ewMaterialDiff = tme 8 8, ewKingSafe = tme 1 0, - ewKingOpen = tme 4 0, - ewKingPlaceCent = tme 6 2, + ewKingOpen = tme 2 4, + ewKingPlaceCent = tme 8 1, ewKingPlacePwns = tme 0 4, - ewKingPawn1 = tme 7 49, - ewKingPawn2 = tme 12 64, - ewRookHOpen = tme 158 183, - ewRookOpen = tme 212 185, - ewRookConn = tme 96 54, - ewMobilityKnight = tme 45 60, - ewMobilityBishop = tme 51 30, - ewMobilityRook = tme 23 24, - ewMobilityQueen = tme 5 4, - ewCenterPAtts = tme 77 56, - ewCenterNAtts = tme 43 39, - ewCenterBAtts = tme 49 36, - ewCenterRAtts = tme 8 29, - ewCenterQAtts = tme 7 55, - ewCenterKAtts = tme 4 55, + ewKingPawn1 = tme 11 42, + ewKingPawn2 = tme 10 69, + ewRookHOpen = tme 167 183, + ewRookOpen = tme 205 179, + ewRookConn = tme 92 58, + ewMobilityKnight = tme 50 56, + ewMobilityBishop = tme 53 33, + ewMobilityRook = tme 18 32, + ewMobilityQueen = tme 2 11, + ewCenterPAtts = tme 73 59, + ewCenterNAtts = tme 48 37, + ewCenterBAtts = tme 52 35, + ewCenterRAtts = tme 14 23, + ewCenterQAtts = tme 13 53, + ewCenterKAtts = tme 2 62, ewSpace = tme 1 0, - ewAdvAtts = tme 4 13, - ewIsolPawns = tme (-38) (-109), - ewIsolPassed = tme (-48) (-154), - ewBackPawns = tme (-112) (-150), - ewBackPOpen = tme (-24) (-19), - ewEnpHanging = tme (-20) (-35), - ewEnpEnPrise = tme (-28) (-28), - ewEnpAttacked = tme (-9) (-8), - ewWepAttacked = tme 47 64, - ewLastLinePenalty = tme 108 8, - ewBishopPair = tme 388 318, - ewBishopPawns = tme (-24) (-59), - ewRedundanceRook = tme (-30) (-61), - ewRookPawn = tme (-48) (-38), - ewAdvPawn5 = tme 5 116, - ewAdvPawn6 = tme 355 334, - ewPawnBlockP = tme (-115) (-91), - ewPawnBlockO = tme (-22) (-26), - ewPawnBlockA = tme (-14) (-71), - ewPassPawnLev = tme (-1) 9 + ewAdvAtts = tme 1 17, + ewIsolPawns = tme (-38) (-105), + ewIsolPassed = tme (-57) (-150), + ewBackPawns = tme (-105) (-148), + ewBackPOpen = tme (-23) (-26), + ewEnpHanging = tme (-19) (-27), + ewEnpEnPrise = tme (-29) (-26), + ewEnpAttacked = tme (-2) (-14), + ewWepAttacked = tme 46 61, + ewLastLinePenalty = tme 100 0, + ewBishopPair = tme 386 323, + ewBishopPawns = tme (-25) (-54), + ewRedundanceRook = tme (-27) (-52), + ewRookPawn = tme (-49) (-27), + ewAdvPawn5 = tme 8 109, + ewAdvPawn6 = tme 359 330, + ewPawnBlockP = tme (-117) (-95), + ewPawnBlockO = tme (-18) (-27), + ewPawnBlockA = tme (-15) (-64), + ewPassPawnLev = tme 2 8 } npColParm = collectEvalWeights npSetParm = id From 9049ca50ffe16441facf66a5faf08449dcecb086 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Tue, 28 Nov 2017 14:56:31 +0100 Subject: [PATCH 50/71] Delta cut refactoring (QS) for speed --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 24 ++++++++++++++++-------- Search/Albeta.hs | 33 +++++++++++++++------------------ 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index dc3df6c8..0b55a801 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "dspsa6" +progVerSuff = "delta1" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index 59af5b62..c6b25f51 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -286,15 +286,23 @@ finNode str nodes = fen = posToFen p logMes $ str ++ " Score: " ++ show (staticScore p) ++ " Fen: " ++ fen -{-# INLINE qsDelta #-} -qsDelta :: Game Int -qsDelta = do +-- {-# INLINE qsDelta #-} +qsDelta :: Int -> Game Bool +qsDelta !a = do p <- getPos - if yo p .&. queens p .&. myAttacs p /= 0 - then return $! matPiece White Queen - else if yo p .&. rooks p .&. myAttacs p /= 0 - then return $! matPiece White Rook - else return $! matPiece White Bishop + if matPiece White Bishop >= a + then return False + else if matPiece White Queen < a + then return True + else do + let !ua = yo p .&. myAttacs p -- under attack! + if ua .&. queens p /= 0 -- TODO: need to check also pawns on 7th! + then return False + else if matPiece White Rook < a + then return True + else if ua .&. rooks p /= 0 + then return False + else return True {-# INLINE ttRead #-} ttRead :: Game (Int, Int, Int, Move, Int64) diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 947045fb..27f2a6c6 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -1011,29 +1011,26 @@ pvQSearch !a !b !c = do !nc = c + esc - 1 pvQLoop b nc a edges else do - let !stp = staticScore pos - -- what if hsc < b? + let stp = staticScore pos if stp >= b then do when collectFens $ finWithNodes "BETA" return b else do - !qsdelta <- lift qsDelta - let !a1 = a - qsdelta - qsDeltaMargin - -- what if hsc + ... > a? - if stp < a1 - then do - when collectFens $ finWithNodes "DELT" - return a - else do - edges <- Alt <$> lift genTactMoves - if noMove edges - then do -- no more captures - when collectFens $ finWithNodes "NOCA" - return $! trimax a b stp - else if stp > a - then pvQLoop b c stp edges - else pvQLoop b c a edges + !dcut <- lift $ qsDelta $ a - stp - qsDeltaMargin + if dcut + then do + when collectFens $ finWithNodes "DELT" + return a + else do + edges <- Alt <$> lift genTactMoves + if noMove edges + then do -- no more captures + when collectFens $ finWithNodes "NOCA" + return $! trimax a b stp + else if stp > a + then pvQLoop b c stp edges + else pvQLoop b c a edges where lenmax2 (_:_:_) = 2 lenmax2 _ = 1 -- we know here it is not empty From f5861febe78210179931b38f1aadcc75f7474056 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Fri, 8 Dec 2017 16:58:00 +0100 Subject: [PATCH 51/71] QS: search quiet checking moves Only on frontier and with SEE >= 0 --- Eval/Eval.hs | 2 +- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 11 ++++++--- Moves/Board.hs | 58 ++++++++++++++++++++++++++++------------------ Search/Albeta.hs | 12 +++++----- 5 files changed, 52 insertions(+), 33 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index 21b01799..74ef65af 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -248,7 +248,7 @@ attCoef = listArray (0, 272) $ take zeros (repeat 0) ++ [ f x | x <- [0..63] ] + maxks = 3800 kingSquare :: BBoard -> BBoard -> Square -kingSquare kingsb colorp = head $ bbToSquares $ kingsb .&. colorp +kingSquare kingsb colorp = firstOne $ kingsb .&. colorp {-# INLINE kingSquare #-} ------ Material ------ diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index dc3df6c8..f9513685 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "dspsa6" +progVerSuff = "chk1" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index 59af5b62..1d41b248 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -97,12 +97,17 @@ genMoves d = do -- Generate only tactical moves, i.e. promotions & captures -- Needed only in QS, when we know we are not in check -genTactMoves :: Game [Move] -genTactMoves = do +-- In the fronties nodes (i.e. first level QS) we generate +-- also checking quiet moves with non-negative SEE +genTactMoves :: Bool -> Game [Move] +genTactMoves front = do p <- getPos let l1 = genMovePromo p l2w = fst $ genMoveCaptWL p - return $ l1 ++ l2w + l3 = genMoveNCaptToCheck p + if front + then return $ l1 ++ l2w ++ l3 + else return $ l1 ++ l2w -- Generate only escape moves: needed only in QS when we know we have to escape genEscapeMoves :: Game [Move] diff --git a/Moves/Board.hs b/Moves/Board.hs index df709542..d795da64 100644 --- a/Moves/Board.hs +++ b/Moves/Board.hs @@ -38,7 +38,7 @@ inCheck = (/= 0) . check goPromo :: MyPos -> Move -> Bool goPromo p m - | moveIsPromo m = True + | moveIsPromo m = True | movePassed p m = True | otherwise = False @@ -151,12 +151,12 @@ findChecking !pos = concat [ pChk, nChk, bChk, rChk, qbChk, qrChk ] -- Generate move when in check genMoveFCheck :: MyPos -> [Move] genMoveFCheck !p - | null chklist = error "genMoveFCheck" + | null chklist = error "genMoveFCheck" | null $ tail chklist = r1 ++ kGen ++ r2 -- simple check - | otherwise = kGen -- double check, only king moves help - where !chklist = findChecking p - !kGen = map (moveAddColor (moving p) . moveAddPiece King . uncurry moveFromTo) - $ srcDests (legal . kAttacs) ksq + | otherwise = kGen -- double check, only king moves help + where chklist = findChecking p + kGen = map (moveAddColor (moving p) . moveAddPiece King . uncurry moveFromTo) + $ srcDests (legal . kAttacs) ksq !ksq = firstOne kbb !kbb = kings p .&. me p !ocp1 = occup p `less` kbb @@ -248,29 +248,34 @@ beatOrBlock f !p sq = (beat, block) !line = findLKA f aksq sq !block = blockAt p line -genMoveNCaptToCheck :: MyPos -> [(Square, Square)] +genMoveNCaptToCheck :: MyPos -> [Move] genMoveNCaptToCheck p = genMoveNCaptDirCheck p ++ genMoveNCaptIndirCheck p -- Todo: check with pawns (should be also without promotions) -genMoveNCaptDirCheck :: MyPos -> [(Square, Square)] -genMoveNCaptDirCheck p = concat [ qGenC, rGenC, bGenC, nGenC ] - where nGenC = concatMap (srcDests (target nTar . nAttacs)) - $ bbToSquares $ knights p .&. me p - bGenC = concatMap (srcDests (target bTar . bAttacs (occup p))) - $ bbToSquares $ bishops p .&. me p - rGenC = concatMap (srcDests (target rTar . rAttacs (occup p))) - $ bbToSquares $ rooks p .&. me p - qGenC = concatMap (srcDests (target qTar . qAttacs (occup p))) - $ bbToSquares $ queens p .&. me p +genMoveNCaptDirCheck :: MyPos -> [Move] +genMoveNCaptDirCheck p = map (moveAddColor $ moving p) $ concat [ qGenC, rGenC, bGenC, nGenC ] + where nGenC = map (moveAddPiece Knight . uncurry moveFromTo) + $ filtQPSEE p Knight $ concatMap (srcDests (target nTar . nAttacs)) + $ bbToSquares $ knights p .&. me p + bGenC = map (moveAddPiece Bishop . uncurry moveFromTo) + $ filtQPSEE p Bishop $ concatMap (srcDests (target bTar . bAttacs (occup p))) + $ bbToSquares $ bishops p .&. me p + rGenC = map (moveAddPiece Rook . uncurry moveFromTo) + $ filtQPSEE p Rook $ concatMap (srcDests (target rTar . rAttacs (occup p))) + $ bbToSquares $ rooks p .&. me p + qGenC = map (moveAddPiece Queen . uncurry moveFromTo) + $ filtQPSEE p Queen $ concatMap (srcDests (target qTar . qAttacs (occup p))) + $ bbToSquares $ queens p .&. me p target b = (.&. b) + !nyop = complement $ yo p !ksq = firstOne $ yo p .&. kings p - !nTar = fAttacs ksq Knight (occup p) `less` yo p - !bTar = fAttacs ksq Bishop (occup p) `less` yo p - !rTar = fAttacs ksq Rook (occup p) `less` yo p + !nTar = fAttacs ksq Knight (occup p) .&. nyop + !bTar = fAttacs ksq Bishop (occup p) .&. nyop + !rTar = fAttacs ksq Rook (occup p) .&. nyop !qTar = bTar .|. rTar -- TODO: indirect non capture checking moves -genMoveNCaptIndirCheck :: MyPos -> [(Square, Square)] +genMoveNCaptIndirCheck :: MyPos -> [Move] genMoveNCaptIndirCheck _ = [] -- Generate the castle moves @@ -785,7 +790,7 @@ genEPCapts !pos | epBB == 0 = [] | otherwise = map (\s -> makeEnPas s dst) $ bbToSquares srcBB where !epBB = epcas pos .&. epMask - dst = head $ bbToSquares epBB -- safe because epBB /= 0 + dst = head $ bbToSquares epBB -- safe because epBB /= 0 srcBB = pAttacs (other $ moving pos) dst .&. me pos .&. pawns pos perCaptFieldWL :: MyPos -> BBoard -> BBoard -> Square -> ([LMove], [LMove]) -> ([LMove], [LMove]) @@ -835,3 +840,12 @@ addHanging pos vict to from (wsqs, lsqs) addHangingP :: Piece -> Square -> Square -> ([LMove], [LMove]) -> ([LMove], [LMove]) addHangingP vict to from (wsqs, lsqs) = ((moveToLMove Pawn vict $ makePromo Queen from to) : wsqs, lsqs) + +filtQPSEE :: MyPos -> Piece -> [(Square, Square)] -> [(Square, Square)] +filtQPSEE !pos piece = filter (quietPositiveSEE pos v0) + where v0 = seeValue piece + +quietPositiveSEE :: MyPos -> Int -> (Square, Square) -> Bool +quietPositiveSEE !pos !v0 (!sqfa, !sq) = adv <= 0 + where !allAttRec = theAttacs pos sq + adv = seeMoveValue pos allAttRec sqfa sq v0 diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 947045fb..b40ab640 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -454,7 +454,7 @@ checkFailHard s a b c = -- PV Search pvSearch :: NodeState -> Int -> Int -> Int -> Search Path pvSearch _ !a !b !d | d <= 0 = do - v <- pvQSearch a b 0 + v <- pvQSearch a b 0 True checkFailHard "QS" a b v return $ pathFromScore ("pvQSearch 1:" ++ show v) v -- ok: fail hard in QS pvSearch nst !a !b !d = do @@ -521,7 +521,7 @@ pvSearch nst !a !b !d = do -- PV Zero Window pvZeroW :: NodeState -> Int -> Int -> Bool -> Search Path pvZeroW !_ !b !d _ | d <= 0 = do - v <- pvQSearch bGrain b 0 + v <- pvQSearch bGrain b 0 True checkFailHard "QS" bGrain b v return $ pathFromScore ("pvQSearch 21:" ++ show v) v where !bGrain = b - scoreGrain @@ -976,8 +976,8 @@ trimax a b x | otherwise = x -- PV Quiescent Search -pvQSearch :: Int -> Int -> Int -> Search Int -pvQSearch !a !b !c = do +pvQSearch :: Int -> Int -> Int -> Bool -> Search Int +pvQSearch !a !b !c front = do -- TODO: use e as first move if legal & capture -- (hdeep, tp, hsc, e, _) <- reTrieve >> lift ttRead (hdeep, tp, hsc, _, _) <- reTrieve >> lift ttRead @@ -1026,7 +1026,7 @@ pvQSearch !a !b !c = do when collectFens $ finWithNodes "DELT" return a else do - edges <- Alt <$> lift genTactMoves + edges <- Alt <$> lift (genTactMoves front) if noMove edges then do -- no more captures when collectFens $ finWithNodes "NOCA" @@ -1051,7 +1051,7 @@ pvQInnerLoop !b c !a e = timeToAbort (True, b) $ do if r then do newNodeQS - !sc <- negate <$> pvQSearch (-b) (-a) c + !sc <- negate <$> pvQSearch (-b) (-a) c False lift undoMove if sc >= b then return (True, b) From 9ce1288c7ad3659afde26382651e296d1b795c8c Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 13 Dec 2017 15:22:16 +0100 Subject: [PATCH 52/71] Eval: rook on 7th line (when opponent king on 8th) After this: DSPSA optimisation of rook related weights depth 4, 2 games, 20k steps, differential, adagrad --- Eval/Eval.hs | 12 +++++++++++- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 18 ++++++++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index 21b01799..f6e8e841 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -396,7 +396,10 @@ matKCArr = listArray (0, 63) $ [0, 0, 0, 1, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12] ++ ------ Rook placement points ------ evalRookPlc :: MyPos -> EvalWeights -> MidEnd -> MidEnd -evalRookPlc p !ew mide = mad (mad (mad mide (ewRookHOpen ew) ho) (ewRookOpen ew) op) (ewRookConn ew) rc +evalRookPlc p !ew mide = mad (mad (mad (mad mide (ewRook7th ew) r7) + (ewRookHOpen ew) ho) + (ewRookOpen ew) op) + (ewRookConn ew) rc where !mRs = rooks p .&. me p !mPs = pawns p .&. me p (mho, mop) = foldr (perRook (pawns p) mPs) (0, 0) $ bbToSquares mRs @@ -410,6 +413,13 @@ evalRookPlc p !ew mide = mad (mad (mad mide (ewRookHOpen ew) ho) (ewRookOpen ew) !yrc | yoRAttacs p .&. yo p .&. rooks p == 0 = 0 | otherwise = 1 !rc = mrc - yrc + !r7 = r7m - r7y + (!my7, !my8, !yo7, !yo8) | moving p == White = (row7, row8, row2, row1) + | otherwise = (row2, row1, row7, row8) + !r7m | yo p .&. kings p .&. my8 == 0 = 0 + | otherwise = popCount $ me p .&. rooks p .&. my7 + !r7y | me p .&. kings p .&. yo8 == 0 = 0 + | otherwise = popCount $ yo p .&. rooks p .&. yo7 perRook :: BBoard -> BBoard -> Square -> (Int, Int) -> (Int, Int) perRook allp myp rsq (ho, op) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index dc3df6c8..dae42c27 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "dspsa6" +progVerSuff = "r7" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 5e34df51..0e760a3c 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -83,6 +83,7 @@ data EvalWeights ewRookHOpen :: !MidEnd, ewRookOpen :: !MidEnd, ewRookConn :: !MidEnd, + ewRook7th :: !MidEnd, ewMobilityKnight :: !MidEnd, ewMobilityBishop :: !MidEnd, ewMobilityRook :: !MidEnd, @@ -179,17 +180,18 @@ instance CollectParams EvalWeights where ewKingPlacePwns = tme 0 4, ewKingPawn1 = tme 11 42, ewKingPawn2 = tme 10 69, - ewRookHOpen = tme 167 183, - ewRookOpen = tme 205 179, - ewRookConn = tme 92 58, + ewRookHOpen = tme 162 182, -- DSPSA with Adadelta + ewRookOpen = tme 205 178, -- 20k steps, depth 4, + ewRookConn = tme 89 59, -- 2 games, beta=0.95, gamma=0.8, + ewRook7th = tme 201 161, -- niu=0.99, eps=1E-6 ewMobilityKnight = tme 50 56, ewMobilityBishop = tme 53 33, - ewMobilityRook = tme 18 32, + ewMobilityRook = tme 16 34, -- DSPSA ... ewMobilityQueen = tme 2 11, ewCenterPAtts = tme 73 59, ewCenterNAtts = tme 48 37, ewCenterBAtts = tme 52 35, - ewCenterRAtts = tme 14 23, + ewCenterRAtts = tme 14 22, -- DSPSA ... ewCenterQAtts = tme 13 53, ewCenterKAtts = tme 2 62, ewSpace = tme 1 0, @@ -205,7 +207,7 @@ instance CollectParams EvalWeights where ewLastLinePenalty = tme 100 0, ewBishopPair = tme 386 323, ewBishopPawns = tme (-25) (-54), - ewRedundanceRook = tme (-27) (-52), + ewRedundanceRook = tme (-27) (-51), -- DSPSA ... ewRookPawn = tme (-49) (-27), ewAdvPawn5 = tme 8 109, ewAdvPawn6 = tme 359 330, @@ -237,6 +239,8 @@ collectEvalWeights (s, v) ew = lookApply s v ew [ ("end.rookOpen", setEndRookOpen), ("mid.rookConn", setMidRookConn), ("end.rookConn", setEndRookConn), + ("mid.rook7th", setMidRook7th), + ("end.rook7th", setEndRook7th), ("mid.mobilityKnight", setMidMobilityKnight), ("end.mobilityKnight", setEndMobilityKnight), ("mid.mobilityBishop", setMidMobilityBishop), @@ -318,6 +322,8 @@ collectEvalWeights (s, v) ew = lookApply s v ew [ setEndRookOpen v' ew' = ew' { ewRookOpen = (ewRookOpen ew') { end = round v' }} setMidRookConn v' ew' = ew' { ewRookConn = (ewRookConn ew') { mid = round v' }} setEndRookConn v' ew' = ew' { ewRookConn = (ewRookConn ew') { end = round v' }} + setMidRook7th v' ew' = ew' { ewRook7th = (ewRook7th ew') { mid = round v' }} + setEndRook7th v' ew' = ew' { ewRook7th = (ewRook7th ew') { end = round v' }} setMidMobilityKnight v' ew' = ew' { ewMobilityKnight = (ewMobilityKnight ew') { mid = round v' }} setEndMobilityKnight v' ew' = ew' { ewMobilityKnight = (ewMobilityKnight ew') { end = round v' }} setMidMobilityBishop v' ew' = ew' { ewMobilityBishop = (ewMobilityBishop ew') { mid = round v' }} From abbfca8d33ab4d3b7c61769bf0219917f389a0e0 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 10 Jan 2018 02:33:06 +0100 Subject: [PATCH 53/71] Search extenstions when capturing last queen/rook --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 19 ++++++++++++++++++- Search/Albeta.hs | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 0b55a801..4bb4ca37 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "delta1" +progVerSuff = "qex" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index c6b25f51..d9802700 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -200,7 +200,8 @@ doMove m = do if remis then return $ Final 0 else do - let dext = if inCheck p then 1 else 0 + -- let dext = exten pc p m + let dext = exten pc p return $! Exten dext $ moveIsCaptPromo pc m -- Move from a node to a descendent - the QS search version @@ -250,6 +251,22 @@ countRepetitions s = length f6 - uniq undoMove :: Game () undoMove = modify $ \s -> s { stack = tail $ stack s } +{-- +exten :: MyPos -> MyPos -> Move -> Int +exten p1 p2 m | queens p1 `uBitSet` toSquare m = 1 + | inCheck p2 = 1 + | otherwise = 0 +--} + +exten :: MyPos -> MyPos -> Int +exten p1 p2 | inCheck p2 = 1 + | queens p2 /= 0 = 0 + | queens p1 /= 0 = 1 + | rooks p2 /= 0 = 0 + | rooks p1 /= 0 = 1 + -- | passed p1 /= passed p2 = 1 + | otherwise = 0 + -- Tactical positions will be searched complete in quiescent search -- Currently only when in in check {-# INLINE tacticalPos #-} diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 27f2a6c6..5fc5490b 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -36,7 +36,7 @@ scoreGrain, depthForCM, maxDepthExt, minPvDepth :: Int useTTinPv :: Bool scoreGrain = 4 -- score granularity depthForCM = 7 -- from this depth inform current move -maxDepthExt = 3 -- maximum depth extension +maxDepthExt = 4 -- maximum depth extension useTTinPv = False -- retrieve from TT in PV? minPvDepth = 2 -- from this depth we use alpha beta search From b9ba4de3e3e324e2461a373c00b51f7651a514d9 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Mon, 15 Jan 2018 00:15:09 +0100 Subject: [PATCH 54/71] DSPSA eval weights for pawns Normal method with 2000 steps, final rate 5 --- Main/Barbarossa.hs | 2 +- Struct/Status.hs | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index dae42c27..cb97aa7a 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "r7" +progVerSuff = "r7px" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Struct/Status.hs b/Struct/Status.hs index 0e760a3c..e6644dc1 100644 --- a/Struct/Status.hs +++ b/Struct/Status.hs @@ -178,8 +178,8 @@ instance CollectParams EvalWeights where ewKingOpen = tme 2 4, ewKingPlaceCent = tme 8 1, ewKingPlacePwns = tme 0 4, - ewKingPawn1 = tme 11 42, - ewKingPawn2 = tme 10 69, + ewKingPawn1 = tme 4 53, + ewKingPawn2 = tme 2 68, ewRookHOpen = tme 162 182, -- DSPSA with Adadelta ewRookOpen = tme 205 178, -- 20k steps, depth 4, ewRookConn = tme 89 59, -- 2 games, beta=0.95, gamma=0.8, @@ -188,7 +188,7 @@ instance CollectParams EvalWeights where ewMobilityBishop = tme 53 33, ewMobilityRook = tme 16 34, -- DSPSA ... ewMobilityQueen = tme 2 11, - ewCenterPAtts = tme 73 59, + ewCenterPAtts = tme 73 57, ewCenterNAtts = tme 48 37, ewCenterBAtts = tme 52 35, ewCenterRAtts = tme 14 22, -- DSPSA ... @@ -196,24 +196,24 @@ instance CollectParams EvalWeights where ewCenterKAtts = tme 2 62, ewSpace = tme 1 0, ewAdvAtts = tme 1 17, - ewIsolPawns = tme (-38) (-105), - ewIsolPassed = tme (-57) (-150), - ewBackPawns = tme (-105) (-148), - ewBackPOpen = tme (-23) (-26), + ewIsolPawns = tme (-36) (-113), + ewIsolPassed = tme (-63) (-143), + ewBackPawns = tme (-108) (-141), + ewBackPOpen = tme (-21) (-27), ewEnpHanging = tme (-19) (-27), ewEnpEnPrise = tme (-29) (-26), ewEnpAttacked = tme (-2) (-14), - ewWepAttacked = tme 46 61, + ewWepAttacked = tme 35 73, ewLastLinePenalty = tme 100 0, ewBishopPair = tme 386 323, ewBishopPawns = tme (-25) (-54), ewRedundanceRook = tme (-27) (-51), -- DSPSA ... - ewRookPawn = tme (-49) (-27), - ewAdvPawn5 = tme 8 109, - ewAdvPawn6 = tme 359 330, - ewPawnBlockP = tme (-117) (-95), - ewPawnBlockO = tme (-18) (-27), - ewPawnBlockA = tme (-15) (-64), + ewRookPawn = tme (-44) (-32), + ewAdvPawn5 = tme 14 106, + ewAdvPawn6 = tme 352 333, + ewPawnBlockP = tme (-112) (-92), + ewPawnBlockO = tme (-23) (-26), + ewPawnBlockA = tme (-19) (-69), ewPassPawnLev = tme 2 8 } npColParm = collectEvalWeights From dbb1f19be57e0b1fd6c36b48ce4da745de665207 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 27 Jan 2018 01:48:56 +0100 Subject: [PATCH 55/71] Correct quiet checking moves Small optimizations Order of quiet moves generation --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 2 +- Moves/Board.hs | 54 +++++++++++++++++++++++++++++----------------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index f9513685..ca3bcde0 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "chk1" +progVerSuff = "chk2" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index 1d41b248..14811081 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -97,7 +97,7 @@ genMoves d = do -- Generate only tactical moves, i.e. promotions & captures -- Needed only in QS, when we know we are not in check --- In the fronties nodes (i.e. first level QS) we generate +-- In the frontier nodes (i.e. first level QS) we generate -- also checking quiet moves with non-negative SEE genTactMoves :: Bool -> Game [Move] genTactMoves front = do diff --git a/Moves/Board.hs b/Moves/Board.hs index d795da64..156e8cf7 100644 --- a/Moves/Board.hs +++ b/Moves/Board.hs @@ -45,11 +45,17 @@ goPromo p m movePassed :: MyPos -> Move -> Bool movePassed p m = passed p .&. (uBit $ fromSquare m) /= 0 +moveGenAscendent :: Bool +moveGenAscendent = False + genMoveNCapt :: MyPos -> [Move] -genMoveNCapt !p = map (moveAddColor c) - $ concat [ nGenNC, bGenNC, rGenNC, qGenNC, pGenNC1, pGenNC2, kGenNC ] +genMoveNCapt !p + | moveGenAscendent + = map (moveAddColor c) $ nGenNC ++ bGenNC ++ rGenNC ++ qGenNC ++ pGenNC1 ++ pGenNC2 ++ kGenNC + | otherwise + = map (moveAddColor c) $ qGenNC ++ rGenNC ++ bGenNC ++ nGenNC ++ pGenNC1 ++ pGenNC2 ++ kGenNC where pGenNC1 = map (moveAddPiece Pawn . uncurry moveFromTo) - $ pAll1Moves c (pawns p .&. me p `less` traR) (occup p) + $ pAll1Moves c (pawns p .&. me p .&. traR) (occup p) pGenNC2 = map (moveAddPiece Pawn . uncurry moveFromTo) $ pAll2Moves c (pawns p .&. me p) (occup p) nGenNC = map (moveAddPiece Knight . uncurry moveFromTo) @@ -67,10 +73,12 @@ genMoveNCapt !p = map (moveAddColor c) kGenNC = map (moveAddPiece King . uncurry moveFromTo) $ srcDests (ncapt . legal . kAttacs) $ firstOne $ kings p .&. me p - ncapt = (`less` occup p) - legal = (`less` yoAttacs p) - traR = if c == White then 0x00FF000000000000 else 0xFF00 - !c = moving p + !noccup = complement (occup p) + ncapt = ((.&.) noccup) + !nyoa = complement $ yoAttacs p + legal = ((.&.) nyoa) + traR = complement $ if c == White then 0x00FF000000000000 else 0xFF00 + c = moving p -- Generate only promotions (now only to queen) non captures -- The promotion captures are generated together with the other captures @@ -82,7 +90,7 @@ genMovePromo !p = map (uncurry (makePromo Queen)) pGenNC !myfpc = me p .&. traR -- pcapt = (.&. yo p) !traR = if c == White then 0x00FF000000000000 else 0xFF00 - !c = moving p + c = moving p {-# INLINE srcDests #-} srcDests :: (Square -> BBoard) -> Square -> [(Square, Square)] @@ -160,8 +168,8 @@ genMoveFCheck !p !ksq = firstOne kbb !kbb = kings p .&. me p !ocp1 = occup p `less` kbb - legal = (`less` alle) - !alle = me p .|. yoAttacs p .|. excl + !call = complement $ me p .|. yoAttacs p .|. excl + legal = ((.&.) call) !excl = foldl' (.|.) 0 $ map chkAtt chklist chkAtt (NormalCheck f s) = fAttacs s f ocp1 chkAtt (QueenCheck f s) = fAttacs s f ocp1 @@ -177,7 +185,7 @@ genMoveFCheck !p -- Generate moves ending on a given square (used to defend a check by capture or blocking) -- This part is only for queens, rooks, bishops and knights (no pawns and, of course, no kings) defendAt :: MyPos -> BBoard -> [Move] -defendAt p !bb = map (moveAddColor $ moving p) $ concat [ nGenC, bGenC, rGenC, qGenC ] +defendAt p !bb = map (moveAddColor $ moving p) $ nGenC ++ bGenC ++ rGenC ++ qGenC where nGenC = map (moveAddPiece Knight . uncurry moveFromTo) $ concatMap (srcDests (target . nAttacs)) $ bbToSquares $ knights p .&. me p @@ -253,7 +261,11 @@ genMoveNCaptToCheck p = genMoveNCaptDirCheck p ++ genMoveNCaptIndirCheck p -- Todo: check with pawns (should be also without promotions) genMoveNCaptDirCheck :: MyPos -> [Move] -genMoveNCaptDirCheck p = map (moveAddColor $ moving p) $ concat [ qGenC, rGenC, bGenC, nGenC ] +genMoveNCaptDirCheck p + | moveGenAscendent + = map (moveAddColor $ moving p) $ nGenC ++ bGenC ++ rGenC ++ qGenC + | otherwise + = map (moveAddColor $ moving p) $ qGenC ++ rGenC ++ bGenC ++ nGenC where nGenC = map (moveAddPiece Knight . uncurry moveFromTo) $ filtQPSEE p Knight $ concatMap (srcDests (target nTar . nAttacs)) $ bbToSquares $ knights p .&. me p @@ -267,11 +279,13 @@ genMoveNCaptDirCheck p = map (moveAddColor $ moving p) $ concat [ qGenC, rGenC, $ filtQPSEE p Queen $ concatMap (srcDests (target qTar . qAttacs (occup p))) $ bbToSquares $ queens p .&. me p target b = (.&. b) - !nyop = complement $ yo p + !nocp = complement $ occup p !ksq = firstOne $ yo p .&. kings p - !nTar = fAttacs ksq Knight (occup p) .&. nyop - !bTar = fAttacs ksq Bishop (occup p) .&. nyop - !rTar = fAttacs ksq Rook (occup p) .&. nyop + !nTar = fAttacs ksq Knight (occup p) .&. nocp + !bTar | me p .&. (bishops p .|. queens p) == 0 = 0 + | otherwise = fAttacs ksq Bishop (occup p) .&. nocp + !rTar | me p .&. (rooks p .|. queens p) == 0 = 0 + | otherwise = fAttacs ksq Rook (occup p) .&. nocp !qTar = bTar .|. rTar -- TODO: indirect non capture checking moves @@ -287,12 +301,12 @@ genMoveCast p | c == White = (caRMKw, caRMQw, caRAKw, caRAQw) | otherwise = (caRMKb, caRMQb, caRAKb, caRAQb) kingside = if castKingRookOk p c && (occup p .&. cmidk == 0) && (yoAttacs p .&. cattk == 0) - then [caks] else [] + then [caks] else [] queenside = if castQueenRookOk p c && (occup p .&. cmidq == 0) && (yoAttacs p .&. cattq == 0) - then [caqs] else [] + then [caqs] else [] caks = makeCastleFor c True caqs = makeCastleFor c False - !c = moving p + c = moving p {-# INLINE castKingRookOk #-} castKingRookOk :: MyPos -> Color -> Bool @@ -428,7 +442,7 @@ legalMove p m | otherwise = False where src = fromSquare m dst = toSquare m - !mc = moving p + mc = moving p specialMoveIsLegal :: MyPos -> Move -> Bool specialMoveIsLegal p m | moveIsCastle m = elem m $ genMoveCast p From a8b2884c29bd64fdb1937ed3ce54ae6d80fee42f Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Thu, 1 Feb 2018 16:19:39 +0100 Subject: [PATCH 56/71] Extend moves that are pawn threat --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 4bb4ca37..d059ea9c 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "qex" +progVerSuff = "pat" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index d9802700..34ebde3d 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -258,15 +258,25 @@ exten p1 p2 m | queens p1 `uBitSet` toSquare m = 1 | otherwise = 0 --} +-- We extend when last move: +-- - gives check +-- - captures last queen +-- - captures last rook when no queens +-- - (new) is a pawn attack on a figure exten :: MyPos -> MyPos -> Int exten p1 p2 | inCheck p2 = 1 | queens p2 /= 0 = 0 | queens p1 /= 0 = 1 | rooks p2 /= 0 = 0 | rooks p1 /= 0 = 1 - -- | passed p1 /= passed p2 = 1 + | pawnThreat p1 p2 = 1 | otherwise = 0 +pawnThreat :: MyPos -> MyPos -> Bool +pawnThreat p1 p2 = pt2 `less` pt1 /= 0 + where !pt1 = myPAttacs p1 .&. (yo p1 `less` pawns p1) + !pt2 = yoPAttacs p2 .&. (me p2 `less` pawns p2) + -- Tactical positions will be searched complete in quiescent search -- Currently only when in in check {-# INLINE tacticalPos #-} From 81ef86145b6c2c546095d1b456a06155de1e105b Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 3 Feb 2018 00:45:37 +0100 Subject: [PATCH 57/71] Correct pawn attack extension, more logic --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index d059ea9c..4669edcb 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "pat" +progVerSuff = "patc" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index 34ebde3d..68b47c5a 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -262,23 +262,36 @@ exten p1 p2 m | queens p1 `uBitSet` toSquare m = 1 -- - gives check -- - captures last queen -- - captures last rook when no queens --- - (new) is a pawn attack on a figure +-- - (new) is a (valid) pawn attack on a figure exten :: MyPos -> MyPos -> Int exten p1 p2 | inCheck p2 = 1 + | pawnThreat p1 p2 = 1 | queens p2 /= 0 = 0 | queens p1 /= 0 = 1 | rooks p2 /= 0 = 0 | rooks p1 /= 0 = 1 - | pawnThreat p1 p2 = 1 | otherwise = 0 +validThreat, majorThreat :: Bool +validThreat = True +majorThreat = True + pawnThreat :: MyPos -> MyPos -> Bool -pawnThreat p1 p2 = pt2 `less` pt1 /= 0 - where !pt1 = myPAttacs p1 .&. (yo p1 `less` pawns p1) - !pt2 = yoPAttacs p2 .&. (me p2 `less` pawns p2) +pawnThreat p1 p2 + | npa .&. fig == 0 = False + | validThreat = validPawnThreat p1 p2 + | otherwise = True + where !npa = yoPAttacs p2 `less` myPAttacs p1 + !fig | majorThreat = me p2 .&. (queens p2 .|. rooks p2) + | otherwise = me p2 `less` pawns p2 + +-- Valid pawn threat is when the pawn is defended or not attacked +validPawnThreat :: MyPos -> MyPos -> Bool +validPawnThreat p1 p2 = mvpaw .&. yoAttacs p2 /= 0 || mvpaw .&. myAttacs p2 == 0 + where !mvpaw = yo p2 `less` me p1 -- Tactical positions will be searched complete in quiescent search --- Currently only when in in check +-- Currently only when in check {-# INLINE tacticalPos #-} tacticalPos :: MyPos -> Bool tacticalPos = (/= 0) . check From 1d9542e3c009a919f109ef29f0b5f76adb15ea52 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 7 Mar 2018 17:48:45 +0100 Subject: [PATCH 58/71] Some move generation: from low to high piece value --- Main/Barbarossa.hs | 2 +- Moves/Board.hs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index ca3bcde0..a89f5240 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "chk2" +progVerSuff = "chk2a" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Board.hs b/Moves/Board.hs index 156e8cf7..56eafd81 100644 --- a/Moves/Board.hs +++ b/Moves/Board.hs @@ -46,7 +46,7 @@ movePassed :: MyPos -> Move -> Bool movePassed p m = passed p .&. (uBit $ fromSquare m) /= 0 moveGenAscendent :: Bool -moveGenAscendent = False +moveGenAscendent = True genMoveNCapt :: MyPos -> [Move] genMoveNCapt !p @@ -77,7 +77,7 @@ genMoveNCapt !p ncapt = ((.&.) noccup) !nyoa = complement $ yoAttacs p legal = ((.&.) nyoa) - traR = complement $ if c == White then 0x00FF000000000000 else 0xFF00 + !traR = complement $ if c == White then 0x00FF000000000000 else 0xFF00 c = moving p -- Generate only promotions (now only to queen) non captures From 8793106b4e9218126fe8091d133c1077fdcf42f5 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 10 Mar 2018 12:28:13 +0100 Subject: [PATCH 59/71] Pawn extension only in last ply --- Moves/Base.hs | 41 +++++++++++++++++------------------------ Search/Albeta.hs | 6 +++--- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/Moves/Base.hs b/Moves/Base.hs index 68b47c5a..7fa8eeb1 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -174,8 +174,8 @@ doRealMove m = do return $ Exten 0 False -- Move from a node to a descendent - the normal search version -doMove :: Move -> Game DoResult -doMove m = do +doMove :: Move -> Int -> Game DoResult +doMove m !d = do s <- get let (pc:_) = stack s -- we never saw an empty stack error until now -- Moving a non-existent piece? @@ -199,10 +199,7 @@ doMove m = do remis <- checkRemisRules p if remis then return $ Final 0 - else do - -- let dext = exten pc p m - let dext = exten pc p - return $! Exten dext $ moveIsCaptPromo pc m + else return $! Exten (exten pc p d) $ moveIsCaptPromo pc m -- Move from a node to a descendent - the QS search version -- Here we do only a restricted check for illegal moves @@ -251,30 +248,26 @@ countRepetitions s = length f6 - uniq undoMove :: Game () undoMove = modify $ \s -> s { stack = tail $ stack s } -{-- -exten :: MyPos -> MyPos -> Move -> Int -exten p1 p2 m | queens p1 `uBitSet` toSquare m = 1 - | inCheck p2 = 1 - | otherwise = 0 ---} +-- Parameters for extensions +validThreat, majorThreat :: Bool +validThreat = True -- pawn threat must be valid? +majorThreat = False -- pawn threat: only majors? +ptMaxDepth :: Int +ptMaxDepth = 1 -- max depth for pawn threat extension -- We extend when last move: -- - gives check -- - captures last queen -- - captures last rook when no queens -- - (new) is a (valid) pawn attack on a figure -exten :: MyPos -> MyPos -> Int -exten p1 p2 | inCheck p2 = 1 - | pawnThreat p1 p2 = 1 - | queens p2 /= 0 = 0 - | queens p1 /= 0 = 1 - | rooks p2 /= 0 = 0 - | rooks p1 /= 0 = 1 - | otherwise = 0 - -validThreat, majorThreat :: Bool -validThreat = True -majorThreat = True +exten :: MyPos -> MyPos -> Int -> Int +exten p1 p2 !d | inCheck p2 = 1 + | d <= ptMaxDepth && pawnThreat p1 p2 = 1 + | queens p2 /= 0 = 0 + | queens p1 /= 0 = 1 + | rooks p2 /= 0 = 0 + | rooks p1 /= 0 = 1 + | otherwise = 0 pawnThreat :: MyPos -> MyPos -> Bool pawnThreat p1 p2 diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 5fc5490b..2aec3132 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -329,7 +329,7 @@ pvInnerRoot :: Int -- current beta -> Search (Bool, NodeState) pvInnerRoot b d nst e = timeToAbort (True, nst) $ do -- do the move - exd <- lift $ doMove e + exd <- lift $ doMove e d if legalResult exd then do old <- get @@ -658,7 +658,7 @@ pvInnerLoop b d prune nst e = timeToAbort (True, nst) $ do return (False, nst1) else do old <- get - exd <- lift $ doMove e -- do the move + exd <- lift $ doMove e d -- do the move if legalResult exd then do newNode d @@ -696,7 +696,7 @@ pvInnerLoopZ b d prune nst e redu = timeToAbort (True, nst) $ do return (False, nst1) else do old <- get - exd <- lift $ doMove e -- do the move + exd <- lift $ doMove e d -- do the move -- even the legality could be checked before, maybe much cheaper if legalResult exd then do From 1eb5d46b8dffadcb40bb253944a1d956c5ea364c Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 21 Mar 2018 09:59:41 +0100 Subject: [PATCH 60/71] TT update: only after position search In PV, when alpha raised, the update was immediately, with exact score which was not correct, as the score could be raised by a later move. If inbetween an abort occured, score in TT was wrong Also: activate TT in PV note --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 152 ++++++++++++++++++--------------------------- 2 files changed, 61 insertions(+), 93 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index cb97aa7a..48d21a31 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "r7px" +progVerSuff = "ust" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 947045fb..be96fdde 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -33,12 +33,12 @@ useAspirWin = False -- Some fix search parameter scoreGrain, depthForCM, maxDepthExt, minPvDepth :: Int -useTTinPv :: Bool scoreGrain = 4 -- score granularity depthForCM = 7 -- from this depth inform current move maxDepthExt = 3 -- maximum depth extension -useTTinPv = False -- retrieve from TT in PV? minPvDepth = 2 -- from this depth we use alpha beta search +useTTinPv :: Bool +useTTinPv = True -- retrieve from TT in PV? -- Parameters for late move reduction: lmrInitLv, lmrInitLim, lmrLevMin, lmrLevMax :: Int @@ -151,7 +151,7 @@ data NodeState movno :: !Int, -- current move number spcno :: !Int, -- last move number of a special move albe :: !Bool, -- in alpha/beta search (for small depths) - rbmch :: !Int, -- number of changes in root best move + rbmch :: !Int, -- number of changes in root best move / score type otherwise cursc :: Path, -- current alpha value (now plus path & depth) killer :: Killer, -- the current killer moves cpos :: MyPos, -- current position for this node @@ -223,7 +223,7 @@ nst0 = NSt { crtnt = PVNode, nxtnt = PVNode, cursc = pathFromScore "Zero" 0, rbm -- to avoid in any way reducing the tt move resetNSt :: Path -> Killer -> NodeState -> NodeState -resetNSt !sc !kill nst = nst { cursc = sc, movno = 1, spcno = 1, killer = kill } +resetNSt !sc !kill nst = nst { cursc = sc, movno = 1, spcno = 1, killer = kill, rbmch = 0 } pvro00 :: PVReadOnly pvro00 = PVReadOnly { draft = 0, albest = False, timeli = False, abmili = 0 } @@ -370,8 +370,7 @@ pvInnerRootExten b d !exd nst = do -- no futility pruning & no LMR for root moves! -- Here we expect to fail low s1 <- pnextlev <$> pvZeroW nst (-a) d1 True - whenAbort s1 $ do - checkFailHard "pvZeroW" a b (pathScore s1) + whenAbort s1 $ if pathScore s1 <= a -- we failed low as expected then return s1 else do @@ -446,16 +445,10 @@ insertToPvs d p ps@(q:qs) pmate = pnearmate $ pvPath p qmate = pnearmate $ pvPath q -checkFailHard :: String -> Int -> Int -> Int -> Search () -checkFailHard s a b c = - when (c < a || c > b) $ lift - $ absurd $ "Fail not hard (" ++ s ++ "): " ++ show a ++ " / " ++ show c ++ " / " ++ show b - -- PV Search pvSearch :: NodeState -> Int -> Int -> Int -> Search Path pvSearch _ !a !b !d | d <= 0 = do v <- pvQSearch a b 0 - checkFailHard "QS" a b v return $ pathFromScore ("pvQSearch 1:" ++ show v) v -- ok: fail hard in QS pvSearch nst !a !b !d = do let !inPv = crtnt nst == PVNode @@ -491,7 +484,7 @@ pvSearch nst !a !b !d = do nst' = nst { cpos = pos } edges <- genAndSort nst' mttmv a b d if noMove edges - then return $ trimaxPath a b $ if tacticalPos pos then matedPath else staleMate + then return $ failHardNoValidMove a b pos else do nodes0 <- gets (sNodes . stats) -- futility pruning: @@ -500,29 +493,24 @@ pvSearch nst !a !b !d = do let !nsti = resetNSt (pathFromScore "low limit" a) NoKiller nst' nstf <- pvSLoop b d prune nsti edges let s = cursc nstf - whenAbort s $ do - if pathScore s > a - then checkFailHard "pvSLoop improve" a b (pathScore s) >> return s - else if movno nstf > 1 - then do - -- here we failed low - let de = max d $ pathDepth s - nodes1 <- gets (sNodes . stats) - -- store as upper score, and as move, the first one generated - lift $ do - let typ = 0 - !deltan = nodes1 - nodes0 - mv = head $ unalt edges -- not null - we are on "else" of noMove - ttStore de typ a mv deltan - checkFailHard "pvSLoop low" a b (pathScore s) - return s - else return $ trimaxPath a b $ if tacticalPos pos then matedPath else staleMate + whenAbort s $ + if movno nstf == 1 + then return $ failHardNoValidMove a b pos + else do + let de = max d $ pathDepth s + nodes1 <- gets (sNodes . stats) + lift $ do + let !deltan = nodes1 - nodes0 + mvs = pathMoves s + mv | nullSeq mvs = head $ unalt edges -- not null - on "else" of noMove + | otherwise = head $ unseq mvs + ttStore de (rbmch nstf) (pathScore s) mv deltan + return s -- PV Zero Window pvZeroW :: NodeState -> Int -> Int -> Bool -> Search Path pvZeroW !_ !b !d _ | d <= 0 = do v <- pvQSearch bGrain b 0 - checkFailHard "QS" bGrain b v return $ pathFromScore ("pvQSearch 21:" ++ show v) v where !bGrain = b - scoreGrain pvZeroW !nst !b !d redu = do @@ -541,7 +529,7 @@ pvZeroW !nst !b !d redu = do when (hdeep < 0) reFail pos <- lift getPos nmhigh <- nullMoveFailsHigh pos nst b d - whenAbort (pathFromScore "Aborted" b) $ do + whenAbort (pathFromScore "Aborted" b) $ case nmhigh of NullMoveHigh -> return $ pathFromScore "NullMoveHigh" b _ -> do @@ -550,7 +538,7 @@ pvZeroW !nst !b !d redu = do nst' = nst { cpos = pos } edges <- genAndSort nst' mttmv bGrain b d if noMove edges - then return $ trimaxPath bGrain b $ if tacticalPos pos then matedPath else staleMate + then return $ failHardNoValidMove bGrain b pos else do !nodes0 <- gets (sNodes . stats) -- futility pruning: @@ -562,23 +550,19 @@ pvZeroW !nst !b !d redu = do !nsti = resetNSt (pathFromScore "low limit" bGrain) kill1 nst' nstf <- pvZLoop b d prune redu nsti edges let s = cursc nstf - whenAbort s $ do - checkFailHard "pvZLoop" bGrain b (pathScore s) - -- Here we expect bGrain <= s < b -- this must be checked - if pathScore s >= b - then return s -- failed high - else if movno nstf > 1 -- we failed low - then do - let !de = max d $ pathDepth s - !nodes1 <- gets (sNodes . stats) - -- store as upper score, and as move the first one (generated) - lift $ do - let typ = 0 - !deltan = nodes1 - nodes0 - mv = head $ unalt edges -- not null, we are in "else" of noMove - ttStore de typ bGrain mv deltan - return s - else return $ trimaxPath bGrain b $ if tacticalPos pos then matedPath else staleMate + whenAbort s $ + if movno nstf == 1 + then return $ failHardNoValidMove bGrain b pos + else do + let !de = max d $ pathDepth s + !nodes1 <- gets (sNodes . stats) + lift $ do + let !deltan = nodes1 - nodes0 + mvs = pathMoves s + mv | nullSeq mvs = head $ unalt edges -- not null - on "else" of noMove + | otherwise = head $ unseq mvs + ttStore de (rbmch nstf) (pathScore s) mv deltan + return s where !bGrain = b - scoreGrain data NullMoveResult = NoNullMove | NullMoveHigh | NullMoveLow | NullMoveThreat Path @@ -677,7 +661,7 @@ pvInnerLoop b d prune nst e = timeToAbort (True, nst) $ do lift undoMove -- undo the move modify $ \s' -> s' { absdp = absdp old, usedext = usedext old } let s' = addToPath e s - checkFailOrPVLoop (stats old) b d e s' nst + checkFailOrPVLoop b d e s' nst else return (False, nst) -- This part for the zero window search @@ -723,7 +707,7 @@ pvInnerLoopZ b d prune nst e redu = timeToAbort (True, nst) $ do lift undoMove -- undo the move modify $ \s' -> s' { absdp = absdp old, usedext = usedext old } let s' = addToPath e s - checkFailOrPVLoopZ (stats old) b d e s' nst + checkFailOrPVLoopZ b d e s' nst else return (False, nst) resetSpc :: NodeState -> NodeState @@ -752,7 +736,7 @@ pvInnerLoopExten b d !exd nst = do -- Here we must be in a Cut node (will fail low) -- and we should have: crtnt = CutNode, nxtnt = AllNode s1 <- pnextlev <$> pvZeroW nst (-a) d1 True - whenAbort s1 $ do + whenAbort s1 $ if pathScore s1 <= a then return s1 -- failed low (as expected) or aborted else do @@ -791,7 +775,7 @@ pvInnerLoopExtenZ b d spec !exd nst redu = do when (pathScore sr < b && pathScore s1 >= b) $ do incReMi -- LMR missed the point when collectFens $ lift $ finNode "LMRM" 0 - whenAbort sr $ do + whenAbort sr $ if pathScore sr < b then do moreLMR True 1 -- more LMR @@ -807,42 +791,30 @@ pvInnerLoopExtenZ b d spec !exd nst redu = do when (pathScore sf >= b) $ moreLMR False d1 return sf -checkFailOrPVLoop :: SStats -> Int -> Int -> Move -> Path - -> NodeState -> Search (Bool, NodeState) -checkFailOrPVLoop xstats b d e s nst = whenAbort (True, nst) $ do +checkFailOrPVLoop :: Int -> Int -> Move -> Path -> NodeState -> Search (Bool, NodeState) +checkFailOrPVLoop b d e s nst = whenAbort (True, nst) $ do sst <- get let mn = movno nst if pathScore s <= pathScore (cursc nst) then do let nst1 = nst { movno = mn+1, killer = newKiller d s nst } return (False, nst1) - else do - let nodes0 = sNodes xstats - nodes1 = sNodes $ stats sst - !nodes' = nodes1 - nodes0 - !de = max d $ pathDepth s - if pathScore s >= b - then do - lift $ do - let typ = 1 -- best move is e and is beta cut (score is lower limit) - ttStore de typ b e nodes' - betaCut True (absdp sst) e -- anounce a beta move (for example, update history) - incBeta mn - let csc = s { pathScore = b } - nst1 = nst { cursc = csc } - return (True, nst1) - else do -- means: > a && < b - lift $ do - let typ = 2 -- score is exact - ttStore de typ (pathScore s) e nodes' - betaCut True (absdp sst) e -- not really a cut, but good move here - let nst1 = nst { cursc = s, nxtnt = nextNodeType (nxtnt nst), movno = mn+1 } - return (False, nst1) + else if pathScore s >= b + then do + lift $ betaCut True (absdp sst) e -- anounce a beta move (for example, update history) + incBeta mn + let fhsc = s { pathScore = b } + nst1 = nst { cursc = fhsc, movno = mn+1, rbmch = 1 } + return (True, nst1) + else do -- means: > a && < b + lift $ betaCut True (absdp sst) e -- not really a cut, but good move here + let nnt = nextNodeType (nxtnt nst) + nst1 = nst { cursc = s, nxtnt = nnt, movno = mn+1, rbmch = 2 } + return (False, nst1) -- For zero window -checkFailOrPVLoopZ :: SStats -> Int -> Int -> Move -> Path - -> NodeState -> Search (Bool, NodeState) -checkFailOrPVLoopZ xstats b d e s nst = whenAbort (True, nst) $ do +checkFailOrPVLoopZ :: Int -> Int -> Move -> Path -> NodeState -> Search (Bool, NodeState) +checkFailOrPVLoopZ b d e s nst = whenAbort (True, nst) $ do sst <- get let mn = movno nst if pathScore s < b -- failed low @@ -850,17 +822,10 @@ checkFailOrPVLoopZ xstats b d e s nst = whenAbort (True, nst) $ do let nst1 = nst { movno = mn+1, killer = newKiller d s nst } return (False, nst1) else do -- here is s >= b: failed high - let nodes0 = sNodes xstats - nodes1 = sNodes $ stats sst - nodes' = nodes1 - nodes0 - !de = max d $ pathDepth s - lift $ do - let typ = 1 -- best move is e and is beta cut (score is lower limit) - ttStore de typ b e nodes' - betaCut True (absdp sst) e -- anounce a beta move (for example, update history) + lift $ betaCut True (absdp sst) e -- anounce a beta move (for example, update history) incBeta mn - let csc = s { pathScore = b } - nst1 = nst { cursc = csc } + let fhsc = s { pathScore = b } + nst1 = nst { cursc = fhsc, movno = mn+1, rbmch = 1 } return (True, nst1) newKiller :: Int -> Path -> NodeState -> Killer @@ -966,6 +931,9 @@ xchangeFutil varFutVal :: Search Int varFutVal = max futMinVal <$> gets futme +failHardNoValidMove :: Int -> Int -> MyPos -> Path +failHardNoValidMove a b pos = trimaxPath a b $ if tacticalPos pos then matedPath else staleMate + trimaxPath :: Int -> Int -> Path -> Path trimaxPath a b x = x { pathScore = trimax a b (pathScore x) } From f74d383adb5a49725f15ae05406d0c2286fc7e5a Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Wed, 21 Mar 2018 17:28:14 +0100 Subject: [PATCH 61/71] A few relevant changes for search - turn off pawn threat extension - separate conditions for furility pruning & lmr - don't prune nor lmr passed pawn moves --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 58 +++++++++++++++++++++++-------------------- Moves/Board.hs | 7 +++++- Search/Albeta.hs | 49 +++++++++++++++++------------------- Search/AlbetaTypes.hs | 2 +- 5 files changed, 62 insertions(+), 56 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 4669edcb..06f63660 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "patc" +progVerSuff = "dpp" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index 7fa8eeb1..a1cb0b7b 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -32,7 +32,7 @@ import Struct.Context import Struct.Status import Hash.TransTab import Moves.Board -import Moves.BitBoard (less) +import Moves.BitBoard (less, uBit) import Eval.BasicEval import Eval.Eval import Moves.ShowMe @@ -139,11 +139,11 @@ showMyPos p = showTab (black p) (slide p) (kkrq p) (diag p) ++ "================ {-# INLINE uBitSet #-} uBitSet :: BBoard -> Int -> Bool -uBitSet bb sq = bb .&. (1 `unsafeShiftL` sq) /= 0 +uBitSet bb sq = bb .&. uBit sq /= 0 {-# INLINE uBitClear #-} uBitClear :: BBoard -> Int -> Bool -uBitClear bb sq = bb .&. (1 `unsafeShiftL` sq) == 0 +uBitClear bb sq = bb .&. uBit sq == 0 -- Move from a node to a descendent - the real move version doRealMove :: Move -> Game DoResult @@ -171,11 +171,11 @@ doRealMove m = do then return Illegal else do put s { stack = p' : stack s } - return $ Exten 0 False + return $ Exten 0 False False -- Move from a node to a descendent - the normal search version -doMove :: Move -> Int -> Game DoResult -doMove m !d = do +doMove :: Move -> Game DoResult +doMove m = do s <- get let (pc:_) = stack s -- we never saw an empty stack error until now -- Moving a non-existent piece? @@ -199,7 +199,9 @@ doMove m !d = do remis <- checkRemisRules p if remis then return $ Final 0 - else return $! Exten (exten pc p d) $ moveIsCaptPromo pc m + else if captOrPromo pc m + then return $! Exten (exten pc p) True True + else return $! Exten (exten pc p) False (noLMR pc m) -- Move from a node to a descendent - the QS search version -- Here we do only a restricted check for illegal moves @@ -248,26 +250,23 @@ countRepetitions s = length f6 - uniq undoMove :: Game () undoMove = modify $ \s -> s { stack = tail $ stack s } --- Parameters for extensions -validThreat, majorThreat :: Bool -validThreat = True -- pawn threat must be valid? -majorThreat = False -- pawn threat: only majors? -ptMaxDepth :: Int -ptMaxDepth = 1 -- max depth for pawn threat extension - -- We extend when last move: -- - gives check -- - captures last queen -- - captures last rook when no queens --- - (new) is a (valid) pawn attack on a figure -exten :: MyPos -> MyPos -> Int -> Int -exten p1 p2 !d | inCheck p2 = 1 - | d <= ptMaxDepth && pawnThreat p1 p2 = 1 - | queens p2 /= 0 = 0 - | queens p1 /= 0 = 1 - | rooks p2 /= 0 = 0 - | rooks p1 /= 0 = 1 - | otherwise = 0 +exten :: MyPos -> MyPos -> Int +exten p1 p2 | inCheck p2 = 1 + | queens p2 /= 0 = 0 + | queens p1 /= 0 = 1 + | rooks p2 /= 0 = 0 + | rooks p1 /= 0 = 1 + | otherwise = 0 + +{-- +-- Parameters for pawn threats +validThreat, majorThreat :: Bool +validThreat = True -- pawn threat must be valid? +majorThreat = False -- pawn threat: only majors? pawnThreat :: MyPos -> MyPos -> Bool pawnThreat p1 p2 @@ -282,6 +281,7 @@ pawnThreat p1 p2 validPawnThreat :: MyPos -> MyPos -> Bool validPawnThreat p1 p2 = mvpaw .&. yoAttacs p2 /= 0 || mvpaw .&. myAttacs p2 == 0 where !mvpaw = yo p2 `less` me p1 +--} -- Tactical positions will be searched complete in quiescent search -- Currently only when in check @@ -373,13 +373,16 @@ betaCut good absdp m _ -> return () | otherwise = return () --- Will not be pruned nor LMR reduced --- Now: only for captures or promotions (but check that with LMR!!!) -moveIsCaptPromo :: MyPos -> Move -> Bool -moveIsCaptPromo p m +-- Captures & promotions +captOrPromo :: MyPos -> Move -> Bool +captOrPromo p m | moveIsPromo m || moveIsEnPas m = True | otherwise = moveIsCapture p m +-- Can be LMR reduced, if not captures & promotions +noLMR :: MyPos -> Move -> Bool +noLMR = movePassed + -- We will call this function before we do the move -- This will spare a heavy operation for pruned moved {-# INLINE canPruneMove #-} @@ -387,6 +390,7 @@ canPruneMove :: MyPos -> Move -> Bool canPruneMove p m | not (moveIsNormal m) = False | moveIsCapture p m = False + | movePassed p m = False | otherwise = not $ moveChecks p m -- Score difference obtained by last move, from POV of the moving part diff --git a/Moves/Board.hs b/Moves/Board.hs index df709542..cf919d63 100644 --- a/Moves/Board.hs +++ b/Moves/Board.hs @@ -2,7 +2,7 @@ module Moves.Board ( posFromFen, initPos, isCheck, inCheck, - goPromo, moveIsCapture, + movePassed, moveIsCapture, castKingRookOk, castQueenRookOk, genMoveCast, genMoveNCapt, genMovePromo, genMoveFCheck, genMoveCaptWL, genMoveNCaptToCheck, @@ -36,14 +36,19 @@ isCheck p Black | check p .&. black p == 0 = False inCheck :: MyPos -> Bool inCheck = (/= 0) . check +{-- goPromo :: MyPos -> Move -> Bool goPromo p m | moveIsPromo m = True | movePassed p m = True | otherwise = False +--} +{-# INLINE movePassed #-} movePassed :: MyPos -> Move -> Bool movePassed p m = passed p .&. (uBit $ fromSquare m) /= 0 + -- && target .&. (uBit $ toSquare m) /= 0 + -- where target = 0x00FF00000000FF00 genMoveNCapt :: MyPos -> [Move] genMoveNCapt !p = map (moveAddColor c) diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 2aec3132..250f250f 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -329,7 +329,7 @@ pvInnerRoot :: Int -- current beta -> Search (Bool, NodeState) pvInnerRoot b d nst e = timeToAbort (True, nst) $ do -- do the move - exd <- lift $ doMove e d + exd <- lift $ doMove e if legalResult exd then do old <- get @@ -337,8 +337,8 @@ pvInnerRoot b d nst e = timeToAbort (True, nst) $ do newNode d modify $ \s -> s { absdp = absdp s + 1 } s <- case exd of - Exten exd' spc -> do - when (exd' == 0 && not spc) $ do + Exten exd' _ _ -> do + when (canPruneMove (cpos nst) e) $ do sdiff <- lift scoreDiff updateFutil sdiff -- e xchangeFutil @@ -652,22 +652,23 @@ pvInnerLoop :: Int -- current beta -> Search (Bool, NodeState) pvInnerLoop b d prune nst e = timeToAbort (True, nst) $ do -- What about TT & killer moves??? - if prune && movno nst > 1 && canPruneMove (cpos nst) e + let !canPrune = canPruneMove (cpos nst) e + if prune && movno nst > 1 && canPrune then do let !nst1 = nst { movno = movno nst + 1 } return (False, nst1) else do old <- get - exd <- lift $ doMove e d -- do the move + exd <- lift $ doMove e -- do the move if legalResult exd then do newNode d modify $ \s -> s { absdp = absdp s + 1 } s <- case exd of - Exten exd' spc -> do - when (exd' == 0 && not spc) $ do -- not quite ok here - sdiff <- lift scoreDiff -- cause spc has a slighty - updateFutil sdiff -- e -- different meaning... + Exten exd' _ _ -> do + when canPrune $ do + sdiff <- lift scoreDiff + updateFutil sdiff -- e xchangeFutil s <- pvInnerLoopExten b d exd' (deepNSt nst) xchangeFutil @@ -690,34 +691,30 @@ pvInnerLoopZ :: Int -- current beta -> Search (Bool, NodeState) pvInnerLoopZ b d prune nst e redu = timeToAbort (True, nst) $ do -- What about TT & killer moves??? - if prune && canPruneMove (cpos nst) e + let !canPrune = canPruneMove (cpos nst) e + if prune && canPrune then do let !nst1 = nst { movno = movno nst + 1 } return (False, nst1) else do old <- get - exd <- lift $ doMove e d -- do the move + exd <- lift $ doMove e -- do the move -- even the legality could be checked before, maybe much cheaper if legalResult exd then do newNode d modify $ \s -> s { absdp = absdp s + 1 } s <- case exd of - Exten exd' spc -> do - if spc - then do - xchangeFutil - s <- pvInnerLoopExtenZ b d spc exd' (deepNSt $ resetSpc nst) redu - xchangeFutil - return s - else do - when (exd' == 0) $ do - sdiff <- lift scoreDiff - updateFutil sdiff -- e - xchangeFutil - s <- pvInnerLoopExtenZ b d spc exd' (deepNSt nst) redu - xchangeFutil - return s + Exten exd' cap nolmr -> do + when canPrune $ do + sdiff <- lift scoreDiff + updateFutil sdiff -- e + xchangeFutil + s <- if cap + then pvInnerLoopExtenZ b d True exd' (deepNSt $ resetSpc nst) redu + else pvInnerLoopExtenZ b d nolmr exd' (deepNSt nst) redu + xchangeFutil + return s Final sco -> return $! pathFromScore "Final" (-sco) Illegal -> error "Cannot be illegal here" lift undoMove -- undo the move diff --git a/Search/AlbetaTypes.hs b/Search/AlbetaTypes.hs index 49d9c6f2..5aa41a62 100644 --- a/Search/AlbetaTypes.hs +++ b/Search/AlbetaTypes.hs @@ -22,7 +22,7 @@ data ABControl = ABC { stoptime :: Int } deriving Show -data DoResult = Exten !Int !Bool -- return mit extension & special +data DoResult = Exten !Int !Bool !Bool -- return mit extension, iscapt & canlmr | Final !Int -- return with a final score (probably draw) | Illegal -- illegal move From 1d5b2451cf568d980d351746652d9f18206ed001 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 31 Mar 2018 12:30:28 +0200 Subject: [PATCH 62/71] TT update: best so far exact score as lower limit When search ends: exact score will be updated Advantage: when search aborts, we have some partial results in TT (plus good TT moves) Also: when pruning, we want now to have at least 1 legal move, otherwise mates or stalemates missed Also: TT score in PV inactiv (again) --- Main/Barbarossa.hs | 2 +- Moves/Base.hs | 2 -- Search/Albeta.hs | 9 ++++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 48d21a31..8328caf1 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "ust" +progVerSuff = "ust1" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/Base.hs b/Moves/Base.hs index 59af5b62..e26d5fee 100644 --- a/Moves/Base.hs +++ b/Moves/Base.hs @@ -265,14 +265,12 @@ isMoveLegal :: MyPos -> Move -> Bool isMoveLegal = legalMove -- Why not just like isTKillCand? --- Also: if not normal, it is useless, as now it is not recognized as legal... {-# INLINE isKillCand #-} isKillCand :: MyPos -> Move -> Move -> Bool isKillCand p mm ym | toSquare mm == toSquare ym = False | otherwise = not $ moveIsCapture p ym --- If not normal, it is useless, as now it is not recognized as legal... {-# INLINE isTKillCand #-} isTKillCand :: MyPos -> Move -> Bool isTKillCand p mm = not $ moveIsCapture p mm diff --git a/Search/Albeta.hs b/Search/Albeta.hs index be96fdde..9571bc61 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -38,7 +38,7 @@ depthForCM = 7 -- from this depth inform current move maxDepthExt = 3 -- maximum depth extension minPvDepth = 2 -- from this depth we use alpha beta search useTTinPv :: Bool -useTTinPv = True -- retrieve from TT in PV? +useTTinPv = False -- retrieve from TT in PV? -- Parameters for late move reduction: lmrInitLv, lmrInitLim, lmrLevMin, lmrLevMax :: Int @@ -674,7 +674,7 @@ pvInnerLoopZ :: Int -- current beta -> Search (Bool, NodeState) pvInnerLoopZ b d prune nst e redu = timeToAbort (True, nst) $ do -- What about TT & killer moves??? - if prune && canPruneMove (cpos nst) e + if prune && movno nst > 1 && canPruneMove (cpos nst) e then do let !nst1 = nst { movno = movno nst + 1 } return (False, nst1) @@ -807,7 +807,10 @@ checkFailOrPVLoop b d e s nst = whenAbort (True, nst) $ do nst1 = nst { cursc = fhsc, movno = mn+1, rbmch = 1 } return (True, nst1) else do -- means: > a && < b - lift $ betaCut True (absdp sst) e -- not really a cut, but good move here + lift $ do + betaCut True (absdp sst) e -- not really a cut, but good move here + let de = max d $ pathDepth s + ttStore de 1 (pathScore s) e 0 -- best move so far (score is lower limit) let nnt = nextNodeType (nxtnt nst) nst1 = nst { cursc = s, nxtnt = nnt, movno = mn+1, rbmch = 2 } return (False, nst1) From 4f0e6455caf78fc6678de3595c124980f2e4a0dc Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Mon, 2 Apr 2018 02:31:54 +0200 Subject: [PATCH 63/71] Just a few twicks for more speed in eval: - less: replace by complement/& when same argument a few times - 2 arrays with smaller dimensions (Int32 instead of Int) Also a few cases of better formatting --- Eval/Eval.hs | 73 +++++++++++++++++++++++++--------------------- Main/Barbarossa.hs | 2 +- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/Eval/Eval.hs b/Eval/Eval.hs index f6e8e841..e9d801ab 100644 --- a/Eval/Eval.hs +++ b/Eval/Eval.hs @@ -13,6 +13,7 @@ import Data.Bits import Data.List (minimumBy) import Data.Array.Unboxed import Data.Ord (comparing) +import Data.Int import Struct.Struct import Struct.Status @@ -111,8 +112,9 @@ evalNoPawns p !sti = sc | kMxk = mateKMajxK p kaloneyo -- simple mate with at least one major | lessRook p = (normalEval p sti) `div` 2 | otherwise = normalEval p sti - kaloneme = me p `less` kings p == 0 - kaloneyo = yo p `less` kings p == 0 + nokings = complement (kings p) + kaloneme = me p .&. nokings == 0 + kaloneyo = yo p .&. nokings == 0 onlykings = kaloneme && kaloneyo kmk = (kaloneme || kaloneyo) && minorcnt == 1 && majorcnt == 0 knnk = (kaloneme || kaloneyo) && minorcnt == 2 && majorcnt == 0 && bishops p == 0 @@ -167,14 +169,17 @@ scoreToMate f p mywin = msc !wsc = if mywin then sc else -sc !msc = mtr + wsc -squareDistArr :: UArray (Square, Square) Int -squareDistArr = array ((0,0), (63,63)) [((s1, s2), squareDist s1 s2) | s1 <- [0..63], s2 <- [0..63]] +squareDistArr :: UArray Int Int32 +squareDistArr = array (0, 64*64-1) [(sqSqIdx s1 s2, squareDist s1 s2) | s1 <- [0..63], s2 <- [0..63]] where squareDist f t = max (abs (fr - tr)) (abs (fc - tc)) - where (fr, fc) = f `divMod` 8 - (tr, tc) = t `divMod` 8 + where (fr, fc) = fromIntegral f `divMod` 8 + (tr, tc) = fromIntegral t `divMod` 8 squareDistance :: Square -> Square -> Int -squareDistance = curry (squareDistArr!) +squareDistance !sq1 !sq2 = fromIntegral $ squareDistArr `unsafeAt` sqSqIdx sq1 sq2 + +sqSqIdx :: Square -> Square -> Int +sqSqIdx !sq1 !sq2 = (sq1 `unsafeShiftL` 6) + sq2 -- This center distance should be pre calculated centerDistance :: Int -> Int @@ -194,8 +199,10 @@ bnMateDistance wbish sq = min (squareDistance sq ocor1) (squareDistance sq ocor2 ------ King Safety ------ kingSafe :: MyPos -> EvalWeights -> MidEnd -> MidEnd kingSafe p !ew !mide = madm mide (ewKingSafe ew) ksafe - where !ksafe = ksSide (yo p) (yoKAttacs p) (myPAttacs p) (myNAttacs p) (myBAttacs p) (myRAttacs p) (myQAttacs p) (myKAttacs p) (myAttacs p) - - ksSide (me p) (myKAttacs p) (yoPAttacs p) (yoNAttacs p) (yoBAttacs p) (yoRAttacs p) (yoQAttacs p) (yoKAttacs p) (yoAttacs p) + where !ksafe = ksSide (yo p) (yoKAttacs p) (myPAttacs p) (myNAttacs p) (myBAttacs p) (myRAttacs p) + (myQAttacs p) (myKAttacs p) (myAttacs p) + - ksSide (me p) (myKAttacs p) (yoPAttacs p) (yoNAttacs p) (yoBAttacs p) (yoRAttacs p) + (yoQAttacs p) (yoKAttacs p) (yoAttacs p) -- To make the sum and count in one pass data Flc = Flc !Int !Int @@ -225,7 +232,7 @@ ksSide !yop !yok !myp !myn !myb !myr !myq !myk !mya !(Flc c q) = fadd qp $ fadd qn $ fadd qb $ fadd qr $ fadd qq qk !mattacs | c == 0 = 0 - | otherwise = attCoef `unsafeAt` ixt + | otherwise = fromIntegral $ attCoef `unsafeAt` ixt -- where !freey = popCount $ yok `less` (mya .|. yop) -- !conce = popCount $ yok .&. mya -- This is equivalent to: @@ -238,10 +245,10 @@ ksSide !yop !yok !myp !myn !myb !myr !myq !myk !mya -- Quali max: 8 * (1 + 2 + 2 + 4 + 8 + 2) = 168 -- Flag max: 6 -- 6 * 168 / 4 + 6 + 13 = 272 -attCoef :: UArray Int Int +attCoef :: UArray Int Int32 attCoef = listArray (0, 272) $ take zeros (repeat 0) ++ [ f x | x <- [0..63] ] ++ repeat (f 63) where -- Without the scaling, f will take max value of 4000 for 63 - f :: Int -> Int + f :: Int -> Int32 f x = let y = fromIntegral x :: Double in round $ maxks * (2.92968750 - 0.03051758*y)*y*y / 4000 zeros = 8 @@ -301,10 +308,11 @@ kingPlace ep p !ew mide = made (madm (mad (mad (mad mide (ewKingPawn2 ew) kpa2) materFun m r q = (m * epMaterMinor ep + r * epMaterRook ep + q * epMaterQueen ep) `unsafeShiftR` epMaterScale ep !ko = adv - own - mwb = popCount $ bAttacs paw mks `less` paw - mwr = popCount $ rAttacs paw mks `less` paw - ywb = popCount $ bAttacs paw yks `less` paw - ywr = popCount $ rAttacs paw yks `less` paw + nopaw = complement paw + mwb = popCount $ bAttacs paw mks .&. nopaw + mwr = popCount $ rAttacs paw mks .&. nopaw + ywb = popCount $ bAttacs paw yks .&. nopaw + ywr = popCount $ rAttacs paw yks .&. nopaw paw = pawns p comb !oR !oQ !wb !wr = let r = oR * wr q = oQ * (wb + wr) @@ -514,7 +522,7 @@ spaceWhite !mpawns !matts !ypatts !yatts = sv safe = (yard .&. (matts .|. complement yatts)) `less` (mpawns .|. ypatts) behi = shadowDown mpawns spa = popCount $ (safe `unsafeShiftL` 32) .|. (behi .&. safe) - !sv = spaceVals `unsafeAt` spa + !sv = fromIntegral $ spaceVals `unsafeAt` spa {-# INLINE spaceBlack #-} spaceBlack :: BBoard -> BBoard -> BBoard -> BBoard -> Int @@ -523,10 +531,10 @@ spaceBlack !mpawns !matts !ypatts !yatts = sv safe = (yard .&. (matts .|. complement yatts)) `less` (mpawns .|. ypatts) behi = shadowUp mpawns spa = popCount $ (safe `unsafeShiftR` 32) .|. (behi .&. safe) - !sv = spaceVals `unsafeAt` spa + !sv = fromIntegral $ spaceVals `unsafeAt` spa -- Non linear space values: -spaceVals :: UArray Int Int +spaceVals :: UArray Int Int32 spaceVals = listArray (0, 24) $ map f [1..25] where f x = round $ spf * (sqrt x - 1) spf = 270 :: Double @@ -560,8 +568,9 @@ isol ps pp = (ris, pis) !myu = myf `unsafeShiftL` 8 !myd = myf `unsafeShiftR` 8 !myc = myf .|. myu .|. myd - !ris = popCount $ myr `less` myc - !pis = popCount $ myp `less` myc + !nomyc = complement myc + !ris = popCount $ myr .&. nomyc + !pis = popCount $ myp .&. nomyc -------- Backward pawns -------- @@ -638,10 +647,11 @@ enPrise p !ew mide = mad (mad (mad (mad mide (ewEnpHanging ew) ha) !atM = meM .&. yoAttacs p !atR = meR .&. yoAttacs p !atQ = meQ .&. yoAttacs p - !haP = atP `less` myAttacs p -- attacked and not defended (hanging) - !haM = atM `less` myAttacs p - !haR = atR `less` myAttacs p - !haQ = atQ `less` myAttacs p + !noma = complement $ myAttacs p + !haP = atP .&. noma -- attacked and not defended (hanging) + !haM = atM .&. noma + !haR = atR .&. noma + !haQ = atQ .&. noma !epM = meM .&. yoPAttacs p -- defended, but attacked by less valuable opponent pieces !epR = meR .&. yoA1 !epQ = meQ .&. yoA2 @@ -650,8 +660,8 @@ enPrise p !ew mide = mad (mad (mad (mad mide (ewEnpHanging ew) ha) !ha = popCount haP + 3 * popCount haM + 5 * popCount haR + 9 * popCount haQ !ep = 3 * popCount epM + 5 * popCount epR + 9 * popCount epQ !at = popCount atP + 3 * popCount atM + 5 * popCount atR + 9 * popCount atQ - !wp1 = popCount$ (meP `less` myPAttacs p) .&. yoAttacs p -- my weak attacked pawns - !wp2 = popCount$ (yo p .&. pawns p `less` yoPAttacs p) .&. myAttacs p -- your weak attacked pawns + !wp1 = popCount $ (meP `less` myPAttacs p) .&. yoAttacs p -- my weak attacked pawns + !wp2 = popCount $ (yo p .&. pawns p `less` yoPAttacs p) .&. myAttacs p -- your weak attacked pawns !wp = wp2 - wp1 ------ Last Line ------ @@ -801,11 +811,9 @@ perPassedPawnOk !gph ep p c sq sqbb moi toi moia toia = val | otherwise = moia .&. way !bbyoctrl | yobehind = way `less` bbmyctrl | otherwise = toia .&. (way `less` bbmyctrl) - !bbfree = way `less` (bbmyctrl .|. bbyoctrl) !myctrl = popCount bbmyctrl !yoctrl = popCount bbyoctrl - !free = popCount bbfree - !x = myctrl + yoctrl + free + !x = popCount way a0 = 10 b0 = -120 c0 = 410 @@ -857,7 +865,6 @@ advPawns p !ew mide = mad (mad mide (ewAdvPawn5 ew) ap5) (ewAdvPawn6 ew) ap6 -- passed pawns - now with queens) pawnEndGame :: MyPos -> Maybe Int pawnEndGame p - -- | null mescds && null yescds = Nothing | not (null mescds) && not (null yescds) = Just dpr | not (null mescds) = Just myrace | not (null yescds) = Just yorace @@ -872,9 +879,9 @@ pawnEndGame p | moving p == White = (escMeWhite yoking, escYoBlack myking, mater p) | otherwise = (escMeBlack yoking, escYoWhite myking, - mater p) mpsqs = map escMe $ bbToSquares mfpbb -- my pp squares & distances to promotion - !mescds = map snd $ filter fst mpsqs -- my escaped passed pawns + mescds = map snd $ filter fst mpsqs -- my escaped passed pawns ypsqs = map escYo $ bbToSquares yfpbb -- your pp squares & distances to promotion - !yescds = map snd $ filter fst ypsqs -- your escaped passed pawns + yescds = map snd $ filter fst ypsqs -- your escaped passed pawns dpr | mim < miy = myrace | mim > miy + 1 = yorace | otherwise = withQueens -- Here: this is more complex, e.g. if check while promoting diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index cb97aa7a..9ccc4c5e 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "r7px" +progVerSuff = "spe" data Options = Options { optConfFile :: Maybe String, -- config file From 68b57e261664de0821fd1588f567ccd46eee54bf Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Thu, 19 Apr 2018 12:57:22 +0200 Subject: [PATCH 64/71] LMR: no overlap with futility (i.e. depth > 3) --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index cb97aa7a..0598030f 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "r7px" +progVerSuff = "lmr4" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 947045fb..2736ac74 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -900,8 +900,8 @@ genAndSort nst mttmv a b d = do {-# INLINE reduceLmr #-} reduceLmr :: Bool -> Bool -> Int -> Int -> Int -> Int reduceLmr nearmatea spec d lmrlev w - | spec || d <= 1 || nearmatea = d - | otherwise = max 1 $ d - lmrArr!(lmrlev, w) + | spec || d <= maxFutilDepth || nearmatea = d + | otherwise = max 1 $ d - lmrArr!(lmrlev, w) -- Adjust the LMR related parameters in the state moreLMR :: Bool -> Int -> Search () From b478f3169ffacc37f66db7d63f88d785c32a92a7 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Thu, 19 Apr 2018 22:12:59 +0200 Subject: [PATCH 65/71] LMR also in PV node --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 134 +++++++++++++++++++----------------------- Search/AlbetaTypes.hs | 17 ++---- 3 files changed, 68 insertions(+), 85 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 0598030f..48993df0 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "lmr4" +progVerSuff = "lmr4p" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 2736ac74..96cfc4da 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -369,7 +369,7 @@ pvInnerRootExten b d !exd nst = do else do -- no futility pruning & no LMR for root moves! -- Here we expect to fail low - s1 <- pnextlev <$> pvZeroW nst (-a) d1 True + s1 <- pnextlev <$> pvZeroW nst (-a) d1 whenAbort s1 $ do checkFailHard "pvZeroW" a b (pathScore s1) if pathScore s1 <= a -- we failed low as expected @@ -519,13 +519,13 @@ pvSearch nst !a !b !d = do else return $ trimaxPath a b $ if tacticalPos pos then matedPath else staleMate -- PV Zero Window -pvZeroW :: NodeState -> Int -> Int -> Bool -> Search Path -pvZeroW !_ !b !d _ | d <= 0 = do +pvZeroW :: NodeState -> Int -> Int -> Search Path +pvZeroW !_ !b !d | d <= 0 = do v <- pvQSearch bGrain b 0 checkFailHard "QS" bGrain b v return $ pathFromScore ("pvQSearch 21:" ++ show v) v where !bGrain = b - scoreGrain -pvZeroW !nst !b !d redu = do +pvZeroW !nst !b !d = do -- Check if we have it in TT (hdeep, tp, hsc, e, nodes') <- reTrieve >> lift ttRead if hdeep >= d && (tp == 2 || tp == 1 && hsc >= b || tp == 0 && hsc < b) @@ -560,7 +560,7 @@ pvZeroW !nst !b !d redu = do NullMoveThreat s -> newTKiller pos d s _ -> NoKiller !nsti = resetNSt (pathFromScore "low limit" bGrain) kill1 nst' - nstf <- pvZLoop b d prune redu nsti edges + nstf <- pvZLoop b d prune nsti edges let s = cursc nstf whenAbort s $ do checkFailHard "pvZLoop" bGrain b (pathScore s) @@ -598,8 +598,8 @@ nullMoveFailsHigh pos nst b d xchangeFutil let nst' = deepNSt nst val <- if v > b + bigDiff - then fmap pnextlev $ pvZeroW nst' (-nma) d2 True - else fmap pnextlev $ pvZeroW nst' (-nma) d1 True + then fmap pnextlev $ pvZeroW nst' (-nma) d2 + else fmap pnextlev $ pvZeroW nst' (-nma) d1 lift undoMove -- undo null move xchangeFutil if pathScore val >= nmb @@ -633,11 +633,11 @@ pvSLoop b d p = go if cut then return s' else go s' $ Alt es -pvZLoop :: Int -> Int -> Bool -> Bool -> NodeState -> Alt Move -> Search NodeState -pvZLoop b d p redu = go +pvZLoop :: Int -> Int -> Bool -> NodeState -> Alt Move -> Search NodeState +pvZLoop b d p = go where go !s (Alt []) = return s go !s (Alt (e:es)) = do - (!cut, !s') <- pvInnerLoopZ b d p s e redu + (!cut, !s') <- pvInnerLoopZ b d p s e if cut then return s' else go s' $ Alt es @@ -664,16 +664,18 @@ pvInnerLoop b d prune nst e = timeToAbort (True, nst) $ do newNode d modify $ \s -> s { absdp = absdp s + 1 } s <- case exd of - Exten exd' spc -> do - when (exd' == 0 && not spc) $ do -- not quite ok here - sdiff <- lift scoreDiff -- cause spc has a slighty - updateFutil sdiff -- e -- different meaning... - xchangeFutil - s <- pvInnerLoopExten b d exd' (deepNSt nst) - xchangeFutil - return s - Final sco -> return $! pathFromScore "Final" (-sco) - Illegal -> error "Cannot be illegal here" + Exten exd' spc -> do + when (exd' == 0 && not spc) $ do + sdiff <- lift scoreDiff + updateFutil sdiff -- e + xchangeFutil + s <- if spc + then pvInnerLoopExten b d spc exd' (deepNSt $ resetSpc nst) + else pvInnerLoopExten b d spc exd' (deepNSt nst) + xchangeFutil + return s + Final sco -> return $! pathFromScore "Final" (-sco) + Illegal -> error "Cannot be illegal here" lift undoMove -- undo the move modify $ \s' -> s' { absdp = absdp old, usedext = usedext old } let s' = addToPath e s @@ -686,9 +688,8 @@ pvInnerLoopZ :: Int -- current beta -> Bool -- prune? -> NodeState -- node status -> Move -- move to search - -> Bool -- reduce in LMR? -> Search (Bool, NodeState) -pvInnerLoopZ b d prune nst e redu = timeToAbort (True, nst) $ do +pvInnerLoopZ b d prune nst e = timeToAbort (True, nst) $ do -- What about TT & killer moves??? if prune && canPruneMove (cpos nst) e then do @@ -704,20 +705,15 @@ pvInnerLoopZ b d prune nst e redu = timeToAbort (True, nst) $ do modify $ \s -> s { absdp = absdp s + 1 } s <- case exd of Exten exd' spc -> do - if spc - then do - xchangeFutil - s <- pvInnerLoopExtenZ b d spc exd' (deepNSt $ resetSpc nst) redu - xchangeFutil - return s - else do - when (exd' == 0) $ do - sdiff <- lift scoreDiff - updateFutil sdiff -- e - xchangeFutil - s <- pvInnerLoopExtenZ b d spc exd' (deepNSt nst) redu - xchangeFutil - return s + when (exd' == 0 && not spc) $ do + sdiff <- lift scoreDiff + updateFutil sdiff -- e + xchangeFutil + s <- if spc + then pvInnerLoopExtenZ b d spc exd' (deepNSt $ resetSpc nst) + else pvInnerLoopExtenZ b d spc exd' (deepNSt nst) + xchangeFutil + return s Final sco -> return $! pathFromScore "Final" (-sco) Illegal -> error "Cannot be illegal here" lift undoMove -- undo the move @@ -736,8 +732,8 @@ reserveExtension !uex !exd modify $ \s -> s { usedext = usedext s + exd } return exd -pvInnerLoopExten :: Int -> Int -> Int -> NodeState -> Search Path -pvInnerLoopExten b d !exd nst = do +pvInnerLoopExten :: Int -> Int -> Bool -> Int -> NodeState -> Search Path +pvInnerLoopExten b d spec !exd nst = do old <- get exd' <- reserveExtension (usedext old) exd let !inPv = crtnt nst == PVNode @@ -745,52 +741,46 @@ pvInnerLoopExten b d !exd nst = do a = pathScore $ cursc nst if inPv || d <= minPvDepth then do - -- Set albe only when not in PV and not already set (to spare a copy) - let nst' = if not (inPv || albe nst) then nst { albe = True } else nst - pnextlev <$> pvSearch nst' (-b) (-a) d1 + -- Set albe only when not in PV and not already set (to spare a copy) + let nst' = if not (inPv || albe nst) then nst { albe = True } else nst + pnextlev <$> pvSearch nst' (-b) (-a) d1 else do - -- Here we must be in a Cut node (will fail low) - -- and we should have: crtnt = CutNode, nxtnt = AllNode - s1 <- pnextlev <$> pvZeroW nst (-a) d1 True - whenAbort s1 $ do - if pathScore s1 <= a - then return s1 -- failed low (as expected) or aborted - else do - -- we didn't fail low and need re-search: full window - let nst1 = nst { crtnt = PVNode, nxtnt = PVNode } - pnextlev <$> pvSearch nst1 (-b) (-a) d1 + -- Here we must be in a Cut node (will fail low) + -- and we should have: crtnt = CutNode, nxtnt = AllNode + let !d' = reduceLmr (nearmate b) spec d1 (lmrlv old) (movno nst - spcno nst) + -- s1 <- pnextlev <$> pvZeroW nst (-a) d1 + s1 <- zeroWithLMR d' d1 (-a) (a+1) nst + whenAbort s1 $ do + if pathScore s1 <= a + then return s1 -- failed low (as expected) or aborted + else do + -- we didn't fail low and need re-search: full window + let nst1 = nst { crtnt = PVNode, nxtnt = PVNode } + pnextlev <$> pvSearch nst1 (-b) (-a) d1 -- For zero window -pvInnerLoopExtenZ :: Int -> Int -> Bool -> Int -> NodeState -> Bool -> Search Path -pvInnerLoopExtenZ b d spec !exd nst redu = do +pvInnerLoopExtenZ :: Int -> Int -> Bool -> Int -> NodeState -> Search Path +pvInnerLoopExtenZ b d spec !exd nst = do old <- get exd' <- reserveExtension (usedext old) exd -- late move reduction let !d1 = d + exd' - 1 -- this is the normal (unreduced) depth for next search - !d' = if redu - then reduceLmr (nearmate b) spec d1 (lmrlv old) (movno nst - spcno nst) - else d1 - let !onemB = scoreGrain - b - if not redu || d' == d1 + !d' = reduceLmr (nearmate b) spec d1 (lmrlv old) (movno nst - spcno nst) + !onemB = scoreGrain - b + zeroWithLMR d' d1 onemB b nst + +zeroWithLMR :: Int -> Int -> Int -> Int -> NodeState -> Search Path +zeroWithLMR !d' !d1 !onemB !b nst = + if d' == d1 then do moreLMR True 1 -- more LMR - pnextlev <$> pvZeroW nst onemB d' redu + pnextlev <$> pvZeroW nst onemB d' else do incRedu nds0 <- gets $ sNodes . stats - !sr <- pnextlev <$> pvZeroW nst onemB d' True + !sr <- pnextlev <$> pvZeroW nst onemB d' nds1 <- gets $ sNodes . stats let nodre = nds1 - nds0 - !s1 <- if lmrDebug - then pnextlev <$> pvZeroW nst onemB d1 False - else return sr - nds2 <- gets $ sNodes . stats - let nodnr = nds2 - nds1 - when lmrDebug $ do - incReBe (nodnr - nodre) -- so many nodes we spare by reducing - when (pathScore sr < b && pathScore s1 >= b) $ do - incReMi -- LMR missed the point - when collectFens $ lift $ finNode "LMRM" 0 whenAbort sr $ do if pathScore sr < b then do @@ -802,7 +792,7 @@ pvInnerLoopExtenZ b d spec !exd nst redu = do moreLMR False d' -- less LMR -- Now we expect to fail high, i.e. exchange the crt/nxt node type let nst1 = nst { crtnt = nxtnt nst, nxtnt = crtnt nst } - sf <- pnextlev <$> pvZeroW nst1 onemB d1 True + sf <- pnextlev <$> pvZeroW nst1 onemB d1 whenAbort sf $ do when (pathScore sf >= b) $ moreLMR False d1 return sf @@ -1073,7 +1063,7 @@ bestMoveFromIID nst a b d = do s <- pvSearch nst a b d' return $! unseq $ pathMoves s | nt == CutNode && (d >= minIIDCut || (d >= minIIDCutNK && killer nst == NoKiller)) - = do s <- pvZeroW nst b d' False + = do s <- pvZeroW nst b d' return $! unseq $ pathMoves s | otherwise = return [] where d' = min maxIIDDepth (iidNewDepth d) diff --git a/Search/AlbetaTypes.hs b/Search/AlbetaTypes.hs index 49d9c6f2..72b25006 100644 --- a/Search/AlbetaTypes.hs +++ b/Search/AlbetaTypes.hs @@ -6,7 +6,7 @@ module Search.AlbetaTypes ( ABControl(..), SStats(..), ssts0, formatStats, addStats, - lmrDebug, nulDebug + nulDebug ) where import Data.Int @@ -55,8 +55,7 @@ addStats a b = SStats { sReSe = sReSe a + sReSe b, sReNo = sReNo a + sReNo b } -lmrDebug, nulDebug :: Bool -lmrDebug = False +nulDebug :: Bool nulDebug = False formatStats :: SStats -> [String] @@ -73,12 +72,6 @@ formatStats sst = [ ++ ", move 4+: " ++ show (sBM4p sst) ++ " (move 1%: " ++ show (if sBeta sst == 0 then 0 else 100 * sBM1 sst `div` sBeta sst) ++ ")" ] ++ - if lmrDebug - then [ - "Reduced: " ++ show (sRedu sst) ++ ", Re-benefits: " ++ show (sReBe sst) - ++ ", Re-Searched: " ++ show (sReSe sst) ++ ", Re-waste: " ++ show (sReNo sst) - ++ ", missed: " ++ show (sReMi sst) ++ ", net benefit: " - ++ show (sReBe sst - sReNo sst) ] - else if nulDebug - then [ "Null moves: " ++ show (sReBe sst) ++ ", Low: " ++ show (sReMi sst) ] - else [ "Reduced: " ++ show (sRedu sst) ++ ", Re-Searched: " ++ show (sReSe sst) ] + if nulDebug + then [ "Null moves: " ++ show (sReBe sst) ++ ", Low: " ++ show (sReMi sst) ] + else [ "Reduced: " ++ show (sRedu sst) ++ ", Re-Searched: " ++ show (sReSe sst) ] From 7e331668a2ff95fea358cb07bc16f214b76b2cca Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 19 May 2018 20:48:21 +0200 Subject: [PATCH 66/71] LMR for depth 2 & 3 too --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 48993df0..2affb76a 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "lmr4p" +progVerSuff = "lmr1p" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 96cfc4da..f554cad6 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -41,11 +41,12 @@ useTTinPv = False -- retrieve from TT in PV? minPvDepth = 2 -- from this depth we use alpha beta search -- Parameters for late move reduction: -lmrInitLv, lmrInitLim, lmrLevMin, lmrLevMax :: Int -lmrInitLv = 8 -lmrInitLim = 8500 -lmrLevMin = 0 -lmrLevMax = 15 +lmrInitLv, lmrInitLim, lmrLevMin, lmrLevMax, lmrNoDepth :: Int +lmrInitLv = 8 +lmrInitLim = 8500 +lmrLevMin = 0 +lmrLevMax = 15 +lmrNoDepth = 1 -- The late move reduction is variable and regulated by the number of re-searches -- Lower levels (towards 0) means less reductions, higher - more @@ -890,8 +891,8 @@ genAndSort nst mttmv a b d = do {-# INLINE reduceLmr #-} reduceLmr :: Bool -> Bool -> Int -> Int -> Int -> Int reduceLmr nearmatea spec d lmrlev w - | spec || d <= maxFutilDepth || nearmatea = d - | otherwise = max 1 $ d - lmrArr!(lmrlev, w) + | spec || d <= lmrNoDepth || nearmatea = d + | otherwise = max 1 $ d - lmrArr!(lmrlev, w) -- Adjust the LMR related parameters in the state moreLMR :: Bool -> Int -> Search () From 6244700a904fc3c437f4675c92383d60021ac356 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sun, 10 Jun 2018 22:42:24 +0200 Subject: [PATCH 67/71] Unify some parts between PV & ZW search --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 127 +++++++++++++++------------------------------ 2 files changed, 43 insertions(+), 86 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 2affb76a..c5179d3a 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "lmr1p" +progVerSuff = "lmru" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index f554cad6..039f7f19 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -499,7 +499,7 @@ pvSearch nst !a !b !d = do prune <- isPruneFutil d a True (staticScore pos) -- Loop thru the moves let !nsti = resetNSt (pathFromScore "low limit" a) NoKiller nst' - nstf <- pvSLoop b d prune nsti edges + nstf <- pvSLoop b d False prune nsti edges let s = cursc nstf whenAbort s $ do if pathScore s > a @@ -561,7 +561,7 @@ pvZeroW !nst !b !d = do NullMoveThreat s -> newTKiller pos d s _ -> NoKiller !nsti = resetNSt (pathFromScore "low limit" bGrain) kill1 nst' - nstf <- pvZLoop b d prune nsti edges + nstf <- pvSLoop b d True prune nsti edges let s = cursc nstf whenAbort s $ do checkFailHard "pvZLoop" bGrain b (pathScore s) @@ -626,102 +626,59 @@ nmDArr1, nmDArr2 :: UArray Int Int nmDArr1 = listArray (0, 20) [ 0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12 ] nmDArr2 = listArray (0, 20) [ 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11 ] -pvSLoop :: Int -> Int -> Bool -> NodeState -> Alt Move -> Search NodeState -pvSLoop b d p = go +pvSLoop :: Int -> Int -> Bool -> Bool -> NodeState -> Alt Move -> Search NodeState +pvSLoop b d zw p = go where go !s (Alt []) = return s go !s (Alt (e:es)) = do - (!cut, !s') <- pvInnerLoop b d p s e + (!cut, !s') <- pvInnerLoop b d zw p s e if cut then return s' else go s' $ Alt es -pvZLoop :: Int -> Int -> Bool -> NodeState -> Alt Move -> Search NodeState -pvZLoop b d p = go - where go !s (Alt []) = return s - go !s (Alt (e:es)) = do - (!cut, !s') <- pvInnerLoopZ b d p s e - if cut then return s' - else go s' $ Alt es - --- This is the inner loop of the PV search, executed at every level (except root) once per possible move +-- This is the unified inner loop of the PV & ZW search, executed at every level (except root) +-- once per possible move -- See the parameter -- Returns: flag if it was a beta cut and new status pvInnerLoop :: Int -- current beta -> Int -- current search depth + -> Bool -- zero window search? -> Bool -- prune? -> NodeState -- node status -> Move -- move to search -> Search (Bool, NodeState) -pvInnerLoop b d prune nst e = timeToAbort (True, nst) $ do - -- What about TT & killer moves??? - if prune && movno nst > 1 && canPruneMove (cpos nst) e - then do - let !nst1 = nst { movno = movno nst + 1 } - return (False, nst1) - else do - old <- get - exd <- lift $ doMove e -- do the move - if legalResult exd - then do - newNode d - modify $ \s -> s { absdp = absdp s + 1 } - s <- case exd of - Exten exd' spc -> do - when (exd' == 0 && not spc) $ do - sdiff <- lift scoreDiff - updateFutil sdiff -- e - xchangeFutil - s <- if spc - then pvInnerLoopExten b d spc exd' (deepNSt $ resetSpc nst) - else pvInnerLoopExten b d spc exd' (deepNSt nst) - xchangeFutil - return s - Final sco -> return $! pathFromScore "Final" (-sco) - Illegal -> error "Cannot be illegal here" - lift undoMove -- undo the move - modify $ \s' -> s' { absdp = absdp old, usedext = usedext old } - let s' = addToPath e s - checkFailOrPVLoop (stats old) b d e s' nst - else return (False, nst) - --- This part for the zero window search -pvInnerLoopZ :: Int -- current beta - -> Int -- current search depth - -> Bool -- prune? - -> NodeState -- node status - -> Move -- move to search - -> Search (Bool, NodeState) -pvInnerLoopZ b d prune nst e = timeToAbort (True, nst) $ do - -- What about TT & killer moves??? - if prune && canPruneMove (cpos nst) e - then do - let !nst1 = nst { movno = movno nst + 1 } - return (False, nst1) - else do - old <- get - exd <- lift $ doMove e -- do the move - -- even the legality could be checked before, maybe much cheaper - if legalResult exd - then do - newNode d - modify $ \s -> s { absdp = absdp s + 1 } - s <- case exd of - Exten exd' spc -> do - when (exd' == 0 && not spc) $ do - sdiff <- lift scoreDiff - updateFutil sdiff -- e - xchangeFutil - s <- if spc - then pvInnerLoopExtenZ b d spc exd' (deepNSt $ resetSpc nst) - else pvInnerLoopExtenZ b d spc exd' (deepNSt nst) - xchangeFutil - return s - Final sco -> return $! pathFromScore "Final" (-sco) - Illegal -> error "Cannot be illegal here" - lift undoMove -- undo the move - modify $ \s' -> s' { absdp = absdp old, usedext = usedext old } - let s' = addToPath e s - checkFailOrPVLoopZ (stats old) b d e s' nst - else return (False, nst) +pvInnerLoop b d zw prune nst e = timeToAbort (True, nst) $ do + if prune && (zw || movno nst > 1) && canPruneMove (cpos nst) e + then do + let !nst1 = nst { movno = movno nst + 1 } + return (False, nst1) + else do + old <- get + !exd <- lift $ doMove e -- do the move + if legalResult exd + then do + newNode d + modify $ \s -> s { absdp = absdp s + 1 } + s <- case exd of + Exten exd' spc -> do + when (exd' == 0 && not spc) $ do + sdiff <- lift scoreDiff + updateFutil sdiff -- e + xchangeFutil + s <- if spc + then extenFunc b d spc exd' (deepNSt $ resetSpc nst) + else extenFunc b d spc exd' (deepNSt nst) + xchangeFutil + return s + Final sco -> return $! pathFromScore "Final" (-sco) + Illegal -> error "Cannot be illegal here" + lift undoMove -- undo the move + modify $ \s' -> s' { absdp = absdp old, usedext = usedext old } + let s' = addToPath e s + checkFunc (stats old) b d e s' nst + else return (False, nst) + where extenFunc | zw = pvInnerLoopExtenZ + | otherwise = pvInnerLoopExten + checkFunc | zw = checkFailOrPVLoopZ + | otherwise = checkFailOrPVLoop resetSpc :: NodeState -> NodeState resetSpc nst = nst { spcno = movno nst } From b503d9db76bbdae59189d5e78d8c672dc9eef5b9 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sun, 10 Jun 2018 23:31:43 +0200 Subject: [PATCH 68/71] Correct LMR aplitude: distance to last capture --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 29 +++++++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index c5179d3a..d5cae26b 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "lmru" +progVerSuff = "lmruc" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index 039f7f19..b166458c 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -657,23 +657,24 @@ pvInnerLoop b d zw prune nst e = timeToAbort (True, nst) $ do then do newNode d modify $ \s -> s { absdp = absdp s + 1 } - s <- case exd of - Exten exd' spc -> do - when (exd' == 0 && not spc) $ do - sdiff <- lift scoreDiff - updateFutil sdiff -- e - xchangeFutil - s <- if spc - then extenFunc b d spc exd' (deepNSt $ resetSpc nst) - else extenFunc b d spc exd' (deepNSt nst) - xchangeFutil - return s - Final sco -> return $! pathFromScore "Final" (-sco) - Illegal -> error "Cannot be illegal here" + (s, nst1) <- case exd of + Exten exd' spc -> do + when (exd' == 0 && not spc) $ do + sdiff <- lift scoreDiff + updateFutil sdiff -- e + -- Resetting means we reduce less (only with distance to last capture) + let nst1 | spc = resetSpc nst + | otherwise = nst + xchangeFutil + s <- extenFunc b d spc exd' (deepNSt nst1) + xchangeFutil + return (s, nst1) + Final sco -> return (pathFromScore "Final" (-sco), nst) + Illegal -> error "Cannot be illegal here" lift undoMove -- undo the move modify $ \s' -> s' { absdp = absdp old, usedext = usedext old } let s' = addToPath e s - checkFunc (stats old) b d e s' nst + checkFunc (stats old) b d e s' nst1 else return (False, nst) where extenFunc | zw = pvInnerLoopExtenZ | otherwise = pvInnerLoopExten From 5b49fffc7e85bd6a566f94f5076bb68a8e4d4fb9 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sat, 15 Sep 2018 01:57:11 +0200 Subject: [PATCH 69/71] Search: QS logic change when in check No limit for check escapes, but delta pruning applies --- Main/Barbarossa.hs | 2 +- Search/Albeta.hs | 74 ++++++++++++++++++++-------------------------- 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 406282e7..132e56ff 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "aug" +progVerSuff = "tac" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Search/Albeta.hs b/Search/Albeta.hs index d5aa8251..b23fbd0c 100644 --- a/Search/Albeta.hs +++ b/Search/Albeta.hs @@ -77,10 +77,6 @@ futMinVal = 30 futDecayB = 13 futDecayW = (1 `unsafeShiftL` futDecayB) - 1 --- Parameters for quiescent search: -qsMaxChess :: Int -qsMaxChess = 2 -- max number of chess for a quiet search path - -- Parameters for null move pruning nulMargin, nulSubmrg, nulTrig :: Int nulMargin = 1 -- margin to search the null move (over beta) (in scoreGrain units!) @@ -103,8 +99,7 @@ iidNewDepth :: Int -> Int iidNewDepth = subtract 1 -- Parameter for quiescenst search -inEndlessCheck, qsDeltaMargin :: Int -inEndlessCheck = -scoreGrain -- there is a risk to be left in check +qsDeltaMargin :: Int qsDeltaMargin = 100 type Search a = CState PVState Game a @@ -448,7 +443,7 @@ insertToPvs d p ps@(q:qs) -- PV Search pvSearch :: NodeState -> Int -> Int -> Int -> Search Path pvSearch _ !a !b !d | d <= 0 = do - v <- pvQSearch a b 0 True + v <- pvQSearch a b True return $ pathFromScore ("pvQSearch 1:" ++ show v) v -- ok: fail hard in QS pvSearch nst !a !b !d = do let !inPv = crtnt nst == PVNode @@ -510,7 +505,7 @@ pvSearch nst !a !b !d = do -- PV Zero Window pvZeroW :: NodeState -> Int -> Int -> Bool -> Search Path pvZeroW !_ !b !d _ | d <= 0 = do - v <- pvQSearch bGrain b 0 True + v <- pvQSearch bGrain b True return $ pathFromScore ("pvQSearch 21:" ++ show v) v where !bGrain = b - scoreGrain pvZeroW !nst !b !d redu = do @@ -944,8 +939,8 @@ trimax a b x | otherwise = x -- PV Quiescent Search -pvQSearch :: Int -> Int -> Int -> Bool -> Search Int -pvQSearch !a !b !c front = do +pvQSearch :: Int -> Int -> Bool -> Search Int +pvQSearch !a !b front = do -- TODO: use e as first move if legal & capture -- (hdeep, tp, hsc, e, _) <- reTrieve >> lift ttRead (hdeep, tp, hsc, _, _) <- reTrieve >> lift ttRead @@ -967,17 +962,14 @@ pvQSearch !a !b !c front = do edges <- Alt <$> lift genEscapeMoves if noMove edges then return $! trimax a b (-mateScore) - else if c >= qsMaxChess - then do - when collectFens $ finWithNodes "ENDL" - return $! trimax a b inEndlessCheck - else do - -- for check extensions in case of very few moves (1 or 2): - -- if 1 move: extend 1 (same depth) - -- if 2 moves: no extension - let !esc = lenmax2 $ unalt edges - !nc = c + esc - 1 - pvQLoop b nc a edges + else do + let stp = staticScore pos + !dcut <- lift $ qsDelta $ a - stp - qsDeltaMargin + if dcut + then do + when collectFens $ finWithNodes "DELT" + return a + else pvQLoop b a edges else do let stp = staticScore pos if stp >= b @@ -997,33 +989,31 @@ pvQSearch !a !b !c front = do when collectFens $ finWithNodes "NOCA" return $! trimax a b stp else if stp > a - then pvQLoop b c stp edges - else pvQLoop b c a edges - where lenmax2 (_:_:_) = 2 - lenmax2 _ = 1 -- we know here it is not empty + then pvQLoop b stp edges + else pvQLoop b a edges -pvQLoop :: Int -> Int -> Int -> Alt Move -> Search Int -pvQLoop b c = go +pvQLoop :: Int -> Int -> Alt Move -> Search Int +pvQLoop b = go where go !s (Alt []) = return s go !s (Alt (e:es)) = do - (!cut, !s') <- pvQInnerLoop b c s e + (!cut, !s') <- pvQInnerLoop b s e if cut then return s' else go s' $ Alt es -pvQInnerLoop :: Int -> Int -> Int -> Move -> Search (Bool, Int) -pvQInnerLoop !b c !a e = timeToAbort (True, b) $ do - r <- lift $ doQSMove e - if r - then do - newNodeQS - !sc <- negate <$> pvQSearch (-b) (-a) c False - lift undoMove - if sc >= b - then return (True, b) - else if sc > a - then return (False, sc) - else return (False, a) - else return (False, a) +pvQInnerLoop :: Int -> Int -> Move -> Search (Bool, Int) +pvQInnerLoop !b !a e = timeToAbort (True, b) $ do + r <- lift $ doQSMove e + if r + then do + newNodeQS + !sc <- negate <$> pvQSearch (-b) (-a) False + lift undoMove + if sc >= b + then return (True, b) + else if sc > a + then return (False, sc) + else return (False, a) + else return (False, a) {-# INLINE finWithNodes #-} finWithNodes :: String -> Search () From 03cd2460f06f5151e5847e00c6eb2a6e7ee9e6f2 Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Thu, 27 Sep 2018 22:21:18 +0200 Subject: [PATCH 70/71] Random initialised history --- Main/Barbarossa.hs | 2 +- Moves/History.hs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 406282e7..0676138c 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "aug" +progVerSuff = "rih" data Options = Options { optConfFile :: Maybe String, -- config file diff --git a/Moves/History.hs b/Moves/History.hs index 7323bae0..b52a28e3 100644 --- a/Moves/History.hs +++ b/Moves/History.hs @@ -7,12 +7,14 @@ module Moves.History ( import Control.Monad.ST.Unsafe (unsafeIOToST) import Control.Monad.ST import Data.Bits +import Data.List (unfoldr) import Data.Ord (comparing) import qualified Data.Vector.Algorithms.Heap as H -- Intro sort was slower import qualified Data.Vector.Unboxed.Mutable as V import qualified Data.Vector.Unboxed as U import Data.Int import Data.Word +import System.Random import Struct.Struct @@ -47,8 +49,18 @@ adr' m = squares * moveHisAdr m + toSquare m ofs' :: Move -> Int ofs' m = bloff * moveHisOfs m +-- Produce small random numbers to initialize the new history +smallVals :: RandomGen g => g -> [Word32] +smallVals g = concatMap chop $ randoms g + where chop w = unfoldr f (w, 16) + f :: (Word32, Int) -> Maybe (Word32, (Word32, Int)) + f (_, 0) = Nothing + f (w, k) = Just (w .&. 3, (w `unsafeShiftR` 2, k-1)) + newHist :: IO History -newHist = V.replicate vsize 0 +newHist = do + g <- newStdGen + U.thaw $ U.fromList $ map fromIntegral $ take vsize $ smallVals g {-# INLINE histw #-} histw :: Int -> Int32 From f90e3f6f7406c5aa20a43a58a8ba7b57c0fef93e Mon Sep 17 00:00:00 2001 From: Nicu Ionita Date: Sun, 25 Nov 2018 11:36:54 +0100 Subject: [PATCH 71/71] Integration 2018-11 --- Main/Barbarossa.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main/Barbarossa.hs b/Main/Barbarossa.hs index 08067dff..5ad70ec2 100644 --- a/Main/Barbarossa.hs +++ b/Main/Barbarossa.hs @@ -39,7 +39,7 @@ progName, progVersion, progVerSuff, progAuthor :: String progName = "Barbarossa" progAuthor = "Nicu Ionita" progVersion = "0.5.0" -progVerSuff = "oct20" +progVerSuff = "i1811" data Options = Options { optConfFile :: Maybe String, -- config file