tomdodd4598

Untitled

Oct 5th, 2021
1,059
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.96 KB | None | 0 0
  1. import itertools
  2.  
  3. # -------------------------------#
  4. # ========== SETTINGS ========== #
  5. # -------------------------------#
  6.  
  7. # Note: initial positions are counted clockwise from the bottom for the left wheel/console,
  8. # and anti-clockwise from the bottom for the right wheel/console, zero-indexed.
  9.  
  10. # Note: left wheel is numbered 0, right wheel is numbered 1.
  11.  
  12. wheel_size_left = 6  # default = 6
  13. wheel_size_right = 6  # default = 6
  14.  
  15. start_wheel = 0  # default = 0
  16. start_position = 0  # default = 0
  17. end_wheel = 1  # default = 1
  18. end_position = 4  # default = 4
  19.  
  20. valid_positions_left = {0, 2, 4}  # default = {0, 2, 4}
  21. valid_positions_right = {1, 3, 5}  # default = {1, 3, 5}
  22.  
  23. jumps_left_to_right = {0: 0, 3: 3, 4: 4, 5: 5}  # default = {0: 0, 3: 3, 4: 4, 5: 5}
  24. jumps_right_to_left = {0: 0, 3: 3, 4: 4, 5: 5}  # default = {0: 0, 3: 3, 4: 4, 5: 5}
  25.  
  26. blocked_pegs_left = {0, 2}  # default = {0, 2}
  27. blocked_pegs_right = {0}  # default = {0}
  28.  
  29. # -------------------------------#
  30. # ========== INTERNAL ========== #
  31. # -------------------------------#
  32.  
  33. available_pegs_left = set(range(wheel_size_left)) - blocked_pegs_left
  34. available_pegs_right = set(range(wheel_size_right)) - blocked_pegs_right
  35.  
  36.  
  37. class Wheel:
  38.     def __init__(self, size, raw_valid_positions: set):
  39.         self.size = size
  40.         self.raw_valid_positions = raw_valid_positions
  41.         self.rotation = 0
  42.  
  43.     def rotate(self):
  44.         self.rotation += 1
  45.         self.rotation %= self.size
  46.  
  47.     def is_valid_position(self, position):
  48.         position += (self.size - self.rotation)
  49.         return position % self.size in self.raw_valid_positions
  50.  
  51.  
  52. class Console:
  53.     def __init__(self, size, pegs: set):
  54.         self.size = size
  55.         self.pegs = pegs
  56.         self.current_position = 0
  57.  
  58.     def increment_position(self):
  59.         self.current_position += 1
  60.         self.current_position %= self.size
  61.  
  62.  
  63. class Puzzle:
  64.     def __init__(self, wheel_left: Wheel, wheel_right: Wheel, console_left: Console, console_right: Console):
  65.         self.wheel_left = wheel_left
  66.         self.wheel_right = wheel_right
  67.         self.console_left = console_left
  68.         self.console_right = console_right
  69.         self.ball_wheel = start_wheel
  70.         self.ball_position = start_position
  71.  
  72.     def current_wheel(self):
  73.         return self.wheel_left if self.ball_wheel == 0 else self.wheel_right
  74.  
  75.     def current_console(self):
  76.         return self.console_left if self.ball_wheel == 0 else self.console_right
  77.  
  78.     def is_fail(self):
  79.         wheel = self.current_wheel()
  80.         if not wheel.is_valid_position(self.ball_position):
  81.             return True
  82.         console = self.current_console()
  83.         if len(console.pegs) == 0 or max(console.pegs) < console.current_position:
  84.             return True
  85.         return False
  86.  
  87.     def move(self):
  88.         wheel = self.current_wheel()
  89.         wheel.rotate()
  90.         self.ball_position += (wheel.size - 1)
  91.         self.ball_position %= wheel.size
  92.         self.current_console().increment_position()
  93.  
  94.     def get_jumps(self) -> dict:
  95.         return jumps_left_to_right if self.ball_wheel == 0 else jumps_right_to_left
  96.  
  97.     def try_jump(self):
  98.         console = self.current_console()
  99.         if console.current_position in console.pegs:
  100.             jumps = self.get_jumps()
  101.             if self.ball_position in jumps:
  102.                 self.ball_position = jumps[self.ball_position]
  103.                 self.ball_wheel = 1 - self.ball_wheel
  104.                 console.pegs.remove(console.current_position)
  105.                 wheel = self.current_wheel()
  106.                 if not wheel.is_valid_position(self.ball_position):
  107.                     if self.ball_wheel == end_wheel and self.ball_position == end_position:
  108.                         return 1
  109.                     return -1
  110.             else:
  111.                 return -1
  112.         return 0
  113.  
  114.     def simulate(self):
  115.         while True:
  116.             if self.is_fail():
  117.                 return False
  118.             self.move()
  119.             jump = self.try_jump()
  120.             if jump == 1:
  121.                 return len(self.console_left.pegs) == 0 and len(self.console_right.pegs) == 0
  122.             if jump == -1:
  123.                 return False
  124.  
  125.  
  126. def subsets(s, n):
  127.     return map(lambda x: {} if not x else set(x), itertools.combinations(s, n))
  128.  
  129.  
  130. def is_solution(pegs_left, pegs_right):
  131.     wheel_left = Wheel(wheel_size_left, valid_positions_left)
  132.     wheel_right = Wheel(wheel_size_right, valid_positions_right)
  133.     console_left = Console(wheel_size_left, pegs_left)
  134.     console_right = Console(wheel_size_right, pegs_right)
  135.     return Puzzle(wheel_left, wheel_right, console_left, console_right).simulate()
  136.  
  137.  
  138. for i in range(0, 1 + len(available_pegs_left)):
  139.     for j in range(0, 1 + len(available_pegs_right)):
  140.         for left in subsets(available_pegs_left, i):
  141.             for right in subsets(available_pegs_right, j):
  142.                 if is_solution(left.copy(), right.copy()):
  143.                     print(list(left), list(right))
  144.  
Advertisement
Add Comment
Please, Sign In to add comment