diff --git a/__pycache__/pgn_parser.cpython-39.pyc b/__pycache__/pgn_parser.cpython-39.pyc index 54e75d0..c7f47fc 100644 Binary files a/__pycache__/pgn_parser.cpython-39.pyc and b/__pycache__/pgn_parser.cpython-39.pyc differ diff --git a/__pycache__/stockfish.cpython-39.pyc b/__pycache__/stockfish.cpython-39.pyc index a5efe96..04c8962 100644 Binary files a/__pycache__/stockfish.cpython-39.pyc and b/__pycache__/stockfish.cpython-39.pyc differ diff --git a/data/model10.txt b/data/model10.txt new file mode 100644 index 0000000..d5165b3 --- /dev/null +++ b/data/model10.txt @@ -0,0 +1,51 @@ +iter Level 01 Level 05 Level 10 Level 15 Level 20 + 1: 41 35 22 20 24 + 2: 34 34 31 35 26 + 3: 30 15 34 26 21 + 4: 30 30 27 22 22 + 5: 15 28 38 29 31 + 6: 33 40 26 24 19 + 7: 44 31 24 43 37 + 8: 19 18 43 36 24 + 9: 20 42 39 40 30 + 10: 30 48 13 22 22 + 11: 46 36 30 25 29 + 12: 35 12 32 24 26 + 13: 20 31 39 32 18 + 14: 46 36 34 24 32 + 15: 28 35 35 26 35 + 16: 38 49 26 33 23 + 17: 13 50 26 23 30 + 18: 24 34 19 19 25 + 19: 40 30 40 29 28 + 20: 45 44 27 9 19 + 21: 27 38 26 28 26 + 22: 45 47 30 43 26 + 23: 56 25 36 36 25 + 24: 36 15 19 29 18 + 25: 36 44 32 27 31 + 26: 49 31 27 35 24 + 27: 44 24 27 28 18 + 28: 20 72 30 21 20 + 29: 15 42 23 35 29 + 30: 16 13 41 22 18 + 31: 10 24 14 25 24 + 32: 35 38 27 35 27 + 33: 17 29 30 26 14 + 34: 46 48 14 36 35 + 35: 47 32 27 29 37 + 36: 38 41 36 22 28 + 37: 35 61 16 33 17 + 38: 61 31 34 38 36 + 39: 36 38 24 35 18 + 40: 51 28 28 30 18 + 41: 36 38 22 38 18 + 42: 59 29 30 36 32 + 43: 26 29 32 33 27 + 44: 20 36 25 22 18 + 45: 26 28 21 28 23 + 46: 46 40 17 25 27 + 47: 54 28 24 30 23 + 48: 40 34 19 36 25 + 49: 37 34 33 46 18 + 50: 12 58 22 27 18 diff --git a/data/model12.txt b/data/model12.txt new file mode 100644 index 0000000..5052621 --- /dev/null +++ b/data/model12.txt @@ -0,0 +1,51 @@ +iter Level 01 Level 05 Level 10 Level 15 Level 20 + 1: 31 48 34 40 23 + 2: 25 30 22 30 17 + 3: 43 20 19 46 26 + 4: 27 26 22 39 30 + 5: 32 37 16 24 17 + 6: 39 21 44 26 24 + 7: 49 40 23 36 27 + 8: 29 40 23 24 32 + 9: 48 31 23 26 11 + 10: 27 47 17 45 29 + 11: 34 33 32 31 26 + 12: 28 31 17 19 27 + 13: 39 33 26 13 31 + 14: 54 36 37 23 24 + 15: 30 39 27 46 28 + 16: 36 25 24 32 26 + 17: 33 31 18 36 28 + 18: 64 18 30 26 13 + 19: 33 40 24 42 21 + 20: 43 45 36 38 16 + 21: 58 35 36 34 23 + 22: 31 28 35 22 36 + 23: 44 21 25 24 26 + 24: 39 29 19 19 24 + 25: 23 16 47 31 20 + 26: 56 13 28 21 24 + 27: 29 38 36 34 32 + 28: 36 21 27 36 36 + 29: 26 45 21 32 34 + 30: 53 48 25 39 37 + 31: 40 40 14 24 37 + 32: 60 32 35 40 21 + 33: 16 26 26 20 36 + 34: 39 28 18 39 34 + 35: 15 25 29 17 23 + 36: 35 26 34 27 27 + 37: 35 41 29 29 31 + 38: 34 24 27 36 39 + 39: 41 42 33 28 39 + 40: 59 41 34 32 27 + 41: 35 38 19 27 28 + 42: 23 37 39 27 36 + 43: 31 39 27 38 27 + 44: 61 45 27 29 26 + 45: 80 20 31 30 29 + 46: 48 33 23 19 23 + 47: 35 29 17 33 24 + 48: 37 23 18 32 35 + 49: 23 27 11 30 31 + 50: 37 38 32 19 24 diff --git a/data/model14.txt b/data/model14.txt new file mode 100644 index 0000000..2c96e03 --- /dev/null +++ b/data/model14.txt @@ -0,0 +1,52 @@ +iter Level 01 Level 05 Level 10 Level 15 Level 20 + 1: 27 42 51 31 27 + 2: 45 41 31 19 27 + 3: 24 37 35 32 28 + 4: 17 28 38 20 21 + 5: 44 33 51 32 27 + 6: 55 38 27 32 20 + 7: 57 41 40 34 34 + 8: 37 55 25 36 38 + 9: 35 12 28 27 21 + 10: 20 48 29 39 34 + 11: 51 27 32 30 35 + 12: 50 61 25 34 28 + 13: 43 42 23 20 27 + 14: 38 21 38 34 28 + 15: 16 34 15 36 16 + 16: 34 41 34 25 20 + 17: 29 34 26 32 29 + 18: 35 42 27 26 29 + 19: 43 34 30 41 26 + 20: 40 51 32 35 31 + 21: 30 34 35 34 31 + 22: 32 46 18 30 30 + 23: 36 29 24 29 27 + 24: 74 39 24 31 20 + 25: 58 41 35 17 19 + 26: 36 51 27 42 35 + 27: 37 29 27 6 33 + 28: 37 31 29 23 40 + 29: 33 37 25 13 33 + 30: 45 18 31 26 20 + 31: 38 38 37 29 21 + 32: 91 47 42 20 21 + 33: 43 49 67 26 37 + 34: 82 30 30 41 21 + 35: 40 28 36 26 24 + 36: 32 32 29 21 26 + 37: 33 29 15 40 28 + 38: 28 24 35 25 31 + 39: 20 35 39 22 31 + 40: 27 21 30 19 14 + 41: 28 30 29 29 28 + 42: 30 17 31 25 25 + 43: 43 31 24 17 12 + 44: 56 35 30 33 24 + 45: 35 24 31 25 21 + 46: 11 53 32 32 16 + 47: 41 36 6 32 31 + 48: 38 37 44 37 30 + 49: 29 24 21 25 31 + 50: 21 36 36 33 24 +win: 0 0 0 0 0 diff --git a/data/model16.txt b/data/model16.txt new file mode 100644 index 0000000..3d0e169 --- /dev/null +++ b/data/model16.txt @@ -0,0 +1,52 @@ +iter Level_01 Level_05 Level_10 Level_15 Level_20 + 1: 53 27 19 32 12 + 2: 36 31 35 47 34 + 3: 29 39 16 34 23 + 4: 41 39 33 36 22 + 5: 27 47 30 35 34 + 6: 31 47 41 14 31 + 7: 52 16 48 13 30 + 8: 45 34 26 26 27 + 9: 83 46 37 27 29 + 10: 26 37 39 26 26 + 11: 43 38 35 24 41 + 12: 38 41 29 29 31 + 13: 45 33 35 43 32 + 14: 23 41 21 29 15 + 15: 36 19 26 43 13 + 16: 41 32 40 19 18 + 17: 43 25 32 21 30 + 18: 33 47 25 31 18 + 19: 44 39 49 42 20 + 20: 30 44 25 26 24 + 21: 32 43 19 22 33 + 22: 35 18 33 24 27 + 23: 52 32 29 19 17 + 24: 28 39 22 32 13 + 25: 38 40 20 20 22 + 26: 35 35 31 34 17 + 27: 24 44 31 16 26 + 28: 52 29 25 29 25 + 29: 30 38 32 33 27 + 30: 85 34 24 31 24 + 31: 50 19 49 9 23 + 32: 48 19 35 28 23 + 33: 57 20 29 21 24 + 34: 35 30 34 15 27 + 35: 25 33 30 35 25 + 36: 52 27 29 20 20 + 37: 37 33 42 9 29 + 38: 25 33 46 34 9 + 39: 50 28 32 16 17 + 40: 25 37 15 24 37 + 41: 85 54 26 36 17 + 42: 53 32 27 21 28 + 43: 18 28 24 29 16 + 44: 53 30 16 22 31 + 45: 43 35 23 25 33 + 46: 52 37 36 16 24 + 47: 62 37 34 39 24 + 48: 47 31 33 27 23 + 49: 35 45 32 24 26 + 50: 59 33 26 21 36 +win: 0 0 0 0 0 diff --git a/data/model18.txt b/data/model18.txt new file mode 100644 index 0000000..3e0dcbc --- /dev/null +++ b/data/model18.txt @@ -0,0 +1,52 @@ +iter Level_01 Level_05 Level_10 Level_15 Level_20 + 1: 40 22 39 33 27 + 2: 33 28 26 15 29 + 3: 41 41 39 29 23 + 4: 27 43 28 37 28 + 5: 41 38 41 17 23 + 6: 36 42 39 19 25 + 7: 39 26 33 23 31 + 8: 36 50 28 18 27 + 9: 59 49 47 43 29 + 10: 49 43 20 25 23 + 11: 50 33 26 27 19 + 12: 30 42 24 27 29 + 13: 31 40 53 25 19 + 14: 40 21 37 16 20 + 15: 35 29 45 28 23 + 16: 29 38 36 29 15 + 17: 35 36 17 18 16 + 18: 32 17 46 30 25 + 19: 28 31 22 33 21 + 20: 31 17 36 19 20 + 21: 43 22 20 32 28 + 22: 33 26 27 33 29 + 23: 28 36 23 32 28 + 24: 15 46 31 33 33 + 25: 44 31 30 27 24 + 26: 39 26 27 24 25 + 27: 41 28 27 26 21 + 28: 24 19 33 32 16 + 29: 40 51 33 30 27 + 30: 31 30 28 37 26 + 31: 43 35 34 49 24 + 32: 32 28 18 24 30 + 33: 45 29 42 50 32 + 34: 28 36 38 28 27 + 35: 70 33 30 28 21 + 36: 32 35 29 31 21 + 37: 71 30 27 24 31 + 38: 16 26 23 17 24 + 39: 46 32 35 24 36 + 40: 25 11 33 33 26 + 41: 48 43 34 36 22 + 42: 44 17 25 22 33 + 43: 44 35 41 36 33 + 44: 29 37 30 28 31 + 45: 68 34 37 17 28 + 46: 23 33 45 27 27 + 47: 28 42 31 32 30 + 48: 36 26 39 34 34 + 49: 64 31 36 34 20 + 50: 27 47 34 36 23 +win: 0 0 0 0 0 diff --git a/data/model20.txt b/data/model20.txt new file mode 100644 index 0000000..781dc93 --- /dev/null +++ b/data/model20.txt @@ -0,0 +1,52 @@ +iter Level 01 Level 05 Level 10 Level 15 Level 20 + 1: 98 34 31 24 34 + 2: 45 17 31 35 29 + 3: 31 42 21 40 30 + 4: 55 34 50 28 21 + 5: 41 40 37 32 25 + 6: 71 39 38 30 26 + 7: 56 35 33 28 22 + 8: 46 29 17 33 19 + 9: 51 41 60 43 26 + 10: 34 17 31 34 16 + 11: 52 35 31 41 31 + 12: 36 31 25 34 28 + 13: 49 43 19 32 26 + 14: 43 46 39 25 27 + 15: 43 30 45 29 32 + 16: 37 21 32 39 29 + 17: 25 30 30 43 24 + 18: 40 29 38 45 26 + 19: 113 73 34 22 30 + 20: 34 29 21 42 27 + 21: 33 26 49 29 25 + 22: 27 42 31 35 29 + 23: 47 66 40 28 27 + 24: 37 42 34 28 38 + 25: 65 30 26 27 29 + 26: 58 31 30 30 29 + 27: 48 31 23 33 34 + 28: 52 30 19 33 36 + 29: 38 45 53 19 33 + 30: 55 35 38 36 26 + 31: 32 28 22 21 28 + 32: 39 81 26 30 26 + 33: 39 43 29 47 28 + 34: 38 43 42 34 29 + 35: 28 35 27 26 27 + 36: 25 25 52 36 27 + 37: 45 25 36 35 35 + 38: 7 35 47 35 37 + 39: 37 29 35 36 20 + 40: 35 30 27 35 24 + 41: 48 32 37 25 18 + 42: 35 35 25 31 38 + 43: 38 26 27 26 28 + 44: 42 64 42 20 26 + 45: 42 28 35 31 32 + 46: 40 35 33 30 27 + 47: 36 53 41 29 31 + 48: 29 37 34 29 28 + 49: 28 34 38 37 23 + 50: 40 25 39 24 33 +win: 0 0 0 0 0 diff --git a/data/model22.txt b/data/model22.txt new file mode 100644 index 0000000..aa0f96e --- /dev/null +++ b/data/model22.txt @@ -0,0 +1,52 @@ +iter Level_01 Level_05 Level_10 Level_15 Level_20 + 1: 51 33 30 27 24 + 2: 55 22 34 26 21 + 3: 38 49 34 21 32 + 4: 40 28 35 34 38 + 5: 41 45 34 27 23 + 6: 30 34 28 37 26 + 7: 39 24 35 34 28 + 8: 56 46 26 30 24 + 9: 99 29 40 34 27 + 10: 21 48 29 34 31 + 11: 37 29 23 33 24 + 12: 40 22 31 30 41 + 13: 61 42 29 26 27 + 14: 39 37 28 27 31 + 15: 63 50 27 34 27 + 16: 46 14 29 32 30 + 17: 74 32 33 15 27 + 18: 33 28 41 25 34 + 19: 28 31 29 20 40 + 20: 49 34 32 40 32 + 21: 70 43 26 25 29 + 22: 42 36 33 36 34 + 23: 27 38 23 26 28 + 24: 78 35 23 15 29 + 25: 20 44 26 35 24 + 26: 63 32 24 46 24 + 27: 38 38 38 30 21 + 28: 27 50 22 32 27 + 29: 25 32 36 27 31 + 30: 31 38 19 31 28 + 31: 82 38 38 19 31 + 32: 31 34 37 45 35 + 33: 36 21 26 38 30 + 34: 30 27 31 39 38 + 35: 42 41 32 27 35 + 36: 44 28 43 36 31 + 37: 27 41 35 24 27 + 38: 30 43 30 26 27 + 39: 25 31 33 37 32 + 40: 36 45 32 33 28 + 41: 19 26 24 21 32 + 42: 17 38 32 22 29 + 43: 37 34 46 31 25 + 44: 45 27 33 40 28 + 45: 47 41 13 20 28 + 46: 38 38 28 41 30 + 47: 47 31 23 26 29 + 48: 17 32 20 34 25 + 49: 44 62 39 38 31 + 50: 41 19 37 52 28 +win: 0 0 0 0 0 diff --git a/data/model24.txt b/data/model24.txt new file mode 100644 index 0000000..ccc85be --- /dev/null +++ b/data/model24.txt @@ -0,0 +1,52 @@ +iter Level_01 Level_05 Level_10 Level_15 Level_20 + 1: 62 48 26 25 20 + 2: 32 39 77 34 22 + 3: 64 58 28 30 32 + 4: 45 40 33 28 28 + 5: 25 32 26 24 37 + 6: 48 31 39 35 23 + 7: 36 29 42 22 24 + 8: 81 33 34 28 21 + 9: 43 28 27 25 30 + 10: 28 50 35 29 30 + 11: 44 42 32 24 30 + 12: 45 49 33 15 26 + 13: 37 46 38 32 32 + 14: 38 33 22 29 29 + 15: 33 46 23 23 30 + 16: 35 25 34 40 24 + 17: 72 40 33 32 28 + 18: 30 18 17 28 28 + 19: 39 37 32 37 20 + 20: 33 27 28 48 28 + 21: 47 34 29 28 25 + 22: 38 48 24 37 18 + 23: 48 34 28 38 24 + 24: 37 74 39 26 30 + 25: 48 51 26 24 27 + 26: 50 35 45 32 23 + 27: 57 20 27 40 29 + 28: 34 49 41 37 33 + 29: 66 39 27 36 15 + 30: 24 33 28 37 28 + 31: 50 34 28 31 26 + 32: 29 39 38 47 29 + 33: 48 34 31 27 24 + 34: 42 37 37 32 30 + 35: 28 29 34 30 31 + 36: 20 34 29 40 19 + 37: 27 46 54 29 21 + 38: 39 51 26 40 18 + 39: 32 52 14 22 32 + 40: 47 38 22 38 36 + 41: 33 36 24 46 31 + 42: 39 31 42 20 34 + 43: 29 31 28 31 27 + 44: 49 42 28 24 38 + 45: 58 33 39 31 29 + 46: 45 52 31 24 26 + 47: 48 44 30 35 25 + 48: 26 37 25 34 18 + 49: 23 24 29 32 35 + 50: 34 42 30 35 25 +win: 0 0 0 0 0 diff --git a/data/model26.txt b/data/model26.txt new file mode 100644 index 0000000..be33c1a --- /dev/null +++ b/data/model26.txt @@ -0,0 +1,52 @@ +iter Level_01 Level_05 Level_10 Level_15 Level_20 + 1: 29 25 16 22 29 + 2: 46 5 30 34 30 + 3: 42 33 34 29 48 + 4: 36 51 25 34 32 + 5: 33 22 51 41 38 + 6: 26 36 12 28 29 + 7: 35 25 24 33 25 + 8: 39 30 15 30 39 + 9: 27 24 27 26 25 + 10: 62 35 52 17 34 + 11: 58 36 38 19 37 + 12: 57 19 28 22 25 + 13: 66 47 18 34 17 + 14: 39 8 26 27 29 + 15: 46 26 21 42 18 + 16: 57 18 34 37 27 + 17: 73 33 32 18 33 + 18: 30 48 23 34 34 + 19: 40 67 32 42 21 + 20: 27 24 9 55 27 + 21: 43 21 44 19 9 + 22: 25 20 28 20 36 + 23: 13 23 15 30 18 + 24: 79 67 22 41 28 + 25: 34 24 20 16 22 + 26: 20 54 28 34 33 + 27: 25 34 35 32 30 + 28: 30 14 30 29 28 + 29: 35 18 38 44 34 + 30: 48 21 26 24 34 + 31: 31 37 22 37 38 + 32: 39 36 27 43 28 + 33: 49 39 33 29 32 + 34: 34 29 17 36 38 + 35: 44 77 11 25 41 + 36: 23 22 37 26 40 + 37: 39 23 17 22 35 + 38: 37 19 27 33 22 + 39: 49 90 45 29 29 + 40: 43 32 37 19 26 + 41: 61 15 13 35 32 + 42: 44 39 36 23 22 + 43: 45 32 21 37 29 + 44: 33 25 27 30 40 + 45: 59 46 25 35 30 + 46: 36 43 47 35 38 + 47: 14 31 32 44 45 + 48: 43 34 32 21 27 + 49: 33 50 28 22 30 + 50: 52 57 46 31 42 +win: 0 0 0 0 0 diff --git a/data/model28.txt b/data/model28.txt new file mode 100644 index 0000000..c7eb738 --- /dev/null +++ b/data/model28.txt @@ -0,0 +1,52 @@ +iter Level_01 Level_05 Level_10 Level_15 Level_20 + 1: 53 44 36 26 29 + 2: 27 33 19 20 20 + 3: 27 38 39 23 30 + 4: 56 34 29 39 28 + 5: 71 39 23 13 27 + 6: 27 21 31 31 33 + 7: 37 35 26 30 31 + 8: 23 24 32 35 17 + 9: 62 38 31 29 19 + 10: 55 38 35 32 19 + 11: 39 38 30 40 32 + 12: 22 43 48 19 31 + 13: 49 21 19 27 20 + 14: 34 27 30 22 18 + 15: 47 35 32 31 29 + 16: 75 27 37 32 34 + 17: 27 33 29 42 23 + 18: 11 10 21 36 23 + 19: 31 39 26 29 12 + 20: 38 27 33 25 34 + 21: 32 36 32 27 30 + 22: 47 37 27 19 17 + 23: 37 29 36 25 37 + 24: 28 33 24 31 24 + 25: 49 46 20 24 37 + 26: 73 31 44 31 30 + 27: 25 38 20 28 27 + 28: 27 44 33 38 21 + 29: 42 45 25 30 28 + 30: 33 29 22 36 20 + 31: 31 28 29 32 25 + 32: 40 45 34 24 20 + 33: 41 11 12 34 21 + 34: 48 26 25 21 31 + 35: 35 16 31 38 15 + 36: 28 29 26 52 28 + 37: 65 24 23 23 14 + 38: 26 25 13 21 24 + 39: 34 39 19 25 20 + 40: 31 38 51 28 28 + 41: 40 36 33 25 27 + 42: 23 37 27 19 33 + 43: 48 19 28 15 19 + 44: 36 46 19 44 28 + 45: 21 34 31 27 37 + 46: 49 72 31 26 24 + 47: 45 31 47 34 39 + 48: 30 42 34 37 33 + 49: 53 11 32 27 28 + 50: 32 54 35 24 19 +win: 0 0 0 0 0 diff --git a/data/model30.txt b/data/model30.txt new file mode 100644 index 0000000..af46931 --- /dev/null +++ b/data/model30.txt @@ -0,0 +1,52 @@ +iter Level_01 Level_05 Level_10 Level_15 Level_20 + 1: 48 22 20 16 23 + 2: 39 32 9 30 17 + 3: 20 35 27 34 28 + 4: 61 43 22 40 16 + 5: 58 36 10 27 25 + 6: 49 22 74 42 26 + 7: 20 21 24 33 58 + 8: 32 32 43 28 12 + 9: 47 15 17 25 17 + 10: 34 38 19 34 30 + 11: 57 18 43 27 23 + 12: 16 25 37 21 25 + 13: 26 45 23 30 23 + 14: 30 40 38 31 20 + 15: 50 34 35 19 9 + 16: 43 30 23 32 9 + 17: 32 47 21 19 10 + 18: 33 35 37 34 10 + 19: 38 34 33 27 19 + 20: 40 50 21 30 15 + 21: 59 52 32 22 25 + 22: 25 31 42 23 27 + 23: 27 21 40 31 27 + 24: 50 27 35 29 27 + 25: 37 32 41 35 36 + 26: 25 51 53 16 22 + 27: 22 12 28 14 34 + 28: 47 42 28 34 40 + 29: 67 47 41 47 23 + 30: 79 29 33 22 18 + 31: 39 30 30 30 27 + 32: 51 47 26 33 32 + 33: 28 50 70 42 28 + 34: 40 21 42 18 27 + 35: 68 24 38 35 21 + 36: 20 16 37 34 27 + 37: 32 29 31 17 18 + 38: 59 35 23 32 19 + 39: 38 63 34 34 17 + 40: 58 26 52 25 29 + 41: 35 50 58 51 23 + 42: 38 30 13 49 26 + 43: 37 41 35 27 31 + 44: 42 59 22 24 21 + 45: 6 24 23 33 23 + 46: 63 34 40 33 21 + 47: 32 31 22 16 14 + 48: 31 51 47 30 30 + 49: 20 27 25 26 22 + 50: 39 27 36 22 27 +win: 0 0 0 0 0 diff --git a/data/model32.txt b/data/model32.txt new file mode 100644 index 0000000..f4c5b4c --- /dev/null +++ b/data/model32.txt @@ -0,0 +1,52 @@ +iter Level_01 Level_05 Level_10 Level_15 Level_20 + 1: 53 22 29 27 25 + 2: 41 37 34 25 31 + 3: 46 36 43 28 19 + 4: 40 30 29 34 19 + 5: 38 27 19 29 28 + 6: 38 37 26 39 24 + 7: 45 60 44 28 27 + 8: 60 40 41 32 23 + 9: 29 32 41 35 18 + 10: 42 31 40 28 27 + 11: 54 36 29 30 34 + 12: 52 25 43 16 23 + 13: 15 45 43 34 23 + 14: 39 31 30 43 33 + 15: 22 38 31 25 31 + 16: 22 39 30 35 34 + 17: 56 42 19 37 31 + 18: 56 33 45 18 32 + 19: 36 27 32 29 29 + 20: 49 37 39 33 30 + 21: 48 37 26 20 32 + 22: 40 53 31 40 25 + 23: 41 21 44 27 27 + 24: 31 58 31 35 24 + 25: 43 43 23 31 35 + 26: 38 48 39 37 36 + 27: 58 49 45 29 29 + 28: 15 27 15 38 30 + 29: 23 34 47 36 29 + 30: 78 19 39 28 28 + 31: 23 40 28 31 25 + 32: 40 27 30 35 37 + 33: 38 27 28 15 33 + 34: 40 29 37 27 33 + 35: 27 31 49 17 23 + 36: 29 16 38 28 27 + 37: 24 20 25 25 29 + 38: 43 26 35 31 24 + 39: 30 33 25 20 27 + 40: 39 39 40 33 41 + 41: 37 55 22 32 26 + 42: 34 41 26 31 32 + 43: 37 17 37 26 29 + 44: 35 49 33 31 26 + 45: 55 41 48 31 26 + 46: 39 37 37 22 26 + 47: 30 24 47 13 29 + 48: 44 30 47 34 24 + 49: 57 35 29 25 37 + 50: 55 50 38 33 29 +win: 0 0 0 0 0 diff --git a/data/model34.txt b/data/model34.txt new file mode 100644 index 0000000..4c93047 --- /dev/null +++ b/data/model34.txt @@ -0,0 +1,52 @@ +iter Level_01 Level_05 Level_10 Level_15 Level_20 + 1: 26 20 38 28 32 + 2: 33 44 41 32 32 + 3: 43 51 15 40 29 + 4: 39 38 25 31 21 + 5: 43 39 50 35 26 + 6: 17 30 25 11 28 + 7: 22 34 28 45 41 + 8: 29 44 8 37 37 + 9: 42 29 40 28 32 + 10: 63 38 8 22 17 + 11: 40 30 37 28 49 + 12: 29 43 31 33 22 + 13: 63 34 23 26 20 + 14: 43 21 29 37 27 + 15: 33 26 26 28 26 + 16: 46 39 58 34 33 + 17: 21 37 21 18 25 + 18: 45 20 38 24 23 + 19: 74 34 19 18 17 + 20: 71 17 32 35 28 + 21: 46 24 34 31 35 + 22: 59 21 28 19 23 + 23: 24 59 50 35 29 + 24: 57 27 23 25 17 + 25: 20 14 25 28 23 + 26: 21 32 34 51 23 + 27: 62 40 43 17 29 + 28: 25 46 30 30 15 + 29: 41 38 27 29 28 + 30: 28 34 37 32 22 + 31: 31 40 24 33 34 + 32: 51 39 33 28 30 + 33: 53 36 26 23 27 + 34: 56 36 46 27 31 + 35: 40 43 51 39 24 + 36: 41 40 33 38 26 + 37: 29 39 28 30 26 + 38: 36 47 29 19 24 + 39: 41 33 18 57 22 + 40: 36 45 33 35 21 + 41: 18 30 36 27 22 + 42: 60 44 31 34 17 + 43: 35 23 16 21 33 + 44: 27 39 11 24 35 + 45: 30 50 15 46 25 + 46: 38 47 34 22 29 + 47: 38 40 38 30 33 + 48: 25 64 23 26 27 + 49: 31 41 46 33 31 + 50: 40 27 43 35 25 +win: 0 0 0 0 0 diff --git a/data/output_1.png b/data/output_1.png new file mode 100644 index 0000000..36be18a Binary files /dev/null and b/data/output_1.png differ diff --git a/data/output_2.png b/data/output_2.png new file mode 100644 index 0000000..af1ae1b Binary files /dev/null and b/data/output_2.png differ diff --git a/engine/chessEngine.py b/engine/chessEngine.py index 0a5b3dd..6c901e4 100644 --- a/engine/chessEngine.py +++ b/engine/chessEngine.py @@ -17,12 +17,11 @@ class ChessEngine: model: models.Sequential - depth: int # Depth to search when evaluating a move - numMoveChecks: int # Checks n top moves from neural network with min-max and PeSTO evaluation + depth: int + numMoveChecks: int tp_finds: int def __init__(self, modelPath: str, depth: int, moves: int): - # Load Model self.model = models.load_model(modelPath, safe_mode=False) self.depth = depth self.numMoveChecks = moves @@ -34,22 +33,17 @@ def get_legal_move_probabilities(self, board: chess.Board): encoded_board = np.expand_dims(encoded_board, axis=-1) encoded_board = np.expand_dims(encoded_board, axis=0) - # Predict move probabilities move_probabilities = self.model.predict(encoded_board, verbose = 1)[0] - - # Filter by legal moves legal_moves_probabilities = { move: move_probabilities[encode_move(move)] for move in board.legal_moves } - # Sort legal moves by their predicted probabilities (highest first) sorted_moves = sorted( legal_moves_probabilities.items(), key=lambda item: item[1], reverse=True ) - # Return top n moves return sorted_moves[:self.numMoveChecks] def evaluate_move(self, current_score: int, move: chess.Move, board: chess.Board, probability: float): @@ -58,7 +52,6 @@ def evaluate_move(self, current_score: int, move: chess.Move, board: chess.Board beta = float('inf') value = 0 - # Start alpha-beta pruning search on board if board.turn == chess.WHITE: value, _ = self.alphaBetaMax(board, alpha, beta, self.depth) else: @@ -71,12 +64,10 @@ def evaluate_move(self, current_score: int, move: chess.Move, board: chess.Board def predict_best_move(self, board: chess.Board, networkOnly: bool): start_time = time.time() - # Get Moves from Neural Network sorted_moves = self.get_legal_move_probabilities(board) if(networkOnly): # Skips Static Analysis return sorted_moves[0][0] if len(sorted_moves) > 0 else None - # Initialize move variables best_value = 0 current_score = self.eval(board) best_move = sorted_moves[0][0] @@ -87,8 +78,6 @@ def predict_best_move(self, board: chess.Board, networkOnly: bool): moves = [] probs = [] - # Evaluate moves using alpha-beta pruning - # Threading used since alpha-beta pruning is time consuming with concurrent.futures.ThreadPoolExecutor() as executor: futures = [] for move, probability in sorted_moves: @@ -101,10 +90,8 @@ def predict_best_move(self, board: chess.Board, networkOnly: bool): moves.append(gmove) probs.append(prob) - # Normalize value differences val_diffs_norm = (val_diffs - np.min(val_diffs)) / (np.max(val_diffs) - np.min(val_diffs)) - # Calculate Final Move Scoring for vdif, value, gmove, prob, static_change in zip(val_diffs_norm, vals, moves, probs, val_diffs): wvalue = (vdif * 0.4) + (prob * 0.6) if(wvalue > best_value): @@ -120,16 +107,13 @@ def predict_best_move(self, board: chess.Board, networkOnly: bool): def eval(self, board: chess.Board) -> int: - # End Game Conditions if board.is_checkmate(): return -99999 if board.turn else 99999 if board.is_stalemate() or board.is_insufficient_material(): return 0 - # Preform Static Evaluation eval_score = static_eval(board, WHITE if board.turn else BLACK) - # Cache the evaluation return eval_score diff --git a/evaluate.py b/evaluate.py new file mode 100644 index 0000000..54a6cc3 --- /dev/null +++ b/evaluate.py @@ -0,0 +1,91 @@ +import chess +import chess.engine +from engine.chessEngine import ChessEngine + +#This program evaluates our chess engine by playing against stockfish. +#it plays against stockfish at 5 skill levels (1,5,10,15,20). + +engine_name = "models/movepredictorV2_34.keras" +fname = "data/model34.txt" + +def playGame(stock,engine): + player = 0 + n_moves = 0 + board = chess.Board() + while not board.is_game_over(): + if player == 1: + result = stock.play(board, chess.engine.Limit(time=0.01)) + board.push(result.move) + player = 0 + n_moves += 1 + else : + result = engine.predict_best_move(board,True) + board.push(result) + player = 1 + + return (n_moves,player) + + + + +stock1 = chess.engine.SimpleEngine.popen_uci("data/stockfish/stockfish-windows-x86-64-avx2.exe") +stock1.configure({"Skill Level": 1}) +stock2 = chess.engine.SimpleEngine.popen_uci("data/stockfish/stockfish-windows-x86-64-avx2.exe") +stock2.configure({"Skill Level": 5}) +stock3 = chess.engine.SimpleEngine.popen_uci("data/stockfish/stockfish-windows-x86-64-avx2.exe") +stock3.configure({"Skill Level": 10}) +stock4 = chess.engine.SimpleEngine.popen_uci("data/stockfish/stockfish-windows-x86-64-avx2.exe") +stock4.configure({"Skill Level": 15}) +stock5 = chess.engine.SimpleEngine.popen_uci("data/stockfish/stockfish-windows-x86-64-avx2.exe") +stock5.configure({"Skill Level": 20}) + +engine = ChessEngine(engine_name, 1, 3) +max_iter = 50 +iter = 0 +n_wins = [0,0,0,0,0] + +f = open(fname,"w") +f.write("iter Level 01 Level 05 Level 10 Level 15 Level 20\n") + +while (iter < max_iter): + n_moves = [0,0,0,0,0] + + res = playGame(stock1,engine) + n_moves[0] = res[0] + if (res[1] == 1): + n_wins[0] += 1 + + res = playGame(stock2,engine) + n_moves[1] = res[0] + if (res[1] == 1): + n_wins[1] += 1 + + res = playGame(stock3,engine) + n_moves[2] = res[0] + if (res[1] == 1): + n_wins[2] += 1 + + res = playGame(stock4,engine) + n_moves[3] = res[0] + if (res[1] == 1): + n_wins[3] += 1 + + res = playGame(stock5,engine) + n_moves[4] = res[0] + if (res[1] == 1): + n_wins[4] += 1 + + iter += 1 + + txt = "{0:3d}: {1:8d} {2:8d} {3:8d} {4:8d} {5:8d}\n" + f.write(txt.format(iter,n_moves[0],n_moves[1],n_moves[2],n_moves[3],n_moves[4])) + +txt = "win: {0:8d} {1:8d} {2:8d} {3:8d} {4:8d}\n" +f.write(txt.format(n_wins[0],n_wins[1],n_wins[2],n_wins[3],n_wins[4])) +f.close() + +stock1.quit() +stock2.quit() +stock3.quit() +stock4.quit() +stock5.quit() diff --git a/gui.py b/gui.py index 34561f8..3295e8d 100644 --- a/gui.py +++ b/gui.py @@ -1,4 +1,3 @@ -# importing required librarys import pygame import chess import math @@ -16,19 +15,15 @@ engine = ChessEngine("models/movepredictorV2_24.keras", 1, 3) def highlight_king_square(scrn, outcome, BOARD): - # Find the position of the checkmated king king_square = None if outcome.winner == chess.WHITE: - # White won, so the black king is checkmated king_square = BOARD.king(chess.BLACK) else: - # Black won, so the white king is checkmated king_square = BOARD.king(chess.WHITE) - # Highlight the square of the checkmated king if king_square is not None: row, col = divmod(king_square, 8) - flipped_row = 7 - row # Flip the row for display purposes + flipped_row = 7 - row square_x = col * 100 square_y = flipped_row * 100 pygame.draw.rect(scrn, (255, 215, 0), pygame.Rect(square_x, square_y, 100, 100)) @@ -37,24 +32,17 @@ def display_game_over(scrn, outcome, BOARD): font = pygame.font.Font(None, 74) if outcome.winner is not None: - # If there is a winner, show who won winner = "White" if outcome.winner == chess.WHITE else "Black" - text = font.render(f"Checkmate! {winner} wins!", True, (255, 0, 0)) # Red color for checkmate + text = font.render(f"Checkmate! {winner} wins!", True, (255, 0, 0)) else: - # If it's a draw text = font.render("Game Over - Draw!", True, (255, 0, 0)) - scrn.blit(text, (150, 300)) # Display message at the center of the screen - pygame.display.flip() # Update display + scrn.blit(text, (150, 300)) + pygame.display.flip() def promotion_choice(): - """ - Prompts the player to select a piece for pawn promotion. - Returns the piece type for the promotion (e.g., rook, knight, queen, bishop). - """ # Display choices for promotion (e.g., through Pygame or console) - # Here, we'll use a simple prompt for simplicity print("Select a piece to promote your pawn to:") print("1. Queen") print("2. Rook") @@ -76,41 +64,30 @@ def promotion_choice(): return chess.QUEEN def draw_piece(scrn, piece_image, row, col, square_size, piece_scale=0.8): - # Scale the piece scaled_size = (int(square_size * piece_scale), int(square_size * piece_scale)) piece_image = pygame.transform.scale(piece_image, scaled_size) - # Calculate square position square_x = col * square_size square_y = row * square_size - # Center the piece in the square piece_x = square_x + (square_size - scaled_size[0]) // 2 piece_y = square_y + (square_size - scaled_size[1]) // 2 - # Draw the piece scrn.blit(piece_image, (piece_x, piece_y)) -# Function to get the legal moves for the clicked piece def get_legal_moves(board, clicked_square): - # Get all legal moves for the current board position - # Need to convert away from iterator all_moves = list(board.legal_moves) - # Filter the legal moves to only those where the move's from_square matches the clicked square piece_moves = [move.to_square for move in all_moves if move.from_square == clicked_square] return piece_moves def highlight_moves(scrn, board, moves, selected_square): - # Transparency level for overlays transparency = 128 - # Create a translucent overlay for the selected piece's square overlay = pygame.Surface((SQUARE_SIZE, SQUARE_SIZE), pygame.SRCALPHA) - overlay.fill((*HIGHLIGHT_COLOUR, transparency)) # Add alpha value for transparency + overlay.fill((*HIGHLIGHT_COLOUR, transparency)) - # Highlight the selected piece's square if selected_square is not None: row, col = divmod(selected_square, 8) flipped_row = 7 - row @@ -121,22 +98,19 @@ def highlight_moves(scrn, board, moves, selected_square): circle_overlay.fill((0, 0, 0, 0)) - # Draw translucent grey circles for the destination squares for move in moves: row, col = divmod(move, 8) circle_overlay.fill((0, 0, 0, 0)) - # Calculate the center of the square center_x = SQUARE_SIZE // 2 center_y = SQUARE_SIZE // 2 - # Draw a translucent circle pygame.draw.circle( circle_overlay, - (*GREY, transparency), # Semi-transparent grey - (center_x, center_y), # Circle's center - SQUARE_SIZE // 6 # Circle radius + (*GREY, transparency), + (center_x, center_y), + SQUARE_SIZE // 6 ) flipped_row = 7 - row @@ -144,10 +118,7 @@ def highlight_moves(scrn, board, moves, selected_square): scrn.blit(circle_overlay, (col * SQUARE_SIZE, flipped_row * SQUARE_SIZE)) def draw_board(scrn): - ''' - Draws the chessboard grid, including alternating square colors and row/column labels. - ''' - + COLUMN_LABEL_ALIGNX = SQUARE_SIZE * 0.05 COLUMN_LABEL_ALIGNY = SQUARE_SIZE * 0.05 @@ -163,53 +134,43 @@ def draw_board(scrn): else: pygame.draw.rect(scrn, DARK_SQUARE_COLOUR, rect) - # Draw row numbers on the left side if j == 0: - row_number = 8 - i # Numbers go 8 to 1 from top to bottom + row_number = 8 - i row_text = font.render( str(row_number), True, DARK_SQUARE_COLOUR if (i + j) % 2 == 0 else LIGHT_SQUARE_COLOUR ) - scrn.blit(row_text, (COLUMN_LABEL_ALIGNX, i * SQUARE_SIZE + COLUMN_LABEL_ALIGNY)) # Position it on the left side + scrn.blit(row_text, (COLUMN_LABEL_ALIGNX, i * SQUARE_SIZE + COLUMN_LABEL_ALIGNY)) - # Draw column letters at the bottom if i == 7: - col_letter = chr(97 + j) # ASCII 97 = 'a' + col_letter = chr(97 + j) col_text = font.render( col_letter, True, DARK_SQUARE_COLOUR if (i + j) % 2 == 0 else LIGHT_SQUARE_COLOUR ) - scrn.blit(col_text, ((j + 1) * SQUARE_SIZE + ROW_LABEL_ALIGNX, ROW_LABEL_ALIGNY)) # Position it on the bottom row + scrn.blit(col_text, ((j + 1) * SQUARE_SIZE + ROW_LABEL_ALIGNX, ROW_LABEL_ALIGNY)) def draw_pieces(scrn, board): - ''' - Draws the chess pieces based on the current board state. - ''' for i in range(64): piece = board.piece_at(i) if piece is None: continue - row = i // 8 # Row index (0 to 7) - col = i % 8 # Column index (0 to 7) - flipped_row = 7 - row # Flip row for proper display + row = i // 8 + col = i % 8 + flipped_row = 7 - row draw_piece(scrn, pieces[str(piece)], flipped_row, col, 100, piece_scale=0.9) def main(BOARD): - ''' - for human vs human game - ''' - # Make background black + scrn.fill(BLACK) - # Name window pygame.display.set_caption('Chess') - # Variables to be used later selected_piece = None selected_square = None moves = [] @@ -219,7 +180,6 @@ def main(BOARD): Running = True while Running: - # Check if the game has had an outcome yet outcome = BOARD.outcome() draw_board(scrn) @@ -230,58 +190,46 @@ def main(BOARD): pygame.display.flip() if outcome is not None: - # Game has ended display_game_over(scrn, outcome, BOARD) - pygame.time.wait(3000) # Wait 3 seconds before closing + pygame.time.wait(3000) break if BOARD.turn == ai_player: - # AI's turn ai_move = engine.predict_best_move(BOARD, True) BOARD.push(ai_move) continue for event in pygame.event.get(): - # If event type is QUIT, exit the game if event.type == pygame.QUIT: Running = False - # If mouse clicked if event.type == pygame.MOUSEBUTTONDOWN: - # Get the position of the mouse click pos = pygame.mouse.get_pos() - # Find which square was clicked and its index square = (math.floor(pos[0] / 100), math.floor(pos[1] / 100)) - clicked_square = (7 - square[1]) * 8 + square[0] # Convert to board index + clicked_square = (7 - square[1]) * 8 + square[0] - # If there is no piece selected and a piece is clicked if selected_square is None: piece = BOARD.piece_at(clicked_square) - if piece and piece.color == human_player: # There is a piece on the square and it's the human's turn + if piece and piece.color == human_player: selected_piece = piece selected_square = clicked_square moves = get_legal_moves(BOARD, selected_square) else: - # If a square is clicked that is a valid move if clicked_square in moves: - # Perform the move move = chess.Move(selected_square, clicked_square) if BOARD.piece_at(selected_square).piece_type == chess.PAWN: - # If the move lands on the promotion rank, we need to handle promotion if (BOARD.turn == chess.WHITE and clicked_square // 8 == 7) or \ (BOARD.turn == chess.BLACK and clicked_square // 8 == 0): - # Apply promotion (Queen, Rook, Bishop, or Knight) - promotion_piece = chess.QUEEN # Default promotion to a Queen + promotion_piece = chess.QUEEN promotion_piece = promotion_choice() - move.promotion = promotion_piece # Set the promotion type + move.promotion = promotion_piece - if move in BOARD.legal_moves: # Ensure the move is legal + if move in BOARD.legal_moves: BOARD.push(move) - # Reset the selected square and possible moves for next turn selected_square = None selected_piece = None moves = [] @@ -293,11 +241,9 @@ def main(BOARD): pygame.quit() -#initialise display scrn = pygame.display.set_mode((SCREENX, SCREENY)) pygame.init() -#basic colours WHITE = (255, 255, 255) GREY = (128, 128, 128) YELLOW = (204, 204, 0) @@ -308,12 +254,10 @@ def main(BOARD): DARK_SQUARE_COLOUR = (139, 69, 19) HIGHLIGHT_COLOUR = (200, 200, 180) -font = pygame.font.SysFont(None, 36) # Create a font for the text +font = pygame.font.SysFont(None, 36) -#initialise chess board board = chess.Board() -#load piece images pieces = {'p': pygame.image.load('data/assets/black-pawn.png').convert_alpha(), 'n': pygame.image.load('data/assets/black-knight.png').convert_alpha(), 'b': pygame.image.load('data/assets/black-bishop.png').convert_alpha(), diff --git a/main.py b/main.py index ed01a98..f1618d3 100644 --- a/main.py +++ b/main.py @@ -8,7 +8,6 @@ engine = ChessEngine("models/movepredictorV2_24.keras", 1, 3) def play_game_pgn(pgn_file): - # Load games from the PGN file print(f"Loading games from {pgn_file}.") games = load_pgn_file(pgn_file, 100) if games: @@ -42,25 +41,20 @@ def play_ai_vs_ai(num_games=100): return all_accuracy_scores def visualize_accuracy_scores(all_accuracy_scores): - # Find the maximum number of moves in any game max_moves = max(len(scores) for scores in all_accuracy_scores) - # Initialize a list to hold the sum of centipawn losses for each move number summed_scores = np.zeros(max_moves) move_counts = np.zeros(max_moves) - # Sum the centipawn losses for each move number across all games for game_scores in all_accuracy_scores: for i, score in enumerate(game_scores): - if score <= 8000: # Filter out scores greater than 8000 - capped_score = min(score, 1000) # Cap the score at 1000 + if score <= 8000: + capped_score = min(score, 1000) summed_scores[i] += capped_score move_counts[i] += 1 - # Calculate the average centipawn loss for each move number average_scores = summed_scores / move_counts - # Plot the average centipawn loss per move plt.plot(average_scores) plt.xlabel('Move Number') plt.ylabel('Average Centipawn Loss') diff --git a/models/movepredictorV2_11.keras b/models/movepredictorV2_11.keras new file mode 100644 index 0000000..d81469e Binary files /dev/null and b/models/movepredictorV2_11.keras differ diff --git a/models/movepredictorV2_12.keras b/models/movepredictorV2_12.keras new file mode 100644 index 0000000..42a7f50 Binary files /dev/null and b/models/movepredictorV2_12.keras differ diff --git a/models/movepredictorV2_13.keras b/models/movepredictorV2_13.keras new file mode 100644 index 0000000..57e6649 Binary files /dev/null and b/models/movepredictorV2_13.keras differ diff --git a/models/movepredictorV2_14.keras b/models/movepredictorV2_14.keras new file mode 100644 index 0000000..851a9d2 Binary files /dev/null and b/models/movepredictorV2_14.keras differ diff --git a/models/movepredictorV2_15.keras b/models/movepredictorV2_15.keras new file mode 100644 index 0000000..b667f51 Binary files /dev/null and b/models/movepredictorV2_15.keras differ diff --git a/models/movepredictorV2_16.keras b/models/movepredictorV2_16.keras new file mode 100644 index 0000000..85e8101 Binary files /dev/null and b/models/movepredictorV2_16.keras differ diff --git a/models/movepredictorV2_17.keras b/models/movepredictorV2_17.keras new file mode 100644 index 0000000..eaed346 Binary files /dev/null and b/models/movepredictorV2_17.keras differ diff --git a/models/movepredictorV2_18.keras b/models/movepredictorV2_18.keras new file mode 100644 index 0000000..acef0a0 Binary files /dev/null and b/models/movepredictorV2_18.keras differ diff --git a/models/movepredictorV2_25.keras b/models/movepredictorV2_25.keras new file mode 100644 index 0000000..4e18e97 Binary files /dev/null and b/models/movepredictorV2_25.keras differ diff --git a/models/movepredictorV2_26.keras b/models/movepredictorV2_26.keras new file mode 100644 index 0000000..6f51264 Binary files /dev/null and b/models/movepredictorV2_26.keras differ diff --git a/models/movepredictorV2_27.keras b/models/movepredictorV2_27.keras new file mode 100644 index 0000000..6cb5a67 Binary files /dev/null and b/models/movepredictorV2_27.keras differ diff --git a/models/movepredictorV2_28.keras b/models/movepredictorV2_28.keras new file mode 100644 index 0000000..110483f Binary files /dev/null and b/models/movepredictorV2_28.keras differ diff --git a/models/movepredictorV2_29.keras b/models/movepredictorV2_29.keras new file mode 100644 index 0000000..f1bc9ae Binary files /dev/null and b/models/movepredictorV2_29.keras differ diff --git a/models/movepredictorV2_30.keras b/models/movepredictorV2_30.keras new file mode 100644 index 0000000..96dcd37 Binary files /dev/null and b/models/movepredictorV2_30.keras differ diff --git a/models/movepredictorV2_31.keras b/models/movepredictorV2_31.keras new file mode 100644 index 0000000..4639c52 Binary files /dev/null and b/models/movepredictorV2_31.keras differ diff --git a/models/movepredictorV2_32.keras b/models/movepredictorV2_32.keras new file mode 100644 index 0000000..2a7751f Binary files /dev/null and b/models/movepredictorV2_32.keras differ diff --git a/models/movepredictorV2_33.keras b/models/movepredictorV2_33.keras new file mode 100644 index 0000000..4f2eccc Binary files /dev/null and b/models/movepredictorV2_33.keras differ diff --git a/models/movepredictorV2_34.keras b/models/movepredictorV2_34.keras new file mode 100644 index 0000000..c1bc098 Binary files /dev/null and b/models/movepredictorV2_34.keras differ diff --git a/neural_net.py b/neural_net.py index 638020b..f9ab6cc 100644 --- a/neural_net.py +++ b/neural_net.py @@ -7,9 +7,6 @@ import numpy as np from concurrent.futures import ProcessPoolExecutor, as_completed -############################################# -# Dataset Preparation -############################################# def get_board_and_moves(game): board = game.board() @@ -23,7 +20,6 @@ def get_board_and_moves(game): def encode_board(board: chess.Board): encoded = np.zeros((8, 8, 17), dtype=np.float32) - # Mapping from piece type and color to channel index piece_to_channel = { (chess.PAWN, chess.WHITE): 0, (chess.KNIGHT, chess.WHITE): 1, @@ -38,7 +34,6 @@ def encode_board(board: chess.Board): (chess.QUEEN, chess.BLACK): 10, (chess.KING, chess.BLACK): 11 } - WHITEATTACK = 12 BLACKATTACK = 13 PINNED = 14 @@ -49,37 +44,31 @@ def encode_board(board: chess.Board): mobility_map = np.zeros(64) for square in chess.SQUARES: - row = 7 - (square // 8) # get row from square index - col = square % 8 # get column from square index + row = 7 - (square // 8) + col = square % 8 - # Encode Pieces (Channels 0-11) piece = board.piece_at(square) if piece is not None: channel = piece_to_channel[(piece.piece_type, piece.color)] encoded[row, col, channel] = 1.0 - # Encode Attackers if board.is_attacked_by(chess.WHITE, square): encoded[row, col, WHITEATTACK] = 1.0 if board.is_attacked_by(chess.BLACK, square): encoded[row, col, BLACKATTACK] = 1.0 - # Encode Pinned if board.is_pinned(board.turn, square): encoded[row, col, PINNED] = 1.0 for move in board.legal_moves: - # Encode Mobility mobility_map[move.from_square] += 1 - # Encode Legal Move Destinations to_square = move.to_square r2 = 7 - (to_square // 8) c2 = to_square % 8 encoded[r2, c2, LEGALDEST] = 1.0 - # Normalize Mobility between 0 and 1 mobility_map = (np.array(mobility_map) - np.min(mobility_map)) / (np.max(mobility_map) - np.min(mobility_map)) for i in range(len(mobility_map)): @@ -99,9 +88,9 @@ def process_single_game(game): game_data, result = game weighting_scheme = { - "1-0": {chess.WHITE: 1.2, chess.BLACK: 0.8}, # White win - "0-1": {chess.WHITE: 0.8, chess.BLACK: 1.2}, # Black win - "1/2-1/2": {chess.WHITE: 1.0, chess.BLACK: 1.0} # Draw + "1-0": {chess.WHITE: 1.2, chess.BLACK: 0.8}, + "0-1": {chess.WHITE: 0.8, chess.BLACK: 1.2}, + "1/2-1/2": {chess.WHITE: 1.0, chess.BLACK: 1.0} } board_and_moves = get_board_and_moves(game_data) @@ -112,8 +101,8 @@ def process_single_game(game): for move_num, (board, move) in enumerate(board_and_moves, 1): move_factor = ( - (1.0 + (move_num / total_moves) * 0.5) # Endgame Prioritization - * base_weights[board.turn] # Winner Prioritization + (1.0 + (move_num / total_moves) * 0.5) + * base_weights[board.turn] ) X.append(encode_board(board)) @@ -127,7 +116,7 @@ def prepare_dataset(games, parallelization_factor: int = 1): X, y, weights_all = [], [], [] processed_games = 0 - + with ProcessPoolExecutor(max_workers=parallelization_factor) as executor: future_to_game = { executor.submit(process_single_game, game): game @@ -158,71 +147,49 @@ def prepare_dataset(games, parallelization_factor: int = 1): return X, y, weights -############################################# -# Neural Network -############################################# - def build_chess_cnn() -> models.Model: print("[NEURAL] - Creating Model") - rv = 0.1 # Regularization Value - # Input layer board_input = layers.Input(shape=(8, 8, 17), name='board_input') - # Split Input by pieces and info piece_channels = layers.Lambda(lambda x: x[..., :12], name='piece_channels')(board_input) info_channels = layers.Lambda(lambda x: x[..., 12:], name='info_channels')(board_input) - # Piece Position CNN with residual connections piece_conv = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(piece_channels) piece_conv = layers.BatchNormalization()(piece_conv) - - # First residual block - residual = piece_conv + residual = piece_conv piece_conv = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(piece_conv) piece_conv = layers.BatchNormalization()(piece_conv) piece_conv = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(piece_conv) piece_conv = layers.BatchNormalization()(piece_conv) - piece_conv = layers.Add()([piece_conv, residual]) - - # Increase channels with 1x1 conv + piece_conv = layers.Add()([piece_conv, residual]) piece_conv = layers.Conv2D(128, (1, 1), activation='relu')(piece_conv) piece_conv = layers.BatchNormalization()(piece_conv) - piece_conv = layers.SpatialDropout2D(0.1)(piece_conv) # More efficient dropout for conv layers + piece_conv = layers.SpatialDropout2D(0.1)(piece_conv) - # Board Info CNN with squeeze-and-excitation info_conv = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(info_channels) info_conv = layers.BatchNormalization()(info_conv) - - # Squeeze and Excitation block - se = layers.GlobalAveragePooling2D()(info_conv) - se = layers.Dense(32 // 4, activation='relu')(se) - se = layers.Dense(32, activation='sigmoid')(se) - se = layers.Reshape((1, 1, 32))(se) - info_conv = layers.Multiply()([info_conv, se]) - + info_conv2 = layers.GlobalAveragePooling2D()(info_conv) + info_conv2 = layers.Dense(8, activation='relu')(info_conv2) + info_conv2 = layers.Dense(32, activation='relu')(info_conv2) + info_conv2 = layers.Reshape((1, 1, 32))(info_conv2) + info_conv = layers.Multiply()([info_conv, info_conv2]) info_conv = layers.SpatialDropout2D(0.1)(info_conv) - # Combine features combined = layers.Concatenate()([piece_conv, info_conv]) - # Efficient feature extraction x = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(combined) x = layers.BatchNormalization()(x) - x = layers.GlobalAveragePooling2D()(x) # Replace Flatten with GlobalAveragePooling2D + x = layers.GlobalAveragePooling2D()(x) - # Efficient dense layers with skip connections dense1 = layers.Dense(512, activation='relu')(x) dense1 = layers.BatchNormalization()(dense1) dense1 = layers.Dropout(0.1)(dense1) - dense2 = layers.Dense(512, activation='relu')(dense1) dense2 = layers.BatchNormalization()(dense2) - dense2 = layers.Add()([dense1, dense2]) # Skip connection + dense2 = layers.Add()([dense1, dense2]) - # Output with label smoothing outputs = layers.Dense(4096, activation='softmax')(dense2) - model = models.Model(inputs=board_input, outputs=outputs, name='chess_cnn') return model diff --git a/pgn_parser.py b/pgn_parser.py index b1ae682..871e672 100644 --- a/pgn_parser.py +++ b/pgn_parser.py @@ -5,7 +5,6 @@ import io def load_pgn_file(filepath, numGames, minELO=0): - # Returns list of games games = [] with open(filepath, buffering=1048576) as pgn_file: while numGames > 0: @@ -30,7 +29,6 @@ def load_pgn_file(filepath, numGames, minELO=0): except ValueError: result = "" - # Add game if Elo ratings are above the minimum threshold if minELO <= 0 or (elo1 >= minELO and elo2 >= minELO) and type.find("Classical"): games.append((game, result)) numGames -= 1 diff --git a/stockfish.py b/stockfish.py index ae21b6f..ba6d959 100644 --- a/stockfish.py +++ b/stockfish.py @@ -25,7 +25,6 @@ def evaluate_move_stockfish(board: chess.Board): def evaluate_game_stockfish(move_sequence): - # Rather than evaluate a single move, this attempts to evaluate a move sequence board = chess.Board() accuracy_scores = [] @@ -37,7 +36,6 @@ def evaluate_game_stockfish(move_sequence): evaluation = engine.analyse(board, chess.engine.Limit(depth=stockfish_depth)) best_move = engine.play(board, chess.engine.Limit(time=0.2)) - # If increase time, it increases accuracy but decreases speed (obviously) eval_score = evaluation['score'].relative.score(mate_score=10000) @@ -45,7 +43,6 @@ def evaluate_game_stockfish(move_sequence): best_move_score = best_move_evaluation['score'].relative.score(mate_score=10000) # We compare the centipawn loss between the best move, and the move given to get a delta. Average the delta for average centipawn loss - # print(f"Move: {move_str} -> Eval: {eval_score}, Best Move: {best_move_score}") accuracy_score = abs(eval_score - best_move_score) accuracy_scores.append(accuracy_score)