Skip to content

Instantly share code, notes, and snippets.

@bonetechnologies
Created November 30, 2014 03:27
Show Gist options
  • Save bonetechnologies/c115cc74499dc4ea43c6 to your computer and use it in GitHub Desktop.
Save bonetechnologies/c115cc74499dc4ea43c6 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
"""
@author JGNickerson
"""
from pyprocessing import *
from PIL import Image
import random
# Some constants that control the size of the window and the size of the tiles on the board
WIDTH = 600
HEIGHT = 600
CELL_SIZE=25
class Tile:
def __init__(self, tileType, x, y, gameBoard):
"""
Initialize the tile, setting its position and default values.
"""
self.tileType = tileType
self.x = x
self.y = y
self.gameBoard = gameBoard
self.goal = False
self.occupant = None
self.lava = loadImage('lava.jpg')
self.tile = loadImage('tile.jpg')
self.wall = loadImage('wall.jpg')
def draw(self):
"""
Draw the tile and tell any occupant to draw itself.
"""
rectMode(CENTER)
#blanks
if self.tileType == 'n':
image(self.lava,-12.5,-12.5,25,25) #adding positional arguments 4 & 5 lets you resize image
#floors
if self.tileType == 'o':
#image(self.tile,-12.5,-12.5,25,25)
fill(178,176,168)
rect(0,0,24,24)
fill(0,128,255,90)
rect(0,0,12,12)
#walls
if self.tileType == 'w':
image(self.wall,-12.5,-12.5,25,25)
"""
rectMode(CORNER)
fill(100,100,100)
rect(-12,-12,8,5)
rect(-4,-12,8,5)
rect(4,-12,8,5)
noStroke()
rect(-12,-7,4,4)
stroke(0,0,0)
rect(-8,-7,8,4)
rect(0,-7,7,4)
noStroke()
rect(8,-7,4,4)
stroke(0,0,0)
rect(-12,-2,8,5)
rect(-4,-2,8,5)
rect(4,-2,8,5)
noStroke()
rect(-12,3,4,4)
stroke(0,0,0)
rect(-8,3,8,4)
rect(0,3,7,4)
noStroke()
rect(8,3,4,4)
stroke(0,0,0)
rect(-12,8,8,5)
rect(-4,8,8,5)
rect(4,8,8,5)
"""
if self.goal == True:
rectMode(CENTER)
smooth()
fill(178,176,168)
rect(0,0,24,24)
fill(255,0,0,95)
ellipse(0,0,25,25)
fill(255,255,255)
ellipse(0,0,16,16)
fill(255,0,0,99)
ellipse(0,0,7,7)
if self.goal == True and self.occupant != None and self.occupant != self.gameBoard.player:
fill(0,220,0)
rect(0,0,25,25)
# check if there is a piece here and tell it to draw itself if there is
if self.occupant:
self.occupant.draw()
def isFree(self):
if self.occupant != None or self.tileType == 'w':
return False
else:
return True
def removePiece(self):
piece = self.occupant
self.occupant = None
if piece is not None:
piece.tile = None
return piece
def addPiece(self, piece):
self.occupant = piece
piece.tile = self
def getNeighbor(self, direction):
if direction == 'N':
return self.gameBoard.getTile(self.x,self.y-1)
elif direction == 'S':
return self.gameBoard.getTile(self.x,self.y+1)
elif direction == 'E':
return self.gameBoard.getTile(self.x+1,self.y)
elif direction == 'W':
return self.gameBoard.getTile(self.x-1,self.y)
class Box():
def __init__(self):
self.tile = None
def draw(self):
rectMode(CENTER)
fill(150,100,0)
rect(0,0,20,20)
rect(0,0,14,14)
class Player():
def __init__(self, gameBoard):
self.gameBoard = gameBoard
self.tile = None
def draw(self):
fill(0,153,0)
rect(0,0,14,5)
fill(255,204,153)
arc(-8,0,4,4,PI/2,3*PI/2)
arc(8,0,4,4,PI/2,-PI/2)
fill(255,0,0)
arc(-3,-4,5,7,0,-PI)
arc(3,-4,5,7,0,-PI)
fill(255,204,153)
ellipse(0,0,10,10)
fill(153,102,0)
ellipse(0,1,7,7)
if key.code == UP: #UP arrow
fill(0,153,0)
rect(0,0,14,5)
fill(255,204,153)
arc(-8,0,4,4,PI/2,3*PI/2)
arc(8,0,4,4,PI/2,-PI/2)
fill(255,0,0)
arc(-3,-4,5,7,0,-PI)
arc(3,-4,5,7,0,-PI)
fill(255,204,153)
ellipse(0,0,10,10)
fill(153,102,0)
ellipse(0,1,7,7)
elif key.code == DOWN: #DOWN arrow
#draws a tile underneath player to cover up looping initial player
fill(178,176,168)
rect(0,0,24,24)
fill(156,156,156)
rect(0,0,12,12)
fill(0,153,0)
rect(0,0,14,5)
fill(255,204,153)
arc(-8,0,4,4,PI/2,3*PI/2)
arc(8,0,4,4,PI/2,-PI/2)
fill(255,0,0)
arc(-3,4,5,7,0,PI)
arc(3,4,5,7,0,PI)
fill(255,204,153)
ellipse(0,0,10,10)
fill(153,102,0)
ellipse(0,-1,7,7)
elif key.code == RIGHT: #RIGHT arrow
#draws a tile underneath player to cover up looping initial player
fill(178,176,168)
rect(0,0,24,24)
fill(156,156,156)
rect(0,0,12,12)
#draws player
fill(0,153,0)
rect(0,0,5,14)
fill(255,204,153)
ellipse(0,9,4,4)
ellipse(0,-9,4,4)
fill(255,0,0)
ellipse(4,3,7,5)
ellipse(4,-3,7,5)
fill(255,204,153)
ellipse(0,0,10,10)
fill(153,102,0)
ellipse(-1,0,7,7)
elif key.code == LEFT: #LEFT arrow
#draws a tile underneath player to cover up looping initial player
fill(178,176,168)
rect(0,0,24,24)
fill(156,156,156)
rect(0,0,12,12)
fill(255,204,153)
ellipse(0,9,4,4)
ellipse(0,-9,4,4)
fill(255,0,0)
ellipse(-4,3,7,5)
ellipse(-4,-3,7,5)
fill(0,153,0)
rect(0,0,5,15)
fill(255,204,153)
ellipse(0,0,10,10)
fill(153,102,0)
ellipse(1,0,7,7)
def move(self, direction):
if direction == 'N':
newTile = self.gameBoard.player.tile.getNeighbor('N')
if newTile.isFree():
#remove piece was here, but I think movePiece method already removes it
self.gameBoard.movePiece(self.gameBoard.player,'N')
self.gameBoard.moves += 1
elif newTile.occupant != None:
self.gameBoard.movePiece(newTile.occupant,'N')
self.gameBoard.movePiece(self.gameBoard.player,'N')
self.gameBoard.moves += 1
elif direction == 'S':
newTile = self.gameBoard.player.tile.getNeighbor('S')
if newTile.isFree():
self.gameBoard.movePiece(self.gameBoard.player,'S')
self.gameBoard.moves += 1
elif newTile.occupant != None:
self.gameBoard.movePiece(newTile.occupant,'S')
self.gameBoard.movePiece(self.gameBoard.player,'S')
self.gameBoard.moves += 1
elif direction == 'E':
newTile = self.gameBoard.player.tile.getNeighbor('E')
if newTile.isFree():
self.gameBoard.movePiece(self.gameBoard.player,'E')
self.gameBoard.moves += 1
elif newTile.occupant != None:
self.gameBoard.movePiece(newTile.occupant,'E')
self.gameBoard.movePiece(self.gameBoard.player,'E')
self.gameBoard.moves += 1
else:
newTile = self.gameBoard.player.tile.getNeighbor('W')
if newTile.isFree():
self.gameBoard.movePiece(self.gameBoard.player,'W')
self.gameBoard.moves += 1
elif newTile.occupant != None:
self.gameBoard.movePiece(newTile.occupant,'W')
self.gameBoard.movePiece(self.gameBoard.player,'W')
self.gameBoard.moves += 1
class SokobanBoard:
OPEN = ' '
LAVA = 'l'
WALL = '#'
PLAYER = '@'
BOX = '$'
GOAL = '.' # should have a box on it by the end
BOXGOAL = '*' # a goal that already has a box on it
MAX_LEVEL = 90
def __init__(self):
self.level = 0
self.loadLevel()
def loadLevel(self):
# reinitialize the collection of tiles and the obstacles
self.grid = []
self.boxes = []
self.moves = 0
# read the data in from the correct file
fname = os.path.join('levels', 'level.%02d.txt' % self.level)
# figure out how many rows there should be, and of what width
try:
f = open(fname)
data = []
self.cols = 0 #ultimately will become width of gameboard, i.e. number of columns
for line in f:
line = line.rstrip('\n')
if len(line) > self.cols:
self.cols = len(line)
data.append(line)
f.close()
self.rows = len(data)
# use the textual data to construct the maze and place the objects
# at the end we should have a 2D list of tiles and all of the pieces
# in place on the board.
for y in range(self.rows):
numWalls = 0
row = []
for x in range(self.cols):
if x < len(data[y]):
squareType = data[y][x] #dumps the string
else:
squareType = self.LAVA
if squareType == self.WALL:
# tile is a wall
tile = Tile('w', x,y, self)
numWalls += 1
else:
# tile is open, but might have something there
if numWalls == 0:
tile = Tile('n', x,y, self)
elif squareType == self.LAVA:
tile = Tile('n', x,y, self)
else:
tile = Tile('o', x,y, self)
if squareType == self.PLAYER:
# tile has the player on it
self.player = Player(self)
tile.addPiece(self.player)
if squareType == self.GOAL or squareType == self.BOXGOAL:
# tile is a goal
tile.goal = True
if squareType == self.BOX or squareType == self.BOXGOAL:
# tile has a Box on it
box = Box()
tile.addPiece(box)
self.boxes.append(box)
row.append(tile)
self.grid.append(row)
except IOError:
# some error handling if the file containing the maze can't be found
# if you see these messages, you probably have misplaced the levels folder
print("Error: cannot open " + fname)
print("You need to have the 'levels' folder in this folder")
print("Current folder is:")
print(os.getcwd())
sys.exit(1)
def getTile(self, x, y):
return self.grid[y][x]
def movePiece(self, piece, direction):
if direction == 'N':
newTile = self.getTile(piece.tile.x,piece.tile.y-1)
elif direction == 'S':
newTile = self.getTile(piece.tile.x,piece.tile.y+1)
elif direction == 'E':
newTile = self.getTile(piece.tile.x+1,piece.tile.y)
else:
newTile = self.getTile(piece.tile.x-1,piece.tile.y)
if newTile.isFree():
self.getTile(piece.tile.x,piece.tile.y).removePiece()
if direction == 'N':
newTile.addPiece(piece)
if direction == 'S':
newTile.addPiece(piece)
if direction == 'E':
newTile.addPiece(piece)
else:
newTile.addPiece(piece)
def levelComplete(self):
completion = 0
for y in range(len(self.grid)):
for x in range(len(self.grid[y])):
if self.grid[y][x].goal == True and self.grid[y][x].occupant != None and self.grid[y][x].occupant != self.player:
completion += 1
if completion == len(self.boxes):
return True
def draw(self):
background(0,0,0)
#Draws the scoreboard
fill(255,255,255)
rect(300,40,300,75)
fill(255,0,0)
textAlign(CENTER)
text('Level '+str(self.level),300,20)
text('Your Score: '+str(self.moves),300,60)
translate(WIDTH//2- (len(self.grid[0])//2)*CELL_SIZE, HEIGHT//2- (len(self.grid)//2)*CELL_SIZE)
for row in self.grid:
for tile in row:
pushMatrix()
translate(tile.x*CELL_SIZE, tile.y*CELL_SIZE)
tile.draw()
popMatrix()
def keyPressed(self):
if key.code == UP: #UP arrow
self.player.move('N')
elif key.code == DOWN: #DOWN arrow
self.player.move('S')
elif key.code == RIGHT: #RIGHT arrow
self.player.move('E')
elif key.code == LEFT: #LEFT arrow
self.player.move('W')
elif key.char in 'nN' and self.level < self.MAX_LEVEL:
self.level += 1
self.loadLevel()
elif key.char in 'pP' and self.level > 0:
self.level += -1
self.loadLevel()
if self.levelComplete() == True:
delay(500.0)
self.level += 1
self.loadLevel()
if __name__ == '__main__':
frameRate(30)
size(WIDTH, HEIGHT)
game = SokobanBoard()
draw = lambda: game.draw()
keyPressed = lambda: game.keyPressed()
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment