commit cd585b34938b53c43ab79b817acd8f1ea93af5c1
parent da08927a85bbaf51133c1a1781733e88b22e6ccc
Author: Antoine Amarilli <ant.amarilli@free.fr>
Date: Tue, 17 May 2011 00:38:31 -0400
added files
Diffstat:
README | | | 79 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
continuity.py | | | 435 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
level | | | 27 | --------------------------- |
level1 | | | 27 | +++++++++++++++++++++++++++ |
level2 | | | 164 | +++++++++++++++---------------------------------------------------------------- |
level2.best | | | 10 | ---------- |
level3 | | | 26 | ++++++++++++++++++++++++++ |
level4 | | | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
level5 | | | 26 | ++++++++++++++++++++++++++ |
level6 | | | 134 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
levelb | | | 30 | ------------------------------ |
levelc | | | 26 | -------------------------- |
leveld | | | 42 | ------------------------------------------ |
levele | | | 26 | -------------------------- |
main.py | | | 423 | ------------------------------------------------------------------------------- |
15 files changed, 799 insertions(+), 718 deletions(-)
diff --git a/README b/README
@@ -0,0 +1,79 @@
+continuity -- a curses game inspired by continuitygame.com
+by Antoine Amarilli
+licence: public domain
+
+This game is quite similar to the game at
+<http://continuitygame.com/playcontinuity.html>. However, this is an
+independent creation and is not endorsed by continuitygame.com.
+
+There are a few differences, though:
+- python+curses rather than flash
+- turn-based, not realtime
+- no jumping but ladders
+- not continuous but discrete
+- falling from a block with no suitable block underneath isn't deadly
+- no music
+- only 6 levels
+- score
+- source code available and public domain
+
+== Requirements ==
+
+- Python3
+- Curses bindings
+- Color support on your terminal is recommended
+
+== How to play ==
+
+$ ./continuity.py LEVEL
+
+LEVEL is the path to the file containing the level to play.
+
+=== Controls ===
+
+- hjkl to move player
+- HJKL to move blocks
+- q to quit
+
+=== Elements ===
+
+- '@': the player
+- '*': grab all these items to open the exit
+- '^': reach this exit to win
+- '#': an obstacle you can walk on
+- '%': a ladder which you can walk on and climb
+
+You can go from square to square with player movement keys. You can go
+from block to block if the two blocks are adjacent and their boundaries
+match exactly ('?' indicates a mismatch). If the boundaries do not
+match, you cannot pass. You can walk on mismatched boundaries.
+
+=== Scoring ===
+
+- Moves is the total number of player movement commands
+- Dist is the total number of squares travelled by player (including
+ free falls)
+- Swaps is the total number of block movement commands
+
+== Levels ==
+
+=== Levels provided ===
+
+Provided levels are inspired by some continuitygame.com levels. Levels 1
+to 5 are easy. Level 6 is harder. A non-optimal score for level 6 is 12
+moves, 44 dist, 70 swaps.
+
+=== Writing your own levels ===
+
+Level files are mostly simple text files with a block by block ascii art
+drawing of the level along with more info. level1 contains helpful
+comments to understand what's going on.
+
+== TODO ==
+
+- Support non-square blocks (partially coded)
+- Support multiple levels (ie. running them in order)
+- Better format for levels
+- Code cleanup
+- Design more levels
+
diff --git a/continuity.py b/continuity.py
@@ -0,0 +1,435 @@
+#!/usr/bin/python3
+# continuity -- a curses game inspired by continuitygame.com
+# by Antoine Amarilli
+# licence: public domain
+
+import sys
+import curses
+
+class Square:
+ wall, ladder, empty, exit, player, blank, key = range(7)
+ asciiMap = {wall: '#', ladder:'%', empty:' ', exit:'^', player:'@',
+ blank:'!', key:'*'}
+
+ def __init__(self, parent, type, pos):
+ self.parent = parent
+ self.type = type
+ self.pos = pos
+
+ def getNeighbour(self, dir):
+ return self.parent.getSquare((self.pos[0] + dir[0], self.pos[1] + dir[1]))
+
+ def getType(self):
+ return self.type
+
+ def setType(self, type):
+ self.type = type
+
+ def render(self, pad, x, y):
+ if (self.parent.parent.getPlayer().getPos() == self):
+ self.parent.parent.getPlayer().setGraphPos((x + self.pos[0],y +
+ self.pos[1]))
+ c = '@'
+ mode = curses.A_BOLD + curses.A_BLINK + curses.color_pair(1)
+ else:
+ if (self.parent.parent.getPlayer().getPos().getParent() == self.parent):
+ mode = curses.A_BOLD
+ else:
+ mode = 0
+ c = Square.asciiMap[self.type]
+ if (c == '^'):
+ if (self.parent.parent.keysLeft() == True):
+ mode = curses.A_BOLD + curses.color_pair(8)
+ else:
+ mode = curses.A_BOLD + curses.color_pair(2)
+ if (c == '%'): mode = curses.color_pair(3)
+ if (c == '#'): mode = curses.color_pair(4)
+ if (c == '!'):
+ mode = curses.color_pair(5)
+ pad.addch( x + self.pos[0],y + self.pos[1], c, mode)
+ c = ' '
+ if (c == '*'): mode = curses.A_BOLD + curses.color_pair(2)
+ try:
+ pad.addch( x + self.pos[0],y + self.pos[1], c, mode)
+ except curses.error:
+ pass
+
+ def getParent(self):
+ return self.parent
+
+
+class Block:
+ left, right, top, bottom = range(4)
+ def __init__(self, parent, h, w, pos):
+ self.parent = parent
+ self.h = h
+ self.w = w
+ self.pos = pos
+ self.map = []
+ for i in range(0, h):
+ self.map.append([])
+ for j in range(0, w):
+ self.map[i].append(Square(self, 0, (0, 0)))
+
+ def getBorder(self, t):
+ a = []
+ if (t == Block.left):
+ for i in range(0, self.h):
+ a.append(self.getSquare((i,0)).getType())
+ if (t == Block.right):
+ for i in range(0, self.h):
+ a.append(self.getSquare((i, self.w-1)).getType())
+ if (t == Block.top):
+ for i in range(0, self.w):
+ a.append(self.getSquare((0, i)).getType())
+ if (t == Block.bottom):
+ for i in range(0, self.w):
+ a.append(self.getSquare((self.h-1, i)).getType())
+ return a
+
+ def getNeighbour(self, dir):
+ return self.parent.getBlock((self.pos[0] + dir[0], self.pos[1] + dir[1]))
+
+ def setSquare(self, x, y, s):
+ self.map[x][y] = s
+
+ def getSquare(self, p):
+ x = p[0]
+ y = p[1]
+ if (x < 0):
+ a = self.getNeighbour((-1, 0))
+ if (self.getBorder(Block.top) != a.getBorder(Block.bottom)):
+ return BlockSentry(self.parent, 0, 0, (0, 0)).getSquare((0,0))
+ return a.getSquare((a.getH() + p[0], p[1]))
+ elif (y < 0):
+ a = self.getNeighbour((0, -1))
+ if (self.getBorder(Block.left) != a.getBorder(Block.right)):
+ return BlockSentry(self.parent, 0, 0, (0, 0)).getSquare((0,0))
+ return a.getSquare((p[0], a.getW() + p[1]))
+ elif (x >= self.getH()):
+ a = self.getNeighbour((1, 0))
+ if (self.getBorder(Block.bottom) != a.getBorder(Block.top)):
+ return BlockSentry(self.parent, 0, 0, (0, 0)).getSquare((0,0))
+ return a.getSquare((p[0] - self.getH(), p[1]))
+ elif (y >= self.getW()):
+ a = self.getNeighbour((0, 1))
+ if (self.getBorder(Block.right) != a.getBorder(Block.left)):
+ return BlockSentry(self.parent, 0, 0, (0, 0)).getSquare((0,0))
+ return a.getSquare((p[0], p[1] - self.getW()))
+ else:
+ return self.map[x][y]
+
+ def getW(self):
+ return self.w
+
+ def getH(self):
+ return self.h
+
+ def render(self, pad, x, y):
+ for i in self.map:
+ for j in i:
+ j.render(pad, x, y)
+
+ def loadFromFile(self, f):
+ for i in range(0, self.getH()):
+ l = f.readline()
+ for j in range(0, self.getW()):
+ x = l[j]
+ c = {v:k for k, v in Square.asciiMap.items()}[x]
+ if (x == '*'):
+ self.parent.addKey()
+ if (x == '@'):
+ c = Square.empty
+ self.map[i][j] = Square(self, c, (i, j))
+ if (x == '@'):
+ self.parent.getPlayer().setPos(self.map[i][j])
+
+
+ def move(self, p):
+ self.pos = (self.pos[0] + p[0], self.pos[1] + p[1])
+
+
+
+class BlockSentry(Block):
+ def getSquare(self, p):
+ return Square(self, Square.blank, (0,0))
+
+ def render(self, pad, x, y):
+ for i in range(0, self.h):
+ for j in range(0, self.w):
+ (Square(self, Square.blank, (i,j))).render(pad, x, y)
+
+class Player:
+ keyMap = {(0, -1): 'h', (1, 0):'j', (-1, 0):'k', (0, 1): 'l'}
+
+ def __init__(self, parent, square):
+ self.parent = parent
+ self.pos = square
+ self.graphPos = (0,0)
+
+ def render(self, pad):
+ pad.move(self.graphPos[0], self.graphPos[1])
+
+ def setGraphPos(self, p):
+ self.graphPos = p
+
+ def move(self, direction, volont):
+ a = self.pos.getNeighbour(direction)
+ if (a.getType() != Square.wall and a.getType() != Square.blank):
+ self.pos = a
+ self.parent.addDist()
+ if (volont == True): self.parent.addMoves()
+ if (self.pos.getType() == Square.key):
+ self.parent.removeKey()
+ self.pos.setType(Square.empty)
+ if (self.pos.getType() == Square.exit and not self.parent.keysLeft()):
+ return True
+ else:
+ return self.fall()
+
+ def getPos(self):
+ return self.pos
+
+ def setPos(self, pos):
+ self.pos = pos
+
+ def fall(self):
+ a = self.pos.getType()
+ b = self.pos.getNeighbour((1,0)).getType()
+ while (self.pos.getType() != Square.ladder and (
+ self.pos.getNeighbour((1,0)).getType() == Square.empty or
+ self.pos.getNeighbour((1,0)).getType() == Square.key or
+ self.pos.getNeighbour((1,0)).getType() == Square.exit)):
+ if self.move((1, 0), 0):
+ return True
+ return False
+
+
+class Level:
+ codeMap = {104: 'h', 106:'j', 107:'k', 108: 'l', 113: 'q', 72: 'H',
+ 74:'J', 75: 'K', 76:'L'}
+ def __init__(self, h, w, x, y):
+ self.h = h
+ self.w = w
+ self.holeX = x
+ self.holeY = y
+ self.map = []
+ self.keys = 0
+ self.cswap = 0
+ self.cmove = 0
+ self.cdist = 0
+ for i in range(0, h):
+ self.map.append([])
+ for j in range(0, w):
+ self.map[i].append(Block(0, 0, 0, 0))
+ self.player = Player(self, Square(0, 0, (0,0)))
+
+ def loadFromFile(self, f):
+ bh = int(f.readline())
+ bw = int(f.readline())
+ for i in range(0, self.h):
+ for j in range(0, self.w):
+ if ((i, j) != (self.holeX, self.holeY)):
+ self.map[i][j] = Block(self, bh, bw, (i, j))
+ else:
+ self.map[i][j] = BlockSentry(self, bh, bw, (i, j))
+ self.map[i][j].loadFromFile(f)
+
+ def addKey(self):
+ self.keys+=1
+
+ def addDist(self):
+ self.cdist += 1
+
+ def addMoves(self):
+ self.cmove += 1
+
+ def addSwap(self):
+ self.cswap += 1
+
+ def removeKey(self):
+ self.keys-=1
+
+ def keysLeft(self):
+ return self.keys != 0
+
+ def getPlayer(self):
+ return self.player
+
+ def render(self, pad):
+ m = 0
+ for i in range(0, self.w):
+ m = m + self.map[0][i].getW() + 1
+ for i in range(0, m+1):
+ pad.addch( 0 ,i, '\'', curses.color_pair(5))
+ pad.addch( 0 ,i, ' ', curses.color_pair(5))
+ x = 0
+ for j in range(0, self.h):
+ y = 0
+ for i in range(0, self.map[0][j].getH()+1):
+ pad.addch( j*(self.map[0][j].getH()+1)+1 +i ,0, ' ', curses.color_pair(5))
+ for i in range(0, self.w):
+ a = self.map[j][i]
+ a.render(pad, j*a.getH()+1+j, i*a.getW()+1+i)
+ l = a.getBorder(Block.bottom)
+ l2 = a.getNeighbour((1, 0)).getBorder(Block.top)
+ if (l != l2):
+ for k in range(0, a.getW()+1):
+ if (l2 != [] and l != [] and l[k-1] != l2[k-1]):
+ pad.addch(x+self.map[0][j].getH() +1,y+k,
+ '?', curses.color_pair(5))
+ else:
+ pad.addch( x+self.map[0][j].getH() +1,y+k,
+ '\'', curses.color_pair(5))
+ pad.addch( x+self.map[0][j].getH() +1,y+k,
+ ' ', curses.color_pair(5))
+ else:
+ for k in range(0, a.getW()):
+ if (l[k] == Square.wall):
+ pad.addch( x+self.map[0][j].getH()+1,y+k+1,
+ '|', curses.color_pair(6))
+ else:
+ pad.addch( x+self.map[0][j].getH()+1,y+k+1,
+ '\'', curses.color_pair(7))
+ pad.addch( x+self.map[0][j].getH()+1,y+k+1,
+ ' ', curses.color_pair(7))
+ y = y + a.getW() + 1
+ l = a.getBorder(Block.right)
+ l2 = a.getNeighbour((0, 1)).getBorder(Block.left)
+ if (l != l2):
+ for k in range(0, a.getH()+1):
+ if (l2 != [] and l != [] and l[k-1] != l2[k-1]):
+ pad.addch( x+k ,y, '?', curses.color_pair(5))
+ else:
+ pad.addch( x+k ,y, '\'', curses.color_pair(5))
+ pad.addch( x+k ,y, ' ', curses.color_pair(5))
+ else:
+ for k in range(0, a.getH()):
+ if (l[k] == Square.wall):
+ pad.addch( x+k+1 ,y, '-', curses.color_pair(6))
+ else:
+ pad.addch( x+k+1 ,y, '\'', curses.color_pair(7))
+ pad.addch( x+k+1 ,y, ' ', curses.color_pair(7))
+ for k in range(0, a.getH()+1):
+ pad.addch( x+k ,y, '\'', curses.color_pair(5))
+ pad.addch( x+k ,y, ' ', curses.color_pair(5))
+ x = x + self.map[0][j].getH() + 1
+ m = 0
+ for i in range(0, self.h):
+ m = m + self.map[i][0].getH() + 1
+ for i in range(0, y+1):
+ pad.addch( m ,i, '\'', curses.color_pair(5))
+ pad.addch( m ,i, ' ', curses.color_pair(5))
+ x = 0
+ for j in range(0, self.h+1):
+ y = 0
+ for i in range(0, self.w+1):
+ pad.addch(x, y, '+', curses.color_pair(9))
+ y += self.getBlock((min(j, self.h-1), i)).getW() + 1;
+ x += self.getBlock((j, self.w-1)).getH() + 1;
+
+ pad.addstr(self.scoreRep())
+ self.player.render(pad)
+ pad.refresh()
+
+ def scoreRep(self):
+ return "Moves: %3d\nDist: %4d\nSwaps: %3d" % (
+ self.cmove, self.cdist, self.cswap )
+
+ def getH(self):
+ return self.h
+
+ def getW(self):
+ return self.w
+
+ def getBlock(self, p):
+ x = p[0]
+ y = p[1]
+ if (x < 0 or y < 0 or x >= self.getH() or y >= self.getW()):
+ return BlockSentry(self, 0, 0, (0,0))
+ else:
+ return self.map[x][y]
+
+ def move(self, p):
+ p2 = (-p[0], -p[1])
+ tx = p2[0]+self.holeX
+ ty = p2[1]+self.holeY
+ t = self.getBlock((tx, ty))
+ if (type(t) != BlockSentry):
+ self.map[tx][ty] = self.map[self.holeX][self.holeY]
+ self.map[self.holeX][self.holeY] = t
+ t.move(p)
+ self.map[tx][ty].move(p2)
+ self.holeX = tx
+ self.holeY = ty
+ self.addSwap()
+ return self.player.fall()
+
+if (len(sys.argv) != 2):
+ print("Usage: %s LEVEL" % sys.argv[0])
+ sys.exit(1)
+
+try:
+ f = open(sys.argv[1])
+except IOError as e:
+ print("Cannot access %s: %s" % (sys.argv[1], e.strerror))
+ sys.exit(1)
+
+
+
+stdscr = curses.initscr()
+curses.noecho()
+
+h = int(f.readline())
+w = int(f.readline())
+x = int(f.readline())
+y = int(f.readline())
+l = Level(h, w, x, y)
+l.loadFromFile(f)
+
+pad = curses.newwin(h*(l.getBlock((0,0)).getH()+1)+4,
+ w*(l.getBlock((0,0)).getW()+1)+1)
+
+curses.start_color()
+curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
+curses.init_pair(2, curses.COLOR_RED, curses.COLOR_YELLOW)
+curses.init_pair(3, curses.COLOR_GREEN, curses.COLOR_BLACK)
+curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_BLUE)
+curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_RED)
+curses.init_pair(6, curses.COLOR_RED, curses.COLOR_BLUE)
+curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_BLACK)
+curses.init_pair(8, curses.COLOR_YELLOW, curses.COLOR_BLACK)
+curses.init_pair(9, curses.COLOR_MAGENTA, curses.COLOR_MAGENTA)
+
+exit = False
+won = False
+
+stdscr.refresh()
+
+while (not exit):
+ l.render(pad)
+ try: input = Level.codeMap[stdscr.getch()]
+ except KeyError:
+ input = ''
+ pass
+ if (input == 'q'):
+ exit = True
+ elif (input == input.upper()):
+ try: won = l.move({v:k for k, v in Player.keyMap.items()}[input.lower()])
+ except KeyError: pass
+ else:
+ try: won = l.getPlayer().move({v:k for k, v in
+ Player.keyMap.items()}[input], 1)
+ except KeyError: pass
+ exit = exit or won
+
+curses.nocbreak(); stdscr.keypad(0); curses.echo()
+
+curses.endwin()
+
+if (won):
+ print ("Congratulations, you won!\n")
+ print ("Your score was:")
+ print (l.scoreRep())
+else: print ("Bye.")
+
diff --git a/level b/level
@@ -1,27 +0,0 @@
-2
-2
-0
-1
-5
-5
-##### Level syntax tips
-#@ # First line is number of block lines
-###% Second line is number of block cols
-#* % Third line is line position of empty block
-##### Fourth line is col position of empty block
- Fifth line is width of blocks
- Sixth line is height of blocks
- Following lines are description of blocks one after the other
- Blocks will be assigned left to right and then top to bottom
- (ie. give the blocks for the first line, then second line, etc.)
-##### If there are too many characters on a line, they get ignored
-# %% You can use this to write comments (like these)
- % # The following sprites are allowed:
- %# # - ' ' is empty space (player falls thru, can walk thru)
-##### - '#' is a wall (player can walk over, can't pass thru)
-##### - '%' is a ladder (player can walk over, can climb over)
- ^# - '*' is a key (collect all to open the exit
-#%### - '^' is an exit (reach any with all keys to win)
-#% *# - '@' is the player's start position (only one allowed, will be empty space when player leaves it)
-##### PS: you must give a block description for the empty block, it
- will be ignored
diff --git a/level1 b/level1
@@ -0,0 +1,27 @@
+2
+2
+0
+1
+5
+5
+##### Level syntax tips
+#@ # First line is number of block lines
+###% Second line is number of block cols
+#* % Third line is line position of empty block
+##### Fourth line is col position of empty block
+ Fifth line is width of blocks
+ Sixth line is height of blocks
+ Following lines are description of blocks one after the other
+ Blocks will be assigned left to right and then top to bottom
+ (ie. give the blocks for the first line, then second line, etc.)
+##### If there are too many characters on a line, they get ignored
+# %% You can use this to write comments (like these)
+ % # The following sprites are allowed:
+ %# # - ' ' is empty space (player falls thru, can walk thru)
+##### - '#' is a wall (player can walk over, can't pass thru)
+##### - '%' is a ladder (player can walk over, can climb over)
+ ^# - '*' is a key (collect all to open the exit)
+#%### - '^' is an exit (reach any with all keys to win)
+#% *# - '@' is the player's start position (only one allowed, will be empty space when player leaves it)
+##### PS: you must give a block description for the empty block, it
+ will be ignored
diff --git a/level2 b/level2
@@ -1,134 +1,30 @@
-4
-4
-3
-3
-8
-8
- ##
- ##
- @ ## ^
- # ## #
- ##
- ##
- ##
- ## end
- ##
- #
- #####
-
-
-
-
- ## end
-
-
-
-
-### ###
-### ###
-
- end
- ##
- ##
- ##
- ##
- ## ##
- ## ##
- ##
- ## End
- ##
- ##
- *##
- ###
- ## #
- ##
- ##
- ## end
-
-
-
- %%%%##
-#
-#
-
- end
-
-
-
- ##%%%%
- #
- #
-
- end
- ##
- ##
- ##
- ##
-########
-########
-
- End
-
-
- % %
- # # ##
-
-
-
- end
- ##
-
-###
- #
- ######
- ######
-
- end
-
-
- % %
- # # ##
-
-
-
- end
- ##
- ##
- ##
- ##
-## ##
-## ##
- ##
- ## End
-
-
-
-
-######
-######
-
- end
- ##
- ##
- ##
- ##
- ## ##
- ## ##
- ##
- ## end
-
- *
- %##%
- %####%
- ######
-
-
- END
- BLANK
- BLANK
- BLANK
- BLANK
- BLANK
- BLANK
- BLANK
- BLANK
+2
+2
+0
+1
+6
+6
+######
+# @
+######
+#
+# ^
+######
+
+
+
+
+
+
+######
+
+######
+ ###
+
+######
+######
+ ##
+# ## #
+# ## #
+ ##
+######
diff --git a/level2.best b/level2.best
@@ -1,10 +0,0 @@
- Your score was:
- Moves: 14
- Dist: 62
- Swaps: 55
-
-
-Your score was:
- Moves: 20
- Dist: 52
- Swaps: 79
diff --git a/level3 b/level3
@@ -0,0 +1,26 @@
+2
+2
+1
+1
+5
+5
+#####
+# @#
+# ##
+# #
+### #
+### #
+# #
+# ###
+# #
+# # #
+# # #
+# ^ #
+ ####
+#
+#####
+
+
+
+
+
diff --git a/level4 b/level4
@@ -0,0 +1,42 @@
+2
+3
+1
+2
+6
+8
+## #####
+## @ #
+##### #
+##### #
+## #
+## #####
+### # ##
+ # # ##
+### # ##
+ # #
+ #### #
+## ## #
+## #####
+##
+########
+ #
+ #
+### # ##
+## ## #
+## #
+###### #
+## #
+## ^ #
+## #####
+########
+ ####
+### ####
+ #
+ #
+## #####
+
+
+
+
+
+
diff --git a/level5 b/level5
@@ -0,0 +1,26 @@
+2
+2
+1
+0
+5
+10
+
+
+
+
+ #
+
+
+ ^
+@
+#
+
+
+
+
+
+#
+
+
+
+
diff --git a/level6 b/level6
@@ -0,0 +1,134 @@
+4
+4
+3
+3
+8
+8
+ ##
+ ##
+ @ ## ^
+ # ## #
+ ##
+ ##
+ ##
+ ## end
+ ##
+ #
+ #####
+
+
+
+
+ ## end
+
+
+
+
+### ###
+### ###
+
+ end
+ ##
+ ##
+ ##
+ ##
+ ## ##
+ ## ##
+ ##
+ ## End
+ ##
+ ##
+ *##
+ ###
+ ## #
+ ##
+ ##
+ ## end
+
+
+
+ %%%%##
+#
+#
+
+ end
+
+
+
+ ##%%%%
+ #
+ #
+
+ end
+ ##
+ ##
+ ##
+ ##
+########
+########
+
+ End
+
+
+ % %
+ # # ##
+
+
+
+ end
+ ##
+
+###
+ #
+ ######
+ ######
+
+ end
+
+
+ % %
+ # # ##
+
+
+
+ end
+ ##
+ ##
+ ##
+ ##
+## ##
+## ##
+ ##
+ ## End
+
+
+
+
+######
+######
+
+ end
+ ##
+ ##
+ ##
+ ##
+ ## ##
+ ## ##
+ ##
+ ## end
+
+ *
+ %##%
+ %####%
+ ######
+
+
+ END
+ BLANK
+ BLANK
+ BLANK
+ BLANK
+ BLANK
+ BLANK
+ BLANK
+ BLANK
diff --git a/levelb b/levelb
@@ -1,30 +0,0 @@
-2
-2
-0
-1
-6
-6
-######
-# @
-######
-#
-# ^
-######
-
-
-
-
-
-
-######
-
-######
- ###
-
-######
-######
- ##
-# ## #
-# ## #
- ##
-######
diff --git a/levelc b/levelc
@@ -1,26 +0,0 @@
-2
-2
-1
-1
-5
-5
-#####
-# @#
-# ##
-# #
-### #
-### #
-# #
-# ###
-# #
-# # #
-# # #
-# ^ #
- ####
-#
-#####
-
-
-
-
-
diff --git a/leveld b/leveld
@@ -1,42 +0,0 @@
-2
-3
-1
-2
-6
-8
-## #####
-## @ #
-##### #
-##### #
-## #
-## #####
-### # ##
- # # ##
-### # ##
- # #
- #### #
-## ## #
-## #####
-##
-########
- #
- #
-### # ##
-## ## #
-## #
-###### #
-## #
-## ^ #
-## #####
-########
- ####
-### ####
- #
- #
-## #####
-
-
-
-
-
-
diff --git a/levele b/levele
@@ -1,26 +0,0 @@
-2
-2
-1
-0
-5
-10
-
-
-
-
- #
-
-
- ^
-@
-#
-
-
-
-
-
-#
-
-
-
-
diff --git a/main.py b/main.py
@@ -1,423 +0,0 @@
-#/usr/bin/python
-
-
-import sys
-import curses
-
-
-class Square:
- wall, ladder, empty, exit, player, blank, key = range(7)
- asciiMap = {wall: '#', ladder:'%', empty:' ', exit:'^', player:'@', blank:'!', key:'*'}
-
- def __init__(self, parent, type, pos):
- self.parent = parent
- self.type = type
- self.pos = pos
-
- def getNeighbour(self, dir):
- return self.parent.getSquare((self.pos[0] + dir[0], self.pos[1] + dir[1]))
-
- def getType(self):
- return self.type
-
- def setType(self, type):
- self.type = type
-
- def render(self, pad, x, y):
- if (self.parent.parent.getPlayer().getPos() == self):
- self.parent.parent.getPlayer().setGraphPos((x + self.pos[0],y + self.pos[1]))
- c = '@'
- mode = curses.A_BOLD + curses.A_BLINK + curses.color_pair(1)
- else:
- if (self.parent.parent.getPlayer().getPos().getParent() == self.parent):
- mode = curses.A_BOLD
- else:
- mode = 0
- c = Square.asciiMap[self.type]
- if (c == '^'):
- if (self.parent.parent.keysLeft() == True):
- mode = curses.A_BOLD + curses.color_pair(8)
- else:
- mode = curses.A_BOLD + curses.color_pair(2)
- if (c == '%'): mode = curses.color_pair(3)
- if (c == '#'): mode = curses.color_pair(4)
- if (c == '!'):
- mode = curses.color_pair(5)
- pad.addch( x + self.pos[0],y + self.pos[1], c, mode)
- c = ' '
- if (c == '*'): mode = curses.A_BOLD + curses.color_pair(2)
- try:
- pad.addch( x + self.pos[0],y + self.pos[1], c, mode)
- except curses.error:
- pass
-
- def getParent(self):
- return self.parent
-
-
-class Block:
- left, right, top, bottom = range(4)
- def __init__(self, parent, h, w, pos):
- self.parent = parent
- self.h = h
- self.w = w
- self.pos = pos
- self.map = []
- for i in range(0, h):
- self.map.append([])
- for j in range(0, w):
- self.map[i].append(Square(self, 0, (0, 0)))
-
- def getBorder(self, t):
- a = []
- if (t == Block.left):
- for i in range(0, self.h):
- a.append(self.getSquare((i,0)).getType())
- if (t == Block.right):
- for i in range(0, self.h):
- a.append(self.getSquare((i, self.w-1)).getType())
- if (t == Block.top):
- for i in range(0, self.w):
- a.append(self.getSquare((0, i)).getType())
- if (t == Block.bottom):
- for i in range(0, self.w):
- a.append(self.getSquare((self.h-1, i)).getType())
- return a
-
- def getNeighbour(self, dir):
- return self.parent.getBlock((self.pos[0] + dir[0], self.pos[1] + dir[1]))
-
- def setSquare(self, x, y, s):
- self.map[x][y] = s
-
- def getSquare(self, p):
- x = p[0]
- y = p[1]
- if (x < 0):
- a = self.getNeighbour((-1, 0))
- if (self.getBorder(Block.top) != a.getBorder(Block.bottom)):
- return BlockSentry(self.parent, 0, 0, (0, 0)).getSquare((0,0))
- return a.getSquare((a.getH() + p[0], p[1]))
- elif (y < 0):
- a = self.getNeighbour((0, -1))
- if (self.getBorder(Block.left) != a.getBorder(Block.right)):
- return BlockSentry(self.parent, 0, 0, (0, 0)).getSquare((0,0))
- return a.getSquare((p[0], a.getW() + p[1]))
- elif (x >= self.getH()):
- a = self.getNeighbour((1, 0))
- if (self.getBorder(Block.bottom) != a.getBorder(Block.top)):
- return BlockSentry(self.parent, 0, 0, (0, 0)).getSquare((0,0))
- return a.getSquare((p[0] - self.getH(), p[1]))
- elif (y >= self.getW()):
- a = self.getNeighbour((0, 1))
- if (self.getBorder(Block.right) != a.getBorder(Block.left)):
- return BlockSentry(self.parent, 0, 0, (0, 0)).getSquare((0,0))
- return a.getSquare((p[0], p[1] - self.getW()))
- else:
- return self.map[x][y]
-
- def getW(self):
- return self.w
-
- def getH(self):
- return self.h
-
- def render(self, pad, x, y):
- for i in self.map:
- for j in i:
- j.render(pad, x, y)
-
- def loadFromFile(self, f):
- for i in range(0, self.getH()):
- l = f.readline()
- for j in range(0, self.getW()):
- x = l[j]
- c = {v:k for k, v in Square.asciiMap.items()}[x]
- if (x == '*'):
- self.parent.addKey()
- if (x == '@'):
- c = Square.empty
- self.map[i][j] = Square(self, c, (i, j))
- if (x == '@'):
- self.parent.getPlayer().setPos(self.map[i][j])
-
-
- def move(self, p):
- self.pos = (self.pos[0] + p[0], self.pos[1] + p[1])
-
-
-
-class BlockSentry(Block):
- def getSquare(self, p):
- return Square(self, Square.blank, (0,0))
-
- def render(self, pad, x, y):
- for i in range(0, self.h):
- for j in range(0, self.w):
- (Square(self, Square.blank, (i,j))).render(pad, x, y)
-
-class Player:
- keyMap = {(0, -1): 'h', (1, 0):'j', (-1, 0):'k', (0, 1): 'l'}
-
- def __init__(self, parent, square):
- self.parent = parent
- self.pos = square
- self.graphPos = (0,0)
-
- def render(self, pad):
- pad.move(self.graphPos[0], self.graphPos[1])
-
- def setGraphPos(self, p):
- self.graphPos = p
-
- def move(self, direction, volont):
- a = self.pos.getNeighbour(direction)
- if (a.getType() != Square.wall and a.getType() != Square.blank):
- self.pos = a
- self.parent.addDist()
- if (volont == True): self.parent.addMoves()
- if (self.pos.getType() == Square.key):
- self.parent.removeKey()
- self.pos.setType(Square.empty)
- if (self.pos.getType() == Square.exit and not self.parent.keysLeft()):
- return True
- else:
- return self.fall()
-
- def getPos(self):
- return self.pos
-
- def setPos(self, pos):
- self.pos = pos
-
- def fall(self):
- a = self.pos.getType()
- b = self.pos.getNeighbour((1,0)).getType()
- while (self.pos.getType() != Square.ladder and (self.pos.getNeighbour((1,0)).getType() == Square.empty or self.pos.getNeighbour((1,0)).getType() == Square.key or self.pos.getNeighbour((1,0)).getType() == Square.exit)):
- if self.move((1, 0), 0):
- return True
- return False
-
-
-class Level:
- codeMap = {104: 'h', 106:'j', 107:'k', 108: 'l', 113: 'q', 72: 'H', 74:'J', 75: 'K', 76:'L'}
- def __init__(self, h, w, x, y):
- self.h = h
- self.w = w
- self.holeX = x
- self.holeY = y
- self.map = []
- self.keys = 0
- self.cswap = 0
- self.cmove = 0
- self.cdist = 0
- for i in range(0, h):
- self.map.append([])
- for j in range(0, w):
- self.map[i].append(Block(0, 0, 0, 0))
- self.player = Player(self, Square(0, 0, (0,0)))
-
- def loadFromFile(self, f):
- bh = int(f.readline())
- bw = int(f.readline())
- for i in range(0, self.h):
- for j in range(0, self.w):
- if ((i, j) != (self.holeX, self.holeY)):
- self.map[i][j] = Block(self, bh, bw, (i, j))
- else:
- self.map[i][j] = BlockSentry(self, bh, bw, (i, j))
- self.map[i][j].loadFromFile(f)
-
- def addKey(self):
- self.keys+=1
-
- def addDist(self):
- self.cdist += 1
-
- def addMoves(self):
- self.cmove += 1
-
- def addSwap(self):
- self.cswap += 1
-
- def removeKey(self):
- self.keys-=1
-
- def keysLeft(self):
- return self.keys != 0
-
- def getPlayer(self):
- return self.player
-
- def render(self, pad):
- m = 0
- for i in range(0, self.w):
- m = m + self.map[0][i].getW() + 1
- for i in range(0, m+1):
- pad.addch( 0 ,i, '\'', curses.color_pair(5))
- pad.addch( 0 ,i, ' ', curses.color_pair(5))
- x = 0
- for j in range(0, self.h):
- y = 0
- for i in range(0, self.map[0][j].getH()+1):
- pad.addch( j*(self.map[0][j].getH()+1)+1 +i ,0, ' ', curses.color_pair(5))
- for i in range(0, self.w):
- a = self.map[j][i]
- a.render(pad, j*a.getH()+1+j, i*a.getW()+1+i)
- l = a.getBorder(Block.bottom)
- l2 = a.getNeighbour((1, 0)).getBorder(Block.top)
- if (l != l2):
- for k in range(0, a.getW()+1):
- if (l2 != [] and l != [] and l[k-1] != l2[k-1]):
- pad.addch( x+self.map[0][j].getH() +1,y+k, '?', curses.color_pair(5))
- else:
- pad.addch( x+self.map[0][j].getH() +1,y+k, '\'', curses.color_pair(5))
- pad.addch( x+self.map[0][j].getH() +1,y+k, ' ', curses.color_pair(5))
- else:
- for k in range(0, a.getW()):
- if (l[k] == Square.wall):
- pad.addch( x+self.map[0][j].getH()+1,y+k+1, '|', curses.color_pair(6))
- else:
- pad.addch( x+self.map[0][j].getH()+1,y+k+1, '\'', curses.color_pair(7))
- pad.addch( x+self.map[0][j].getH()+1,y+k+1, ' ', curses.color_pair(7))
- y = y + a.getW() + 1
- l = a.getBorder(Block.right)
- l2 = a.getNeighbour((0, 1)).getBorder(Block.left)
- if (l != l2):
- for k in range(0, a.getH()+1):
- if (l2 != [] and l != [] and l[k-1] != l2[k-1]):
- pad.addch( x+k ,y, '?', curses.color_pair(5))
- else:
- pad.addch( x+k ,y, '\'', curses.color_pair(5))
- pad.addch( x+k ,y, ' ', curses.color_pair(5))
- else:
- for k in range(0, a.getH()):
- if (l[k] == Square.wall):
- pad.addch( x+k+1 ,y, '-', curses.color_pair(6))
- else:
- pad.addch( x+k+1 ,y, '\'', curses.color_pair(7))
- pad.addch( x+k+1 ,y, ' ', curses.color_pair(7))
- for k in range(0, a.getH()+1):
- pad.addch( x+k ,y, '\'', curses.color_pair(5))
- pad.addch( x+k ,y, ' ', curses.color_pair(5))
- x = x + self.map[0][j].getH() + 1
- m = 0
- for i in range(0, self.h):
- m = m + self.map[i][0].getH() + 1
- for i in range(0, y+1):
- pad.addch( m ,i, '\'', curses.color_pair(5))
- pad.addch( m ,i, ' ', curses.color_pair(5))
- x = 0
- for j in range(0, self.h+1):
- y = 0
- for i in range(0, self.w+1):
- pad.addch(x, y, '+', curses.color_pair(9))
- y += self.getBlock((min(j, self.h-1), i)).getW() + 1;
- x += self.getBlock((j, self.w-1)).getH() + 1;
-
-
- pad.addstr( self.scoreRep())
- self.player.render(pad)
- pad.refresh()
-
- def scoreRep(self):
- return "Moves: %3d\nDist: %4d\nSwaps: %3d" %(self.cmove, self.cdist, self.cswap )
-
- def getH(self):
- return self.h
-
- def getW(self):
- return self.w
-
- def getBlock(self, p):
- x = p[0]
- y = p[1]
- if (x < 0 or y < 0 or x >= self.getH() or y >= self.getW()):
- return BlockSentry(self, 0, 0, (0,0))
- else:
- return self.map[x][y]
-
- def move(self, p):
- p2 = (-p[0], -p[1])
- tx = p2[0]+self.holeX
- ty = p2[1]+self.holeY
- t = self.getBlock((tx, ty))
- if (type(t) != BlockSentry):
- self.map[tx][ty] = self.map[self.holeX][self.holeY]
- self.map[self.holeX][self.holeY] = t
- t.move(p)
- self.map[tx][ty].move(p2)
- self.holeX = tx
- self.holeY = ty
- self.addSwap()
- return self.player.fall()
-
-
-
-
-
-
-
-
-
-
-
-stdscr = curses.initscr()
-curses.noecho()
-curses.cbreak()
-stdscr.keypad(1)
-
-
-f = open(sys.argv[1])
-h = int(f.readline())
-w = int(f.readline())
-x = int(f.readline())
-y = int(f.readline())
-l = Level(h, w, x, y)
-l.loadFromFile(f)
-
-pad = curses.newwin(h*(l.getBlock((0,0)).getH()+1)+4, w*(l.getBlock((0,0)).getW()+1)+1)
-
-curses.start_color()
-curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
-curses.init_pair(2, curses.COLOR_RED, curses.COLOR_YELLOW)
-curses.init_pair(3, curses.COLOR_GREEN, curses.COLOR_BLACK)
-curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_BLUE)
-curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_RED)
-curses.init_pair(6, curses.COLOR_RED, curses.COLOR_BLUE)
-curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_BLACK)
-curses.init_pair(8, curses.COLOR_YELLOW, curses.COLOR_BLACK)
-curses.init_pair(9, curses.COLOR_MAGENTA, curses.COLOR_MAGENTA)
-
-exit = False
-won = False
-
-stdscr.addstr ("Continuity\nGame\n\nNameless\ncurses\nclone\n\nPress\nany\nkey\n")
-
-while (not exit):
- l.render(pad)
- try: input = Level.codeMap[stdscr.getch()]
- except KeyError:
- input = ''
- pass
- if (input == 'q'):
- exit = True
- elif (input == input.upper()):
- try: won = l.move({v:k for k, v in Player.keyMap.items()}[input.lower()])
- except KeyError: pass
- else:
- try: won = l.getPlayer().move({v:k for k, v in Player.keyMap.items()}[input], 1)
- except KeyError: pass
- exit = exit or won
-
-curses.endwin()
-
-curses.nocbreak(); stdscr.keypad(0); curses.echo()
-
-
-if (won):
- print ("Congratulations, you won!\n")
- print ("Your score was:")
- print (l.scoreRep())
-else: print ("Bye.\n")
-