Skip to content

Commit

Permalink
Implement rust to python board encoding translation
Browse files Browse the repository at this point in the history
  • Loading branch information
Casper-Guo committed Jun 13, 2024
1 parent 84d968f commit f3f0bd9
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 1 deletion.
4 changes: 3 additions & 1 deletion .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ jobs:
python3 -m pip install pytest
python3 -m pip install -e .
- name: Run tests with pytest
run: pytest ./royal_game/tests/
run: |
pytest ./royal_game/tests/
pytest ./test_translate.py
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,6 @@ ignore = ["D105", "D107", "D203", "D212", "PTH123"]
[tool.ruff.lint.per-file-ignores]
# ignores docstring requirements for test files
"royal_game/tests/**.py" = ["D"]
"test_translate.py" = ["D"]
# ignores requirement for exception classes to end in 'Error'
"royal_game/_exceptions.py" = ["N818", "D"]
63 changes: 63 additions & 0 deletions rust_translate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Translate Rust board seed to Python board seed."""

from royal_game._exceptions import BoardError
from royal_game.modules.board import Board


def translate(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:
print(f"Provided rust seed {rust_seed} is invalid.")
raise e

return py_seed
20 changes: 20 additions & 0 deletions test_translate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import pytest

from royal_game._exceptions import BoardError
from rust_translate import translate


def test_translate():
assert (
translate(0b0010111000000000000010000100000000100000000000001000010000000000)
== 87510499392
)

assert (
translate(0b0110000000000000000000000010100000100000000000000000001000000000)
== 83751871040
)

with pytest.raises(BoardError):
# too many black pieces
translate(0b0000000000001010101010101010000000000000101010101010101000000000)

0 comments on commit f3f0bd9

Please sign in to comment.