Skip to content

Commit 6bd10a1

Browse files
committed
Update
1 parent a0b08d4 commit 6bd10a1

13 files changed

Lines changed: 2327 additions & 1825 deletions

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
node_modules/
2-
ciassabase/
2+
caissabase/
33
.idea/

InterestingPosition.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import ast
2+
import io
3+
from chess.pgn import read_game
4+
5+
games = []
6+
with open('chesscraziness/logs/tcecresults.log') as f:
7+
lines = f.readlines()
8+
for line in lines[1:]:
9+
if len(line):
10+
game_data = ast.literal_eval(line)
11+
game= read_game(io.StringIO(game_data['game']))
12+
games.append(game_data)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ Inspired from https://github.com/santient/GeneticChess but designed to be more u
1111
1. `npm install`
1212
1. `npm run build`
1313
1. `npm run serve` or any other method to serve the app on http://localhost:8000
14-
1. `npm run watch` to modify it for development/testing
14+
1. `npm run watch` to modify it for development/testing
3.99 KB
Binary file not shown.

chesscraziness

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit f5c214b8f1aecde0019cfdacdadd041d2d500fe6

craziness.py

Lines changed: 68 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from io import StringIO
44

55
import chess.pgn
6+
from stockfish import Stockfish
67

78
PIECE_VALUES = {
89
chess.PAWN: 1,
@@ -27,21 +28,39 @@
2728
def opposite_colour(colour: str):
2829
return "black" if colour == "white" else "white"
2930

31+
32+
stockfish_path = '/home/alexli/fun/stockfish/stockfish-ubuntu-x86-64-avx2'
33+
fish_params = {"Threads": 12, "Hash": 8192 * 2, "Slow Mover": 0}
34+
engine = Stockfish(path=stockfish_path, parameters=fish_params)
35+
engine.set_depth(25)
36+
3037
# takes in a parsed PGN, estimates game craziness
3138
# and returns a score
3239
def estimate_game_craziness(game: chess.pgn.Game):
33-
score = 0
34-
3540
game_moves = list(game.mainline())
36-
41+
if game.headers['Result'] != '1/2-1/2':
42+
if len(game_moves) <= 50:
43+
engine.set_fen_position(game_moves[40].board().fen())
44+
evaluation = engine.get_evaluation()
45+
if evaluation['type'] != 'cp':
46+
return 0, None # It's a mate-in-N
47+
elif evaluation['value'] > 0.5 and game.headers['Result'] == '1-0':
48+
return 0, None # Black lost and black's position is worse
49+
elif evaluation['value'] < -0.5 and game.headers['Result'] == '0-1':
50+
return 0, None # White lost and white's position is worse
51+
offset = 20
3752
pieces_moved: list[chess.PieceType] = []
38-
material_differences = []
39-
40-
for node_index, move_node in enumerate(game_moves):
53+
move_scores = [0] * offset
54+
total_material = [78] * offset
55+
for node_index, move_node in list(enumerate(game_moves))[offset:]:
56+
score = 0
57+
if node_index >= 40 or total_material[-1] < 20:
58+
break
59+
4160
move = move_node.move
4261
board = move_node.board()
4362

44-
turn_colour = "black" if board.turn else "white"
63+
turn_colour = "white" if board.turn else "black"
4564

4665
try:
4766
pieces_moved.append(
@@ -56,10 +75,6 @@ def estimate_game_craziness(game: chess.pgn.Game):
5675
"black": 0
5776
}
5877

59-
material_differences.append(
60-
abs(material["white"] - material["black"])
61-
)
62-
6378
piece_counts = {
6479
"white": {},
6580
"black": {}
@@ -90,21 +105,11 @@ def estimate_game_craziness(game: chess.pgn.Game):
90105
king_square[piece_colour] = square
91106

92107
pieces_remaining += 1
93-
94-
# if material difference has been high for too long, discard game
95-
if len(material_differences) >= 14:
96-
balanced_position_found = False
97-
98-
for i in range(14):
99-
current_difference = material_differences[-(i + 1)]
100-
101-
if current_difference <= 11:
102-
balanced_position_found = True
103-
break
104-
105-
if not balanced_position_found:
106-
return -1
107-
108+
total_material.append(material['white'] + material['black'])
109+
imbalance = 0
110+
for piece_type in chess.PIECE_TYPES:
111+
imbalance += abs(piece_counts["white"][piece_type] - piece_counts["black"][piece_type]) * PIECE_VALUES[piece_type] ** .5
112+
score += imbalance
108113
# number of simultaneously hanging pieces
109114
for square in chess.SQUARES:
110115
piece = board.piece_at(square)
@@ -123,58 +128,29 @@ def estimate_game_craziness(game: chess.pgn.Game):
123128
# there's no sacrifice
124129
last_position = game_moves[node_index - 1].board()
125130
last_piece = last_position.piece_at(square)
131+
piece_has_been_sitting_here = last_piece is not None and last_piece.color == piece.color
126132

127-
if (
128-
last_piece is not None
129-
and PIECE_VALUES[last_piece.piece_type] >= PIECE_VALUES[piece.piece_type]
130-
):
133+
if not piece_has_been_sitting_here:
131134
continue
132135

133136
# Get the attackers of the current square
134137
attacker_squares = board.attackers(not piece.color, square)
138+
attacker_values = sorted([PIECE_VALUES[board.piece_at(attacker).piece_type] for attacker in attacker_squares])
135139

136140
# Get defenders of the current square
137141
defender_squares = board.attackers(piece.color, square)
142+
defender_values = [PIECE_VALUES[piece.piece_type]] + sorted([PIECE_VALUES[board.piece_at(defender).piece_type] for defender in defender_squares])
138143

139-
if len(attacker_squares) > len(defender_squares):
140-
score += PIECE_VALUES[piece.piece_type]
141-
else:
142-
# Count attackers that are of less value than the piece
143-
for attacker_square in attacker_squares:
144-
attacker = board.piece_at(attacker_square)
145-
146-
if PIECE_VALUES[attacker.piece_type] < PIECE_VALUES[piece.piece_type]:
147-
score += PIECE_VALUES[piece.piece_type]
148-
break
149-
150-
# discard threefold repetitions
151-
if board.can_claim_threefold_repetition():
152-
return -1
153-
154-
# reward castling or king mates
155-
if (
156-
board.is_checkmate()
157-
and (
158-
"O-" in move_node.san()
159-
or "K" in move_node.san()
160-
)
161-
):
162-
score += 20
163-
164-
# number of pieces on the board ABOVE that which is typical
165-
# weighted towards rarity of this happening
166-
for colour in piece_counts.keys():
167-
for piece_type, count in piece_counts[colour].items():
168-
if count > TYPICAL_PIECE_COUNTS[piece_type]:
169-
extra_count = count - TYPICAL_PIECE_COUNTS[piece_type]
170-
171-
if piece_type == chess.QUEEN:
172-
if extra_count == 1:
173-
score += 0.5
174-
else:
175-
score += 0.5 + (5 * (extra_count - 1))
176-
else:
177-
score += 4 * extra_count
144+
for i in range(len(attacker_values)):
145+
if i == len(defender_values):
146+
# There is nothing to take
147+
break
148+
if i + 1 == len(defender_values):
149+
# There is nothing defending this piece, we can simply take.
150+
score += defender_values[i] ** .5
151+
elif attacker_values[i] < defender_values[i] and i <= len(defender_values):
152+
# Can take this piece and, when the next defender takes back, we have gained material
153+
score += (defender_values[i] - attacker_values[i]) ** .5
178154

179155
# underpromotions, weighted towards their rarity
180156
if move.promotion == chess.QUEEN:
@@ -191,42 +167,35 @@ def estimate_game_craziness(game: chess.pgn.Game):
191167
if (
192168
"O-" not in move_node.san()
193169
and move.to_square in CORNER_SQUARES
170+
and board.piece_at(move.to_square).piece_type == chess.KNIGHT
194171
):
195-
moved_piece_type = board.piece_at(move.to_square).piece_type
196-
197-
if moved_piece_type in [chess.QUEEN, chess.BISHOP]:
198-
score += 2
199-
elif moved_piece_type == chess.KNIGHT:
200-
score += 3
172+
score += 0.5
201173

202174
# is king in the centre of the board when there are lots of pieces left
203175
if (
204-
king_square[turn_colour] > 23
205-
and king_square[turn_colour] < 40
206-
and node_index <= 30
207-
and piece_counts[opposite_colour(turn_colour)][chess.QUEEN] > 0
208-
):
209-
score += 2.5
210-
211-
# consecutive moves of the king
212-
if (
213-
node_index <= 30
214-
and pieces_remaining >= 20
215-
and pieces_moved[-1] == chess.KING
176+
23 < king_square[turn_colour] < 40
177+
and material[opposite_colour(turn_colour)] > 30
216178
):
217-
pieces_moved_index = 1
179+
score += 1.5
218180

219-
while pieces_moved_index <= len(pieces_moved):
220-
last_moved_piece = pieces_moved[-pieces_moved_index]
221-
222-
if last_moved_piece == chess.KING:
223-
score += 1.5 * (1.075 ** ((pieces_moved_index - 1) / 2))
224-
else:
225-
break
226-
227-
pieces_moved_index += 2
228-
229-
return round(score, 2)
181+
# discard threefold repetitions
182+
if board.can_claim_threefold_repetition():
183+
score -= 30
184+
185+
move_scores.append(score)
186+
best_node_value = 0
187+
best_node = game_moves[0]
188+
ws = [1.3,1.5,1,1,.5,.5,.2,.2,.2,.2]
189+
190+
for i in range(offset, len(move_scores) - len(ws)):
191+
if game_moves[i].board().turn: # white to move only
192+
cur_node_value = total_material[min(len(total_material) - 1, i + 4)] ** .3
193+
for j, w in enumerate(ws):
194+
cur_node_value += w * move_scores[i+j]
195+
if cur_node_value > best_node_value:
196+
best_node_value = cur_node_value
197+
best_node = game_moves[i]
198+
return best_node_value, best_node.board()
230199

231200

232201
# takes in a PGN string and returns the estimated

dist/index.min.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/style.min.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)