Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

with rotation

  • Loading branch information...
commit 0330a0a2eaa0dfc8c19cf9fe3648deb1978f1973 1 parent 74c2411
@gareth-lloyd authored
Showing with 168 additions and 64 deletions.
  1. +2 −0  .gitignore
  2. +24 −64 carcas.py
  3. +89 −0 constants.py
  4. +53 −0 utils.py
View
2  .gitignore
@@ -0,0 +1,2 @@
+*.pyc
+*.swp
View
88 carcas.py
@@ -2,32 +2,11 @@
import random
from collections import OrderedDict
-FIELD = 0
-ROAD = 1
+from utils import Display
+from constants import N, E, S, W, TILES, RotatableTile, TYPES
-N = (0, 1)
-E = (1, 0)
-S = (0, -1)
-W = (-1, 0)
OPPOSITES = {N: S, E: W, S: N, W: E}
-TILES = {
- (1, 0, 1, 1) : u'',
- (1, 1, 0, 1) : u'',
-# (1, 0, 0, 0) : u'╵',
- (0, 1, 1, 0) : u'',
- (1, 0, 1, 0) : u'',
-# (0, 0, 0, 1) : u'╴',
- (0, 0, 1, 1) : u'',
- (1, 0, 0, 1) : u'',
-# (0, 1, 0, 0) : u'╶',
- (1, 1, 1, 1) : u'',
- (0, 0, 0, 0) : u'\u25A2',
-# (0, 0, 1, 0) : u'╷',
- (0, 1, 0, 1) : u'',
- (1, 1, 1, 0) : u'',
- (0, 1, 1, 1) : u'',
- (1, 1, 0, 0) : u'',
-}
+alter_position = lambda pos, drctn: (pos[0] + drctn[0], pos[1] + drctn[1])
class Tile(object):
def __init__(self, north, east, south, west):
@@ -39,65 +18,46 @@ def edge(self, direction):
def __unicode__(self):
return TILES[(tuple(self.edges.values()))]
-def random_tile():
- if random.random() > .5:
- return Tile(0, 0, 0, 0)
- return Tile(*random.choice(TILES.keys()))
-
-def alter_position(position, delta):
- return (position[0] + delta[0], position[1] + delta[1])
-
class Surface(object):
def __init__(self):
self.tiles = {}
def grow_randomly(self):
- new_tile = random_tile()
+ new_tile = RotatableTile(random.choice(TYPES))
if not self.tiles:
self.place(new_tile, (0, 0))
return
- for position, tile in self.tiles.iteritems():
- for delta in (N, E, S, W):
- desired = alter_position(position, delta)
- try:
- self.place(new_tile, desired)
- return
- except ValueError:
- pass
+ for position, tile in self.tiles.items():
+ for direction in (N, E, S, W):
+ for _ in range(4):
+ try:
+ desired = alter_position(position, direction)
+ self.place(new_tile, desired)
+ return
+ except AssertionError:
+ new_tile.rotate()
def place(self, new_tile, desired_position):
- if desired_position in self.tiles:
- raise ValueError("Can't place here")
+ assert desired_position not in self.tiles
for direction in (N, E, S, W):
- test_position = alter_position(desired_position, direction)
- if test_position in self.tiles:
- existing_tile = self.tiles[test_position]
- else:
+ try:
+ existing_tile = self.tiles[alter_position(desired_position, direction)]
+ except KeyError:
continue
- if new_tile.edge(direction) == existing_tile.edge(OPPOSITES[direction]):
- continue
+ assert new_tile.edge(direction) == existing_tile.edge(OPPOSITES[direction])
- raise ValueError("Can't place here")
self.tiles[desired_position] = new_tile
-if __name__ == '__main__':
- import locale, sys, curses, time
- locale.setlocale(locale.LC_ALL, '')
- encoding = locale.getpreferredencoding()
+if __name__ == '__main__':
surface = Surface()
- try:
- window = curses.initscr()
+ with Display() as display:
while True:
- window.clear()
- display = filter(lambda pt: pt[0][0] + 20 >= 0 and (-1 * pt[0][1]) + 20 >= 0, surface.tiles.iteritems())
- for position, tile in display:
- window.addstr((-1 * position[1]) + 20, position[0] + 20, unicode(tile).encode(encoding))
- window.refresh()
- time.sleep(.05)
+ for position, tile in surface.tiles.iteritems():
+ display.place_char(unicode(tile), position[0], position[1])
+ display.refresh(sleep_time=.05)
surface.grow_randomly()
- finally:
- curses.endwin()
+
View
89 constants.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+FIELD = 0
+ROAD = 1
+
+# Directions defined as positive or negative movements in the
+# x- and y-axis, respectively
+N = (0, 1)
+E = (1, 0)
+S = (0, -1)
+W = (-1, 0)
+
+TYPES = ('cloisters', 'straight', 'bend', 't-junction')
+
+# These are some useful unicode characters, organized according to
+# a rudimentary coding system which you can use or improve.
+TILES = {
+# N E S W
+ (FIELD, FIELD, FIELD, FIELD) : u'.', # cloisters
+
+ ( ROAD, FIELD, ROAD, FIELD) : u'', # straight
+ (FIELD, ROAD, FIELD, ROAD) : u'',
+
+ ( ROAD, ROAD, FIELD, FIELD) : u'', # bend
+ ( ROAD, FIELD, FIELD, ROAD) : u'',
+ (FIELD, FIELD, ROAD, ROAD) : u'',
+ (FIELD, ROAD, ROAD, FIELD) : u'',
+
+ ( ROAD, ROAD, ROAD, FIELD) : u'', # t
+ ( ROAD, ROAD, FIELD, ROAD) : u'',
+ ( ROAD, FIELD, ROAD, ROAD) : u'',
+ (FIELD, ROAD, ROAD, ROAD) : u'',
+}
+
+ORIENTATIONS = {
+ N: 0,
+ 0: N,
+ E: 1,
+ 1: E,
+ S: 2,
+ 2: S,
+ W: 3,
+ 3: W,
+}
+
+
+TILE_ORIENTATIONS = {
+ 'bend' : {
+ 0: ( ROAD, ROAD, FIELD, FIELD),
+ 1: ( ROAD, FIELD, FIELD, ROAD),
+ 2: (FIELD, FIELD, ROAD, ROAD),
+ 3: (FIELD, ROAD, ROAD, FIELD),
+ },
+ 'cloisters' : {
+ 0: (FIELD, FIELD, FIELD, FIELD),
+ 1: (FIELD, FIELD, FIELD, FIELD),
+ 2: (FIELD, FIELD, FIELD, FIELD),
+ 3: (FIELD, FIELD, FIELD, FIELD),
+ },
+ 'straight' : {
+ 0: ( ROAD, FIELD, ROAD, FIELD),
+ 1: (FIELD, ROAD, FIELD, ROAD),
+ 2: ( ROAD, FIELD, ROAD, FIELD),
+ 3: (FIELD, ROAD, FIELD, ROAD),
+ },
+ 't-junction' : {
+ 0: ( ROAD, ROAD, ROAD, FIELD),
+ 1: ( ROAD, ROAD, FIELD, ROAD),
+ 2: ( ROAD, FIELD, ROAD, ROAD),
+ 3: (FIELD, ROAD, ROAD, ROAD),
+ },
+}
+
+class RotatableTile(object):
+ def __init__(self, _type):
+ self._type = _type
+ self.orientation = 0
+
+ def rotate(self):
+ self.orientation += 1
+ self.orientation %= 4
+
+ def edge(self, direction):
+ topography = TILE_ORIENTATIONS[self._type][self.orientation]
+ edge_index = ORIENTATIONS[direction]
+ return topography[edge_index]
+
+ def __unicode__(self):
+ topography = TILE_ORIENTATIONS[self._type][self.orientation]
+ return TILES[topography]
View
53 utils.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+import locale, curses, time
+
+class Display(object):
+ def __enter__(self):
+ locale.setlocale(locale.LC_ALL, '')
+ self.encoding = locale.getpreferredencoding()
+
+ self.window = curses.initscr()
+ self.height, self.width = self.window.getmaxyx()
+ self.center_x, self.center_y = self.width / 2, self.height / 2
+ return self
+
+ def __exit__(self, type, value, traceback):
+ curses.endwin()
+
+ def place_char(self, ch, x, y):
+ """Call this method for each character that you want to place within
+ a particular frame.
+
+ ch must be an 8-bit or unicode string of length 1
+
+ The x/y space is a grid with 0, 0 at the centre of the screen. The x
+ and y args can be arbitrarily large positive or negative numbers: only
+ points within the window will be drawn.
+ """
+ # the window's vertical axis grows from top to bottom
+ y *= -1
+ y += self.center_y
+ x += self.center_x
+
+ if 0 < x < self.width and 0 < y < self.height:
+ self.window.addstr(y, x, ch.encode(self.encoding))
+
+ def refresh(self, sleep_time=0.1):
+ self.window.refresh()
+ time.sleep(sleep_time)
+ self.window.clear()
+
+
+if __name__ == '__main__':
+ """Dumb code to demonstrate use of a Display object.
+ """
+ from constants import PERMUTED_TILES
+ import random
+ with Display() as display:
+ while True:
+ tile = random.choice(PERMUTED_TILES.values())
+ x, y = random.randint(-40, 40), random.randint(-40, 40)
+ display.place_char(unicode(tile), x, y)
+
+ display.refresh()
+
Please sign in to comment.
Something went wrong with that request. Please try again.