SergeyO7 commited on
Commit
f706229
·
verified ·
1 Parent(s): 7126ad4

Create prechess.py

Browse files
Files changed (1) hide show
  1. prechess.py +151 -0
prechess.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+
4
+ @tool
5
+ def PNG2FENTool(png_file: str) -> str:
6
+ """Tool for converting a PNG file containing a chess board to a FEN position string.
7
+ Args:
8
+ png_file (str): The path to the PNG file.
9
+ Returns:
10
+ str: The FEN position string representing the chess board.
11
+ """
12
+ # Raises:
13
+ # - FileNotFoundError:
14
+ # If the PNG file does not exist.
15
+ # - ValueError:
16
+ # If the PNG file cannot be processed or does not contain a valid chess board.
17
+
18
+ try:
19
+ # Open and preprocess image with modern Pillow
20
+ img = Image.open(png_file)
21
+ img = ImageOps.exif_transpose(img).convert("L")
22
+
23
+ # Use LANCZOS instead of ANTIALIAS
24
+ img = img.resize((img.width*2, img.height*2), Image.Resampling.LANCZOS)
25
+
26
+ # Save temp file for OCR
27
+ temp_path = "chess_temp.png"
28
+ img.save(temp_path)
29
+
30
+ # Perform OCR
31
+ import easyocr
32
+ reader = easyocr.Reader(['en'])
33
+ result = reader.readtext(png_file, detail=0)
34
+ fen_candidates = [text for text in result if validate_fen_format(text)]
35
+
36
+ if not fen_candidates:
37
+ raise ValueError("No valid FEN found in image")
38
+
39
+ return fen_candidates[0]
40
+
41
+ except Exception as e:
42
+ raise ValueError(f"OCR processing failed: {str(e)}")
43
+
44
+
45
+ # try:
46
+ # # Open the PNG file using PIL
47
+ # image = Image.open(png_file)
48
+ #
49
+ # # Use pytesseract to extract text from the image
50
+ # text = pytesseract.image_to_string(image)
51
+ #
52
+ # # Process the extracted text to get the FEN position string
53
+ # fen_position = process_text_to_fen(text)
54
+ #
55
+ # return fen_position
56
+ #
57
+ except FileNotFoundError:
58
+ raise FileNotFoundError("PNG file not found.")
59
+ #
60
+ # except Exception as e:
61
+ # raise ValueError("Error processing PNG file: " + str(e))
62
+
63
+ def process_text_to_fen(text):
64
+ """
65
+ Processes the extracted text from the image to obtain the FEN position string.
66
+ Parameters:
67
+ - text: str
68
+ The extracted text from the image.
69
+ Returns:
70
+ - str:
71
+ The FEN position string representing the chess board.
72
+ Raises:
73
+ - ValueError:
74
+ If the extracted text does not contain a valid chess board.
75
+ """
76
+
77
+ # Process the text to remove any unnecessary characters or spaces
78
+ processed_text = text.strip().replace("\n", "").replace(" ", "")
79
+
80
+ # Check if the processed text matches the expected format of a FEN position string
81
+ if not validate_fen_format(processed_text):
82
+ raise ValueError("Invalid chess board.")
83
+
84
+ return processed_text
85
+
86
+ def validate_fen_format(fen_string):
87
+ """
88
+ Validates if a given string matches the format of a FEN (Forsyth–Edwards Notation) position string.
89
+ Parameters:
90
+ - fen_string: str
91
+ The string to be validated.
92
+ Returns:
93
+ - bool:
94
+ True if the string matches the FEN format, False otherwise.
95
+ """
96
+
97
+ # FEN format: 8 sections separated by '/'
98
+ sections = fen_string.split("/")
99
+ if len(sections) != 8:
100
+ return False
101
+
102
+ # Check if each section contains valid characters
103
+ for section in sections:
104
+ if not validate_section(section):
105
+ return False
106
+
107
+ return True
108
+
109
+ def validate_section(section):
110
+ """
111
+ Validates if a given section of a FEN (Forsyth–Edwards Notation) position string contains valid characters.
112
+ Parameters:
113
+ - section: str
114
+ The section to be validated.
115
+ Returns:
116
+ - bool:
117
+ True if the section contains valid characters, False otherwise.
118
+ """
119
+
120
+ # Valid characters: digits 1-8 or letters 'r', 'n', 'b', 'q', 'k', 'p', 'R', 'N', 'B', 'Q', 'K', 'P'
121
+ valid_chars = set("12345678rnbqkpRNBQKP")
122
+ return all(char in valid_chars for char in section)
123
+
124
+ import chess
125
+ import chess.engine
126
+
127
+ class ChessEngineTool(Tool):
128
+ name = "chess_engine"
129
+ description = "Analyzes a chess position (FEN) with Stockfish and returns the best move."
130
+ inputs = {
131
+ "fen": {"type": "string", "description": "FEN string of the position."},
132
+ "time_limit": {"type": "number", "description": "Time in seconds for engine analysis.", "nullable": True}
133
+ }
134
+ output_type = "string"
135
+
136
+ def forward(self, fen: str, time_limit: float = 0.1) -> str:
137
+ # figure out where the binary actually is
138
+ sf_bin = shutil.which("stockfish") or "/usr/games/stockfish"
139
+ if not sf_bin:
140
+ raise RuntimeError(
141
+ f"Cannot find stockfish on PATH or at /usr/games/stockfish. "
142
+ "Did you install it in apt.txt or via apt-get?"
143
+ )
144
+
145
+ board = chess.Board(fen)
146
+ engine = chess.engine.SimpleEngine.popen_uci(sf_bin)
147
+ result = engine.play(board, chess.engine.Limit(time=time_limit))
148
+ engine.quit()
149
+ return board.san(result.move)
150
+
151
+