예제 #1
0
파일: cube_test.py 프로젝트: pikma/rubik
    def test_scrambled_cube(self):
        '''Scrambling the cube with cannot return a solved cube.

        This is guaranteed for 2 and 3 rotations, because scramble_cube does
        not apply two consecutive rotations that cancel each other.
        '''
        self.assertNotEqual(cube_lib.get_scrambled_cube(num_rotations=2),
                            cube_lib.Cube())
        self.assertNotEqual(cube_lib.get_scrambled_cube(num_rotations=3),
                            cube_lib.Cube())
예제 #2
0
def evaluate_solver(solver_fn: Callable[[cube_lib.Cube],
                                        Solver], trajectory_length: int,
                    max_num_steps: int, num_trials: int):
    '''Evaluates a solver.

    Uses the solver to solves `num_trials` cubes that are scrambled with
    `trajectory_length` random rotations.

    Returns a dataframe with statistics about the performance of the solver.
    '''
    evaluation_results = pd.DataFrame()
    for _ in range(num_trials):
        cube = cube_lib.get_scrambled_cube(trajectory_length)
        solver = solver_fn(cube)

        num_steps = num_steps_to_solve(solver, max_num_steps)

        evaluation_results = evaluation_results.append(
            {
                'num_steps_scrambled': trajectory_length,
                'num_steps_to_solve': num_steps,
                'solved': solver.cube.is_solved()
            },
            ignore_index=True)
    evaluation_results.num_steps_scrambled = (
        evaluation_results.num_steps_scrambled.astype('int'))
    # We can't convert 'num_steps_to_solve' to ints, because it contains NAs,
    # which are of type float.
    evaluation_results.num_steps_to_solve = (
        evaluation_results.num_steps_to_solve.astype('float'))
    evaluation_results.solved = evaluation_results.solved.astype('bool')
    return evaluation_results
예제 #3
0
    def test_priority_queue_same_value(self):
        '''Verifies that we can insert two states with the same value.'''
        queue = solver_lib._PriorityQueue()
        first_cube = cube_lib.get_scrambled_cube(num_rotations=3)

        first_state = solver_lib._AStarState(first_cube,
                                             cost_to_come=2,
                                             est_cost_to_go=5,
                                             previous_state=None,
                                             previous_rotation=None)
        queue.add_or_update_state(first_state)

        second_cube = first_cube.copy()
        second_cube.rotate_face(
            cube_lib.Rotation(cube_lib.Face.LEFT, is_clockwise=True))
        second_state = solver_lib._AStarState(second_cube,
                                              cost_to_come=2,
                                              est_cost_to_go=5,
                                              previous_state=None,
                                              previous_rotation=None)
        queue.add_or_update_state(second_state)

        self.assertTrue(queue)

        costs_to_come = set()
        costs_to_come.add(queue.pop_min_state().cube)
        self.assertTrue(queue)
        costs_to_come.add(queue.pop_min_state().cube)
        self.assertFalse(queue)

        self.assertEqual(costs_to_come, set((first_cube, second_cube)))
예제 #4
0
def greedy_solver(depth=3):
    '''Runs the greedy solver.

    Results (2020/05/20):
        3.4 cubes solved / second at depth 3.
    '''
    model = trainer.create_model()
    num_starting_cubes = 20
    num_runs = 3

    num_runs_done = 0
    time_elapsed = 0
    for _ in range(num_starting_cubes):
        cube = cube_lib.get_scrambled_cube(depth)
        begin_time = time.monotonic()

        for _ in range(num_runs):
            solver = solver_lib.GreedySolver(cube, model, depth)
            num_rotations = 0
            while not solver.cube.is_solved():
                if num_rotations == depth:
                    raise Exception(
                        'Done {} rotations, cube still not solved'.format(
                            depth))
                solver.apply_next_rotation()
                num_rotations += 1

        end_time = time.monotonic()
        time_elapsed += (end_time - begin_time)
        num_runs_done += num_runs

    print('{} cubes solved per second at depth {}'.format(
        num_runs_done / time_elapsed, depth))
예제 #5
0
    def test_priority_queue(self):
        queue = solver_lib._PriorityQueue()
        first_cube = cube_lib.get_scrambled_cube(3)

        first_state = solver_lib._AStarState(first_cube,
                                             cost_to_come=2,
                                             est_cost_to_go=5,
                                             previous_state=None,
                                             previous_rotation=None)
        queue.add_or_update_state(first_state)

        second_cube = first_cube.copy()
        second_cube.rotate_face(
            cube_lib.Rotation(cube_lib.Face.LEFT, is_clockwise=True))
        second_state = solver_lib._AStarState(second_cube,
                                              cost_to_come=1,
                                              est_cost_to_go=7,
                                              previous_state=None,
                                              previous_rotation=None)
        queue.add_or_update_state(second_state)

        third_cube = second_cube.copy()
        third_cube.rotate_face(
            cube_lib.Rotation(cube_lib.Face.LEFT, is_clockwise=True))
        third_state = solver_lib._AStarState(third_cube,
                                             cost_to_come=1,
                                             est_cost_to_go=5,
                                             previous_state=None,
                                             previous_rotation=None)
        queue.add_or_update_state(third_state)

        self.assertTrue(queue)
        self.assertEqual(queue.pop_min_state(), third_state)

        second_state = copy.copy(second_state)
        second_state.est_cost_to_go = 3
        queue.add_or_update_state(second_state)

        self.assertTrue(queue)
        self.assertEqual(queue.pop_min_state(), second_state)

        first_state = copy.copy(first_state)
        first_state.est_cost_to_go = 3
        queue.add_or_update_state(first_state)

        self.assertTrue(queue)
        self.assertEqual(queue.pop_min_state(), first_state)

        self.assertFalse(queue)
예제 #6
0
파일: trainer.py 프로젝트: pikma/rubik
def fraction_solved_greedy(model: tf.keras.Model, trajectory_length: int,
                           num_trials: int, greedy_depth: int) -> float:
    '''Computes the fraction of random cubes that can be solved greedily.'''
    num_solved = 0
    for _ in range(num_trials):
        cube = cube_lib.get_scrambled_cube(trajectory_length)
        solver = solver_lib.GreedySolver(cube, model, depth=greedy_depth)
        for _ in range(trajectory_length):
            if solver.cube.is_solved():
                break
            solver.apply_next_rotation()

        if solver.cube.is_solved():
            num_solved += 1
    return num_solved / num_trials