git @ Cat's Eye Technologies ALPACA / master src / alpaca / playfield.py
master

Tree @master (Download .tar.gz)

playfield.py @masterraw · history · blame

class Playfield(object):
    def __init__(self, default, map):
        self.store = {}
        self.default = default
        self.recalculate_limits()
        self.repr_to_state = map
        self.state_to_repr = dict([(v, k) for (k, v) in map.items()])

    def items(self):
        y = self.min_y
        while y <= self.max_y:
            x = self.min_x
            while x <= self.max_x:
                c = self.get(x, y)
                if c != self.default:
                    yield (x, y, c)
                x += 1
            y += 1
        raise StopIteration

    def copy(self, pf):
        y = pf.min_y
        while y <= pf.max_y:
            x = pf.min_x
            while x <= pf.max_x:
                self.set(x, y, pf.get(x, y))
                x += 1
            y += 1
        self.recalculate_limits()

    def equals(self, pf):
        if (self.min_y != pf.min_y or
            self.max_y != pf.max_y or
            self.min_x != pf.min_x or
            self.max_x != pf.max_x):
            return False
        y = pf.min_y
        while y <= pf.max_y:
            x = pf.min_x
            while x <= pf.max_x:
                if self.get(x, y) != pf.get(x, y):
                    return False
                x += 1
            y += 1
        return True

    def load(self, f):
        y = 0
        for line in f:
            x = 0
            for c in line.rstrip('\r\n'):
                self.set(x, y, self.repr_to_state[c])
                x += 1
            y += 1
        self.recalculate_limits()

    def recalculate_limits(self):
        self.min_x = None
        self.min_y = None
        self.max_x = None
        self.max_y = None
        if len(self.store) == 0:
            return
        for (x, y) in self.store:
            if self.store[(x, y)] == self.default:
                continue
            if self.min_x is None or self.min_x > x:
                self.min_x = x
            if self.max_x is None or self.max_x < x:
                self.max_x = x
            if self.min_y is None or self.min_y > y:
                self.min_y = y
            if self.max_y is None or self.max_y < y:
                self.max_y = y
        #print "(%s,%s)-(%s,%s)" % (self.min_x, self.min_y, self.max_x, self.max_y)
          
    def set(self, x, y, value):
        """Does not recalculate limits."""
        if value == self.default:
            if (x, y) in self.store:
                del self.store[(x, y)]
        else:
            self.store[(x, y)] = value

    def get(self, x, y):
        return self.store.get((x, y), self.default)

    def represent(self, name):
        return self.state_to_repr[name]

    def to_str(self, min_x, min_y, max_x, max_y):
        s = ''
        y = min_y
        if y is None:
            return ''
        while y <= max_y:
            x = min_x
            while x <= max_x:
                s += self.represent(self.get(x, y))
                x += 1
            y += 1
            s += '\n'
        return s

    def __str__(self):
        return self.to_str(self.min_x, self.min_y, self.max_x, self.max_y)

    def to_svg(self, min_x, min_y, max_x, max_y, stylesheet=None):
        if stylesheet is None:
            stylesheet = 'rect { fill: white } .{} { fill: black }'.format(self.default)
        rects = []
        y = min_y
        while y is not None and y <= max_y:
            x = min_x
            while x <= max_x:
                state = self.get(x, y)
                rects.append(
                    '<rect class="{}" x="{}" y="{}" width="1" height="1" />'.format(state, x, y)
                )
                x += 1
            y += 1
        return """\
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewBox="{} {} {} {}" version="1.1">
  <style type="text/css">
    {}
  </style>
  {}
</svg>""".format(min_x, min_y, max_x-min_x, max_y-min_y, stylesheet, '\n  '.join(rects))