Exemplo n.º 1
0
 def test_invalid_grid(self):
     """
     The only valid grids are all members of GRID.keys()
            (1,2,) (1,3,)
     (2,1,) (2,2,) (2,3,) (2,4,)
            (3,2,) (3,3,)
     """
     state = dict(grid8.GRID) # create a new grid
     grid_square = (1, 9,)
     with self.assertRaises(KeyError):
         grid8.assign_to_grid(grid_square, 1, state)
Exemplo n.º 2
0
 def test_assign_to_filled_space(self):
     """
     Once a grid square has a value it cannot acccept any more values.
     raise ValueError
     """
     state = dict(grid8.GRID) # create a new grid
     grid_square = (1, 2,)
     new_state = grid8.assign_to_grid(grid_square, 1, state)
     # Assert 1 is in the right position.
     self.assertEqual(new_state[grid_square], 1)
     with self.assertRaises(ValueError):
         grid8.assign_to_grid(grid_square, 1, new_state)
Exemplo n.º 3
0
 def test_invalid_grid(self):
     """
     The only valid grids are all members of GRID.keys()
            (1,2,) (1,3,)
     (2,1,) (2,2,) (2,3,) (2,4,)
            (3,2,) (3,3,)
     """
     state = dict(grid8.GRID)  # create a new grid
     grid_square = (
         1,
         9,
     )
     with self.assertRaises(KeyError):
         grid8.assign_to_grid(grid_square, 1, state)
Exemplo n.º 4
0
 def test_assign_to_filled_space(self):
     """
     Once a grid square has a value it cannot acccept any more values.
     raise ValueError
     """
     state = dict(grid8.GRID)  # create a new grid
     grid_square = (
         1,
         2,
     )
     new_state = grid8.assign_to_grid(grid_square, 1, state)
     # Assert 1 is in the right position.
     self.assertEqual(new_state[grid_square], 1)
     with self.assertRaises(ValueError):
         grid8.assign_to_grid(grid_square, 1, new_state)
Exemplo n.º 5
0
 def test_assignment_is_valid(self):
     """
     RULES:
         - No consecutive numbers may appear next to each other either vertically,
           horizontally or diagonally.
         - Each number may only be used once
     """
     state = dict(grid8.GRID) # create a new grid
     grid_square = (1, 2,)
     is_valid = grid8.assignment_valid(grid_square, 1, state)
     # Assert the proposed move is valid
     self.assertTrue(is_valid)
     # Assign the move
     new_state = grid8.assign_to_grid(grid_square, 1, state)
     # Assert 1 is in the right position.
     self.assertEqual(new_state[grid_square], 1)
     ### All slots next to grid(1, 2,) should be invalid
     grid_square = (1, 3,)
     is_valid = grid8.assignment_valid(grid_square, 2, new_state)
     # Assert the proposed move is valid
     self.assertFalse(is_valid)
     grid_square = (2, 1,)
     is_valid = grid8.assignment_valid(grid_square, 2, new_state)
     # Assert the proposed move is valid
     self.assertFalse(is_valid)
     grid_square = (2, 2,)
     is_valid = grid8.assignment_valid(grid_square, 2, new_state)
     # Assert the proposed move is valid
     self.assertFalse(is_valid)
     grid_square = (2, 3,)
     is_valid = grid8.assignment_valid(grid_square, 2, new_state)
     # Assert the proposed move is valid
     self.assertFalse(is_valid)
Exemplo n.º 6
0
 def test_assign_to_grid(self):
     """
     Can we assign a number to a valid square on the grid
     """
     state = dict(grid8.GRID) # create a new grid
     grid_square = (1, 2,)
     new_state = grid8.assign_to_grid(grid_square, 1, state)
     # Assert the state changed after the assignemnt
     self.assertNotEqual(new_state, state)
     # Assert 1 is on the board
     self.assertIn(1, new_state.values())
     # Assert 1 is in the right position.
     self.assertEqual(new_state[grid_square], 1)
Exemplo n.º 7
0
 def test_assignment_is_valid(self):
     """
     RULES:
         - No consecutive numbers may appear next to each other either vertically,
           horizontally or diagonally.
         - Each number may only be used once
     """
     state = dict(grid8.GRID)  # create a new grid
     grid_square = (
         1,
         2,
     )
     is_valid = grid8.assignment_valid(grid_square, 1, state)
     # Assert the proposed move is valid
     self.assertTrue(is_valid)
     # Assign the move
     new_state = grid8.assign_to_grid(grid_square, 1, state)
     # Assert 1 is in the right position.
     self.assertEqual(new_state[grid_square], 1)
     ### All slots next to grid(1, 2,) should be invalid
     grid_square = (
         1,
         3,
     )
     is_valid = grid8.assignment_valid(grid_square, 2, new_state)
     # Assert the proposed move is valid
     self.assertFalse(is_valid)
     grid_square = (
         2,
         1,
     )
     is_valid = grid8.assignment_valid(grid_square, 2, new_state)
     # Assert the proposed move is valid
     self.assertFalse(is_valid)
     grid_square = (
         2,
         2,
     )
     is_valid = grid8.assignment_valid(grid_square, 2, new_state)
     # Assert the proposed move is valid
     self.assertFalse(is_valid)
     grid_square = (
         2,
         3,
     )
     is_valid = grid8.assignment_valid(grid_square, 2, new_state)
     # Assert the proposed move is valid
     self.assertFalse(is_valid)
Exemplo n.º 8
0
 def test_assign_to_grid(self):
     """
     Can we assign a number to a valid square on the grid
     """
     state = dict(grid8.GRID)  # create a new grid
     grid_square = (
         1,
         2,
     )
     new_state = grid8.assign_to_grid(grid_square, 1, state)
     # Assert the state changed after the assignemnt
     self.assertNotEqual(new_state, state)
     # Assert 1 is on the board
     self.assertIn(1, new_state.values())
     # Assert 1 is in the right position.
     self.assertEqual(new_state[grid_square], 1)
Exemplo n.º 9
0
def solve(state):
    """
    Recursive solution that uses a brute force approach to findindg the solution.

    2 essential facts are derived from the board state.
        - The number of empty spaces left.
        - The choice of numbers remaining.

    Solve for a given state
    The base case:
        If no there is no empty spaces the game is over so retrun the end state.
    The recursive case:
        While there are empty spaces, AND while there are choices remaining.
            If you can make a valid assignment,
                then assign the number to the board to create a new state.
                Solve for the new state. <------ Recursion, back to the top with a new step
            Else
                Try another number in this space.
                OR
                None of the numbers fit here so try them in another space.
    Everything failed

    :param dict state: the state of the board
    :return dict: the end state of the game.  None means no solution.
    """
    # uncomment the line below if you would like to see a trace.
    # print state

    # Derive the number of empty spaces left and the choices remaining to go on the board
    empty_spaces = [g for g, v in state.items() if v is None]
    numbers_used = [v for g, v in state.items() if v]
    numbers_left = [
        n for n in (
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
        ) if n not in numbers_used
    ]

    ### BASE CASE
    if not empty_spaces:
        return state

    ### RECURSIVE CASE
    while empty_spaces:
        # Treat the remaining options like a stack
        grid_square = empty_spaces.pop(0)  # Grab the next space available
        while numbers_left:
            value = numbers_left.pop(0)  # Grab the next number available

            # If we can make an assignment
            if grid8.assignment_valid(grid_square, value, state):

                # Make a new state by assiging a number
                new_state = grid8.assign_to_grid(grid_square, value, state)
                ### RECURSION
                # Try to solve things from this state
                # Remember, if the base above is returned then this is where we will catch it.
                new_state = solve(new_state)

                if new_state:  # return the solution
                    return new_state
                # If the state was none we will implicitly try the remaining numbers or spaces
                # in this branch of the solution tree.

    # No sweat, if this branch is exhausted return None.
    # This may be the last branch meaning the state we started in coudln't be solved.
    return None
Exemplo n.º 10
0
    +---+---+
    | {0} | {1} |
+---+---+---+---+
| {2} | {3} | {4} | {5} |
+---+---+---+---+
    | {6} | {7} |
    +---+---+\n"""

    # Cycle through all the possible starting points to see how many solutions there are.
    for start in (
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
    ):
        # Assign a starting point.
        new_state = grid8.assign_to_grid((
            1,
            2,
        ), start, grid8.GRID)
        # try to solve from here
        solution = solve(new_state)

        if solution:  # print a solution if we got one
            values = [solution[k] for k in sorted(solution.keys())]
            print board.format(*values)
Exemplo n.º 11
0
def solve(state):
    """
    Recursive solution that uses a brute force approach to findindg the solution.

    2 essential facts are derived from the board state.
        - The number of empty spaces left.
        - The choice of numbers remaining.

    Solve for a given state
    The base case:
        If no there is no empty spaces the game is over so retrun the end state.
    The recursive case:
        While there are empty spaces, AND while there are choices remaining.
            If you can make a valid assignment,
                then assign the number to the board to create a new state.
                Solve for the new state. <------ Recursion, back to the top with a new step
            Else
                Try another number in this space.
                OR
                None of the numbers fit here so try them in another space.
    Everything failed

    :param dict state: the state of the board
    :return dict: the end state of the game.  None means no solution.
    """
    # uncomment the line below if you would like to see a trace.
    # print state

    # Derive the number of empty spaces left and the choices remaining to go on the board
    empty_spaces = [g for g, v in state.items() if v is None]
    numbers_used = [v for g, v in state.items() if v]
    numbers_left = [n for n in (1, 2, 3, 4, 5, 6, 7, 8,) if n not in numbers_used]

    # BASE CASE
    if not empty_spaces:
        return state

    # RECURSIVE CASE
    while empty_spaces:
        # Treat the remaining options like a stack
        grid_square = empty_spaces.pop(0) # Grab the next space available
        while numbers_left:
            value = numbers_left.pop(0)   # Grab the next number available

            # If we can make an assignment
            if grid8.assignment_valid(grid_square, value, state):

                # Make a new state by assiging a number
                new_state = grid8.assign_to_grid(grid_square, value, state)
                # RECURSION
                # Try to solve things from this state
                # Remember, if the base above is returned then this is where we will catch it.
                new_state = solve(new_state)

                if new_state:  # return the solution
                    return new_state
                # If the state was none we will implicitly try the remaining numbers or spaces
                # in this branch of the solution tree.

    # No sweat, if this branch is exhausted return None.
    # This may be the last branch meaning the state we started in coudln't be solved.
    return None
Exemplo n.º 12
0
                    return new_state
                # If the state was none we will implicitly try the remaining numbers or spaces
                # in this branch of the solution tree.

    # No sweat, if this branch is exhausted return None.
    # This may be the last branch meaning the state we started in coudln't be solved.
    return None


if __name__ == "__main__":
    # create a board for printing purposes
    board = """SOLUTION!! :-)
    +---+---+
    | {0} | {1} |
+---+---+---+---+
| {2} | {3} | {4} | {5} |
+---+---+---+---+
    | {6} | {7} |
    +---+---+\n"""

    # Cycle through all the possible starting points to see how many solutions there are.
    for start in (1, 2, 3, 4, 5, 6, 7, 8,):
        # Assign a starting point.
        new_state = grid8.assign_to_grid((1, 2,), start, grid8.GRID)
        # try to solve from here
        solution = solve(new_state)

        if solution:  # print a solution if we got one
            values = [solution[k] for k in sorted(solution.keys())]
            print(board.format(*values))