From b61f54963d83ad6be59f02607a3962c2ce5202f5 Mon Sep 17 00:00:00 2001 From: Niels Serup Date: Sat, 11 Aug 2012 02:22:29 +0200 Subject: [PATCH] Added preliminary level 4. No lasers yet. --- README.txt | 7 +++ robotgame/level4.py | 94 +++++++++++++++++++++++++++++++++ robotgame/loader.py | 4 +- robotgame/logic/lasermirror.py | 53 +++++++++---------- robotgame/logic/rollingstone.py | 2 +- robotgame/mirror.py | 63 ++++++++++++++++++++++ robotgame/misc.py | 4 ++ tests/lasermirror_tests.py | 2 +- 8 files changed, 199 insertions(+), 30 deletions(-) create mode 100644 robotgame/level4.py create mode 100644 robotgame/mirror.py diff --git a/README.txt b/README.txt index 94fc798..652eef4 100644 --- a/README.txt +++ b/README.txt @@ -1 +1,8 @@ This is a good game. + + +The rolling boulder task in level 1 is not guaranteed to be solvable, because +you might not be able to move an arrow block to the position you need to move +it to. However, this scenario is so unlikely that we have chosen to ignore it. + + diff --git a/robotgame/level4.py b/robotgame/level4.py new file mode 100644 index 0000000..741eb67 --- /dev/null +++ b/robotgame/level4.py @@ -0,0 +1,94 @@ +# This file is part of ROBOTGAME +# +# ROBOTGAME is free software: you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# ROBOTGAME is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# ROBOTGAME. If not, see . +# +# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' +# +# level1.py +# -------------------- +# date created : Fri Aug 10 2012 +# copyright : (C) 2012 Niels G. W. Serup +# maintained by : Niels G. W. Serup + +""" +The fourth level. +""" + +import os +import pygame +import random +import re +import itertools + +import level +import player +import tile +import block +import boulder +import lever +import mirror +import trigger +import misc +import worldobject + +import logic.lasermirror as lm + +class Level4(level.Level): + def __init__(self, game, graphics_dir, paused=False): + level.Level.__init__(self, game, graphics_dir, + size=(64 * 16, 48 * 16), paused=paused) + + self.dimensions = 16, 16 + + for i in range(self.dimensions[0]): + for j in range(self.dimensions[1]): + self.tiles.append( + tile.Tile(self, i*64, (j+1)*48, + self.imgs['indoor%d' % random.randint(1, 6)])) + + self.draw_background() + + playfield = lm.generate_simple_playfield(16) + + for (x, y), t in playfield.items(): + x, y = 64 * x, 48 * (y + 1) + self.objects.append({ + lm.Mirror: mirror.Mirror(self, x, y, random.choice((True, False))), + lm.Lever: lever.Lever( + self, x, y, [], toggling=True, + anim='lever_leftright' if x == 0 or x == 15 * 64 + else 'lever_updown'), + lm.Target: block.Block(self, x, y, self.imgs['block3'], + movable=False), + lm.Blocker: block.Block(self, x, y, self.imgs['block1'], + movable=False) + }[t]) + mirrors = list(filter(lambda obj: isinstance(obj, mirror.Mirror), + self.objects)) + levers = list(filter(lambda obj: isinstance(obj, lever.Lever), + self.objects)) + random.shuffle(levers) + for l in levers: + m = min(mirrors, key=lambda m: misc.manhattan_dist( + (m.x, m.y), (l.x, l.y))) + mirrors.remove(m) + l.links.append((lambda m: lambda setting: m.rotate())(m)) + + self.player.set_pos(64 * 7, 48 * 2) + self.player.set_init_pos() + + + def restart(self): + for obj in self.objects: + obj.reset_pos() + diff --git a/robotgame/loader.py b/robotgame/loader.py index 588564e..2967072 100644 --- a/robotgame/loader.py +++ b/robotgame/loader.py @@ -85,7 +85,9 @@ class Loader(object): ('arrow_down', os.path.join('matt', 'down')), ('arrow_left', os.path.join('matt', 'right')), - ('stairs', 'stairs')] + ('stairs', 'stairs'), + + ('mirror', 'mirror')] ): self.imgs[anim] = [] diff --git a/robotgame/logic/lasermirror.py b/robotgame/logic/lasermirror.py index 3c59c8c..3371b97 100644 --- a/robotgame/logic/lasermirror.py +++ b/robotgame/logic/lasermirror.py @@ -19,8 +19,8 @@ # # lasermirror.py # -------------------- -# date created : Tue Aug 7 2012 -# copyright : (C) 2012 Niels G. W. Serup +# date created : Tue Aug 7 2016 +# copyright : (C) 2016 Niels G. W. Serup # maintained by : Niels G. W. Serup """ @@ -33,6 +33,7 @@ import random import itertools from robotgame.logic.direction import * import robotgame.logic.rollingstone as rstone +from robotgame.logic.rollingstone import Blocker import robotgame.misc as misc class Mirror(object): @@ -46,12 +47,12 @@ class Target(object): def generate_simple_playfield(nmirrors): """ - Generate a completable 12x12 playfield where: + Generate a completable 16x16 playfield where: * there are four laser sources, one in each corner + the one in the upper left corner (0, 0) starts in (0, -1) heading down - + the one in the upper right corner (11, 0) starts in (12, 0), heading left - + the one in the lower right corner (11, 11) starts in (11, 12), heading up - + the one in the lower left corner (0, 11) starts in (-1, 11), heading right + + the one in the upper right corner (15, 0) starts in (16, 0), heading left + + the one in the lower right corner (15, 15) starts in (15, 16), heading up + + the one in the lower left corner (0, 15) starts in (-1, 15), heading right * there are four laser targets * there are nmirrors mirrors * there are nmirrors levers @@ -59,14 +60,14 @@ def generate_simple_playfield(nmirrors): Return playfield : {(x, y): Target | Mirror | rstone.Blocker | Lever} """ - playfield = {(4, 4): Target, - (7, 4): Target, - (4, 7): Target, - (7, 7): Target, - (5, 5): rstone.Blocker, - (5, 6): rstone.Blocker, - (6, 5): rstone.Blocker, - (6, 6): rstone.Blocker, + playfield = {(6, 6): Target, + (9, 6): Target, + (6, 9): Target, + (9, 9): Target, + (7, 7): rstone.Blocker, + (7, 8): rstone.Blocker, + (8, 7): rstone.Blocker, + (8, 8): rstone.Blocker, } succs = lambda d: d source_direc = Up @@ -75,23 +76,21 @@ def generate_simple_playfield(nmirrors): nm = nmirrors / missing nmirrors -= nm stone_playfield, _ = rstone.generate_simple_playfield( - 5, 5, nm, 0, False, False) + 7, 7, nm, 0, False, False) for pos, direc in stone_playfield.items(): - if direc is not None and pos >= (0, 0): - playfield[_adjust(source_direc, 12 - 1, 12 - 1, *pos)] = Mirror + playfield[_adjust(source_direc, 16 - 1, 16 - 1, *pos)] = Mirror succs = (lambda s: lambda d: succ(s(d)))(succs) source_direc = succ(source_direc) - occup = set(playfield.keys()) - emptys = list( - set([(0, y) for y in filter(lambda y: (1, y) not in occup, range(12))] - + [(11, y) for y in filter(lambda y: (10, y) not in occup, range(12))] - + [(x, 0) for x in filter(lambda x: (x, 1) not in occup, range(12))] - + [(x, 11) for x in filter(lambda x: (x, 10) not in occup, range(12))]) - - occup) - if len(emptys) < nlevers: - raise Exception("Not enough space for all levers!") - for pos in misc.pick_random_elements(emptys, nlevers): + 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 return playfield diff --git a/robotgame/logic/rollingstone.py b/robotgame/logic/rollingstone.py index 75b5ca9..fd0831c 100644 --- a/robotgame/logic/rollingstone.py +++ b/robotgame/logic/rollingstone.py @@ -123,7 +123,7 @@ def generate_simple_playfield(width, height, nturns, nstones, break else: allowed = set(range(0, height)) - set(not_allowed_y) - if missing == 3: + if missing <= 3: allowed -= set((height - 1,)) if missing == nturns: allowed -= set((0,)) diff --git a/robotgame/mirror.py b/robotgame/mirror.py new file mode 100644 index 0000000..5d2f867 --- /dev/null +++ b/robotgame/mirror.py @@ -0,0 +1,63 @@ +# This file is part of ROBOTGAME +# +# ROBOTGAME is free software: you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# ROBOTGAME is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# ROBOTGAME. If not, see . +# +# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' +# +# mirror.py +# -------------------- +# date created : Fri Aug 10 2012 +# copyright : (C) 2012 Niels G. W. Serup +# maintained by : Niels G. W. Serup + +""" +A generic mirror for drawing. +""" + +import pygame + +import worldobject + +class Mirror(worldobject.WorldObject): + def __init__(self, level, x, y, left_up=True): + self.__dict__.update(locals()) + worldobject.WorldObject.__init__(self, level, x, y) + + self.in_rotation = False + + self.frame = 7 + self.anim_speed = 12 + self._half_anim_len = len(self.level.imgs['mirror']) / 2 + + def rotate(self): + if self.in_rotation: + return + self.in_rotation = True + self.left_up = not self.left_up + self.frame = 0 + + def update(self, e, t, dt): + if self.in_rotation: + top = self._half_anim_len - 1 + self.frame = min(self.frame + self.anim_speed * dt, top) + if self.frame == top: + self.in_rotation = False + + worldobject.WorldObject.update(self, e, t, dt) + + def draw(self, window): + fn = self.frame + 1 if not self.left_up else self.frame + self._half_anim_len + self.img = self.level.imgs['mirror'][int(fn)] + window.blit(self.img, (self.x - 32 - self.level.camera_x, + self.y - self.img.get_size()[1] + 24 + - self.level.camera_y)) diff --git a/robotgame/misc.py b/robotgame/misc.py index 04547a3..038b629 100644 --- a/robotgame/misc.py +++ b/robotgame/misc.py @@ -7,3 +7,7 @@ def pick_random_elements(xs, n): yield xs[i1] xs[i1] = xs[i] +def manhattan_dist(p0, p1): + x0, y0 = p0 + x1, y1 = p1 + return abs(x1 - x0) + abs(y1 - y0) diff --git a/tests/lasermirror_tests.py b/tests/lasermirror_tests.py index bda9483..bd40f24 100644 --- a/tests/lasermirror_tests.py +++ b/tests/lasermirror_tests.py @@ -8,7 +8,7 @@ from robotgame.logic.direction import * class LaserMirrorTest(unittest.TestCase): def test_playfield_generation(self): print() - playfield = generate_simple_playfield(13) + playfield = generate_simple_playfield(16) print_playfield(playfield, 12, 12) if __name__ == '__main__':