Advertisement
asweigart

Untitled

Sep 9th, 2021
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.64 KB | None | 0 0
  1. import random, time
  2.  
  3. random.seed(42) # Select which puzzle to solve.
  4. SIZE = 4 # Set this to either 3 or 4.
  5. BLANK = ' ' # The string that represents the blank space:
  6.  
  7. # Constants for directions:
  8. UP = 'up'
  9. DOWN = 'down'
  10. LEFT = 'left'
  11. RIGHT = 'right'
  12.  
  13.  
  14. def displayBoard(board):
  15. """Display `board` on the screen."""
  16. for y in range(SIZE):
  17. for x in range(SIZE):
  18. print(board[x][y] + ' ', end='')
  19. print() # Print a newline at the end of the row.
  20.  
  21.  
  22. def getNewBoard():
  23. """Return a list of lists that represents a new tile puzzle."""
  24. # NOTE: All the single digit numbers have a space in front of them.
  25. if SIZE == 3:
  26. return [[' 1', ' 4', ' 7'], [' 2', ' 5', ' 8'],
  27. [' 3', ' 6', BLANK]]
  28. elif SIZE == 4:
  29. return [[' 1', ' 5', ' 9', '13'], [' 2', ' 6', '10', '14'],
  30. [' 3', ' 7', '11', '15'], [' 4', ' 8', '12', BLANK]]
  31.  
  32.  
  33. def findBlankSpace(board):
  34. """Return an (x, y) tuple of the blank space's location."""
  35. for x in range(SIZE):
  36. for y in range(SIZE):
  37. if board[x][y] == BLANK:
  38. return (x, y)
  39.  
  40.  
  41. def makeMove(b, move):
  42. """Carry out the given move on the given board in `b`."""
  43. bx, by = findBlankSpace(b)
  44.  
  45. if move == UP:
  46. b[bx][by], b[bx][by+1] = b[bx][by+1], b[bx][by]
  47. elif move == LEFT:
  48. b[bx][by], b[bx+1][by] = b[bx+1][by], b[bx][by]
  49. elif move == DOWN:
  50. b[bx][by], b[bx][by-1] = b[bx][by-1], b[bx][by]
  51. elif move == RIGHT:
  52. b[bx][by], b[bx-1][by] = b[bx-1][by], b[bx][by]
  53.  
  54.  
  55. def undoMove(board, move):
  56. """Do the opposite move of `move` to undo it on `board`."""
  57. if move == UP:
  58. makeMove(board, DOWN)
  59. elif move == DOWN:
  60. makeMove(board, UP)
  61. elif move == LEFT:
  62. makeMove(board, RIGHT)
  63. elif move == RIGHT:
  64. makeMove(board, LEFT)
  65.  
  66.  
  67. def getValidMoves(board):
  68. """Returns a list of the valid moves to make on this board."""
  69. blankx, blanky = findBlankSpace(board)
  70.  
  71. validMoves = []
  72. if blanky != SIZE - 1: # Blank space is not on the bottom row.
  73. validMoves.append(UP)
  74. if blankx != SIZE - 1: # Blank space is not on the right column.
  75. validMoves.append(LEFT)
  76. if blanky != 0: # Blank space is not on the top row.
  77. validMoves.append(DOWN)
  78. if blankx != 0: # Blank space is not on the left column.
  79. validMoves.append(RIGHT)
  80. return validMoves
  81.  
  82.  
  83. def makeRandomMove(board):
  84. """Perform a slide in a random direction."""
  85. makeMove(board, random.choice(getValidMoves(board)))
  86.  
  87.  
  88. def getNewPuzzle():
  89. """Get a new puzzle by making random slides from a solved state."""
  90. board = getNewBoard()
  91. for i in range(200):
  92. makeRandomMove(board)
  93. return board
  94.  
  95.  
  96. def solve(board, maxMoves):
  97. """Attempt to solve the puzzle in `board` in at most `maxMoves`
  98. moves. Returns True if solved, otherwise False."""
  99. print('Attempting to solve in at most', maxMoves, 'moves...')
  100. solutionMoves = [] # A list of UP, DOWN, LEFT, RIGHT values.
  101. solved = attemptMove(board, solutionMoves, maxMoves)
  102. if solved:
  103. displayBoard(board)
  104. for move in solutionMoves:
  105. print('Move', move)
  106. makeMove(board, move)
  107. print() # Print a newline.
  108. displayBoard(board)
  109. print() # Print a newline.
  110.  
  111. print('Solved in', len(solutionMoves), 'moves:')
  112. print(', '.join(solutionMoves))
  113. return True # Puzzle was solved.
  114. else:
  115. return False # Unable to solve in maxMoves moves.
  116.  
  117.  
  118. def attemptMove(board, movesMade, maxMoves, iteration=1, lastMove=None):
  119. """A recursive function that attempts all possible moves on `board`
  120. until a solution is found or we've reached the `maxMoves` limit.
  121. Returns True if a solution was found, in which case, movesMade
  122. contains the series of moves to solve the puzzle. Returns False
  123. if no solution was found in `maxMoves` moves."""
  124. if iteration > maxMoves:
  125. return False # BASE CASE
  126.  
  127. # Get the valid moves, but don't consider a move that would undo
  128. # the last move made on this board:
  129. validMoves = getValidMoves(board)
  130. if lastMove == UP and DOWN in validMoves:
  131. validMoves.remove(DOWN)
  132. if lastMove == DOWN and UP in validMoves:
  133. validMoves.remove(UP)
  134. if lastMove == LEFT and RIGHT in validMoves:
  135. validMoves.remove(RIGHT)
  136. if lastMove == RIGHT and LEFT in validMoves:
  137. validMoves.remove(LEFT)
  138.  
  139. # Attempt each of the valid moves:
  140. for move in validMoves:
  141. # Make the move:
  142. makeMove(board, move)
  143. movesMade.append(move)
  144.  
  145. if board == getNewBoard():
  146. # BASE CASE - Solved the puzzle:
  147. undoMove(board, move)
  148. return True
  149. else:
  150. # RECURSIVE CASE - Attempt another move:
  151. if attemptMove(board, movesMade, maxMoves, iteration + 1, move):
  152. # If the puzzle is solved, return True:
  153. undoMove(board, move)
  154. return True
  155.  
  156. # Undo this last move to set up for the next move:
  157. undoMove(board, move)
  158. movesMade.pop() # Remove the last move since it was undone.
  159. return False # BASE CASE - Unable to find a solution.
  160.  
  161.  
  162. # Start the program:
  163. gameBoard = getNewPuzzle()
  164. displayBoard(gameBoard)
  165. input('Press Enter to solve...')
  166. startTime = time.time()
  167.  
  168. maxMoves = 1
  169. while True:
  170. if solve(gameBoard, maxMoves):
  171. break # Break out of the loop when a solution is found.
  172. maxMoves += 1
  173. print('Run in', round(time.time() - startTime, 1), 'seconds.')
  174.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement