solve.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. from graphviz import Digraph
  2. from chess_state import ChessState
  3. proof = Digraph(format='svg', node_attr={'shape': 'record'}, comment='Proof that chess domino is not possible')
  4. def state_id(index):
  5. return f'state{index}'
  6. class Solver:
  7. def __init__(self, board_size=8):
  8. self.board_size = board_size
  9. self.steps = 1
  10. self.starting_state = ChessState(board_size=board_size)
  11. max_steps = (board_size * board_size - 1) // 3
  12. self.states = [[] for _ in range(max_steps + 1)]
  13. self.states[0].append(self.starting_state)
  14. def solvable(self, state):
  15. bricks_on_field = len(state.history())
  16. current_id = (bricks_on_field, len(self.states[bricks_on_field]) - 1)
  17. x, y = state.next_move()
  18. if x is None:
  19. return True # end of board
  20. for direction in ['right', 'down']:
  21. if state.possible(x, y, direction):
  22. next_state = state.put(x, y, direction)
  23. self.steps += 1
  24. found_symmetry = -1
  25. # look for symmetry
  26. for i, b in enumerate(self.states[bricks_on_field + 1]):
  27. if next_state.symmetric_to(b):
  28. print(f'found symmetry between states {current_id} and {(bricks_on_field, i)}')
  29. found_symmetry = i
  30. break
  31. # symmetry found
  32. if found_symmetry != -1:
  33. proof.edge(state_id(current_id),
  34. state_id(found_symmetry),
  35. label=f'put next brick facing {direction} at {(x,y)}')
  36. continue
  37. # pace next brick
  38. bricks_on_field += 1
  39. self.states[bricks_on_field].append(next_state)
  40. next_id = (bricks_on_field, len(self.states[bricks_on_field]) - 1)
  41. proof.edge(state_id(current_id),
  42. state_id(next_id),
  43. label=f'put next brick facing {direction} at {(x,y)}')
  44. proof.node(name=state_id(next_id), label=next_state.board_label())
  45. # try to solve the remaining board
  46. if self.solvable(next_state):
  47. return True
  48. return False
  49. if __name__ == '__main__':
  50. s = Solver(board_size=14)
  51. proof.node(name=state_id(0), label=s.starting_state.board_label())
  52. result = s.solvable(s.starting_state)
  53. print('solvable:', result)
  54. print('steps:', s.steps)
  55. print('states:', len(s.states))
  56. proof.render(f'img/proof.gv', view=False)