KingOfThoughtFleuren commited on
Commit
e1861ed
·
1 Parent(s): 3af071f

Create chess_mind.py

Browse files
Files changed (1) hide show
  1. services/chess_mind.py +133 -0
services/chess_mind.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import chess
2
+ import json
3
+ import os
4
+ import random
5
+
6
+ class ChessMind:
7
+ """
8
+ Represents Aetherius's personal, learning chess-playing entity.
9
+ This module handles board evaluation, move calculation, and learning from experience.
10
+ """
11
+ def __init__(self, data_directory):
12
+ self.weights_file = os.path.join(data_directory, "chess_mind_weights.json")
13
+ self.weights = self._load_weights()
14
+ print("ChessMind says: I am ready to learn and calculate.")
15
+
16
+ def _load_weights(self):
17
+ """Loads the evaluation weights from a file, or creates default ones."""
18
+ if os.path.exists(self.weights_file):
19
+ try:
20
+ with open(self.weights_file, 'r') as f:
21
+ return json.load(f)
22
+ except Exception as e:
23
+ print(f"ChessMind WARNING: Could not load weights file. Error: {e}. Using defaults.")
24
+
25
+ # Default weights if no file exists
26
+ return {
27
+ 'MATERIAL': {
28
+ str(chess.PAWN): 100,
29
+ str(chess.KNIGHT): 320,
30
+ str(chess.BISHOP): 330,
31
+ str(chess.ROOK): 500,
32
+ str(chess.QUEEN): 900,
33
+ str(chess.KING): 20000
34
+ },
35
+ 'POSITION': {
36
+ 'CENTER_CONTROL': 10 # Bonus for each piece in the center
37
+ }
38
+ }
39
+
40
+ def _save_weights(self):
41
+ """Saves the current evaluation weights to a file."""
42
+ try:
43
+ with open(self.weights_file, 'w') as f:
44
+ json.dump(self.weights, f, indent=4)
45
+ except Exception as e:
46
+ print(f"ChessMind ERROR: Could not save weights. Error: {e}")
47
+
48
+ def evaluate_board(self, board):
49
+ """
50
+ Evaluates the board from White's perspective.
51
+ Positive score is good for White, negative is good for Black.
52
+ """
53
+ if board.is_checkmate():
54
+ if board.turn == chess.WHITE: return -99999
55
+ else: return 99999
56
+ if board.is_game_over():
57
+ return 0
58
+
59
+ # Material Score
60
+ material_score = 0
61
+ for piece_type in [chess.PAWN, chess.KNIGHT, chess.BISHOP, chess.ROOK, chess.QUEEN]:
62
+ material_score += len(board.pieces(piece_type, chess.WHITE)) * self.weights['MATERIAL'][str(piece_type)]
63
+ material_score -= len(board.pieces(piece_type, chess.BLACK)) * self.weights['MATERIAL'][str(piece_type)]
64
+
65
+ # Positional Score
66
+ white_center = len(board.pieces(chess.PAWN, chess.WHITE) & chess.BB_CENTER) + len(board.pieces(chess.KNIGHT, chess.WHITE) & chess.BB_CENTER)
67
+ black_center = len(board.pieces(chess.PAWN, chess.BLACK) & chess.BB_CENTER) + len(board.pieces(chess.KNIGHT, chess.BLACK) & chess.BB_CENTER)
68
+ positional_score = (white_center - black_center) * self.weights['POSITION']['CENTER_CONTROL']
69
+
70
+ return material_score + positional_score
71
+
72
+ def find_best_move(self, board, depth=2):
73
+ """Finds the best move using minimax with alpha-beta pruning."""
74
+ best_move = None
75
+ is_maximizing = board.turn == chess.WHITE
76
+
77
+ if is_maximizing:
78
+ best_value = -float('inf')
79
+ for move in board.legal_moves:
80
+ board.push(move)
81
+ board_value = self.minimax(board, depth - 1, -float('inf'), float('inf'), False)
82
+ board.pop()
83
+ if board_value > best_value:
84
+ best_value = board_value
85
+ best_move = move
86
+ else: # Minimizing
87
+ best_value = float('inf')
88
+ for move in board.legal_moves:
89
+ board.push(move)
90
+ board_value = self.minimax(board, depth - 1, -float('inf'), float('inf'), True)
91
+ board.pop()
92
+ if board_value < best_value:
93
+ best_value = board_value
94
+ best_move = move
95
+
96
+ return best_move or random.choice(list(board.legal_moves))
97
+
98
+ def minimax(self, board, depth, alpha, beta, is_maximizing_player):
99
+ if depth == 0 or board.is_game_over():
100
+ return self.evaluate_board(board)
101
+
102
+ if is_maximizing_player:
103
+ max_eval = -float('inf')
104
+ for move in board.legal_moves:
105
+ board.push(move)
106
+ evaluation = self.minimax(board, depth - 1, alpha, beta, False)
107
+ board.pop()
108
+ max_eval = max(max_eval, evaluation)
109
+ alpha = max(alpha, evaluation)
110
+ if beta <= alpha:
111
+ break
112
+ return max_eval
113
+ else: # Minimizing player
114
+ min_eval = float('inf')
115
+ for move in board.legal_moves:
116
+ board.push(move)
117
+ evaluation = self.minimax(board, depth - 1, alpha, beta, True)
118
+ board.pop()
119
+ min_eval = min(min_eval, evaluation)
120
+ beta = min(beta, evaluation)
121
+ if beta <= alpha:
122
+ break
123
+ return min_eval
124
+
125
+ def learn_from_game(self, was_winner):
126
+ """Adjusts weights based on the game outcome."""
127
+ print("ChessMind: Learning from the last game...")
128
+ if was_winner:
129
+ self.weights['POSITION']['CENTER_CONTROL'] += 1
130
+ else:
131
+ self.weights['POSITION']['CENTER_CONTROL'] = max(1, self.weights['POSITION']['CENTER_CONTROL'] - 1)
132
+ self._save_weights()
133
+ print(f"ChessMind: New center control weight is {self.weights['POSITION']['CENTER_CONTROL']}")