diff --git a/robotgame/level4.py b/robotgame/level4.py index 678fa60..1d7be3f 100644 --- a/robotgame/level4.py +++ b/robotgame/level4.py @@ -58,19 +58,30 @@ class Level4(level.Level): self.draw_background() - playfield = lm.generate_simple_playfield(16) + self.playfield = lm.generate_simple_playfield(16) - for (x, y), t in playfield.items(): - x, y = 64 * x, 48 * (y + 1) + for (x, y), t in self.playfield.items(): + x1, y1 = 64 * x, 48 * (y + 1) + def mir(b, x1, y1): + def f(x, y): + def g(setting): + self.playfield[(x, y)] = lm.MirrorLeft \ + if self.playfield[(x, y)] is lm.MirrorRight \ + else lm.MirrorRight + self.generate_lasers() + return g + return mirror.Mirror(self, x1, y1, b, links=[f(x, y)]) self.objects.append({ - lm.Mirror: mirror.Mirror(self, x, y, random.choice((True, False))), + lm.MirrorLeft: mir(True, x1, y1), + lm.MirrorRight: mir(False, x1, y1), lm.Lever: lever.Lever( - self, x, y, [lambda setting: self.generate_lasers], toggling=True, - anim='lever_leftright' if x == 0 or x == 15 * 64 + self, x1, y1, [lambda setting: self.generate_lasers], + toggling=True, + anim='lever_leftright' if x in (0, 15) else 'lever_updown'), - lm.Target: block.Block(self, x, y, self.imgs['block3'], + lm.Target: block.Block(self, x1, y1, self.imgs['block3'], movable=False), - lm.Blocker: block.Block(self, x, y, self.imgs['block1'], + lm.Blocker: block.Block(self, x1, y1, self.imgs['block1'], movable=False) }[t]) mirrors = list(filter(lambda obj: isinstance(obj, mirror.Mirror), @@ -94,26 +105,33 @@ class Level4(level.Level): obj.reset_pos() def generate_lasers(self): + lml = lm.generate_lasers(self.playfield) self.lasers = [] - + for (x0, y0), (x1, y1) in lml: + self.lasers.append(((x0 * 64 + 32, y0 * 48 + 32), + (x1 * 64 + 32, y1 * 48 + 32))) def draw_lasers(self, window): - for p0, p1 in self.lasers: - pygame.draw.line(p0, p1, (255, 0, 0)) + for (x0, y0), (x1, y1) in self.lasers: + pygame.draw.line(window, (255, 0, 0), + (x0 - self.camera_x, y0 - 28 - self.camera_y), + (x1 - self.camera_x, y1 - 28 - self.camera_y), 4) def draw(self, window): self._blit_background(window) objs = self._sorted_objs() - nonmirrors = filter(lambda obj: not isinstance(obj, mirror.Mirror), - objs) - mirrors = filter(lambda obj: isinstance(obj, mirror.Mirror), objs) - for obj in nonmirrors: + for obj in objs: obj.draw(window) + # nonmirrors = filter(lambda obj: not isinstance(obj, mirror.Mirror), + # objs) + # mirrors = filter(lambda obj: isinstance(obj, mirror.Mirror), objs) + # for obj in nonmirrors: + # obj.draw(window) self.draw_lasers(window) - for obj in mirrors: - obj.draw(window) + # for obj in mirrors: + # obj.draw(window) self.darkness.draw(window) diff --git a/robotgame/logic/lasermirror.py b/robotgame/logic/lasermirror.py index 3371b97..d1f744d 100644 --- a/robotgame/logic/lasermirror.py +++ b/robotgame/logic/lasermirror.py @@ -19,8 +19,8 @@ # # lasermirror.py # -------------------- -# date created : Tue Aug 7 2016 -# copyright : (C) 2016 Niels G. W. Serup +# date created : Tue Aug 7 2012 +# copyright : (C) 2012 Niels G. W. Serup # maintained by : Niels G. W. Serup """ @@ -36,7 +36,10 @@ import robotgame.logic.rollingstone as rstone from robotgame.logic.rollingstone import Blocker import robotgame.misc as misc -class Mirror(object): +class MirrorLeft(object): + pass + +class MirrorRight(object): pass class Lever(object): @@ -58,7 +61,8 @@ def generate_simple_playfield(nmirrors): * there are nmirrors levers * all levers are at the wall - Return playfield : {(x, y): Target | Mirror | rstone.Blocker | Lever} + Return playfield : {(x, y): + Target | MirrorLeft | MirrorRight | rstone.Blocker | Lever} """ playfield = {(6, 6): Target, (9, 6): Target, @@ -69,6 +73,8 @@ def generate_simple_playfield(nmirrors): (8, 7): rstone.Blocker, (8, 8): rstone.Blocker, } + width, height = 16, 16 + succs = lambda d: d source_direc = Up nlevers = nmirrors @@ -78,22 +84,54 @@ def generate_simple_playfield(nmirrors): stone_playfield, _ = rstone.generate_simple_playfield( 7, 7, nm, 0, False, False) for pos, direc in stone_playfield.items(): - playfield[_adjust(source_direc, 16 - 1, 16 - 1, *pos)] = Mirror + playfield[_adjust(source_direc, 16 - 1, 16 - 1, *pos)] \ + = random.choice((MirrorLeft, MirrorRight)) succs = (lambda s: lambda d: succ(s(d)))(succs) source_direc = succ(source_direc) + occup = set(playfield.keys()) + + is_empty = lambda x, y: (x, y) not in occup + + ok_a = lambda y: is_empty(1, y) + ok_b = lambda y: is_empty(width - 2, y) + ok_c = lambda x: is_empty(x, 1) + ok_d = lambda x: is_empty(x, height - 2) + no_block = lambda x, y: \ + all((ok_a(y) if x == 0 else True, + ok_b(y) if x == width - 1 else True, + ok_c(x) if y == 0 else True, + ok_d(x) if y == height - 1 else True)) + + emptys = set([(0, y) for y in filter(ok_a, range(height))] + + [(width - 1, y) for y in filter(ok_b, range(height))] + + [(x, 0) for x in filter(ok_c, range(width))] + + [(x, height - 1) for x in filter(ok_d, range(width))]) - occup + emptys_full = set(itertools.product(range(width), range(height))) - occup + + emptys = list(emptys) + random.shuffle(emptys) + emptys = set(emptys) + + is_empty = lambda x, y: (x, y) in emptys_full + + levers = [] for _ in range(nlevers): - # This needs to be optimized... - occup = set(playfield.keys()) - emptys = list( - set([(0, y) for y in filter(lambda y: (1, y) not in occup, range(16))] - + [(15, y) for y in filter(lambda y: (10, y) not in occup, range(16))] - + [(x, 0) for x in filter(lambda x: (x, 1) not in occup, range(16))] - + [(x, 15) for x in filter(lambda x: (x, 10) not in occup, range(16))]) - occup) - pos = emptys[random.randrange(len(emptys))] - playfield[pos] = Lever + while True: + pos = next(iter(emptys)) + emptys.remove(pos) + emptys_full.remove(pos) + if no_block(*pos): + playfield[pos] = Lever + if not all(no_block(*pos) for pos in levers): + del playfield[pos] + else: + levers.append(pos) + break + return playfield + def _adjust(source_direc, w, h, x, y): return { Up: lambda x, y: (x, y), @@ -101,7 +139,45 @@ def _adjust(source_direc, w, h, x, y): Down: lambda x, y: (w - x, h - y), Left: lambda x, y: (y, h - x), }[source_direc](x, y) - + +def generate_lasers(playfield): + width, height = 16, 16 + sources = (((0, -1), Down), + ((width, 0), Left), + ((width - 1, height), Up), + ((-1, height - 1), Right)) + lasers = [] + for start, direc in sources: + end = start + while True: + cur = playfield.get(end) + if cur is Target: + lasers.append((start, end)) + break + if cur is Blocker: + lasers.append((start, end)) + break + if cur in (MirrorLeft, MirrorRight): + if (start, end) in lasers: + break + lasers.append((start, end)) + direc = _mirror_new_direc(cur, direc) + start = end + new_end = direc.next_pos(end) + if new_end[0] < 0 or new_end[1] < 0 or new_end[0] >= width or new_end[1] >= height: + if (start, end) not in lasers: + lasers.append((start, new_end)) + break + end = new_end + return lasers + +def _mirror_new_direc(mirror_type, old_direc): + return {Down: (Left, Right), + Left: (Down, Up), + Up: (Right, Left), + Right: (Up, Down)}[old_direc][ + 0 if mirror_type is MirrorLeft else 1] + def print_playfield(playfield, width, height, hide_directions=False): text = [['ยท' for _ in range(width)] for _ in range(height)] for (x, y), val in playfield.items(): diff --git a/robotgame/mirror.py b/robotgame/mirror.py index 0c9a9e3..40ecce1 100644 --- a/robotgame/mirror.py +++ b/robotgame/mirror.py @@ -29,7 +29,7 @@ import pygame import worldobject class Mirror(worldobject.WorldObject): - def __init__(self, level, x, y, left_up=True): + def __init__(self, level, x, y, left_up=True, links=[]): self.__dict__.update(locals()) worldobject.WorldObject.__init__(self, level, x, y) @@ -54,6 +54,8 @@ class Mirror(worldobject.WorldObject): if self.frame == top: self.in_rotation = False self.left_up = not self.left_up + for link in self.links: + link(self.left_up) worldobject.WorldObject.update(self, e, t, dt)