import unittest
from dds3 import solve_board, solve_board_pbn
from test_utils import assert_raises
class TestSolveBoard(unittest.TestCase):
def test_solve_board_basic(self) -> None:
deal = {
"trump": 0, "first": 0, "remain_cards": [
[0x7FFC, 0, 0, 0], [0, 0x7FFC, 0, 0], [0, 0, 0x7FFC, 0], [0, 0, 0, 0x7FFC], ],
"current_trick_suit": (0, 0, 0),
"current_trick_rank": (0, 0, 0),
}
result = solve_board(deal)
self.assertIn("nodes", result)
self.assertIsInstance(result["score"], tuple)
def test_solve_board_with_defaults(self) -> None:
deal = {
"trump": 4, "first": 0,
"remain_cards": [
[0x7FFC, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
],
"current_trick_suit": (0, 0, 0),
"current_trick_rank": (0, 0, 0),
}
try:
result = solve_board(deal)
self.assertIn("nodes", result)
except RuntimeError:
pass
def test_solve_board_invalid_trump(self) -> None:
deal = {
"trump": 5, "first": 0,
"remain_cards": [[0, 0, 0, 0]] * 4,
"current_trick_suit": (0, 0, 0),
"current_trick_rank": (0, 0, 0),
}
assert_raises(ValueError, solve_board, deal, match="invalid value 5")
def test_solve_board_invalid_first(self) -> None:
deal = {
"trump": 0,
"first": 4, "remain_cards": [[0, 0, 0, 0]] * 4,
"current_trick_suit": (0, 0, 0),
"current_trick_rank": (0, 0, 0),
}
assert_raises(ValueError, solve_board, deal, match="invalid value 4")
def test_solve_board_invalid_trick_suit(self) -> None:
deal = {
"trump": 0,
"first": 0,
"remain_cards": [[0, 0, 0, 0]] * 4,
"current_trick_suit": (0, 0, 5), "current_trick_rank": (0, 0, 0),
}
assert_raises(ValueError, solve_board, deal, match="invalid value 5")
def test_solve_board_invalid_trick_rank(self) -> None:
deal = {
"trump": 0,
"first": 0,
"remain_cards": [[0, 0, 0, 0]] * 4,
"current_trick_suit": (0, 0, 0),
"current_trick_rank": (2, 2, 15), }
assert_raises(ValueError, solve_board, deal, match="invalid value 15")
def test_solve_board_invalid_cards_size(self) -> None:
deal = {
"trump": 0,
"first": 0,
"remain_cards": [[0, 0, 0]], "current_trick_suit": (0, 0, 0),
"current_trick_rank": (0, 0, 0),
}
assert_raises(ValueError, solve_board, deal)
class TestSolveBoardPBN(unittest.TestCase):
def test_solve_board_pbn_basic(self) -> None:
pbn = "N:QJ6.K652.J85.T98 873.J97.AT764.Q4 K5.T83.KQ9.A7652 AT942.AQ4.32.KJ3"
result = solve_board_pbn(pbn, trump=4, first=0)
self.assertIn("nodes", result)
def test_solve_board_pbn_with_defaults(self) -> None:
pbn = "N:QJ6.K652.J85.T98 873.J97.AT764.Q4 K5.T83.KQ9.A7652 AT942.AQ4.32.KJ3"
result = solve_board_pbn(pbn) self.assertIn("nodes", result)
def test_solve_board_pbn_invalid_format(self) -> None:
invalid_pbn = "This is not a valid PBN"
assert_raises((ValueError, RuntimeError), solve_board_pbn, invalid_pbn)
def test_solve_board_pbn_invalid_trump(self) -> None:
pbn = "N:QJ6.K652.J85.T98 873.J97.AT764.Q4 K5.T83.KQ9.A7652 AT942.AQ4.32.KJ3"
assert_raises((ValueError, RuntimeError), solve_board_pbn, pbn, trump=5)
def test_solve_board_pbn_invalid_first(self) -> None:
pbn = "N:QJ6.K652.J85.T98 873.J97.AT764.Q4 K5.T83.KQ9.A7652 AT942.AQ4.32.KJ3"
assert_raises((ValueError, RuntimeError), solve_board_pbn, pbn, first=4)
def test_solve_board_pbn_default_trump_is_nt(self) -> None:
pbn = "N:QJ6.K652.J85.T98 873.J97.AT764.Q4 K5.T83.KQ9.A7652 AT942.AQ4.32.KJ3"
result = solve_board_pbn(pbn) self.assertGreaterEqual(result["cards"], 0)
def test_solve_board_pbn_default_first_is_north(self) -> None:
pbn = "N:QJ6.K652.J85.T98 873.J97.AT764.Q4 K5.T83.KQ9.A7652 AT942.AQ4.32.KJ3"
result = solve_board_pbn(pbn) self.assertGreaterEqual(result["cards"], 0)
def test_solve_board_pbn_current_trick_validation(self) -> None:
pbn = "N:QJ6.K652.J85.T98 873.J97.AT764.Q4 K5.T83.KQ9.A7652 AT942.AQ4.32.KJ3"
assert_raises(ValueError, solve_board_pbn, pbn, current_trick_suit=(0, 0, 5), match="invalid value")
class TestSolveBoardParity(unittest.TestCase):
def test_default_parameters_consistent(self) -> None:
pbn = "N:QJ6.K652.J85.T98 873.J97.AT764.Q4 K5.T83.KQ9.A7652 AT942.AQ4.32.KJ3"
result_pbn = solve_board_pbn(pbn)
self.assertIn("nodes", result_pbn)
self.assertIn("score", result_pbn)
if __name__ == "__main__":
unittest.main()