From b6700125c40e0bcb049427bc4c4502038d21cbc4 Mon Sep 17 00:00:00 2001 From: Niels Serup Date: Tue, 14 Aug 2012 00:28:50 +0200 Subject: [PATCH] Created teleporter map generation and implemented it in level 1. --- robotgame/level1.py | 46 ++++++----- robotgame/logic/teleportermap.py | 126 +++++++++++++++++++++++++++++++ robotgame/trigger.py | 4 +- tests/teleportermap_tests.py | 20 +++++ 4 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 robotgame/logic/teleportermap.py create mode 100644 tests/teleportermap_tests.py diff --git a/robotgame/level1.py b/robotgame/level1.py index 3bbd036..595afcb 100644 --- a/robotgame/level1.py +++ b/robotgame/level1.py @@ -39,6 +39,7 @@ import lever import trigger import worldobject +import logic.teleportermap import logic.rollingstone import logic.colourboxes @@ -82,64 +83,61 @@ class Level1(level.Level): ### Task 1: Teleporters - task5_size = 5, 8 # y, x -- Note, inverted. + task5_size = 8, 5 task5_pos = (64 * 12, 48 * 19) - task5_nturns = random.randint(2, 4) * 2 - 1 + tmap = logic.teleportermap.generate_teleporter_map3(*task5_size) - playfield, nsteps, directions = ( - logic.rollingstone.generate_simple_unsolved_solvable_extra( - task5_size[0], task5_size[1], task5_nturns, - task5_size[0]*task5_size[1])) - - for x in range(task5_size[1]): - for y in range(task5_size[0]): + for x in range(task5_size[0]): + for y in range(task5_size[1]): + # if not (x, y) in tmap: + # continue self.add_tile(task5_pos[0] - 64 * (x - 1), task5_pos[1] - 48 * y, 'indoor%d' % random.randint(1, 6), blocking=False) - - for i, j in playfield: + for x, y in tmap: self.objects.append( trigger.Trigger(self, - task5_pos[0] - 64 * (j - 1), - task5_pos[1] - 48 * i, + task5_pos[0] - 64 * (x - 1), + task5_pos[1] - 48 * y, [lambda x: self.player.set_pos( task5_pos[0] + 2 * 64, (task5_pos[1] - - random.randint(0, task5_size[0] - 1) * 48))], + - random.randint(0, task5_size[1] - 1) * 48))], self.imgs['hole'], [self.player], - visible=False)) + visible=False, + no_stop=True)) - for i in range(task5_size[1] + 1): + for i in range(task5_size[0] + 1): self.add_tile(task5_pos[0] - 64 * i, task5_pos[1] + 48, 'moat_horizontal') self.add_tile(task5_pos[0] - 64 * i, - task5_pos[1] - task5_size[0] * 48, + task5_pos[1] - task5_size[1] * 48, 'moat_horizontal') self.add_tile(task5_pos[0] + 64, task5_pos[1] + 48, 'moat_end_horizontal_flip') # self.add_tile(task5_pos[0] + 64, - # task5_pos[1] - task5_size[0] * 48, + # task5_pos[1] - task5_size[1] * 48, # 'moat_end_horizontal_flip') - self.add_tile(task5_pos[0] - 64 * (task5_size[1] + 1), + self.add_tile(task5_pos[0] - 64 * (task5_size[0] + 1), task5_pos[1] + 48, 'moat_corner_south') - self.add_tile(task5_pos[0] - 64 * (task5_size[1] + 1), - task5_pos[1] - task5_size[0] * 48, + self.add_tile(task5_pos[0] - 64 * (task5_size[0] + 1), + task5_pos[1] - task5_size[1] * 48, 'moat_corner_north') for i in range(task5_size[0]): - self.add_tile(task5_pos[0] - 64 * (task5_size[1] + 1), + self.add_tile(task5_pos[0] - 64 * (task5_size[0] + 1), task5_pos[1] - 48 * i, 'moat_vertical') self.objects.append( lever.Lever(self, - task5_pos[0] - 64 * (task5_size[1]), - task5_pos[1] - (task5_size[0] / 2) * 48, + task5_pos[0] - 64 * (task5_size[0]), + task5_pos[1] - (task5_size[1] / 2) * 48, [lambda *x: self.complete_task(1)])) ### Task 2: Rolling stone diff --git a/robotgame/logic/teleportermap.py b/robotgame/logic/teleportermap.py new file mode 100644 index 0000000..7043917 --- /dev/null +++ b/robotgame/logic/teleportermap.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# 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 . +# +# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' +# +# teleportermap.py +# -------------------- +# date created : Mon Aug 13 2012 +# copyright : (C) 2012 Niels G. W. Serup +# maintained by : Niels G. W. Serup + +""" +Logic for a map with invisible teleporters. +""" + +from __future__ import print_function +import math +import random +import itertools + +from robotgame.logic.direction import * +import robotgame.misc as misc + +class Empty(object): + pass + +class Forbidden(object): + pass + +class Visited(object): + pass + +def generate_teleporter_map(width, height): + m = [[Empty for _ in range(height)] + for _ in range(width)] + + def _get(p): + if p[0] < 0 or p[0] >= width or p[1] < 0 or p[1] >= height: + return Forbidden + return m[p[0]][p[1]] + + def _set(p, val): + try: + m[p[0]][p[1]] = val + except IndexError: + pass + + def insert_random_point_on_line(x): + t = random.randrange(height) + for y in itertools.chain(xrange(t), xrange(t + 1, height)): + _set((x, y), Forbidden) + _set((x, t), Visited) + return (x, t) + + pos = insert_random_point_on_line(width - 1) + + while True: + while True: + if pos[0] == 1 and random.randint(0, height) == 0: + break + t, found = random.randrange(4), None + for direc in all_directions[t:] + all_directions[:t]: + npos = direc.next_pos(pos) + if found is None and npos[0] != 0 and _get(npos) is Empty and ( + (direc is Right and + len(filter(lambda c: c is Empty, m[pos[0]][:pos[1]] if + opos[1] > pos[1] + else m[pos[0]][pos[1] + 1:])) >= 2) + or direc is not Right): + found = npos + _set(npos, Visited) + else: + if _get(npos) is Empty: + _set(npos, Forbidden) + if found is None: + break + opos = pos + pos = found + if pos[0] == 1: + break + _set(pos, Forbidden) + for direc in all_directions: + npos = direc.next_pos(pos) + if _get(npos) is Visited: + pos = npos + break + + _set((0, pos[1]), Visited) + return m + +def generate_teleporter_map2(width, height): + tmap = generate_teleporter_map(width, height) + res = set() + for y in range(len(tmap[0])): + for x in range(len(tmap)): + if tmap[x][y] is Visited: + res.add((x, y)) + return res + +def generate_teleporter_map3(width, height): + return set(itertools.product(range(width), range(height))) \ + - generate_teleporter_map2(width, height) + +def print_map(tmap): + for y in range(len(tmap[0])): + for x in range(len(tmap)): + c = tmap[x][y] + print({Empty: '%', + Forbidden: '#', + Visited: 'ยท'}[c], end='') + print() + diff --git a/robotgame/trigger.py b/robotgame/trigger.py index a2e39d1..d73309a 100644 --- a/robotgame/trigger.py +++ b/robotgame/trigger.py @@ -32,7 +32,7 @@ class Trigger(worldobject.WorldObject): def __init__(self, level, x, y, links, img, trigger_objs, toggling=False, signal=[0, 1], setting=False, blocking=False, - visible=True): + visible=True, no_stop=False): self.__dict__.update(locals()) worldobject.WorldObject.__init__(self, level, x, y, z=-48, blocking=blocking, visible=visible) @@ -41,7 +41,7 @@ class Trigger(worldobject.WorldObject): self.anim_speed = 15 def trigger(self, setting, obj): - if self.setting != setting: + if self.setting != setting or self.no_stop: self.setting = setting for link in self.links: diff --git a/tests/teleportermap_tests.py b/tests/teleportermap_tests.py new file mode 100644 index 0000000..b73a898 --- /dev/null +++ b/tests/teleportermap_tests.py @@ -0,0 +1,20 @@ + +from __future__ import print_function +import unittest +from robotgame.logic.teleportermap import * +from robotgame.logic.direction import * + + +class TeleporterMapTest(unittest.TestCase): + def test_map_generation(self): + for w, h in ( + (8, 5), + (16, 16) + ): + tmap = generate_teleporter_map(w, h) + print() + print_map(tmap) + print() + +if __name__ == '__main__': + unittest.main()