forked from WintrCat/chessencryption
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathencode.py
More file actions
126 lines (90 loc) · 3.34 KB
/
encode.py
File metadata and controls
126 lines (90 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
from time import time
from math import log2
from chess import pgn, Board
from util import to_binary_string
###
### Enter a file path
### and it returns a string of 1 or more PGNs that represent it
###
def encode(file_path: str):
start_time = time()
# read binary of file
print("reading file...")
file_bytes = list(open(file_path, "rb").read())
# record number of bits in file
file_bits_count = len(file_bytes) * 8
# convert file to chess moves
print("\nencoding file...")
output_pgns: list[str] = []
file_bit_index = 0
chess_board = Board()
while True:
legal_moves = list(chess_board.generate_legal_moves())
# assign moves a binary value based on its index
move_bits = {}
max_binary_length = min(
int(log2(
len(legal_moves)
)),
file_bits_count - file_bit_index
)
for index, legal_move in enumerate(legal_moves):
move_binary = to_binary_string(index, max_binary_length)
if len(move_binary) > max_binary_length:
break
move_bits[legal_move.uci()] = move_binary
# take next binary chunk from the file
closest_byte_index = file_bit_index // 8
file_chunk_pool = "".join([
to_binary_string(byte, 8)
for byte in file_bytes[closest_byte_index : closest_byte_index + 2]
])
next_file_chunk = file_chunk_pool[
file_bit_index % 8
: file_bit_index % 8 + max_binary_length
]
# push chess move that corresponds with next chunk
for move_uci in move_bits:
move_binary = move_bits[move_uci]
if move_binary == next_file_chunk:
chess_board.push_uci(move_uci)
break
# move the pointer along by the chunk size
file_bit_index += max_binary_length
# check if the game is in a terminal state or EOF
# if it is, convert it to a pgn and add to pgn list
eof_reached = file_bit_index >= file_bits_count
if (
chess_board.legal_moves.count() <= 1
or chess_board.is_insufficient_material()
or chess_board.can_claim_draw()
or eof_reached
):
pgn_board = pgn.Game()
pgn_board.add_line(chess_board.move_stack)
output_pgns.append(str(pgn_board))
chess_board.reset()
if eof_reached: break
print(
f"\nsuccessfully converted file to pgn with "
+ f"{len(output_pgns)} game(s) "
+ f"({round(time() - start_time, 3)}s)."
)
# return pgn string
return "\n\n".join(output_pgns)
def run_encoder():
file_path = input("Enter the file path: ")
output_file = input("Enter the output file name (with .pgn extension): ")
try:
# Call the encode function and pass the file path
pgn_result = encode(file_path)
# Save the PGN result into a file
with open(output_file, "w") as file:
file.write(pgn_result)
print(f"\nPGN(s) successfully saved to {output_file}")
except FileNotFoundError:
print(f"Error: The file '{file_path}' was not found.")
except Exception as e:
print(f"An error occurred: {e}")
# To execute the function, simply call run_encoder()
run_encoder()