Advertisement
Guest User

Untitled

a guest
Feb 20th, 2019
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.90 KB | None | 0 0
  1. import time
  2. from random import shuffle, sample
  3.  
  4. size = 9
  5. block_size = 3
  6. wanted = set([x for x in range(1, size + 1)])
  7.  
  8.  
  9. def create_board():
  10. """ Create a board using the following method:
  11. 1. create a row (0-9) and shuffle it
  12. 2. Copy and shift the row to the left
  13. 3. cycle through all shifts, appending each new row.
  14. 4. return valid sudoku board.
  15. """
  16. shifts = [0, 3, 3, 1, 3, 3, 1, 3, 3]
  17. row = [x for x in range(1, size + 1)]
  18. shuffle(row)
  19. board = []
  20. for step in shifts:
  21. row = rotate(row, step)
  22. board.append(row)
  23. return board
  24.  
  25.  
  26. def rotate(l, n):
  27. """ Return a list that was rotated by N steps. Positive N rotates left. """
  28. n = n % len(l)
  29. return l[n:] + l[:n]
  30.  
  31. def depopulate(board):
  32. """Remove a percentage values from a boardto make the Sudoku puzzle."""
  33. for x, y in get_index_samples(percent=0.6):
  34. board[x][y] = 0
  35.  
  36.  
  37. def get_index_samples(percent):
  38. """ Get some percentage of X, Y positions in the board"""
  39. indexes = [(x, y) for x in range(size) for y in range(size)]
  40. samples = sample(indexes, k=int(percent * (size * size)))
  41. return samples
  42.  
  43. def blocks(board):
  44. """ Yields each block (3x3 grid) from the board for validation. """
  45. # iterate in 3x3 blocks starting @ 0,3,6 in the x & y
  46. for x, y in ((x, y)
  47. for y in range(0, size, block_size)
  48. for x in range(0, size, block_size)):
  49. yield [board[by][bx]
  50. for by in range(y, y + block_size)
  51. for bx in range(x, x + block_size)]
  52.  
  53.  
  54. def is_solved(board):
  55. """ Returns True if board is a valid Sudoku solution. """
  56. # check rows have 1-9
  57. for row in board:
  58. if wanted != set(row):
  59. return False
  60. # zip subarrays to make columns and check also
  61. for col in zip(*board):
  62. if wanted != set(col):
  63. return False
  64. # check the 3x3 blocks to ensure they are also good.
  65. for block in blocks(board):
  66. if wanted != set(block):
  67. return False
  68. # its a valid solution!
  69. return True
  70.  
  71.  
  72. def get_positions(board):
  73. """ Return a list of tuples of open positions on a board. """
  74. open_positions = []
  75. for x in range(len(board)):
  76. for y in range(len(board[x])):
  77. if board[x][y] == 0:
  78. open_positions.append((x, y))
  79. return open_positions
  80.  
  81.  
  82. def get_row_set(board, position):
  83. """ Return a unique set of all used values in a row"""
  84. x, y = position
  85. return set([num for num in board[x] if num != 0])
  86.  
  87.  
  88. def get_col_set(board, position):
  89. """ Return a unique set of all used values in a column"""
  90. x, y = position
  91. return set([row[y] for row in board if row[y] != 0])
  92.  
  93.  
  94. def get_block_set(board, position):
  95. """ Return a unique set of all used values in a 3x3 block"""
  96. x, y = position
  97. block_x, block_y = (int(x / block_size), int(y / block_size))
  98. start_x = block_size * block_x
  99. start_y = block_size * block_y
  100. block = [board[x][y]
  101. for y in range(start_y, start_y + block_size)
  102. for x in range(start_x, start_x + block_size)
  103. if board[x][y] != 0]
  104. return set(block)
  105.  
  106.  
  107. def choices(board, position):
  108. """ Combine the sets of used values at a position
  109. and return unused numbers as a list. """
  110. available = set([x for x in range(1, size + 1)])
  111. row_set = get_row_set(board, position)
  112. col_set = get_col_set(board, position)
  113. block_set = get_block_set(board, position)
  114. return list(available.difference(row_set.union(col_set).union(block_set)))
  115.  
  116.  
  117. def solve(board):
  118. """ Recursive Sudoku solve with backtracking. """
  119. positions = get_positions(board)
  120. if len(positions) is 0:
  121. return True # base case, solved all positions
  122. for position in positions:
  123. # get possibilities for position
  124. available_choices = choices(board, position)
  125. for choice in available_choices:
  126. # set board[x,y] == choice
  127. x, y = position
  128. board[x][y] = choice
  129. if solve(board):
  130. return True
  131. # backtrack: unset position
  132. board[x][y] = 0
  133. return False # tried all choices, none fit
  134.  
  135.  
  136. if __name__ == '__main__':
  137. # rank 11 sudoku puzzle.
  138. # board = [
  139. # [8, 0, 0, 0, 0, 0, 0, 0, 0],
  140. # [0, 0, 3, 6, 0, 0, 0, 0, 0],
  141. # [0, 7, 0, 0, 9, 0, 2, 0, 0],
  142. # [0, 5, 0, 0, 0, 7, 0, 0, 0],
  143. # [0, 0, 0, 0, 4, 5, 7, 0, 0],
  144. # [0, 0, 0, 1, 0, 0, 0, 3, 0],
  145. # [0, 0, 1, 0, 0, 0, 0, 6, 8],
  146. # [0, 0, 8, 5, 0, 0, 0, 1, 0],
  147. # [0, 9, 0, 0, 0, 0, 4, 0, 0]
  148. # ]
  149. board = create_board()
  150. print("Board is: ")
  151. for row in board:
  152. print(row)
  153. depopulate(board)
  154. print("Puzzle is: ")
  155. for row in board:
  156. print(row)
  157. print("Solving..")
  158. solve(board)
  159. print("Solved: {}".format(is_solved(board)))
  160. print("Time: {}".format(time.process_time()))
  161. for row in board:
  162. print(row)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement