-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Additional debugging and translating utilities
- Loading branch information
1 parent
6298d21
commit 5fc3b3b
Showing
5 changed files
with
220 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
"""Display board from input seeds.""" | ||
|
||
import logging | ||
from pathlib import Path | ||
from typing import Optional | ||
|
||
import click | ||
|
||
from royal_game._exceptions import BoardError | ||
from royal_game.modules.board import Board | ||
|
||
logging.basicConfig(format="%(levelname)s: %(message)s") | ||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def process_input(seed: str, decimal: bool) -> Board | None: | ||
"""Produce board from input seed string.""" | ||
try: | ||
seed = int(seed, 10 if decimal else 2) | ||
except ValueError as e: | ||
logger.warning(e) | ||
return None | ||
|
||
try: | ||
board = Board(seed) | ||
except BoardError as e: | ||
logger.warning(e) | ||
board = Board(seed, no_verify=True) | ||
finally: | ||
return board | ||
|
||
|
||
@click.command() | ||
@click.option("--decimal/--binary", "-d/-b", default=True) | ||
@click.argument("in_file", required=False, type=click.Path(exists=True, path_type=Path)) | ||
def main(decimal: bool, in_file: Optional[Path]): | ||
""" | ||
Accept seed input from user or file and display the corresponding boards. | ||
If an input file is provided, decimal encoding is assumed. The file should | ||
contain one seed per line. | ||
Warnings are shown for invalid boards but the program will not terminate. | ||
""" | ||
if in_file is not None: | ||
decimal = True | ||
with open(in_file, "r") as fin: | ||
seeds = [line.strip() for line in fin.readlines()] | ||
|
||
for seed in seeds: | ||
board = process_input(seed, decimal) | ||
if board is not None: | ||
print(f"{seed}:\n{board}") | ||
|
||
else: | ||
user_input = "" | ||
while user_input != "quit": | ||
user_input = input("Enter a board seed in the chosen encoding: ") | ||
board = process_input(user_input, decimal) | ||
if board is not None: | ||
print(board) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,40 @@ | ||
import pytest | ||
|
||
from royal_game._exceptions import BoardError | ||
from rust_translate import translate | ||
from translate import rust_to_python, python_to_rust | ||
|
||
|
||
def test_translate(): | ||
def test_rust_to_python(): | ||
assert ( | ||
translate(0b0010111000000000000010000100000000100000000000001000010000000000) | ||
rust_to_python(0b0010111000000000000010000100000000100000000000001000010000000000) | ||
== 87510499392 | ||
) | ||
|
||
assert ( | ||
translate(0b0110000000000000000000000010100000100000000000000000001000000000) | ||
rust_to_python(0b0110000000000000000000000010100000100000000000000000001000000000) | ||
== 83751871040 | ||
) | ||
|
||
with pytest.raises(BoardError): | ||
# too many black pieces | ||
translate(0b0000000000001010101010101010000000000000101010101010101000000000) | ||
rust_to_python(0b0000000000001010101010101010000000000000101010101010101000000000) | ||
|
||
|
||
def test_python_to_rust(): | ||
assert ( | ||
python_to_rust(87510499392) | ||
== 0b1110111000000000000010000100000000100000000000001000010000000000 | ||
) | ||
|
||
assert ( | ||
python_to_rust(83751871040) | ||
== 0b0110000000000000000000000010100000100000000000000000001000000000 | ||
) | ||
|
||
assert ( | ||
python_to_rust(966988398624) | ||
== 0b1000001000000101000000000000000000000100010100000000000000000000 | ||
) | ||
|
||
with pytest.raises(BoardError): | ||
python_to_rust(155055118456) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
"""Translate Rust board seed to Python board seed.""" | ||
|
||
import logging | ||
import click | ||
from pathlib import Path | ||
|
||
from royal_game._exceptions import BoardError | ||
from royal_game._constants import white_order_iter, black_order_iter | ||
from royal_game.modules.board import Board | ||
|
||
logging.basicConfig(format="%(levelname)s: %(message)s") | ||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def rust_to_python(rust_seed: int, verify: bool = True) -> int: | ||
""" | ||
Rust board encoding schema copied below. | ||
Two bits each for board grids to achieve consistency in the order of | ||
W1...W4, 5...12, W13, W14, B1...B4, 5...12, B13, B14 (from least to most significant). | ||
Note the more significant bit of private grids are unused (56 total) | ||
Three bits each for WS and BS from the least to the most significant (6 total) | ||
Bits 62-63 indicate the endgame state. | ||
This is useful for stopping search and assigning rewards. | ||
00: not set/calculated | ||
01: white win | ||
10: black win | ||
11: in progress | ||
""" | ||
py_seed = 0 | ||
white_total, black_total = 0, 0 | ||
|
||
for py_offset, rust_offset in enumerate((0, 2, 4, 6, 24, 26)): | ||
if ((rust_seed & (0b11 << rust_offset)) >> rust_offset) == 0b01: | ||
white_total += 1 | ||
py_seed += 1 << py_offset | ||
|
||
for py_offset, rust_offset in enumerate((28, 30, 32, 34, 52, 54)): | ||
if ((rust_seed & (0b11 << rust_offset)) >> rust_offset) == 0b10: | ||
black_total += 1 | ||
py_seed += 1 << (py_offset + 6) | ||
|
||
for py_offset, rust_offset in zip(range(12, 28, 2), range(8, 24, 2)): | ||
grid_status = (rust_seed & (0b11 << rust_offset)) >> rust_offset | ||
py_seed += grid_status << py_offset | ||
|
||
if grid_status == 0b01: | ||
white_total += 1 | ||
elif grid_status == 0b10: | ||
black_total += 1 | ||
|
||
num_ws = (rust_seed & (0b111 << 56)) >> 56 | ||
py_seed += num_ws << 28 | ||
num_bs = (rust_seed & (0b111 << 59)) >> 59 | ||
py_seed += num_bs << 34 | ||
|
||
# WE | ||
py_seed += (7 - white_total - num_ws) << 31 | ||
# BE | ||
py_seed += (7 - black_total - num_bs) << 37 | ||
|
||
if verify: | ||
try: | ||
_ = Board(py_seed) | ||
except BoardError as e: | ||
logger.warning("Provided rust seed %d is invalid.", rust_seed) | ||
raise e | ||
|
||
return py_seed | ||
|
||
|
||
def python_to_rust(py_seed: int, verify: bool = True) -> int: | ||
""" | ||
Python board encoding schema copied below. | ||
bit 0-5: one bit each for W1...W14 indicating | ||
whether the grid is occupied | ||
bit 6-11: one bit each for B1...B14 indicating | ||
whether the grid is occupied | ||
bit 12-27: two bit each for 5...12 indicating | ||
whether the grid is empty, white, or black | ||
bit 28-39: three bit each for WS, WE, BS, BE | ||
indicating number of pieces at start/end | ||
The endgame state bits will always be set. Thus the following assumption | ||
is not valid: | ||
python_to_rust(rust_to_python(rust_seed)) == rust_seed | ||
Only compare the lower 62 bits if needed. | ||
""" | ||
if verify: | ||
try: | ||
_ = Board(py_seed) | ||
except BoardError as e: | ||
logger.warning("Provided python seed %d is invalid.", py_seed) | ||
raise e | ||
|
||
board = Board(py_seed, no_verify=True) | ||
rust_seed = 0 | ||
|
||
if board.board["WE"].num_pieces == 7: | ||
rust_seed += 0b01 << 62 | ||
elif board.board["BE"].num_pieces == 7: | ||
rust_seed += 0b10 << 62 | ||
else: | ||
rust_seed += 0b11 << 62 | ||
|
||
rust_seed += int(board.board["WS"]) << 56 | ||
rust_seed += int(board.board["BS"]) << 59 | ||
|
||
for grid, offset in zip(list(white_order_iter()), range(0, 28, 2)): | ||
# we can take this shortcut because GridStatus(1) indicates white | ||
# which match the status bit for an occupied white private grid | ||
rust_seed += int(board.board[grid]) << offset | ||
|
||
for grid, offset in zip(list(black_order_iter()), range(28, 56, 2)): | ||
rust_seed += int(board.board[grid]) << offset | ||
|
||
return rust_seed | ||
|
||
def main(): | ||
pass | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |