Added preliminary level 4. No lasers yet.

This commit is contained in:
Niels Serup 2012-08-11 02:22:29 +02:00
parent 5904d29aef
commit b61f54963d
8 changed files with 199 additions and 30 deletions

View File

@ -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.

94
robotgame/level4.py Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
#
# level1.py
# --------------------
# date created : Fri Aug 10 2012
# copyright : (C) 2012 Niels G. W. Serup
# maintained by : Niels G. W. Serup <ns@metanohi.name>
"""
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()

View File

@ -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] = []

View File

@ -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 <ns@metanohi.name>
"""
@ -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

View File

@ -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,))

63
robotgame/mirror.py Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
#
# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
#
# mirror.py
# --------------------
# date created : Fri Aug 10 2012
# copyright : (C) 2012 Niels G. W. Serup
# maintained by : Niels G. W. Serup <ns@metanohi.name>
"""
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))

View File

@ -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)

View File

@ -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__':