Skip to content

Instantly share code, notes, and snippets.

@miclovich
Forked from anonymous/slidingPuzzle.py
Created May 9, 2014 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miclovich/ceb28c4875db45d71d8a to your computer and use it in GitHub Desktop.
Save miclovich/ceb28c4875db45d71d8a to your computer and use it in GitHub Desktop.
"""
slidingPuzzle.py
Emily Johnston
4/26/2014
A command-line, single-player sliding puzzle game of customizable size and difficulty.
"""
import sys
from random import choice
class SlidingPuzzle:
def __init__(self):
# dictionary that stores possible movement options
# keys are keyboard key corresponding to directions of movement (w=up, a=left, s=down, d=right)
# values are lists that store what direction the blank tile should move when that direction is entered
self.moveDict = {'w':[-1,0], 's':[1,0],'a':[0,-1], 'd':[0,1]}
# size: int, stores dimensions of the board (size x size tiles)
# diffLevel: int, stores for how many moves the board should be shuffled before being displayed to the user.
self.size, self.diffLevel = self.getDifficulty()
# generate a solved board of the size specified by the user
# two-dimensional list represents board, indexed by coordinates e.g. board[row][col]
# 0 represents blank square
# solved when blank is at top left and the rest of the tiles are in order
self.solution = self.constructBoard()
# Make a copy of the solved board to be our current board
self.board = []
for row in self.solution:
self.board.append(list(row))
# current position of the blank square
self.blankPos = [0,0]
# shuffle the tiles randomly for diffLevel moves
self.shuffleBoard()
# keeps track of how many moves player takes to solve puzzle
self.turns = 0
def constructBoard(self):
"""
Returns a solved sliding puzzle of the dimensions (self.size x self.size)
in the format of a 2-dimensional list.
"""
sol = []
startRow = 0
for row in range(self.size):
sol.append(range(startRow, startRow + self.size))
startRow += self.size
return sol
def shuffleBoard(self):
"""
Makes a self.diffLevel random moves on the board to shuffle it.
"""
i = 0
while i < self.diffLevel:
# select a random move string from the dictionary of moves, call makeMove to make that move
move = choice(self.moveDict.keys())
legalMove = self.makeMove(move)
# Only count legal moves in count of total moves made.
# Ideally, we wouldn't count repeat moves either, but that would be more trouble than it's worth.
if legalMove:
i += 1
def getDifficulty(self):
"""
Get the board size and difficulty level from the user.
Translate string difficulty level (easy, medium, hard) to a numeric value that
corresopnds to how many moves the board should be shuffled for.
Returns two ints: board size, # moves to shuffle
"""
# Get the board size from the user.
# If the user does not enter a digit, prompt them again.
print "What size board would you like to play with?"
s = raw_input('>> ')
while not s.isdigit():
s = raw_input('>> ')
size = int(s)
# Get the level of difficulty (how much to shuffle the board) from the user.
# If the user does not enter 'easy', 'medium', or 'hard', prompt them again.
diffLevels = {'easy':8, 'medium':15, 'hard':20}
print "\nGreat! What level of difficulty would you like to play?"
print "Easy, Medium, or Hard?"
diff = raw_input('>> ')
diff = (diff.strip()).lower()
while diff not in diffLevels:
diff = raw_input('>> ')
diff = (diff.strip()).lower()
level = diffLevels[diff] * size
return size, level
def clear(self):
""" Clears the terminal window by inserting whitespace (adapts to size of terminal window) """
sys.stderr.write("\x1b[2J\x1b[H")
def getMove(self):
"""
Prompts the user to enter a move and returns it.
If the user does not enter a valid move character, prompts them until they do.
Returns a single lower-case letter that corresponds to a direction, or 'q' if the user wants to quit.
"""
move = ''
while move not in self.moveDict and move != 'q':
print "\nEnter which direction to move the blank space, or q to forfeit.\n", \
" w is up\n", \
"a is left d is right\n", \
" s is down\n"
try:
move = raw_input(">> ")
move = move.strip()
move = move.lower()
# if the end of a file, or EOF character (ctrl-d) is entered
except (EOFError):
move = 'q'
return move
def play(self):
"""
Plays Sliding Puzzle until the user wins, or the user enters 'q' or the EOF character.
"""
self.display()
move = ''
while not self.isSolved():
move = self.getMove()
if move == 'q':
break
if not self.makeMove(move):
print '\nThat\'s an illegal move!'
else:
self.turns += 1
self.display()
if self.isSolved():
print "\nYou won! You solved the puzzle in", self.turns, "moves."
else:
print "\nBye bye!"
print "\n* Thanks for playing Sliding Puzzle! Have a great day! *\n"
def isSolved(self):
"""
Returns a boolean whether or not the puzzle has been solved.
"""
return self.board == self.solution
def makeMove(self, moveStr):
"""
Checks if a move is legal; if so, makes that move,
updating the board and the current position of the blank tile.
"""
move = self.moveDict[moveStr]
nextBlank = [ self.blankPos[0] + move[0], self.blankPos[1] + move[1] ]
if self.isLegal(nextBlank):
# simultaneous assignment - tile at spot where blank will go swaps with blank
self.board[self.blankPos[0]][self.blankPos[1]], self.board[nextBlank[0]][nextBlank[1]] \
= self.board[nextBlank[0]][nextBlank[1]], self.board[self.blankPos[0]][self.blankPos[1]]
self.blankPos = nextBlank
return True
return False
def isLegal(self, position):
"""
Checks if the given move is legal. Takes a two-item list that contains
a position on the board. If the position is out of bounds of the board,
returns False. If within the bounds, returns True.
"""
first = position[0] >= 0 and position[0] < self.size
second = position[1] >= 0 and position[1] < self.size
return first and second
def display(self):
"""
Clears the terminal window, then prints the current state of the board.
"""
self.clear()
# width of one square
width = 5
# construct a horizontal divider of the appropriate width for the board size.
divider = '-' * ((width * self.size) + 1)
print divider
for row in self.board:
for col in row:
tile = ' '
if col != 0:
tile = str(col)
if len(tile) < 2:
tile = ' ' + tile
print '|', tile,
print '|'
print divider
def main():
print
print " ************************************* "
print " * Hello! Welcome to Sliding Puzzle! * "
print " ************************************* "
print
shufflin = SlidingPuzzle()
shufflin.play()
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment