2023-08-30 01:19:05 +00:00
|
|
|
import random
|
2023-08-30 00:57:05 +00:00
|
|
|
from typing import Callable
|
|
|
|
|
|
|
|
from .board import Board
|
|
|
|
|
|
|
|
|
|
|
|
def solve(
|
|
|
|
state: Board,
|
|
|
|
is_solved: Callable[[Board], bool],
|
|
|
|
*,
|
|
|
|
history: list[tuple[int, Board]] | None = None,
|
2023-08-30 01:19:05 +00:00
|
|
|
shuffle: bool = False,
|
2023-08-30 00:57:05 +00:00
|
|
|
) -> list[tuple[int, Board]] | None:
|
|
|
|
|
|
|
|
if history is None:
|
|
|
|
# create starting state
|
|
|
|
history = [(-1, state)]
|
|
|
|
|
|
|
|
if is_solved(state):
|
|
|
|
return history
|
|
|
|
|
2023-08-30 01:19:05 +00:00
|
|
|
buttons = state.buttons
|
|
|
|
if shuffle:
|
|
|
|
buttons = random.sample(buttons, len(buttons))
|
|
|
|
|
|
|
|
for button in buttons:
|
2023-08-30 00:57:05 +00:00
|
|
|
# try to click all buttons
|
|
|
|
next = state.click(button)
|
|
|
|
|
|
|
|
if next is not None:
|
|
|
|
# click successful
|
|
|
|
binary_history = (
|
|
|
|
state.binary_repr
|
|
|
|
for _, state in history
|
|
|
|
)
|
|
|
|
|
|
|
|
if next.binary_repr not in binary_history:
|
|
|
|
# "next" is a new state
|
|
|
|
solution = solve(
|
|
|
|
next, is_solved,
|
|
|
|
history=[*history, (button, next)]
|
|
|
|
)
|
|
|
|
|
|
|
|
if solution is not None:
|
|
|
|
return solution
|