Thursday, June 25, 2026
MODIFICATION - Add comments, Import chess games, catalog them, list from first variation move and by frequency. / Chess and Music brainstorming
Also see hhttps://1a2b3c4d5e6f7g8h9i10j11k12l13m14n.blogspot.com/2026/06/modification-import-chess-games-catalog.html
and https://1a2b3c4d5e6f7g8h9i10j11k12l13m14n.blogspot.com/2026/06/import-chess-games-catalog-them-list.html
"""
chessopenings3cleanup.py
Interactive Opening Catalog + Continuation Analyzer
- Loads existing opening catalog (JSON)
- Processes ONE PGN at a time
- Preserves PGN comments { }
- Displays full interactive catalog
- Allows manual reordering
- Save with comments or without comments
Requires:
pip install python-chess
"""
import chess.pgn
import os
import json
import re
JSON_FILE = "personal_openings.json"
START_PLY = 0
MAX_PLIES = 30
# ----------------------------
# LOAD / SAVE
# ----------------------------
def load_data():
if os.path.exists(JSON_FILE):
with open(JSON_FILE, "r", encoding="utf-8") as f:
return json.load(f)
return {}
def save_data(data):
with open(JSON_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, indent=4)
def strip_comments(text):
return re.sub(r"\s*\{.*?\}", "", text)
def remove_comments_from_data(data):
clean_data = {}
for opening_key, variations in data.items():
clean_data[opening_key] = {}
for line, freq in variations.items():
clean_line = strip_comments(line)
if clean_line not in clean_data[opening_key]:
clean_data[opening_key][clean_line] = freq
else:
clean_data[opening_key][clean_line] += freq
return clean_data
# ----------------------------
# FORMAT MOVES
# ----------------------------
def format_continuation(san_moves, start_ply):
lines = []
i = 0
ply = start_ply
while i < len(san_moves) and ply < MAX_PLIES:
move_number = (ply // 2) + 1
white = san_moves[i]
i += 1
ply += 1
line = f"{move_number}. {white}"
if i < len(san_moves) and ply < MAX_PLIES:
black = san_moves[i]
i += 1
ply += 1
line += f" {black}"
lines.append(line)
return lines
# ----------------------------
# PROCESS PGN
# ----------------------------
def process_pgn(filename, data):
game_count = 0
with open(filename, "r", encoding="utf-8", errors="ignore") as pgn:
while True:
game = chess.pgn.read_game(pgn)
if game is None:
break
game_count += 1
eco = game.headers.get("ECO", "").strip()
opening = game.headers.get("Opening", "").strip()
variation = game.headers.get("Variation", "").strip()
white_elo = game.headers.get("WhiteElo", "")
black_elo = game.headers.get("BlackElo", "")
try:
white_elo = int(white_elo)
black_elo = int(black_elo)
except ValueError:
continue
if white_elo < 2100 and black_elo < 2100:
continue
if not opening:
opening = "Unknown Opening"
key = f"{eco} | {opening}"
if variation:
key += f" | {variation}"
board = game.board()
san_moves = []
node = game
ply_count = 0
while node.variations and ply_count < MAX_PLIES:
next_node = node.variation(0)
move_text = board.san(next_node.move)
comment = next_node.comment.strip()
if comment:
move_text += f" {{{comment}}}"
san_moves.append(move_text)
board.push(next_node.move)
node = next_node
ply_count += 1
catalog_lines = format_continuation(
san_moves,
START_PLY
)
catalog_str = " ".join(catalog_lines)
if key not in data:
data[key] = {}
if catalog_str not in data[key]:
data[key][catalog_str] = 1
else:
data[key][catalog_str] += 1
print("\nGames processed:", game_count)
# ----------------------------
# DISPLAY
# ----------------------------
def display(data):
print("\nOPENING CATALOG")
print("=" * 100)
items = sorted(
data.items(),
key=lambda item: sum(item[1].values()),
reverse=True
)
for i, (key, variations) in enumerate(items, start=1):
print(f"\n{i:3} {key}")
sorted_variations = sorted(
variations.items(),
key=lambda x: x[1],
reverse=True
)
for j, (cont, freq) in enumerate(
sorted_variations[:5],
start=1
):
print(f"\n [{j}] freq={freq}")
print(f" {cont}")
print("-" * 100)
# ----------------------------
# REORDER
# ----------------------------
def reorder(data):
items = list(data.items())
while True:
display(dict(items))
print("\nCommands:")
print(" X=Y move item X to position Y")
print(" s save WITH comments")
print(" n save WITHOUT comments")
print(" q quit")
cmd = input("\nCommand: ").strip().lower()
if cmd == "s":
save_data(dict(items))
print("\nSaved with comments.")
continue
if cmd == "n":
clean_data = remove_comments_from_data(
dict(items)
)
save_data(clean_data)
print("\nSaved without comments.")
continue
if cmd == "q":
return dict(items)
if "=" in cmd:
try:
a, b = cmd.split("=")
a = int(a) - 1
b = int(b) - 1
item = items.pop(a)
items.insert(b, item)
except:
print("Invalid command")
# ----------------------------
# MAIN
# ----------------------------
def main():
data = load_data()
print("\nChessOpenings3 Cleanup")
print("----------------------")
filename = input(
"\nPGN filename (WITHOUT .pgn): "
).strip()
if not filename:
return
filename += ".pgn"
if not os.path.exists(filename):
print("File not found:", filename)
return
process_pgn(filename, data)
data = reorder(data)
print("\nDone.")
if __name__ == "__main__":
main()
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment