how to try not to lose against strong engines with big handicap(engine get the advantage in the opening)

Discussion of anything and everything relating to chess playing software and machines.

Moderator: Ras

Uri Blass
Posts: 11266
Joined: Thu Mar 09, 2006 12:37 am
Location: Tel-Aviv Israel

how to try not to lose against strong engines with big handicap(engine get the advantage in the opening)

Post by Uri Blass »

My idea is simply to make the engines feel bad.
The way to do it is to try all the possible combinations of 2 moves and choose the first move of the combination that leads to the lowest score(I think that it may be improved by using some engine to prune part of the combination and try all the logical combinations of 3 moves).

Still did not work against Stockfish developement version with 10K nodes per second but was closer than earlier tries.

[pgn][Event "Knight-Odds 2-Ply White Search Book"]
[Site "?"]
[Date "????.??.??"]
[Round "?"]
[White "Brute-force 2-Ply (No Engine, No Nb1)"]
[Black "Stockfish 30_09 (10k nodes)"]
[Result "0-1"]
[BlackElo "2200"]
[WhiteElo "2000"]
[TimeControl "300+3"]
[SetUp "1"]
[FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R1BQKBNR w KQkq - 0 1"]
[Termination "normal"]
[PlyCount "192"]
[WhiteType "program"]
[BlackType "program"]

1. e4 c6 2. d4 d6 3. Bd2 g6 4. e5 Bh6 5. f4 Bg7 6. Qf3 Be6 7. O-O-O Nh6 8.
Ne2 Na6 9. Kb1 Qc7 10. Rg1 f6 11. exf6 exf6 12. f5 Bxf5 13. g4 Bc8 14. g5
Nf5 15. gxf6 Bxf6 16. Ng3 Be7 17. Re1 Rf8 18. Qc3 Bd7 19. Bxa6 bxa6 20. d5
O-O-O 21. dxc6 Be8 22. Qc4 Bh4 23. Rxe8 Rdxe8 24. Nxf5 Rxf5 25. Qxh4 Rc5
26. a4 Rxc6 27. Bc3 Rc4 28. Qf6 Qe7 29. Qf1 d5 30. Qd3 Qd6 31. b3 Rc6 32.
Qd2 Kb8 33. Rg5 Qe6 34. Re5 Qf7 35. Rxe8+ Qxe8 36. Kb2 Qe4 37. Qf2 Qf5 38.
Qd4 Rc8 39. Qe3 g5 40. a5 Kb7 41. Qe2 h5 42. Qg2 g4 43. Bd4 h4 44. c3 Rc6
45. Qe2 Re6 46. Qd2 h3 47. Ka3 Re8 48. Bc5 g3 49. hxg3 Qe5 50. Bg1 Re7 51.
g4 Rc7 52. g5 Rf7 53. Qd3 Rc7 54. Qd2 Kc8 55. Kb2 Qe4 56. Qc1 d4 57. c4
Qg2+ 58. Qc2 Qxc2+ 59. Kxc2 Rg7 60. Kd3 Rxg5 61. Bh2 Rxa5 62. Kxd4 Ra2 63.
Bg3 a5 64. Ke3 Kd7 65. Be5 Ra3 66. Kf2 Rxb3 67. Bd4 a4 68. Bh8 a5 69. c5
Kc6 70. Kg1 Ra3 71. Kh1 Rd3 72. Kh2 Re3 73. Kh1 Rg3 74. Be5 Rb3 75. Bd6 Rf3
76. Kh2 Re3 77. Kg1 Re2 78. Kh1 Re3 79. Bb8 Rd3 80. Bd6 Re3 81. Kg1 Rd3 82.
Be7 Rb3 83. Bh4 Rf3 84. Be7 a3 85. Bd6 Re3 86. Kf2 Re6 87. Kg3 a2 88. Kxh3
a4 89. Bb8 a1=Q 90. Kg2 a3 91. Bd6 Qd4 92. Bg3 a2 93. Bb8 a1=Q 94. Bg3 Qg4
95. Kh2 Re2+ 96. Bf2 Rxf2# 0-1
[/pgn]
Here is the python code for that task(comments are in hebrew because I use hebrew to discuss with gemini:

Code: Select all

import os
import chess
import chess.pgn
import chess.engine

STOCKFISH_PATH = "stockfish-30_09.exe"
PGN_OUTPUT = "knight_odds_book_2ply_white.pgn"

# עמדת התחלה ללא פרש ב-b1
START_FEN_KNIGHT_ODDS = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R1BQKBNR w KQkq - 0 1"

BLACK_NODES = 10000   # 10K עמדות לשחור

def score_to_white_cp(score_obj):
    """ממיר תוצאת מנוע לסנטי-רגלים מנקודת המבט של לבן"""
    pov = score_obj.pov(chess.WHITE)
    if pov.is_mate():
        m = pov.mate()
        return (100000.0 - m * 10) if m > 0 else (-100000.0 - m * 10)
    cp = pov.score()
    return float(cp) if cp is not None else 0.0

def evaluate_position_white(engine, board):
    """הערכת סטוקפיש מנקודת המבט של לבן לפי 10k צמתים"""
    info = engine.analyse(board, chess.engine.Limit(nodes=BLACK_NODES))
    return score_to_white_cp(info["score"])

def get_black_reply(engine, board):
    """מחזיר את המסע של שחור לפי סטוקפיש (10k צמתים)"""
    res = engine.play(board, chess.engine.Limit(nodes=BLACK_NODES))
    return res.move

def main():
    if not os.path.exists(STOCKFISH_PATH):
        print(f"שגיאה: קובץ סטוקפיש לא נמצא בנתיב '{STOCKFISH_PATH}'!")
        return

    print("=== מתחיל בניית ספר פתיחות (Knight-Odds: ללא פרש ב-b1) ===")
    print("שיטה: בחינת כל הצירופים של 2 מסעי לבן קדימה מול מענה סטוקפיש 10k לשחור\n")

    engine = chess.engine.SimpleEngine.popen_uci(STOCKFISH_PATH)
    engine.configure({"Threads": 1, "Hash": 256})

    book_moves = []
    move_number = 1

    try:
        while True:
            # שחזור העמדה עד למסע הנוכחי
            board = chess.Board(START_FEN_KNIGHT_ODDS)
            for m in book_moves:
                board.push(m)

            if board.is_game_over():
                outcome = board.outcome()
                print(f"\nהמשחק הסתיים: {outcome.result()} ({outcome.termination.name})")
                break

            legal_w1 = list(board.legal_moves)
            if not legal_w1:
                print("\nאין מסעים חוקיים ללבן.")
                break

            print(f"--- מסע {move_number} של לבן ---")
            print(f"בוחן צירופי 2 מסעים קדימה (מתוך {len(legal_w1)} אפשרויות למסע הראשון)...")

            best_w1_move = None
            best_b1_move = None  # נשמור את המענה המדויק של שחור שנבחר בלולאה!
            best_score = -float("inf")
            best_combination_info = ""

            # לולאת המסע הראשון של לבן (W1)
            for w1 in legal_w1:
                w1_san = board.san(w1)
                board.push(w1)

                if board.is_game_over():
                    outcome = board.outcome()
                    score = 100000.0 if outcome.winner == chess.WHITE else (0.0 if outcome.winner is None else -100000.0)
                    if score > best_score:
                        best_score = score
                        best_w1_move = w1
                        best_b1_move = None
                        best_combination_info = f"{w1_san} (סיום משחק מיידי)"
                    board.pop()
                    continue

                # מענה ראשון של שחור (B1)
                b1 = get_black_reply(engine, board)
                if not b1:
                    board.pop()
                    continue

                b1_san = board.san(b1)
                board.push(b1)

                if board.is_game_over():
                    outcome = board.outcome()
                    score = 100000.0 if outcome.winner == chess.WHITE else (0.0 if outcome.winner is None else -100000.0)
                    if score > best_score:
                        best_score = score
                        best_w1_move = w1
                        best_b1_move = b1
                        best_combination_info = f"{w1_san} -> {b1_san} (סיום משחק)"
                    board.pop()
                    board.pop()
                    continue

                # לולאת המסע השני של לבן (W2)
                legal_w2 = list(board.legal_moves)
                for w2 in legal_w2:
                    w2_san = board.san(w2)
                    board.push(w2)

                    if board.is_game_over():
                        outcome = board.outcome()
                        score = 100000.0 if outcome.winner == chess.WHITE else (0.0 if outcome.winner is None else -100000.0)
                    else:
                        # מענה שני של שחור (B2)
                        b2 = get_black_reply(engine, board)
                        if b2:
                            board.push(b2)
                            score = evaluate_position_white(engine, board)
                            board.pop()
                        else:
                            score = evaluate_position_white(engine, board)

                    board.pop()  # ביטול w2

                    if score > best_score:
                        best_score = score
                        best_w1_move = w1
                        best_b1_move = b1  # מקבעים את b1 שהוביל לתוצאה הטובה ביותר
                        best_combination_info = f"{w1_san} -> {b1_san} -> {w2_san} (הערכה ללבן: {score:+.2f})"

                board.pop()  # ביטול b1
                board.pop()  # ביטול w1

            # 1. קיבוע המסע הנבחר של לבן לספר
            chosen_w1_san = board.san(best_w1_move)
            board.push(best_w1_move)
            book_moves.append(best_w1_move)

            print(f"-> נבחר ללבן לספר: {chosen_w1_san}")
            print(f"   הצירוף המוביל שנמצא: {best_combination_info}")

            if board.is_game_over():
                outcome = board.outcome()
                print(f"\nהמשחק הסתיים לאחר מסע לבן: {outcome.result()}")
                break

            # 2. שחור משחק בדיוק את המסע שחושב בלולאה (b1) – עקביות מלאה של 100%
            if best_b1_move:
                chosen_black_san = board.san(best_b1_move)
                board.push(best_b1_move)
                book_moves.append(best_b1_move)
                print(f"-> שחור משחק לספר: {chosen_black_san}\n")
            else:
                # גיבוי למקרה קצה נדיר
                black_move = get_black_reply(engine, board)
                chosen_black_san = board.san(black_move)
                board.push(black_move)
                book_moves.append(black_move)
                print(f"-> שחור משחק לספר (חישוב ישיר): {chosen_black_san}\n")

            if board.is_game_over():
                outcome = board.outcome()
                print(f"\nהמשחק הסתיים לאחר מסע שחור: {outcome.result()}")
                break

            move_number += 1

    finally:
        engine.quit()

    # שמירה ל-PGN
    final_game = chess.pgn.Game()
    final_game.headers["Event"] = "Knight-Odds 2-Ply White Search Book"
    final_game.headers["White"] = "Brute-force 2-Ply (No Engine, No Nb1)"
    final_game.headers["Black"] = "Stockfish 30_09 (10k nodes)"
    final_game.headers["FEN"] = START_FEN_KNIGHT_ODDS
    final_game.headers["SetUp"] = "1"

    node = final_game
    b_verify = chess.Board(START_FEN_KNIGHT_ODDS)
    for m in book_moves:
        node = node.add_variation(m)
        b_verify.push(m)

    if b_verify.is_game_over():
        final_game.headers["Result"] = b_verify.result()

    with open(PGN_OUTPUT, "w", encoding="utf-8") as f:
        print(final_game, file=f, end="\n\n")

    print(f"הספר נשמר בהצלחה ב-PGN: '{PGN_OUTPUT}'")
    input("\nלחץ Enter לסיום...")

if __name__ == "__main__":
    main()
Uri Blass
Posts: 11266
Joined: Thu Mar 09, 2006 12:37 am
Location: Tel-Aviv Israel

Re: how to try not to lose against strong engines with big handicap(engine get the advantage in the opening)

Post by Uri Blass »

I could produce a game when white won but the game is not reproducable because the python code did not clear the hash when it went forward and backeard.

Here is the game:

[Event "Parallel Knight-Odds 2-Ply Book"]
[Site "?"]
[Date "????.??.??"]
[Round "?"]
[White "Brute-force 2-Ply (6 workers, No Nb1)"]
[Black "Stockfish 30_09 (10k nodes, Clean Replay)"]
[Result "1-0"]
[FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R1BQKBNR w KQkq - 0 1"]
[SetUp "1"]

1. e4 d6 2. d4 g6 3. f3 Bd7 4. f4 a5 5. c3 a4 6. Nf3 Nf6 7. e5 Ng8 8. Bc4 Nh6 9. O-O Bg7 10. Qe1 Nc6 11. h3 O-O 12. g4 b5 13. Bd5 Ra6 14. f5 dxe5 15. dxe5 Bc8 16. c4 Nxf5 17. gxf5 Bxf5 18. cxb5 Qxd5 19. bxa6 Bxh3 20. Rf2 Bg4 21. Qf1 Bxf3 22. Rxf3 Nxe5 23. Rg3 Nc4 24. Bf4 a3 25. b3 Bxa1 26. Qxa1 Qc5+ 27. Kg2 Nb2 28. Qf1 Qc6+ 29. Kh2 Ra8 30. Qe2 Qxa6 31. Qxe7 Qb5 32. Qe5 Qxe5 33. Bxe5 c5 34. Rc3 f5 35. Bd6 Nd1 36. Rc2 Re8 37. Bxc5 Ne3 38. Rc1 Ng4+ 39. Kg3 Re2 40. Rd1 g5 41. Rf1 Nh6 42. Bxa3 f4+ 43. Kf3 Re3+ 44. Kg2 Rg3+ 45. Kh1 Nf5 46. Bc1 Nd4 47. Kh2 Rc3 48. Bxf4 Rc2+ 49. Kh3 gxf4 50. Rxf4 Ne6 51. Rf6 Ng7 52. Ra6 h5 53. b4 Rb2 54. a3 Rb3+ 55. Kh4 Kf7 56. Ra5 Re3 57. b5 Kg6 58. Ra6+ Kf5 59. Ra7 Kf6 60. Ra6+ Kf5 61. Ra7 Re1 62. Rd7 Rh1+ 63. Kg3 Ne6 64. Rf7+ Kg5 65. Re7 Kf5 66. Rh7 Kg6 67. Rd7 Rg1+ 68. Kf2 Rb1 69. a4 Rb2+ 70. Kf3 Rb3+ 71. Kf2 Kf5 72. Rd2 Ng5 73. Ra2 Ne4+ 74. Kf1 Kg4 75. a5 Kf3 76. Kg1 Nc3 77. Ra1 Nxb5 78. Kh2 Nd4 79. Ra4 Nb5 80. a6 Na7 81. Ra1 Rb2+ 82. Kh1 Kg3 83. Ra3+ Kf4 84. Ra1 Re2 85. Kg1 Rd2 86. Ra3 h4 87. Ra1 h3 88. Ra5 Nb5 89. a7 h2+ 90. Kh1 Kg3 91. Ra1 Nc7 92. a8=Q Nxa8 93. Ra3+ Kh4 94. Ra6 Nb6 95. Rxb6 Rd1+ 96. Kxh2 Ra1 97. Rg6 Ra7 98. Rg3 Ra6 99. Rg7 Rc6 100. Rg2 Rf6 101. Rd2 Kg5 102. Kg3 Kh6 103. Kg2 Kg7 104. Kg3 Rg6+ 105. Kf3 Kf8 106. Ke3 Ra6 107. Rd1 Ke7 108. Kf2 Ra3 109. Re1+ Kd6 110. Rg1 Ra2+ 111. Ke3 Kd5 112. Rc1 Ra3+ 113. Kf2 Ke4 114. Rc4+ Kf5 115. Kf1 Ra2 116. Rd4 Ke5 117. Rc4 Kd6 118. Re4 Kc7 119. Re2 Ra5 120. Re8 Kd7 121. Re4 Kd6 122. Kg2 Ra3 123. Kh2 Kd5 124. Rb4 Ke5 125. Rg4 Kf5 126. Rd4 Kg5 127. Re4 Rb3 128. Ra4 Re3 129. Rc4 Rf3 130. Rd4 Ra3 131. Rb4 Kf5 132. Rd4 Kg5 133. Rc4 Kf5 134. Rh4 Ra8 135. Kg2 Ra2+ 136. Kf3 Ra3+ 137. Ke2 Ke5 138. Rh7 Kf4 139. Rd7 Ke4 140. Rh7 Ra2+ 141. Kf1 Kf4 142. Rh8 Kf3 143. Re8 Ra1+ 144. Re1 Ra2 145. Re8 Ra1+ 146. Re1 Kg3 147. Ke2 Kg2 148. Rxa1 Kg3 149. Ra4 Kg2 150. Ra6 Kh3 151. Kf3 Kh2 152. Ra1 Kh3 153. Rh1# 1-0
Uri Blass
Posts: 11266
Joined: Thu Mar 09, 2006 12:37 am
Location: Tel-Aviv Israel

Re: how to try not to lose against strong engines with big handicap(engine get the advantage in the opening)

Post by Uri Blass »

The following game is reproducable but stockfish clear hash between moves(16k hash tables for stockfish but stockfish does not need much with only 10K nodes per move)

[pgn][Event "Pure Replay Knight-Odds Book"]
[Site "?"]
[Date "????.??.??"]
[Round "?"]
[White "Brute-force 2-Ply (6 workers, No Nb1)"]
[Black "Stockfish 30_09 (10k nodes, Pure History Replay)"]
[Result "1-0"]
[FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R1BQKBNR w KQkq - 0 1"]
[SetUp "1"]

1. h3 d6 2. Nf3 e5 3. e4 Be7 4. Be2 Bf6 5. c3 Ne7 6. d4 Nec6 7. Be3 Bd7 8. g4 h6 9. Rg1 Qe7 10. d5 Nd8 11. h4 g6 12. h5 Bc8 13. a4 g5 14. b4 c6 15. c4 Nd7 16. Qc2 a5 17. b5 O-O 18. Kf1 Qe8 19. Rh1 Qe7 20. Nd2 Bg7 21. f3 Nf6 22. Ra3 Nd7 23. Bf2 Re8 24. Bg3 Nf6 25. Rc3 Rf8 26. Qa2 Re8 27. Qc2 Qc7 28. Kg2 Nd7 29. Rf1 Nc5 30. Rd1 Re7 31. Bh2 Bd7 32. Rh1 Re8 33. Rg1 f5 34. exf5 e4 35. Rf1 cxb5 36. cxb5 Nf7 37. f6 Bxf6 38. fxe4 Bxc3 39. Qxc3 Re5 40. Qf3 Be8 41. Bxe5 Nxe5 42. Qf8+ Kh7 43. Qf5+ Kh8 44. Qf8+ Kh7 45. Qf5+ Kg7 46. Qf6+ Kg8 47. Qxh6 Qg7 48. Qxd6 Ned3 49. Bxd3 Nxd3 50. Rf6 Nf4+ 51. Kf2 Bd7 52. h6 Qh7 53. Kg3 Re8 54. Nf3 Ne2+ 55. Kf2 Qe7 56. Nxg5 Nc3 57. Kg2 Bxg4 58. h7+ Qxh7 59. Rg6+ Qg7 60. Qf6 Bf3+ 61. Kxf3 Re7 62. Rxg7+ Rxg7 63. Qd8# 1-0

[/pgn]
Uri Blass
Posts: 11266
Joined: Thu Mar 09, 2006 12:37 am
Location: Tel-Aviv Israel

Re: how to try not to lose against strong engines with big handicap(engine get the advantage in the opening)

Post by Uri Blass »

This draw seems to be without clear hash

[pgn][Event "Top-10 + Predicted W2 Knight-Odds Book"]
[Site "?"]
[Date "????.??.??"]
[Round "?"]
[White "Top-10 + Predicted (Depth 10) + 2-Ply Brute-Force (6 workers)"]
[Black "Stockfish 30_09 (10k nodes, Cumulative Clean Replay)"]
[Result "1/2-1/2"]
[FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R1BQKBNR w KQkq - 0 1"]
[SetUp "1"]

1. e4 d6 2. c3 e5 3. d4 Nf6 4. Bc4 Be7 5. dxe5 dxe5 6. Qxd8+ Bxd8 7. f4 Nfd7 8. f5 a5 9. Be3 a4 10. h4 Nf6 11. Nf3 b5 12. Bxb5+ c6 13. Bf1 Nbd7 14. O-O-O Bc7 15. h5 h6 16. Nd2 O-O 17. Bf2 Rd8 18. Bh4 Ba6 19. Bxa6 Rxa6 20. g4 Nf8 21. g5 hxg5 22. Bxg5 N8h7 23. Bh4 Bb6 24. Kc2 Raa8 25. Rh3 Bc5 26. Rdh1 Rxd2+ 27. Kxd2 Nxe4+ 28. Kc2 f6 29. Rd3 Nhg5 30. Re1 Re8 31. b3 Nf2 32. Rg3 Nfh3 33. Rh1 Nf2 34. Re1 axb3+ 35. axb3 Nfe4 36. Rg4 Nf2 37. Rc4 Nf3 38. Bxf2 Bxf2 39. Rf1 Ra8 40. Ra4 Ne1+ 41. Kd2 Rd8+ 42. Ke2 Nd3 43. Rxf2 Nxf2 44. Kxf2 c5 45. Rg4 Kh8 46. Rg6 Rb8 47. Ke3 Rxb3 48. h6 Rxc3+ 49. Kd2 Rb3 50. hxg7+ Kg8 51. Kc2 Rb4 52. Kd2 Rd4+ 53. Kc3 Rf4 54. Rxf6 Kxg7 55. Re6 Rxf5 56. Rc6 Rf1 57. Kd2 Rb1 58. Re6 Rb2+ 59. Kd3 c4+ 60. Ke4 Rh2 61. Kf5 c3 62. Ke4 Rh6 63. Re7+ Kf6 64. Rxe5 Rh4+ 65. Kd5 Rh8 66. Ke4 c2 67. Rf5+ Kg7 68. Rc5 Rh4+ 69. Ke3 Rh8 70. Kd4 Rd8+ 71. Ke4 Ra8 72. Rc3 Kh8 73. Rc6 Ra2 74. Kd4 Kg7 75. Ke3 Kh8 76. Kf3 Ra1 77. Rxc2 Ra6 78. Kg3 Kg7 79. Kg2 Rg6+ 80. Kh3 Rb6 81. Kh2 Kh7 82. Rc5 Kg7 83. Ra5 Rd6 84. Kg3 Rc6 85. Ra3 Rc2 86. Rd3 Rc5 87. Rd1 Rb5 88. Rd6 Rb3+ 89. Kf4 Rc3 90. Ra6 Kg8 91. Kf5 Rc2 92. Kg6 Kf8 93. Kf6 Ke8 94. Ke6 Rd2 95. Ra8+ Rd8 96. Ra1 Rd2 97. Kf6 Rh2 98. Rb1 Kd7 99. Kg6 Ke7 100. Kf5 Rc2 101. Rb8 Kd6 102. Rb1 Rc4 103. Rh1 Rc3 104. Ra1 Rc5+ 105. Kg4 Ke5 106. Kg3 Rc3+ 107. Kf2 Kf4 108. Ra2 Kg4 109. Ra1 Rc7 110. Ra4+ Kh3 111. Kf3 Rc1 112. Ra6 Kh4 113. Ra7 Kg5 114. Rb7 Kf6 115. Rb4 Re1 116. Kf4 Rg1 117. Rb2 Kg7 118. Kf3 Kh6 119. Rb5 Rg6 120. Rb4 Re6 121. Rf4 Kh5 122. Rb4 Rf6+ 123. Rf4 Rxf4+ 124. Kxf4 1/2-1/2
[/pgn]