Created
November 30, 2014 03:27
-
-
Save bonetechnologies/c115cc74499dc4ea43c6 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
# -*- 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