Created
April 26, 2014 16:42
-
-
Save anonymous/11324813 to your computer and use it in GitHub Desktop.
A command-line, single-player sliding puzzle game of customizable size and difficulty.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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 " * Hello! Welcome to Sliding Puzzle! * " | |
print " ************************************* " | |
shufflin = SlidingPuzzle() | |
shufflin.play() | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment