Created
August 26, 2025 14:07
-
-
Save DUznanski/2ca99ae7315a261494076e888db0e6ac to your computer and use it in GitHub Desktop.
Rolling Block and Phasic Dial solvers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from itertools import product | |
| from math import lcm | |
| sizes = (8,8,8) | |
| initial_positions = (6,5,4) | |
| buttons = [ | |
| (1,1,1), | |
| (0,1,1), | |
| (1,0,1), | |
| ] | |
| def solve_phasic_dial(sizes, initial_positions, buttons): | |
| target = [(s-i) % s for s,i in zip(sizes,initial_positions)] | |
| max_presses = lcm(*sizes) | |
| press_piles = [] | |
| for button in buttons: | |
| pile = [] | |
| for k in range(max_presses): | |
| press_result = tuple((i * k) % s for i, s in zip(button, sizes)) | |
| if k != 0 and max(press_result) == 0: break | |
| pile.append(press_result) | |
| press_piles.append(pile) | |
| best_count = max_presses * len(sizes) | |
| best_result = None | |
| for p in sorted(product(*(range(len(pile)) for pile in press_piles)), key = sum): | |
| pile_selection = [pile[k] for pile, k in zip(press_piles, p)] | |
| pile_sum = [sum(i) for i in zip(*pile_selection)] | |
| fixed_sum = [i % s for i, s in zip(pile_sum, sizes)] | |
| if fixed_sum == target: | |
| return p | |
| print(solve_phasic_dial(sizes, initial_positions, buttons)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| board = """ xxxx | |
| xxxx | |
| xxxx | |
| xxxx | |
| xxxxxxx | |
| xxxxx x | |
| xxxx x | |
| xxxxxxxxx | |
| xxxxxxxxx | |
| """ | |
| start = (4,5,2,1,2) | |
| finish = (7,8,2,1,2) | |
| tiles = set() | |
| fragile = set() | |
| for l, line in enumerate(board.splitlines()): | |
| for c, char in enumerate(line): | |
| if char == 'x': | |
| tiles.add((c,l)) | |
| elif char == 'f': | |
| fragile.add((c,l)) | |
| fragile = frozenset(fragile) | |
| def go_east(pos): | |
| return (pos[0] + pos[2], pos[1], pos[4], pos[3], pos[2]) | |
| def go_west(pos): | |
| return (pos[0] - pos[4], pos[1], pos[4], pos[3], pos[2]) | |
| def go_south(pos): | |
| return (pos[0], pos[1] + pos[3], pos[2], pos[4], pos[3]) | |
| def go_north(pos): | |
| return (pos[0], pos[1] - pos[4], pos[2], pos[4], pos[3]) | |
| def is_legal(pos,fragile,tiles): | |
| for x in range(pos[0], pos[0] + pos[2]): | |
| for y in range(pos[1], pos[1] + pos[3]): | |
| if (x, y) not in tiles and (x, y) not in fragile: | |
| return False | |
| return True | |
| def delete_fragile(pos,fragile): | |
| coverage = frozenset((x,y) for x in range(pos[0], pos[0] + pos[2]) for y in range(pos[1], pos[1] + pos[3])) | |
| return fragile - coverage | |
| def is_solved(pos,fragile,finish): | |
| return not fragile and (finish is None or pos == finish) | |
| directions = [ | |
| ('n', go_north), | |
| ('s', go_south), | |
| ('e', go_east), | |
| ('w', go_west) | |
| ] | |
| fragile = delete_fragile(start, fragile) | |
| itinerary = [(start, fragile)] | |
| known_paths = {(start, fragile): ''} | |
| while itinerary: | |
| pos, fragile = itinerary.pop(0) | |
| path = known_paths[pos, fragile] | |
| for d, move in directions: | |
| new_pos = move(pos) | |
| new_fragile = delete_fragile(new_pos, fragile) | |
| if is_legal(new_pos,fragile,tiles) and (new_pos, new_fragile) not in known_paths: | |
| known_paths[(new_pos, new_fragile)] = path + d | |
| itinerary.append((new_pos, new_fragile)) | |
| for (pos, fragile), path in known_paths.items(): | |
| if is_solved(pos,fragile,finish): | |
| print(path) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment