Added preliminary level 4. No lasers yet.
This commit is contained in:
parent
5904d29aef
commit
b61f54963d
|
@ -1 +1,8 @@
|
||||||
This is a good game.
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -85,7 +85,9 @@ class Loader(object):
|
||||||
('arrow_down', os.path.join('matt', 'down')),
|
('arrow_down', os.path.join('matt', 'down')),
|
||||||
('arrow_left', os.path.join('matt', 'right')),
|
('arrow_left', os.path.join('matt', 'right')),
|
||||||
|
|
||||||
('stairs', 'stairs')]
|
('stairs', 'stairs'),
|
||||||
|
|
||||||
|
('mirror', 'mirror')]
|
||||||
):
|
):
|
||||||
|
|
||||||
self.imgs[anim] = []
|
self.imgs[anim] = []
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#
|
#
|
||||||
# lasermirror.py
|
# lasermirror.py
|
||||||
# --------------------
|
# --------------------
|
||||||
# date created : Tue Aug 7 2012
|
# date created : Tue Aug 7 2016
|
||||||
# copyright : (C) 2012 Niels G. W. Serup
|
# copyright : (C) 2016 Niels G. W. Serup
|
||||||
# maintained by : Niels G. W. Serup <ns@metanohi.name>
|
# maintained by : Niels G. W. Serup <ns@metanohi.name>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -33,6 +33,7 @@ import random
|
||||||
import itertools
|
import itertools
|
||||||
from robotgame.logic.direction import *
|
from robotgame.logic.direction import *
|
||||||
import robotgame.logic.rollingstone as rstone
|
import robotgame.logic.rollingstone as rstone
|
||||||
|
from robotgame.logic.rollingstone import Blocker
|
||||||
import robotgame.misc as misc
|
import robotgame.misc as misc
|
||||||
|
|
||||||
class Mirror(object):
|
class Mirror(object):
|
||||||
|
@ -46,12 +47,12 @@ class Target(object):
|
||||||
|
|
||||||
def generate_simple_playfield(nmirrors):
|
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
|
* 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 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 upper right corner (15, 0) starts in (16, 0), heading left
|
||||||
+ the one in the lower right corner (11, 11) starts in (11, 12), heading up
|
+ the one in the lower right corner (15, 15) starts in (15, 16), heading up
|
||||||
+ the one in the lower left corner (0, 11) starts in (-1, 11), heading right
|
+ the one in the lower left corner (0, 15) starts in (-1, 15), heading right
|
||||||
* there are four laser targets
|
* there are four laser targets
|
||||||
* there are nmirrors mirrors
|
* there are nmirrors mirrors
|
||||||
* there are nmirrors levers
|
* there are nmirrors levers
|
||||||
|
@ -59,14 +60,14 @@ def generate_simple_playfield(nmirrors):
|
||||||
|
|
||||||
Return playfield : {(x, y): Target | Mirror | rstone.Blocker | Lever}
|
Return playfield : {(x, y): Target | Mirror | rstone.Blocker | Lever}
|
||||||
"""
|
"""
|
||||||
playfield = {(4, 4): Target,
|
playfield = {(6, 6): Target,
|
||||||
(7, 4): Target,
|
(9, 6): Target,
|
||||||
(4, 7): Target,
|
(6, 9): Target,
|
||||||
(7, 7): Target,
|
(9, 9): Target,
|
||||||
(5, 5): rstone.Blocker,
|
(7, 7): rstone.Blocker,
|
||||||
(5, 6): rstone.Blocker,
|
(7, 8): rstone.Blocker,
|
||||||
(6, 5): rstone.Blocker,
|
(8, 7): rstone.Blocker,
|
||||||
(6, 6): rstone.Blocker,
|
(8, 8): rstone.Blocker,
|
||||||
}
|
}
|
||||||
succs = lambda d: d
|
succs = lambda d: d
|
||||||
source_direc = Up
|
source_direc = Up
|
||||||
|
@ -75,23 +76,21 @@ def generate_simple_playfield(nmirrors):
|
||||||
nm = nmirrors / missing
|
nm = nmirrors / missing
|
||||||
nmirrors -= nm
|
nmirrors -= nm
|
||||||
stone_playfield, _ = rstone.generate_simple_playfield(
|
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():
|
for pos, direc in stone_playfield.items():
|
||||||
if direc is not None and pos >= (0, 0):
|
playfield[_adjust(source_direc, 16 - 1, 16 - 1, *pos)] = Mirror
|
||||||
playfield[_adjust(source_direc, 12 - 1, 12 - 1, *pos)] = Mirror
|
|
||||||
succs = (lambda s: lambda d: succ(s(d)))(succs)
|
succs = (lambda s: lambda d: succ(s(d)))(succs)
|
||||||
source_direc = succ(source_direc)
|
source_direc = succ(source_direc)
|
||||||
|
|
||||||
occup = set(playfield.keys())
|
for _ in range(nlevers):
|
||||||
emptys = list(
|
# This needs to be optimized...
|
||||||
set([(0, y) for y in filter(lambda y: (1, y) not in occup, range(12))]
|
occup = set(playfield.keys())
|
||||||
+ [(11, y) for y in filter(lambda y: (10, y) not in occup, range(12))]
|
emptys = list(
|
||||||
+ [(x, 0) for x in filter(lambda x: (x, 1) not in occup, range(12))]
|
set([(0, y) for y in filter(lambda y: (1, y) not in occup, range(16))]
|
||||||
+ [(x, 11) for x in filter(lambda x: (x, 10) not in occup, range(12))])
|
+ [(15, y) for y in filter(lambda y: (10, y) not in occup, range(16))]
|
||||||
- occup)
|
+ [(x, 0) for x in filter(lambda x: (x, 1) not in occup, range(16))]
|
||||||
if len(emptys) < nlevers:
|
+ [(x, 15) for x in filter(lambda x: (x, 10) not in occup, range(16))]) - occup)
|
||||||
raise Exception("Not enough space for all levers!")
|
pos = emptys[random.randrange(len(emptys))]
|
||||||
for pos in misc.pick_random_elements(emptys, nlevers):
|
|
||||||
playfield[pos] = Lever
|
playfield[pos] = Lever
|
||||||
return playfield
|
return playfield
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ def generate_simple_playfield(width, height, nturns, nstones,
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
allowed = set(range(0, height)) - set(not_allowed_y)
|
allowed = set(range(0, height)) - set(not_allowed_y)
|
||||||
if missing == 3:
|
if missing <= 3:
|
||||||
allowed -= set((height - 1,))
|
allowed -= set((height - 1,))
|
||||||
if missing == nturns:
|
if missing == nturns:
|
||||||
allowed -= set((0,))
|
allowed -= set((0,))
|
||||||
|
|
|
@ -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))
|
|
@ -7,3 +7,7 @@ def pick_random_elements(xs, n):
|
||||||
yield xs[i1]
|
yield xs[i1]
|
||||||
xs[i1] = xs[i]
|
xs[i1] = xs[i]
|
||||||
|
|
||||||
|
def manhattan_dist(p0, p1):
|
||||||
|
x0, y0 = p0
|
||||||
|
x1, y1 = p1
|
||||||
|
return abs(x1 - x0) + abs(y1 - y0)
|
||||||
|
|
|
@ -8,7 +8,7 @@ from robotgame.logic.direction import *
|
||||||
class LaserMirrorTest(unittest.TestCase):
|
class LaserMirrorTest(unittest.TestCase):
|
||||||
def test_playfield_generation(self):
|
def test_playfield_generation(self):
|
||||||
print()
|
print()
|
||||||
playfield = generate_simple_playfield(13)
|
playfield = generate_simple_playfield(16)
|
||||||
print_playfield(playfield, 12, 12)
|
print_playfield(playfield, 12, 12)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Reference in New Issue