def test_is_valid_row_number_included(self):
     from sudoku_board import SudokuBoard
     board = SudokuBoard()
     for a in range(1, 9):
         board.add_answer(1, a, a)
     for a in range(1, 9):
         self.assertFalse(board.is_valid_row(1, a))
 def test_valid_column_number_not_included(self):
     from sudoku_board import SudokuBoard
     board = SudokuBoard()
     for a in range(1, 9):
         board.add_answer(a, 1, a)
     for a in range(1, 9):
         self.assertFalse(board.is_valid_column(1, a))
 def test_sudoku_boxes_hold_thier_location(self):
     from sudoku_board import SudokuBoard
     board = SudokuBoard()
     for row in range(1, 10):
         for column in range(1, 10):
             self.assertEqual(board.get_sudoku_box(row, column).row, row)
             self.assertEqual(
                 board.get_sudoku_box(row, column).column, column)
 def test_is_valid_nonet_number_not_included(self):
     counter = 0
     from sudoku_board import SudokuBoard
     board = SudokuBoard()
     for i in range(1, 4):
         for j in range(1, 4):
             if counter != 0:
                 board.add_answer(i, j, counter % 9 + 1)
             counter += 1
     for a in range(2, 9):
         self.assertFalse(board.is_valid_nonnet(1, 1, a))
 def test_number_is_possible_number_included(self):
     from sudoku_board import SudokuBoard
     sudokuboard = [[0, 0, 0, 0, 0, 0, 0, 0,
                     0], [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0,
                     0], [0, 0, 0, 0, 0, 0, 0, 0, 6],
                    [0, 0, 0, 0, 0, 0, 0, 0,
                     5], [0, 0, 0, 0, 0, 0, 0, 0, 4],
                    [0, 0, 0, 0, 0, 0, 7, 8,
                     0], [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [1, 2, 3, 0, 0, 0, 0, 0, 0]]
     board = SudokuBoard(sudokuboard)
     self.assertTrue(board.is_valid_number(9, 9, 9))
 def test_is_valid_nonet_number_included(self):
     from sudoku_board import SudokuBoard
     sudoku_board = [[5, 3, 4, 6, 7, 8, 9, 1,
                      2], [6, 7, 2, 1, 9, 5, 3, 4, 8],
                     [1, 9, 8, 3, 4, 2, 5, 6,
                      7], [8, 0, 0, 0, 6, 0, 4, 2, 3],
                     [4, 0, 0, 8, 0, 3, 7, 9,
                      1], [7, 0, 0, 0, 2, 0, 8, 5, 6],
                     [0, 6, 0, 0, 0, 0, 2, 8,
                      4], [0, 0, 0, 4, 1, 9, 6, 3, 5],
                     [0, 0, 0, 0, 8, 0, 1, 7, 9]]
     board = SudokuBoard(sudoku_board)
     self.assertTrue(board.is_valid_nonnet(4, 1, 5))
Example #7
0
class FileReader:
    def __init__(self):
        self.difficulty = "eazy"
        self.file = json.load(open("puzzels/"+self.difficulty+"/"+self.random()+"/incomplete.json", "r"))
        self.used_puzzles = []
        self.board = SudokuBoard(self.file)
        self.impossible = False
    def random(self):
        number = random.randint(0,3)
        if number == 1:
            return "one"
        elif number == 2:
            return "two"
        else:
            return "three"
    def load_newpuzzle(self):
        if self.impossible:
            print("loading new impossible")
            self.file = json.load(open("puzzels/"+self.difficulty+"/"+self.random()+"/compleete.json", "r"))
            self.board = SudokuBoard(self.file)
            x = random.randint(30, 81)
            while x>0:
                print("running forever in progress")
                r=random.randint(0,8)
                c=random.randint(0,8)
                if self.board.get_point(r,c) !=0:
                    self.board.set_point(r,c,0)
                    x=x-1
        else:
            self.file = json.load(open("puzzels/"+self.difficulty+"/"+self.random()+"/incomplete.json", "r"))
            self.board = SudokuBoard(self.file)
    def get_puzzle(self):
        return self.board
    def load_beginner(self):
        self.difficulty = "eazy"
        self.impossible = False
    def load_intermediate(self):
        self.difficulty = "meedium"
        self.impossible = False
    def load_advanced(self):
        self.difficulty = "harrrrrrrrrrrd"
        self.impossible = False
    def load_impossible(self):
        num = random.randint(0,3)
        if num ==1:
            self.difficulty = "eazy"
        elif num ==2:
            self.difficulty = "meedium"
        else:
            self.difficulty = "harrrrrrrrrrrd"
        self.impossible = True
 def test_number_is_possible_not_included(self):
     from sudoku_board import SudokuBoard
     sudokuboard = [[0, 0, 0, 0, 0, 0, 0, 0,
                     0], [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0,
                     0], [0, 0, 0, 0, 0, 0, 0, 0, 6],
                    [0, 0, 0, 0, 0, 0, 0, 0,
                     5], [0, 0, 0, 0, 0, 0, 0, 0, 4],
                    [0, 0, 0, 0, 0, 0, 7, 8,
                     0], [0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [1, 2, 3, 0, 0, 0, 0, 0, 0]]
     board = SudokuBoard(sudokuboard)
     for answer in range(1, 9):
         self.assertFalse(board.is_valid_number(9, 9, answer))
 def test_find_emptyspot(self):
     from sudoku_board import SudokuBoard
     sudoku_board = [[5, 3, 0, 0, 7, 0, 0, 0,
                      0], [6, 0, 0, 1, 9, 5, 0, 0, 0],
                     [0, 9, 8, 0, 0, 0, 0, 6,
                      0], [8, 0, 0, 0, 6, 0, 0, 0, 3],
                     [4, 0, 0, 8, 0, 3, 0, 0,
                      1], [7, 0, 0, 0, 2, 0, 0, 0, 6],
                     [0, 6, 0, 0, 0, 0, 2, 8,
                      0], [0, 0, 0, 4, 1, 9, 0, 0, 5],
                     [0, 0, 0, 0, 8, 0, 0, 7, 9]]
     board = SudokuBoard(sudoku_board)
     self.assertTrue(board.find_emptyspot().column == 3)
     self.assertTrue(board.find_emptyspot().row == 1)
Example #10
0
 def load_newpuzzle(self):
     if self.impossible:
         print("loading new impossible")
         self.file = json.load(open("puzzels/"+self.difficulty+"/"+self.random()+"/compleete.json", "r"))
         self.board = SudokuBoard(self.file)
         x = random.randint(30, 81)
         while x>0:
             print("running forever in progress")
             r=random.randint(0,8)
             c=random.randint(0,8)
             if self.board.get_point(r,c) !=0:
                 self.board.set_point(r,c,0)
                 x=x-1
     else:
         self.file = json.load(open("puzzels/"+self.difficulty+"/"+self.random()+"/incomplete.json", "r"))
         self.board = SudokuBoard(self.file)
 def test_get_answer(self):
     from sudoku_board import SudokuBoard
     board = SudokuBoard()
     board.add_answer(1, 2, 4)
     self.assertEqual(board.get_answer(1, 2), 4)
     with self.assertRaises(IndexError):
         board.get_answer(0, 0)
 def test_find_emptyspot_full(self):
     from sudoku_board import SudokuBoard
     sudoku_board = [
         [1, 2, 3, 4, 5, 6, 7, 8,
          9],  # this sudoku board is not right but it
         [2, 3, 4, 5, 6, 7, 8, 9,
          1],  # doesn't matter we are testing if the board
         [3, 4, 5, 6, 7, 8, 9, 1,
          2],  # is correctly implemented in sudoku board
         [4, 5, 6, 7, 8, 9, 1, 2, 3],
         [5, 6, 7, 8, 9, 1, 2, 3, 4],
         [6, 7, 8, 9, 1, 2, 3, 4, 5],
         [7, 8, 9, 1, 2, 3, 4, 5, 6],
         [8, 9, 1, 2, 3, 4, 5, 6, 7],
         [9, 1, 2, 3, 4, 5, 6, 7, 8]
     ]
     board = SudokuBoard(sudoku_board)
     self.assertTrue(board.find_emptyspot() is None)
 def test_add_answer_stored_in_right_location(self):
     from sudoku_board import SudokuBoard, SudokuBox
     board = SudokuBoard()
     board.add_answer(1, 2,
                      4)  # board uses indexing starting at 1 instead of 0
     self.assertEqual(board.get_sudoku_box(1, 2), SudokuBox(4))
     with self.assertRaises(IndexError):
         board.add_answer(0, 0, 4)
Example #14
0
def main():
    board = SudokuBoard()
    board.add_element(0, 3, 3)
    board.add_element(0, 4, 4)
    board.add_element(0, 5, 6)
    board.add_element(0, 7, 5)
    board.add_element(0, 8, 9)

    ###########

    # board.add_element(0, 0, 5)
    # board.add_element(0, 1, 3)
    # board.add_element(0, 4, 7)
    # board.add_element(1, 0, 6)
    # board.add_element(1, 3, 1)
    # board.add_element(1, 4, 9)
    # board.add_element(1, 5, 5)
    # board.add_element(2, 1, 9)
    # board.add_element(2, 2, 8)
    # board.add_element(2, 7, 6)
    # board.add_element(3, 0, 8)
    # board.add_element(3, 4, 6)
    # board.add_element(3, 8, 3)
    # board.add_element(4, 0, 4)
    # board.add_element(4, 3, 8)
    # board.add_element(4, 5, 3)
    # board.add_element(4, 8, 1)
    # board.add_element(5, 0, 7)
    # board.add_element(5, 4, 2)
    # board.add_element(5, 8, 6)
    # board.add_element(6, 1, 6)
    # board.add_element(6, 6, 2)
    # board.add_element(6, 7, 8)
    # board.add_element(7, 3, 4)
    # board.add_element(7, 4, 1)
    # board.add_element(7, 5, 9)
    # board.add_element(7, 8, 5)
    # board.add_element(8, 4, 8)
    # board.add_element(8, 7, 7)
    # board.add_element(8, 8, 9)
    # board.build_board()
    solver = SudokuSolver(board)
    if solver.board.is_valid_full():
        print("Board before solving: \n")
        print(board, "\n")
        if solver.backtracking(0, 0):
            print("Sudoku has been solved \n")
        print(board)
        if solver.board.is_valid_full():
            print("Solution Exists!!")
    else:
        print("Board entered is not valid. Please enter a valid board.")
Example #15
0
 def __init__(self, display, board=SudokuBoard(9)):
     self.screen = display.screen
     self.board = board
     self.squares_pos = []
     self.wrong = []
     self.interactive = self.interactive_shell()
     self.time = pygame.time.Clock()
     self.font = pygame.font.Font('freesansbold.ttf', 30)
     self.active = False
     self.input = ''
     self.active_cell = None
 def test_get_guesses_out_of_bounds(self):
     from sudoku_board import SudokuBoard
     board = SudokuBoard()
     with self.assertRaises(IndexError):
         board.get_guesses(0, 0)
     with self.assertRaises(IndexError):
         board.get_guesses(10, 10)
 def test_sudoku_boxes_hold_thier_location_import_board(self):
     from sudoku_board import SudokuBoard
     sudoku_board = [
         [1, 2, 3, 4, 5, 6, 7, 8,
          9],  # this sudoku board is not right but it
         [2, 3, 4, 5, 6, 7, 8, 9,
          1],  # doesn't matter we are testing if the board
         [3, 4, 5, 6, 7, 8, 9, 1,
          2],  # is correctly implemented in sudoku board
         [4, 5, 6, 7, 8, 9, 1, 2, 3],
         [5, 6, 7, 8, 9, 1, 2, 3, 4],
         [6, 7, 8, 9, 1, 2, 3, 4, 5],
         [7, 8, 9, 1, 2, 3, 4, 5, 6],
         [8, 9, 1, 2, 3, 4, 5, 6, 7],
         [9, 1, 2, 3, 4, 5, 6, 7, 8]
     ]
     board = SudokuBoard(sudoku_board)
     for row in range(1, 10):
         for column in range(1, 10):
             self.assertEqual(board.get_sudoku_box(row, column).row, row)
             self.assertEqual(
                 board.get_sudoku_box(row, column).column, column)
Example #18
0
    def _on_check_click(self) -> None:
        """
		Check the board's state
		"""
        pg.draw.rect(self.game_screen, self.BUTTON_COLOR,
                     (20, 20, self.dimensions - 40, self.dimensions - 40))

        text = ''

        if (self.board.check_win_condition()):
            text = "Puzzle Solved!"
            self.board = SudokuBoard()
        else:
            text = "Puzzle Not Solved."

        text_surface = self.STATUS_FONT.render(text, True, self.TEXT_COLOR)
        self.game_screen.blit(
            text_surface,
            text_surface.get_rect(center=(self.dimensions // 2,
                                          self.dimensions // 2)))
        pg.display.update()

        t.sleep(3)  # Pause for 3 seconds
Example #19
0
    def __get_all_params(self):
        if self.self.__get_new_or_load() == 1:
            self.self.__game_type = self.self.__get_game_type()
            amount_of_filled_cells = self.self.__get_amount_of_filled_cells()
            self.self.__board = SudokuBoard(amount_of_filled_cells)
            return True
        else:
            val, saves = self.self.__get_save_name()

            if val == 0: return False

            with open(f'{saves[val - 1]}', 'rb') as f:
                self.self = pickle.load(f)

            return True
 def test_create_board(self):
     from sudoku_board import SudokuBoard
     sudoku_board = [
         [1, 2, 3, 4, 5, 6, 7, 8,
          9],  # this sudoku board is not right but it
         [2, 3, 4, 5, 6, 7, 8, 9,
          1],  # doesn't matter we are testing if the board
         [3, 4, 5, 6, 7, 8, 9, 1,
          2],  # is correctly implemented in sudoku board
         [4, 5, 6, 7, 8, 9, 1, 2, 3],
         [5, 6, 7, 8, 9, 1, 2, 3, 4],
         [6, 7, 8, 9, 1, 2, 3, 4, 5],
         [7, 8, 9, 1, 2, 3, 4, 5, 6],
         [8, 9, 1, 2, 3, 4, 5, 6, 7],
         [9, 1, 2, 3, 4, 5, 6, 7, 8]
     ]
     board = SudokuBoard(sudoku_board)
     for sudoku_row, board_row in zip(sudoku_board, board.board):
         for sudoku_number, board_number in zip(sudoku_row, board_row):
             self.assertEqual(sudoku_number, board_number.answer)
Example #21
0
    def __init__(self) -> None:
        """
		params:
		Initialize the sudoku game.
		Calcualte and store positioning and spacing values for UI.
		"""

        pg.init()

        # Used to control the speed of game loop
        # Acts as a buffer for user input
        self.BUFFER_DELAY = (1 / 20)  # 20 FPS

        # Color Palette
        self.BACKGROUND_COLOR = (0, 0, 0)
        self.MAJOR_LINE_COLOR = (200, 200, 200)
        self.MINOR_LINE_COLOR = (150, 150, 150)
        self.SELECTED_BOX_COLOR = (70, 70, 255)
        self.BUTTON_COLOR = (30, 30, 80)
        self.TEXT_COLOR = (250, 250, 250)
        self.NUMBER_ORIGINAL_COLOR = (255, 244, 176)
        self.NUMBER_PLACED_COLOR = (255, 255, 255)

        # Line Widths
        self.MAJOR_LINE_WIDTH = 6
        self.MINOR_LINE_WIDTH = 1

        # Fonts
        self.NUMBER_FONT = pg.font.SysFont('Consolas', 50)
        self.BUTTON_FONT = pg.font.SysFont('Consolas', 30)
        self.STATUS_FONT = pg.font.SysFont('Consolas', 65)

        # The dimensions of the window (window is dimensions x dimensions)
        self.dimensions = 700

        # The dimensions of the buttons
        self.button_width = self.dimensions / 3
        self.button_height = 70
        self.button_padding = 10
        self.button_y_pos = self.dimensions + self.button_padding
        self.check_x_pos = self.button_padding
        self.undo_x_pos = self.button_width + self.button_padding
        self.main_menu_x_pos = 2 * self.button_width + self.button_padding

        # The interval of major box in each direction
        self.major_box_x_interval = self.dimensions / 3
        self.major_box_y_interval = self.dimensions / 3

        # The interval of minor box inside the major box in each direction
        self.minor_box_x_interval = self.dimensions / 9
        self.minor_box_y_interval = self.dimensions / 9

        # Create the sudoku board model
        self.board = SudokuBoard()

        # Represents the current selected box
        self.curr_selected_row = 0
        self.curr_selected_col = 0

        # The number placement history
        self.move_history = []
Example #22
0
 def __init__(self):
     self.difficulty = "eazy"
     self.file = json.load(open("puzzels/"+self.difficulty+"/"+self.random()+"/incomplete.json", "r"))
     self.used_puzzles = []
     self.board = SudokuBoard(self.file)
     self.impossible = False
 def test_add_answer_number_not_included(self):
     from sudoku_board import SudokuBoard
     board = SudokuBoard()
     board.add_answer(1, 2, 4)
     self.assertTrue(board.add_answer(1, 3, 5))
Example #24
0
    def create_menu_1(self):
        if not self.dif_menu:
            pressed_button = None
            buttons = []
            texts = ("Create New Board", "Solve Given Board",
                     "Difficulty Settings")
            if self.interactive:
                texts = ("Create New Board", "Solve Given Board",
                         "Difficulty Settings", "Resume")
            x, y = 0, 50

            for i in range(len(texts)):
                buttons.append([pygame.Rect(x, y, 400, 50), i])
                pygame.draw.rect(self.screen, (160, 160, 160), buttons[i][0])
                pygame.draw.rect(self.screen, (0, 0, 0), buttons[i][0], 2)
                text = self.font.render(texts[i], True, (0, 0, 0))
                self.screen.blit(text, (x + 30, y + 10))
                y += 50
            pygame.display.flip()

            if event.type == pygame.MOUSEBUTTONDOWN:
                for i in buttons:
                    if i[0].collidepoint(event.pos):
                        pygame.draw.rect(self.screen, (0, 0, 255), i[0], 2)
                        pygame.display.flip()
                        pressed_button = texts[i[1]]
                        break

            if pressed_button == "Create New Board":
                self.board = Board(self.display,
                                   SudokuBoard(self.difficulty[0]))
                self.sudoku = self.board.board
                self.sudoku.reset()
                self.sudoku.fill_solve()
                self.sudoku.create_board()
                self.board.interactive = self.board.interactive_shell()
                self.interactive = self.board.interactive
                self.submit_mode = False
                self.active = False

            if pressed_button == "Solve Given Board":
                self.board = Board(self.display)
                self.sudoku = self.board.board
                self.sudoku.reset()
                self.board.interactive = self.board.interactive_shell()
                self.interactive = self.board.interactive
                self.submit_mode = True
                self.active = False

            if pressed_button == "Difficulty Settings":
                self.dif_menu = True
                self.background()

            if pressed_button == "Resume":
                self.active = False

        else:
            pressed_button = None
            buttons = []
            dif_texts = ("Easy", "Normal", "Hard", "Really Hard", "Back")
            x, y = 500, 100

            for i in range(len(dif_texts)):
                buttons.append([pygame.Rect(x, y, 300, 50), i])
                pygame.draw.rect(self.screen, (160, 160, 160), buttons[i][0])
                if self.difficulty[1] == dif_texts[i]:
                    pygame.draw.rect(self.screen, (0, 0, 255), buttons[i][0],
                                     2)
                else:
                    pygame.draw.rect(self.screen, (0, 0, 0), buttons[i][0], 2)
                text = self.font.render(dif_texts[i], True, (0, 0, 0))
                self.screen.blit(text, (x + 30, y + 10))
                y += 50
            pygame.display.flip()

            if event.type == pygame.MOUSEBUTTONDOWN:
                for i in buttons:
                    if i[0].collidepoint(event.pos):
                        pressed_button = dif_texts[i[1]]
                        break

            if pressed_button == "Easy":
                self.difficulty = 3, "Easy"

            if pressed_button == "Normal":
                self.difficulty = 4, "Normal"

            if pressed_button == "Hard":
                self.difficulty = 5, "Hard"

            if pressed_button == "Really Hard":
                self.difficulty = 6, "Really Hard"

            if pressed_button == "Back":
                self.dif_menu = False
                self.background()
    def test_solve(self):
        from sudoku_board import SudokuBoard

        board = SudokuBoard()
        self.assertTrue(board.solve())
        print(board)
 def test_get_guesses(self):
     from sudoku_board import SudokuBoard
     board = SudokuBoard()
     board.add_guess(1, 1, 3)
     self.assertEqual(board.get_guesses(1, 1), [3])
 def test_get_sudoku_box_number_not_between_one_through_nine(self):
     from sudoku_board import SudokuBoard
     board = SudokuBoard()
     with self.assertRaises(IndexError):
         board.get_sudoku_box(0, 0)
Example #28
0
class SudokuGUI:
    """
	The Main GUI Application for Sudoku. 

	Runs the game based on user input.
	"""
    def __init__(self) -> None:
        """
		params:
		Initialize the sudoku game.
		Calcualte and store positioning and spacing values for UI.
		"""

        pg.init()

        # Used to control the speed of game loop
        # Acts as a buffer for user input
        self.BUFFER_DELAY = (1 / 20)  # 20 FPS

        # Color Palette
        self.BACKGROUND_COLOR = (0, 0, 0)
        self.MAJOR_LINE_COLOR = (200, 200, 200)
        self.MINOR_LINE_COLOR = (150, 150, 150)
        self.SELECTED_BOX_COLOR = (70, 70, 255)
        self.BUTTON_COLOR = (30, 30, 80)
        self.TEXT_COLOR = (250, 250, 250)
        self.NUMBER_ORIGINAL_COLOR = (255, 244, 176)
        self.NUMBER_PLACED_COLOR = (255, 255, 255)

        # Line Widths
        self.MAJOR_LINE_WIDTH = 6
        self.MINOR_LINE_WIDTH = 1

        # Fonts
        self.NUMBER_FONT = pg.font.SysFont('Consolas', 50)
        self.BUTTON_FONT = pg.font.SysFont('Consolas', 30)
        self.STATUS_FONT = pg.font.SysFont('Consolas', 65)

        # The dimensions of the window (window is dimensions x dimensions)
        self.dimensions = 700

        # The dimensions of the buttons
        self.button_width = self.dimensions / 3
        self.button_height = 70
        self.button_padding = 10
        self.button_y_pos = self.dimensions + self.button_padding
        self.check_x_pos = self.button_padding
        self.undo_x_pos = self.button_width + self.button_padding
        self.main_menu_x_pos = 2 * self.button_width + self.button_padding

        # The interval of major box in each direction
        self.major_box_x_interval = self.dimensions / 3
        self.major_box_y_interval = self.dimensions / 3

        # The interval of minor box inside the major box in each direction
        self.minor_box_x_interval = self.dimensions / 9
        self.minor_box_y_interval = self.dimensions / 9

        # Create the sudoku board model
        self.board = SudokuBoard()

        # Represents the current selected box
        self.curr_selected_row = 0
        self.curr_selected_col = 0

        # The number placement history
        self.move_history = []

    def _render_sudoku_board(self) -> None:
        """
		Render the sudoku board on the screen by
		drawing the grid lines, the numbers and the
		buttons. 
		"""

        # Reset Screen
        self.game_screen.fill(self.BACKGROUND_COLOR)

        # Draw Grid Lines and Selected Box
        self._render_grid()

        # Draw Numbers
        self._render_numbers()

        # Draw Buttons
        self._render_buttons()

    def _render_grid(self) -> None:
        """
		Draw thin lines to represnet smaller box.
		Draw thick lines to represent the nonets.
		Draw square to represent selected box. 
		"""

        # Draw Minor Lines
        for i in range(3):
            for j in range(1, 3):
                # Vertical Lines
                pg.draw.line(self.game_screen, self.MINOR_LINE_COLOR, ((self.major_box_x_interval*i) + (self.minor_box_x_interval*j), 0), \
                ((self.major_box_x_interval*i) + (self.minor_box_x_interval*j), self.dimensions), self.MINOR_LINE_WIDTH)

                # Horizontal Lines
                pg.draw.line(self.game_screen, self.MINOR_LINE_COLOR, (0, (self.major_box_y_interval*i) + (self.minor_box_y_interval*j)), \
                (self.dimensions, (self.major_box_y_interval*i) + (self.minor_box_y_interval*j)), self.MINOR_LINE_WIDTH)

        # Draw Major Lines
        for i in range(1, 3):
            # Vertical Lines
            pg.draw.line(self.game_screen, self.MAJOR_LINE_COLOR, (self.major_box_x_interval*i, 0), \
            (self.major_box_x_interval*i, self.dimensions), self.MAJOR_LINE_WIDTH)

            # Horizontal Lines
            pg.draw.line(self.game_screen, self.MAJOR_LINE_COLOR, (0, self.major_box_y_interval*i), \
            (self.dimensions, self.major_box_y_interval*i), self.MAJOR_LINE_WIDTH)

        # Draw Outline Border of screen
        pg.draw.rect(self.game_screen, self.MAJOR_LINE_COLOR,
                     (0, 0, self.dimensions, self.dimensions), 5)

        # Draw Selected Box
        pg.draw.rect(self.game_screen, self.SELECTED_BOX_COLOR,
        (self.minor_box_x_interval * self.curr_selected_col, self.minor_box_y_interval * self.curr_selected_row, \
        self.minor_box_x_interval, self.minor_box_y_interval), self.MAJOR_LINE_WIDTH)

    def _render_numbers(self) -> None:
        """
		Draw the numbers and place them inside the box.
		"""

        for row in range(self.board.DIMENSION):
            for col in range(self.board.DIMENSION):

                val, is_original = self.board.get_element(row, col)

                if val:
                    value_string = str(val)

                    if (is_original):
                        text_surface = self.NUMBER_FONT.render(
                            value_string, True, self.NUMBER_ORIGINAL_COLOR)
                    else:
                        text_surface = self.NUMBER_FONT.render(
                            value_string, True, self.NUMBER_PLACED_COLOR)

                    # Text position
                    px = (self.minor_box_x_interval *
                          col) + (self.minor_box_x_interval / 2)
                    py = (self.minor_box_y_interval *
                          row) + (self.minor_box_y_interval / 2)

                    # Center the text
                    text_rect = text_surface.get_rect(center=(px, py))

                    self.game_screen.blit(text_surface, text_rect)

    def _render_buttons(self) -> None:
        """
		Draw the three button rectangles and place the
		button text inside the rectangles.
		"""

        # Pause Button
        pg.draw.rect(self.game_screen, self.BUTTON_COLOR,
        (self.check_x_pos, self.button_y_pos, \
        self.button_width - 2*self.button_padding, self.button_height - 2*self.button_padding))

        px = self.check_x_pos + (
            (self.button_width - 2 * self.button_padding) // 2)
        py = self.button_y_pos + (
            (self.button_height - 2 * self.button_padding) // 2)

        text_surface = self.BUTTON_FONT.render("CHECK", True, self.TEXT_COLOR)
        self.game_screen.blit(text_surface,
                              text_surface.get_rect(center=(px, py)))

        # Clear Button
        pg.draw.rect(self.game_screen, self.BUTTON_COLOR,
        (self.undo_x_pos, self.button_y_pos, \
        self.button_width - 2*self.button_padding, self.button_height - 2*self.button_padding))

        px = self.undo_x_pos + (
            (self.button_width - 2 * self.button_padding) // 2)
        py = self.button_y_pos + (
            (self.button_height - 2 * self.button_padding) // 2)

        text_surface = self.BUTTON_FONT.render("UNDO", True, self.TEXT_COLOR)
        self.game_screen.blit(text_surface,
                              text_surface.get_rect(center=(px, py)))

        # Main Menu Button
        pg.draw.rect(self.game_screen, self.BUTTON_COLOR,
        (self.main_menu_x_pos, self.button_y_pos, \
        self.button_width - 2*self.button_padding, self.button_height - 2*self.button_padding))

        px = self.main_menu_x_pos + (
            (self.button_width - 2 * self.button_padding) // 2)
        py = self.button_y_pos + (
            (self.button_height - 2 * self.button_padding) // 2)

        text_surface = self.BUTTON_FONT.render("MAIN MENU", True,
                                               self.TEXT_COLOR)
        self.game_screen.blit(text_surface,
                              text_surface.get_rect(center=(px, py)))

    def _update_current_selected_box_pos(self, user_input, is_mouse) -> None:
        """
		Parse user input and update position of the current selected box
		"""

        # user_input can be a keyboard direction
        # or it can be a mouse position

        if not is_mouse:
            dr = user_input[0]
            dc = user_input[1]

            # Update current selected box only if direction is valid
            self.curr_selected_row += dr * int(
                0 <= self.curr_selected_row + dr <= 8)
            self.curr_selected_col += dc * int(
                0 <= self.curr_selected_col + dc <= 8)

        else:
            mx = user_input[0]
            my = user_input[1]

            # Convert mouse position to array position
            row = int(my // self.minor_box_y_interval)
            col = int(mx // self.minor_box_x_interval)

            if 0 <= row <= 8 and 0 <= col <= 8:
                self.curr_selected_row = row
                self.curr_selected_col = col

    def _get_player_input(self) -> tuple:
        """
		Get the user's directional input, number key input, and
		mouse position input and return it as a tuple
		"""

        # User keyboard input
        keys = pg.key.get_pressed()

        move_direction = [0, 0]
        # The direction the selected box is moving
        if keys[pg.K_UP] or keys[pg.K_w]:  # Up Direction
            move_direction = [-1, 0]
        elif keys[pg.K_DOWN] or keys[pg.K_s]:  # Down Direction
            move_direction = [1, 0]
        elif keys[pg.K_LEFT] or keys[pg.K_a]:  # Left Direction
            move_direction = [0, -1]
        elif keys[pg.K_RIGHT] or keys[pg.K_d]:  # Right Direction
            move_direction = [0, 1]

        placed_num = -1
        # The number input from user
        if keys[pg.K_1]:
            placed_num = 1
        elif keys[pg.K_2]:
            placed_num = 2
        elif keys[pg.K_3]:
            placed_num = 3
        elif keys[pg.K_4]:
            placed_num = 4
        elif keys[pg.K_5]:
            placed_num = 5
        elif keys[pg.K_6]:
            placed_num = 6
        elif keys[pg.K_7]:
            placed_num = 7
        elif keys[pg.K_8]:
            placed_num = 8
        elif keys[pg.K_9]:
            placed_num = 9
        elif keys[pg.K_0]:
            placed_num = 0

        # Check Mouse Input
        mouse_pos = self._check_player_mouse()

        return move_direction, placed_num, mouse_pos

    def _check_player_mouse(self) -> tuple:
        """
		Return mouse position as a tuple if left click pressed.
		Return None if left click not pressed.
		"""

        mouse_button_state = pg.mouse.get_pressed()

        # Left Click
        if mouse_button_state[0]:

            # Mouse xy position
            mx, my = pg.mouse.get_pos()

            # Check if mouse is in the y-region of the buttons
            if self.button_y_pos <= my <= self.button_y_pos + (
                    self.button_height - 2 * self.button_padding):

                # Check if mouse is in Check Button Rectangle
                if self.check_x_pos <= mx <= self.check_x_pos + (
                        self.button_width - 2 * self.button_padding):
                    # Check Button pressed
                    self._on_check_click()

                # Check if mouse is in Undo Button Rectangle
                elif self.undo_x_pos <= mx <= self.undo_x_pos + (
                        self.button_width - 2 * self.button_padding):
                    # Undo Button pressed
                    self._on_undo_click()

                # Check if mouse is in Main Menu Button Rectangle
                elif self.main_menu_x_pos <= mx <= self.main_menu_x_pos + (
                        self.button_width - 2 * self.button_padding):
                    # Main Menu Button pressed
                    self._on_main_menu_click()

            return (mx, my)

    def _on_check_click(self) -> None:
        """
		Check the board's state
		"""
        pg.draw.rect(self.game_screen, self.BUTTON_COLOR,
                     (20, 20, self.dimensions - 40, self.dimensions - 40))

        text = ''

        if (self.board.check_win_condition()):
            text = "Puzzle Solved!"
            self.board = SudokuBoard()
        else:
            text = "Puzzle Not Solved."

        text_surface = self.STATUS_FONT.render(text, True, self.TEXT_COLOR)
        self.game_screen.blit(
            text_surface,
            text_surface.get_rect(center=(self.dimensions // 2,
                                          self.dimensions // 2)))
        pg.display.update()

        t.sleep(3)  # Pause for 3 seconds

    def _on_undo_click(self) -> None:
        """
		Undo the last move by clearing the board and playing 
		all moves up until the last move (not inclusive).
		"""

        if (self.move_history):
            self.move_history.pop()
            self.board.clear_board()

            for move in self.move_history:
                row, col, val = move
                self.board.set_element(row, col, val)

    def _on_main_menu_click(self) -> None:
        """
		Will be implemented by Greg and Aditya
		"""
        # TODO Implement this method
        print("MAIN MENU BUTTON PRESSED")

    def run_game(self) -> None:
        """
		Initialize the game and run the main game loop
		"""

        # Initialize PyGame Screen
        self.game_screen = pg.display.set_mode(
            (self.dimensions, self.dimensions + self.button_height))
        pg.display.set_caption('PyDoku Inc.')

        self.game_over = False

        self._render_sudoku_board()

        while not self.game_over:

            # Poll user input
            event = pg.event.poll()
            # User closed the window
            if event.type == pg.QUIT:
                return

            # Input for moving the selected box
            user_input, placed_num, mouse_pos = self._get_player_input()

            board_changed = False

            # If user inputs a number other than 0
            if placed_num != -1:
                self.board.set_element(self.curr_selected_row,
                                       self.curr_selected_col, placed_num)
                move = (self.curr_selected_row, self.curr_selected_col,
                        placed_num)

                # Check for repeating moves
                if (not self.move_history):
                    self.move_history.append(move)
                elif (self.move_history[-1] != move):
                    self.move_history.append(move)

                board_changed = True

            # If user moves the selected box in a direction other than (0, 0)
            if any(user_input):
                self._update_current_selected_box_pos(user_input, False)
                board_changed = True

            # If the user clicked on the screen
            if mouse_pos is not None:
                self._update_current_selected_box_pos(mouse_pos, True)
                board_changed = True

            # If the state of the board has changed
            if board_changed:
                self._render_sudoku_board()

            pg.display.update()

            # Delay the game loop to act as a buffer
            t.sleep(self.BUFFER_DELAY)
Example #29
0
 def __init__(self, puzzle: List[List[int]] = None):
     self.guide: int = -1
     self.board: SudokuBoard = SudokuBoard(puzzle)
     self.squares: SudokuSquares = SudokuSquares()
     self.init_squares()
 def test_get_sudoku_box_number_not_between(self):
     from sudoku_board import SudokuBoard, SudokuBox
     board = SudokuBoard()
     board.add_answer(1, 1, 1)
     self.assertEqual(board.get_sudoku_box(1, 1), SudokuBox(1))