# Brewball review

#1

I really like the concept and the lesson it teaches.
Although I was able to pass it with just a couple of lines of code due to catching an extremely easy seed I think you might want to put more explanation into the help file.
“There are multiple ways to tackle this problem. Dynamic fire-trap avoidance using vectors? Evaluating the static mines and creating a path through them?”

You might consider adding a bit more explanation, a little hint, for each of these two options.

Just a thought.

#2

I guess the original idea is to use vectors and dynamic avoidance of traps, as you suspect. After all, this is a glacier level, teaching “advanced techniques”.

However, it is not really enforced: the traps are in the same place in every seed, so yes, you can win with a rather simple code in a few resubmits.

#3

I don’t know about you guys, but I just used vectors. Much simpler… sorta. Tried using flag, didn’t quite work out.

#4

I think it’s a good level, however, my only suggestion is to try and randomize the firetraps. I was able to win the level by adding 2 lines of code to code already there, and resubmitting until I got an easy seed.

#5

Odd error in terms of interaction between firetraps and .isPathClear

I was using SafeMove(potion.targetPos) and am running straight into the firetraps. Can anyone identify why .isPathClear is not identifying the fact there are firetraps on the route?

``````def SafePath(tarA):
vecA = Vector.subtract(tarA, self.pos)
# This creates a 90° rotated, 1 m long vector realtive to vec.
normV = Vector.multiply(Vector.normalize(Vector.rotate(vecA, 1.5708)), 0.5)
targetL = [tarA,   Vector.add(tarA, normV),   Vector.subtract(tarA, normV)]
startL  = [self.pos, Vector.add(self.pos, normV), Vector.subtract(self.pos, normV)]
isFree = True
for s in startL:
for t in targetL:
if s and t:
isFree = isFree and self.isPathClear(s, t)
else:
isFree = False
return isFree

def SafeMove(tarA):
tarLoc = tarA
cAngle = 0
adjAngle = 0.25
while (not(SafePath(tarLoc)) and (cAngle < 2*Math.PI)):
vecA = Vector.normalize(Vector.subtract(tarLoc, self.pos))
adjAngle2 = adjAngle
vecB = Vector.multiply(Vector.rotate(vecA, adjAngle2),5)
tarLoc = Vector.add(self.pos, vecB)
cAngle = cAngle + adjAngle2
self.move(tarLoc)
``````

#6

I guess that fire traps are considered as point objects, so if isPathClear() “misses” it by even 0.1m, it will return “clear”. Unfortunately, our hero is not a point object, and if he/she wants to walk 0.1m close to a trap, then… well… KABOOM!

#7

Also, Brewball, while it appears on the Glacier world, does not beyond to the world, in a sense, that is, it’s not registered as in Kelvintaph Glacier and so redirects you to the “Undefined” screen.

#8

I’m guessing you are correct Ant. Recommendations:

1. Either fix isPathClear for mines or add a warning to the players.
2. Let players know how close they can get to a mine before it blows. (I think it is in the 2-3 range.)
3. Are you aware that on a bad seed, the suggested code can generate more than 1 potion in the air at a time? The current suggested code automatically goes after the first potion when the second potion could have less hang time. I would suggest adding code to prevent this from occurring.

Regards,

#9

Hey everyone, just wanted to say thanks for the feedback!

I’ll work on sprucing up the level sometime next week, and I really appreciate the input.

#10

I ended up reusing the strategy from “Skating Away” with minor changes and it worked.

A strange thing happened though:
On two occasions, Omar threw two potions in quick succession.

They landed too far apart for Tharin to get them both on the first occasion, but he managed to get them both the second time.

#11

Hey everybody, I made some changes.

• Mines spawn in (pseudo)-random spots.
• Omarn only throws 1 potion every 10 seconds.
• Includes a warning that isPathClear doesn’t work with hazards.
• Includes a note about the Fire Trap proximity range.
• Omarn’s minimum throwing position was increased.

I am still able to beat it, so that’s a good sign! Please try it again and let me know your feedback.

#12

The scattered mines seems like an improvement and Omarn doesn’t throw double potions any more. My previous solution still worked for all the tests I tried.
I also tried implementing a flag-following strategy and can say that it is possible, but tricky, to pass just by manually controlling your character. Maybe restrict the use of flags.

#13

Firetraps are not generated immediately. If I want to detect the firetraps before everything (they’re static, so it shouldn’t be in the loop), I get this result:

``````firetraps = self.findHazards()
self.say(firetraps)

>>> [Fire Trap Template]
``````

Which is one single firetrap, instead of 16… if I do a `self.move(self.pos)` before that, it’s OK.

Shouldn’t he throw potions only when you ask for it?!

This is the key.

#14

I just checked and my customized strategy still worked with the changes. Very nice level now, thanks! I don’t see either the warning or the note, but that simply may be because I didn’t reload the code.

Only thing I might recommend is not making all of the obstacles hazards. You could add some ice pillars as well so that folks don’t just need to check hazards but actually might need to use isPathClear … [Not a full maze, mind you, just a couple of random pillars that folks could run into … ]

#15

can help
here is my code:

loop:
potion = self.findFriendlyMissiles()[0]
firetraps = self.findHazards()
# Remember that a Fire Trap will trigger if you move closer than 3 meters!
omarn = self.findByType(“potion-master”)[0]
if potion:
dest = potion.targetPos
# Go get the potion.
if self.isReady(“dash”):
self.dash(potion.pos)
else:
self.move(potion.pos)
else:
if omarn and self.distanceTo(omarn) > 10:
# Move back to Omarn.
self.move(omarn.pos)
# Warning: isPathClear doesn’t work with Hazards!
else:
self.say(“Hup, hup!”)

#16
``````loop:
potion = self.findFriendlyMissiles()[0]
firetraps = self.findHazards()
# Remember that a Fire Trap will trigger if you move closer than 3 meters!
omarn = self.findByType("potion-master")[0]
if potion:
dest = potion.targetPos
# Go get the potion.
if self.isReady("dash"):
self.dash(potion.pos)
else:
self.move(potion.pos)
else:
if omarn and self.distanceTo(omarn) > 10:
# Move back to Omarn.
self.move(omarn.pos)
# Warning: isPathClear doesn't work with Hazards!
else:
self.say("Hup, hup!")``````

#17

You will need to use vectors to beat this level.

I made a poster with advice on how vectors work and showing the concepts needed to beat this level. It on this post

You can also just use the same concepts as in the previous level.

#18

i don’t get it?