#!/usr/bin/env python # -*- coding: utf-8 -*- # This file is part of A Robot's Conundrum. # # A Robot's Conundrum 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. # # A Robot's Conundrum 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 # A Robot's Conundrum. 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 arobotsconundrum.logic.direction import * import arobotsconundrum.misc as misc class Empty(object): pass class Forbidden(object): pass class StrictlyForbidden(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 StrictlyForbidden 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 = random.randrange(4) found = None alldirs = all_directions if random.choice((True, False)): alldirs.reverse() for direc in alldirs[t:] + alldirs[: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, StrictlyForbidden) for direc in all_directions: npos = direc.next_pos(pos) if _get(npos) is Visited: pos = npos break for direc in all_directions: npos = direc.next_pos(pos) if _get(npos) is Forbidden: occup_direc = succ(succ(direc)) if all(ndirec is occup_direc or _get(ndirec.next_pos(npos)) in (Forbidden, Empty) for ndirec in all_directions): _set(npos, Empty) _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: '#', StrictlyForbidden: '!', Visited: 'ยท'}[c], end='') print()