# Sliding Puzzle

This is my version of a sliding puzzle.
A sliding puzzle is based on a number of tiles (15 in this case) which are scrambled.
The objective of the game then is to slide the tiles around and get back to the original image.
As an image I took a photo of an apple in front of a black background.

#### Controls

• F1 takes a screenshot
• F2 starts and stops scrambling the image
• F3 solves the puzzle
• Mouse clicks slide tiles

``````# Python 2.7.7 Code
# Pygame 1.9.1 (for Python 2.7.7)
# Jonathan Frech 15th of April, 2016
#         edited 16th of April, 2016``````

``````# importing needed modules
import pygame, sys, time, math, os, random, re

IMAGE_PATH = os.getcwd() + "/apple.png"

""" CLASSES """
# piece class
class Piece():
# initialize
def __init__(self, gamepos, n):
self.n = n
self.size = [200, 200]
self.setgamepos(gamepos)
self.pos = [random.randint(0, G.width - self.size[0]), random.randint(0, G.height - self.size[1])]

self.surface = pygame.Surface(self.size)
self.surface.blit(G.image, [-self.gamepos[0] * self.size[0], -self.gamepos[1] * self.size[1]])

# gamepos in range [0:3] and [0:3]
def setgamepos(self, gamepos):
self.gamepos = gamepos
self.dest = [self.gamepos[0] * self.size[0], self.gamepos[1] * self.size[1]]

# check if piece was clicked
def clicked(self, gamepos):
if gamepos[0] == self.gamepos[0] and gamepos[1] == self.gamepos[1]:
return True

return False

# tick
def tick(self):
for _ in range(0, 2):
dif = (self.dest[_] - self.pos[_]) / 10.
if abs(dif) < .1:
self.pos[_] = self.dest[_]
else:
self.pos[_] += dif

# render
def render(self, surface):
surface.blit(self.surface, intpos(self.pos))

""" FUNCTIONS """
# returns an integer version of given positon
def intpos(_pos):
return [int(_pos[0]), int(_pos[1])]

# load an image from string
# standard string
if not string:
string = "(1, 1)<<<Here the stringified image would go... The only problem is that that would men 5,000,000 characters...>>>"

# figure out size
size = re.findall("\(\d*, \d*\)", string)[0]
string = string[len(size):len(string)]
size = size[1:len(size)-1]
size = re.split(", ", size)
size = [int(size[0]), int(size[1])]

# draw image
img = pygame.Surface(size)
for _ in range(0, len(string), 3):
img.set_at([(_/3)%size[0], (_/3)/size[1]], [ord(string[_]), ord(string[_+1]), ord(string[_+2])])

# return
return img

# save an image to string
def getimgstr(path):
image = pygame.image.load(os.getcwd() + "/" + path)
rect = image.get_rect()

# generate string
string = "(" + str(rect.right) + ", " + str(rect.bottom) + ")"
for y in range(0, rect.bottom):
for x in range(0, rect.right):
color = image.get_at([x, y])
string += chr(color[0]) + chr(color[1]) + chr(color[2])

# escape and return
return string#.encode("string-escape")

""" GAME """
# game class
class GAME():
# initialize program
def __init__(self):
self.width, self.height = 800, 800
self.size = [self.width, self.height]
self.surface = pygame.Surface(self.size)
self.screen = pygame.display.set_mode(self.size)

self.ticks = 0
self.running = True

self.image = pygame.transform.scale(self.image, self.size)

# functions
pygame.display.set_caption("Sliding Puzzle")

# initialize game
def init(self):
self.pieces = []
n = 0
for x in range(0, 4):
for y in range(0, 4):
self.pieces.append(Piece([x, y], n))
n += 1

self.pieces.pop(-1)

self.scrambling = False

# do one random move
def scramble(self):
moved = False
while not moved:
moved = self.move([random.randint(0, self.width), random.randint(0, self.height)])

def move(self, mousepos):
for piece in self.pieces:
if piece.clicked([mousepos[0] / piece.size[0], mousepos[1] / piece.size[1]]):
for _ in [[-1, 0], [1, 0], [0, -1], [0, 1]]:
pos = [mousepos[0] / piece.size[0] + _[0], mousepos[1] / piece.size[1] + _[1]]
occupied = False
for p in self.pieces:

if p.clicked(pos) or pos[0] < 0 or pos[0] >= 4 or pos[1] < 0 or pos[1] >= 4:
occupied = True

if not occupied:
piece.setgamepos(pos)
return True

return False

# tick function
def tick(self):
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.quit()
if event.type == pygame.KEYDOWN:
# screnshot
if event.key == pygame.K_F1:
self.screenshot()

# scramble
if event.key == pygame.K_F2:
self.scrambling = not self.scrambling

# solve (that is cheating!)
if event.key == pygame.K_F3:
self.init()

# handle mouse button presses
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
mousepos = list(pygame.mouse.get_pos())
self.move(mousepos)

if self.scrambling and self.ticks % 2 == 0:
self.scramble()

for piece in self.pieces:
piece.tick()

# render function
def render(self):
# fill
self.surface.fill([0, 0, 0])

for piece in self.pieces:
piece.render(self.surface)

# blit and flip
self.screen.blit(self.surface, [0, 0])
pygame.display.flip()

# quits
def quit(self):
self.running = False

# takes a screenshot
def screenshot(self):
path = os.getcwd() + "/out/"

try:
if not os.path.isdir(path):
os.mkdir(path)

name = "img" + str(len(os.listdir(path))) + ".png"
pygame.image.save(self.surface, path + name)
except:
pass

# run function (uses tick() and render())
def run(self):
ticksPerSecond = 60
lastTime = time.time() * 1000000000
nsPerTick =  1000000000.0 / float(ticksPerSecond)

ticks = 0
frames = 0

lastTimer = time.time() * 1000
delta = 0.0

while self.running:
now = time.time() * 1000000000
delta += float(now - lastTime) / float(nsPerTick)
lastTime = now
shouldRender = False

while delta >= 1:
ticks += 1
self.ticks += 1
self.tick()
delta -= 1
shouldRender = True

if shouldRender:
frames += 1
self.render()

if time.time() * 1000 - lastTimer >= 1000:
lastTimer += 1000

# debug
#print("Frames: " + str(frames) + ", ticks: " + str(ticks))

frames = 0
ticks = 0

# start game
G = GAME()
G.init()
G.run()``````