Fixed a few bugs and added laser mirror room generator.
Šī revīzija ir iekļauta:
		@@ -23,6 +23,10 @@
 | 
			
		||||
#          copyright : (C) 2012 Niels G. W. Serup
 | 
			
		||||
#      maintained by : Niels G. W. Serup <ns@metanohi.name>
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
Colour boxes.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
def generate_colour_boxes(nwells, nboxes):
 | 
			
		||||
 
 | 
			
		||||
@@ -53,9 +53,7 @@ class Left(Direction):
 | 
			
		||||
        x, y = pos
 | 
			
		||||
        return x - 1, y
 | 
			
		||||
 | 
			
		||||
all_directions = set((Up, Left, Down, Right))
 | 
			
		||||
 | 
			
		||||
succ = lambda d: all_directions[(all_directions.index(d) + 1) % 4]
 | 
			
		||||
pred = lambda d: all_directions[(all_directions.index(d) - 1) % 4]
 | 
			
		||||
 | 
			
		||||
isDirection = lambda obj: obj in (Up, Left, Down, Right)
 | 
			
		||||
all_directions = (Up, Right, Down, Left)
 | 
			
		||||
_sp = lambda n: lambda d: all_directions[(all_directions.index(d) + n) % 4]
 | 
			
		||||
succ, pred = _sp(1), _sp(-1)
 | 
			
		||||
isDirection = all_directions.__contains__
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										116
									
								
								robotgame/logic/lasermirror.py
									
									
									
									
									
										Parasts fails
									
								
							
							
						
						
									
										116
									
								
								robotgame/logic/lasermirror.py
									
									
									
									
									
										Parasts fails
									
								
							@@ -0,0 +1,116 @@
 | 
			
		||||
#!/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 2012
 | 
			
		||||
#          copyright : (C) 2012 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
 | 
			
		||||
 | 
			
		||||
class Mirror(object):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class Lever(object):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class Target(object):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
def generate_simple_playfield(nmirrors):
 | 
			
		||||
    """
 | 
			
		||||
    Generate a completable 12x12 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
 | 
			
		||||
      * 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 = {(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,
 | 
			
		||||
                 }
 | 
			
		||||
    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(
 | 
			
		||||
            5, 5, 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
 | 
			
		||||
        succs = (lambda s: lambda d: succ(s(d)))(succs)
 | 
			
		||||
        source_direc = succ(source_direc)
 | 
			
		||||
 | 
			
		||||
    emptys = set(itertools.product(range(12), range(12))) \
 | 
			
		||||
        - set(playfield.keys())
 | 
			
		||||
    emptys = set([(0, y) for y in range(12)]
 | 
			
		||||
                 + [(11, y) for y in range(12)]
 | 
			
		||||
                 + [(x, 0) for x in range(12)]
 | 
			
		||||
                 + [(x, 11) for x in range(12)])
 | 
			
		||||
    for _ in range(nlevers):
 | 
			
		||||
        if not emptys:
 | 
			
		||||
            raise Exception("Not enough space for all levers!")
 | 
			
		||||
        pos = random.choice(list(emptys))
 | 
			
		||||
        playfield[pos] = Lever
 | 
			
		||||
        emptys.remove(pos)
 | 
			
		||||
    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))
 | 
			
		||||
 | 
			
		||||
@@ -30,9 +30,9 @@ direction-changing turns. Also has a pseudo-random playfield generator.
 | 
			
		||||
 | 
			
		||||
from __future__ import print_function
 | 
			
		||||
import math
 | 
			
		||||
import random
 | 
			
		||||
import itertools
 | 
			
		||||
from robotgame.logic.direction import *
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
class Blocker(object):
 | 
			
		||||
    pass
 | 
			
		||||
@@ -70,7 +70,8 @@ def reaches_goal(playfield, width, height, max_steps, start_pos, goal_pos):
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_simple_playfield(width, height, nturns, nstones):
 | 
			
		||||
def generate_simple_playfield(width, height, nturns, nstones,
 | 
			
		||||
                              do_transpose=None, start_inside=True):
 | 
			
		||||
    """
 | 
			
		||||
    Generate a completable playfield where:
 | 
			
		||||
      * the starting position is in the upper left corner
 | 
			
		||||
@@ -78,7 +79,7 @@ def generate_simple_playfield(width, height, nturns, nstones):
 | 
			
		||||
      * the playfield is completable in nturns or less
 | 
			
		||||
      * the playfield has at most nstones stones
 | 
			
		||||
 | 
			
		||||
    Return (playfield : {(x, y): Direction | Blocker},
 | 
			
		||||
    Return (playfield : {(x, y): Direction | Blocker | None},
 | 
			
		||||
            steps : int)
 | 
			
		||||
    where (x, y) : (int, int)
 | 
			
		||||
 | 
			
		||||
@@ -95,11 +96,13 @@ def generate_simple_playfield(width, height, nturns, nstones):
 | 
			
		||||
        nturns = min(2 * (width - 1), 2 * (height - 1) - 1)
 | 
			
		||||
        min_width, min_height = _min_play_size(nturns)
 | 
			
		||||
 | 
			
		||||
    do_transpose = random.choice((True, False))
 | 
			
		||||
    if do_transpose is None:
 | 
			
		||||
        do_transpose = random.choice((True, False))
 | 
			
		||||
    if do_transpose:
 | 
			
		||||
        width, height = height, width
 | 
			
		||||
 | 
			
		||||
    turns, stones = [((0, 0), None)], []
 | 
			
		||||
    turns = [((0, 0), None)]
 | 
			
		||||
    stones = []
 | 
			
		||||
    x, y = (0, 0)
 | 
			
		||||
    not_allowed_y = []
 | 
			
		||||
    offset_x = 0
 | 
			
		||||
@@ -110,6 +113,7 @@ def generate_simple_playfield(width, height, nturns, nstones):
 | 
			
		||||
            turns.append(((x, height - 1), Right))
 | 
			
		||||
            break
 | 
			
		||||
        elif missing == 0:
 | 
			
		||||
            turns[-1] = ((width - 1, turns[-1][0][1]), Down)
 | 
			
		||||
            break
 | 
			
		||||
        else:
 | 
			
		||||
            allowed = set(range(0, height)) - set(not_allowed_y)
 | 
			
		||||
@@ -129,6 +133,8 @@ def generate_simple_playfield(width, height, nturns, nstones):
 | 
			
		||||
            turns.append(((x1, y1), None))
 | 
			
		||||
            x, y = x1, y1
 | 
			
		||||
    turns.append(((width - 1, height - 1), None))
 | 
			
		||||
    if not start_inside:
 | 
			
		||||
        del turns[0]
 | 
			
		||||
 | 
			
		||||
    if do_transpose:
 | 
			
		||||
        turns[:] = [((y, x), {
 | 
			
		||||
@@ -181,7 +187,7 @@ def print_playfield(playfield, width, height, hide_directions):
 | 
			
		||||
    for (x, y), val in playfield.items():
 | 
			
		||||
        if isDirection(val) and hide_directions:
 | 
			
		||||
            continue
 | 
			
		||||
        text[y][x] = '%' if val == Blocker else repr(val).rsplit('.', 1)[1][0] \
 | 
			
		||||
        text[y][x] = '%' if val is Blocker else repr(val).rsplit('.', 1)[1][0] \
 | 
			
		||||
            if isDirection(val) else 'G'
 | 
			
		||||
    print('\n'.join(''.join(line) for line in text))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								tests/lasermirror_tests.py
									
									
									
									
									
										Parasts fails
									
								
							
							
						
						
									
										15
									
								
								tests/lasermirror_tests.py
									
									
									
									
									
										Parasts fails
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
 | 
			
		||||
from __future__ import print_function
 | 
			
		||||
import unittest
 | 
			
		||||
from robotgame.logic.lasermirror import *
 | 
			
		||||
from robotgame.logic.direction import *
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LaserMirrorTest(unittest.TestCase):
 | 
			
		||||
    def test_playfield_generation(self):
 | 
			
		||||
        print()
 | 
			
		||||
        playfield = generate_simple_playfield(13)
 | 
			
		||||
        print_playfield(playfield, 12, 12)
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    unittest.main()
 | 
			
		||||
@@ -35,5 +35,11 @@ class RollingStoneTest(unittest.TestCase):
 | 
			
		||||
        self.assertTrue(
 | 
			
		||||
            reaches_goal(playfield, 10, 10, steps, (0, 0), (9, 9)))
 | 
			
		||||
 | 
			
		||||
        print()
 | 
			
		||||
        playfield, steps = generate_simple_playfield(10, 10, 4, 11)
 | 
			
		||||
        print_playfield(playfield, 10, 10, True)
 | 
			
		||||
        self.assertTrue(
 | 
			
		||||
            reaches_goal(playfield, 10, 10, steps, (0, 0), (9, 9)))
 | 
			
		||||
        
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    unittest.main()
 | 
			
		||||
 
 | 
			
		||||
		Atsaukties uz šo jaunā problēmā
	
	Block a user