diff --git a/skewb_solver.py b/skewb_solver.py index 4d40faf..7c532b0 100644 --- a/skewb_solver.py +++ b/skewb_solver.py @@ -275,7 +275,10 @@ def instructions(twists: list[Axis]) -> str: def breadth_first_search( - start: Skewb, is_end: Callable[[Skewb], bool], max_steps: int = 2000000 + start: Skewb, + is_end: Callable[[Skewb], bool], + max_steps: int = 2000000, + bidirectional_fallback_threshold: int | None = None, ) -> list[Twist] | None: start.assert_valid() if is_end(start): @@ -293,10 +296,16 @@ def breadth_first_search( out.reverse() return out + step_count = 0 while q and max_steps > 0: - max_steps -= 1 - if max_steps % 1000 == 0: + if max_steps % 1000 == 0 and step_count: print(".", end="", flush=True) + if ( + bidirectional_fallback_threshold is not None + and step_count > bidirectional_fallback_threshold + ): + return bidirectional_search(start, max_steps) + step_count += 1 parent = q.popleft() for twist in TWISTS: @@ -534,13 +543,15 @@ def get_paths_from_heuristic( assert len(matches) == len(mask) return all(match >= m for match, m in zip(matches, mask)) + print(f"{mask=} {s=}", end=" ") if heuristic_i == len(heuristic_permutation) - 3: # print("going bidirectional now.") path = bidirectional_search(s, max_steps=200000) else: - path = breadth_first_search(s, step_finished) - # print() - print(f"{mask=} {s=} {path=}") + path = breadth_first_search( + s, step_finished, bidirectional_fallback_threshold=20000 + ) + print(f" {path=}") if path is None: raise ValueError("oh no! solver could not find solution") out.append(path) @@ -565,26 +576,21 @@ def quadratic_mean(values: list[float]) -> float: return sqrt(sum(x * x for x in values) / len(values)) -def get_mean_path_length( - start: Skewb, - heuristic_permutation: list[int], - mean_fn: Callable[[list[float]], float] = quadratic_mean, -) -> float: - return mean_fn( - [len(p) for p in get_paths_from_heuristic(start, heuristic_permutation)] - ) +def score_fn(values: list[float]) -> float: + return -sum(2**i * v for i, v in enumerate(sorted(values))) @shelve_it("skewb_solver.evaluate_permutation.shelve.sqlite") def evaluate_permutation( heuristic_permutation: list[int], seed=4, sample_size: int = 10 ) -> float: - pls = [] + scores = [] for i in range(sample_size): - pl = get_mean_path_length(random_skewb(seed=i + seed), heuristic_permutation) - print(f"{pl=}") - pls.append(pl) - return sum(pls) / len(pls) + paths = get_paths_from_heuristic(start, heuristic_permutation) + score = score_fn([len(p) for p in paths]) + print(f"{score=}") + scores.append(score) + return sum(scores) / len(scores) def evaluate_all_1_swaps(hp: list[int]): @@ -605,49 +611,11 @@ def evaluate_all_1_swaps_except_first(hp: list[int]): if __name__ == "__main__": - # print(bidirectional_search(start, max_steps=20000000, end=solved_skewb)) - # print(breadth_first_search(start=start, is_end=lambda s: s == solved_skewb)) - # hp = list(range(HURISTIC_PERMUTATION_LENGTH)) + hp = top_bot_mids = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] hp = top_down = [0, 1, 2, 3, 8, 9, 10, 11, 12, 4, 5, 6, 7] - # hp = small_corner_start = [0, 8, 11, 1, 2, 3, 9, 10, 12, 4, 5, 6, 7] - # hp = big_corner_start = [4, 0, 8, 11, 5, 7, 1, 2, 3, 9, 10, 12, 6] - # print(f"{evaluate_permutation(hp, sample_size=22)=}") # evaluate_all_1_swaps(top_down) - # print( - # f"{(hp := [10, 1, 2, 3, 8, 9, 0, 11, 12, 4, 5, 6, 7])} {evaluate_permutation(hp, sample_size=100)=}" - # ) - # print( - # f"{(hp := [0, 10, 2, 3, 8, 9, 1, 11, 12, 4, 5, 6, 7])} {evaluate_permutation(hp, sample_size=100)=}" - # ) - # print( - # f"{(hp := [0, 1, 10, 3, 8, 9, 2, 11, 12, 4, 5, 6, 7])} {evaluate_permutation(hp, sample_size=100)=}" - # ) - # print( - # f"{(hp := [0, 1, 2, 10, 8, 9, 3, 11, 12, 4, 5, 6, 7])} {evaluate_permutation(hp, sample_size=100)=}" - # ) - # print( - # f"{(hp := [0, 1, 2, 3, 10, 9, 8, 11, 12, 4, 5, 6, 7])} {evaluate_permutation(hp, sample_size=100)=}" - # ) - # hp = [10, 1, 2, 3, 8, 9, 0, 11, 12, 4, 5, 6, 7] - # print(f"{hp=} {evaluate_permutation(hp, seed=200, sample_size=200)=}") - # print(f"{hp=} {evaluate_permutation(hp, seed=200, sample_size=200)=}") - # evaluate_all_1_swaps_except_first(hp) - # hp = [10, 11, 2, 3, 8, 9, 0, 1, 12, 4, 5, 6, 7] - # print(f"{hp=} {evaluate_permutation(hp, seed=200, sample_size=200)=}") - # hp = [10, 11, 2, 3, 8, 9, 0, 1, 12, 4, 5, 6, 7] - # print(f"{hp=} {evaluate_permutation(hp, seed=200, sample_size=200)=}") + evaluate_all_1_swaps_except_first(hp) - hp = [10, 0, 1, 2, 3, 8, 9, 11, 12, 4, 5, 6, 7] - print( - bidirectional_search( - Skewb( - top=(G0, O0, B0, R0), bot=(B1, O1, G2, R1), mids=(OO, YY, RO, GR, BO) - ), - max_steps=1000000, - ) - ) - # path = get_paths_from_heuristic( - # Skewb(top=(G0, O0, B0, R0), bot=(B1, O1, G2, R1), mids=(OR, YY, RO, GR, BO)), - # hp, - # ) -# RBOG + start = Skewb((G0, O0, B0, R0), (G0, R1, B2, O2), (BY, OY, RO, GR, YY)) + # print(bidirectional_search(start, max_steps=1000000)) + # print(get_paths_from_heuristic(start, hp))