a-robots-conundrum/robotgame/logic/lasermirror.py

116 lines
4.2 KiB
Python

#!/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 <http://www.gnu.org/licenses/>.
#
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
#
# lasermirror.py
# --------------------
# date created : Tue Aug 7 2016
# copyright : (C) 2016 Niels G. W. Serup
# maintained by : Niels G. W. Serup <ns@metanohi.name>
"""
Management of lasers in rooms of mirrors and targets.
"""
from __future__ import print_function
import math
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):
pass
class Lever(object):
pass
class Target(object):
pass
def generate_simple_playfield(nmirrors):
"""
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 (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
* all levers are at the wall
Return playfield : {(x, y): Target | Mirror | rstone.Blocker | Lever}
"""
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
nlevers = nmirrors
for missing in range(4, 0, -1):
nm = nmirrors / missing
nmirrors -= nm
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
succs = (lambda s: lambda d: succ(s(d)))(succs)
source_direc = succ(source_direc)
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
def _adjust(source_direc, w, h, x, y):
return {
Up: lambda x, y: (x, y),
Right: lambda x, y: (w - y, x),
Down: lambda x, y: (w - x, h - y),
Left: lambda x, y: (y, h - x),
}[source_direc](x, y)
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():
if isDirection(val) and hide_directions:
continue
text[y][x] = '%' if val is rstone.Blocker \
else 'x' if val is Mirror \
else 'L' if val is Lever \
else 'T' if val is Target else 'N'
print('\n'.join(''.join(line) for line in text))