|  | 
|  | 1 | +import random # imports random to pick random numbers and shuffle cells | 
|  | 2 | +import sys # calls sys.exit() so program can end whenver user quits | 
|  | 3 | +# function to print the board | 
|  | 4 | +def print_board(board): | 
|  | 5 | +    ''' | 
|  | 6 | +    displays 9*9 board in a formatted grid | 
|  | 7 | +    with lines separating 3*3 subgrids basically 2d list board 9*9 | 
|  | 8 | +    ''' | 
|  | 9 | +    for i in range(9): | 
|  | 10 | +        if i % 3 == 0 and i != 0: | 
|  | 11 | +            print("- - - - - - - - - - - - - - -") | 
|  | 12 | +            ''' | 
|  | 13 | +            every time i is a multiple of 3 it print horizontal seperator | 
|  | 14 | +            this is row index or used for maing row | 
|  | 15 | +            ''' | 
|  | 16 | +        for j in range(9): | 
|  | 17 | +          ''' | 
|  | 18 | +          every time j is multiple of 3, we print vertical bars without | 
|  | 19 | +          for coloumns | 
|  | 20 | +          ''' | 
|  | 21 | +          if j % 3 == 0 and j != 0: | 
|  | 22 | +                print("|", end=" ") | 
|  | 23 | +          print(board[i][j] if board[i][j] != 0 else ".", end=" ") | 
|  | 24 | +            # prints cells value if nonzero otherwise . to make empty cell | 
|  | 25 | +            # on the same line end=" " | 
|  | 26 | +        print() # for moving to next line | 
|  | 27 | + | 
|  | 28 | +# function to find an empty cell in board | 
|  | 29 | +def find_empty(board):# searches the grid | 
|  | 30 | +    for i in range(9): | 
|  | 31 | +        for j in range(9): | 
|  | 32 | +          # used for scanning every row i and every col j to look for 0(indicates empty) | 
|  | 33 | +            if board[i][j] == 0: | 
|  | 34 | +                return (i, j) # returns row and col as soon as it finds empty  | 
|  | 35 | +    return None | 
|  | 36 | + | 
|  | 37 | +# function to check if placing num at pos is valid | 
|  | 38 | +def is_valid(board, num, pos):# check if you can place a number at row or col | 
|  | 39 | +    row, col = pos | 
|  | 40 | +    if any(board[row][i] == num for i in range(9) if i != col): #scaNS row for duplicates | 
|  | 41 | +        return False | 
|  | 42 | +    if any(board[i][col] == num for i in range(9) if i != row): # scans entire col for duplicates | 
|  | 43 | +        return False | 
|  | 44 | +    box_row = (row // 3) * 3 | 
|  | 45 | +    box_col = (col // 3) * 3 | 
|  | 46 | +    for i in range(box_row, box_row + 3): | 
|  | 47 | +        for j in range(box_col, box_col + 3): | 
|  | 48 | +            if board[i][j] == num and (i, j) != pos: | 
|  | 49 | +                return False # if num appears somewhere else move illegal | 
|  | 50 | +    return True # if not true | 
|  | 51 | + | 
|  | 52 | +# Backtracking solver | 
|  | 53 | +def solve_board(board): | 
|  | 54 | +  # here function find empty and is valid is used  | 
|  | 55 | +  # to fill the board , it tries all numbers from 1 to 9 at each empty cell and proceeds only if valid | 
|  | 56 | +    empty = find_empty(board) | 
|  | 57 | +    if not empty: | 
|  | 58 | +        return True | 
|  | 59 | +    row, col = empty | 
|  | 60 | +    for num in range(1, 10): | 
|  | 61 | +        if is_valid(board, num, (row, col)): | 
|  | 62 | +            board[row][col] = num | 
|  | 63 | +            if solve_board(board): | 
|  | 64 | +                return True | 
|  | 65 | +            board[row][col] = 0 | 
|  | 66 | +    return False | 
|  | 67 | + | 
|  | 68 | +def count_solutions(board): | 
|  | 69 | +  # counts all possible ways to create or complete the solutuion  | 
|  | 70 | +  # no empty you found sol and returns 1 | 
|  | 71 | +  # and finds total num of solution and stores in count | 
|  | 72 | +    empty = find_empty(board) | 
|  | 73 | +    if not empty: | 
|  | 74 | +        return 1 | 
|  | 75 | +    row, col = empty | 
|  | 76 | +    count = 0 | 
|  | 77 | +    for num in range(1, 10): | 
|  | 78 | +        if is_valid(board, num, (row, col)): | 
|  | 79 | +            board[row][col] = num | 
|  | 80 | +            count += count_solutions(board) | 
|  | 81 | +            board[row][col] = 0 | 
|  | 82 | +    return count | 
|  | 83 | + | 
|  | 84 | +def create_board(removals=30): | 
|  | 85 | +   # creates an empty board | 
|  | 86 | +# num cell is used to choose difficulty | 
|  | 87 | +# here removal check that only 1 unique sol remains using count_solutions | 
|  | 88 | +    board = [[0]*9 for _ in range(9)] | 
|  | 89 | +    solve_board(board) | 
|  | 90 | +    removed = 0 | 
|  | 91 | +    while removed < removals: | 
|  | 92 | +        r = random.randrange(9) | 
|  | 93 | +        c = random.randrange(9) | 
|  | 94 | +        if board[r][c] != 0: | 
|  | 95 | +            temp = board[r][c] | 
|  | 96 | +            board[r][c] = 0 | 
|  | 97 | +            copy = [row[:] for row in board] | 
|  | 98 | +            if count_solutions(copy) != 1: | 
|  | 99 | +                board[r][c] = temp | 
|  | 100 | +            else: | 
|  | 101 | +                removed += 1 | 
|  | 102 | +    return board | 
|  | 103 | + | 
|  | 104 | +def is_complete(board): | 
|  | 105 | +    return all(cell != 0 for row in board for cell in row) | 
|  | 106 | +    # returns if every cell in grid is non zero | 
|  | 107 | + | 
|  | 108 | +def get_input(prompt): | 
|  | 109 | +    while True: | 
|  | 110 | +        inp = input(prompt) | 
|  | 111 | +        if inp.lower() == 'q': # q to exit the program | 
|  | 112 | +            sys.exit("Goodbye!") | 
|  | 113 | +        if inp.isdigit() and 1 <= int(inp) <= 9: | 
|  | 114 | +            return int(inp) - 1 | 
|  | 115 | +        print("Invalid input. Enter 1-9 or 'q'.") | 
|  | 116 | + | 
|  | 117 | +def player_turn(board): | 
|  | 118 | +    print("\n your move:") | 
|  | 119 | +    print_board(board) | 
|  | 120 | +    while True: | 
|  | 121 | +        row = get_input("Enter row (1-9) or 'q' to quit: ") | 
|  | 122 | +        col = get_input("Enter column (1-9) or 'q' to quit: ") | 
|  | 123 | +        if board[row][col] == 0: | 
|  | 124 | +            break | 
|  | 125 | +        print("choose another, cell already filled") | 
|  | 126 | +    while True: | 
|  | 127 | +        num = get_input("Enter number (1-9) or 'q' to quit: ") + 1 | 
|  | 128 | +        if is_valid(board, num, (row, col)): | 
|  | 129 | +            board[row][col] = num | 
|  | 130 | +            break | 
|  | 131 | +        print("invalid try again") | 
|  | 132 | + | 
|  | 133 | +def computer_turn(board): | 
|  | 134 | +    print("\nComputer's move:") | 
|  | 135 | +    print_board(board) | 
|  | 136 | +    empties = [(i, j) for i in range(9) for j in range(9) if board[i][j] == 0] | 
|  | 137 | +    random.shuffle(empties) | 
|  | 138 | +    for row, col in empties: | 
|  | 139 | +        for num in range(1, 10): | 
|  | 140 | +            if is_valid(board, num, (row, col)): | 
|  | 141 | +                board[row][col] = num | 
|  | 142 | +                if count_solutions([r[:] for r in board]) == 1: | 
|  | 143 | +                    print(f"Computer placed {num} at ({row+1},{col+1})") | 
|  | 144 | +                    return | 
|  | 145 | +                board[row][col] = 0 | 
|  | 146 | +    print("computer gives up. multiple solutions possible.") | 
|  | 147 | + | 
|  | 148 | +if __name__ == "__main__": | 
|  | 149 | +    puzzle = create_board(removals=30) | 
|  | 150 | +    while True: | 
|  | 151 | +        player_turn(puzzle) | 
|  | 152 | +        cont = input("\nPress 't' if tired and let computer solve it, any other key to continue: ") | 
|  | 153 | +        if cont.lower() == 't': | 
|  | 154 | +            solve_board(puzzle) | 
|  | 155 | +            print_board(puzzle) | 
|  | 156 | +            print("\n Computer has solved the rest of the puzzle :(( Game over.") | 
|  | 157 | +            break | 
|  | 158 | +        if is_complete(puzzle): | 
|  | 159 | +            print_board(puzzle) | 
|  | 160 | +            print("Congratulations! You solved it!!!!") | 
|  | 161 | +            break | 
|  | 162 | +        computer_turn(puzzle) | 
|  | 163 | +        if is_complete(puzzle): | 
|  | 164 | +            print_board(puzzle) | 
|  | 165 | +            print("Computer solved it!! You lose!!!!") | 
|  | 166 | +            break | 
0 commit comments