Amaze the maze - Pi bakery

By Russell Barnes. Posted

Explore the complexity of a moving-barrier maze and let your Raspberry Pi help you navigate it

Here at Mike’s Pi Bakery we have always been interested in mazes. The problem tends to be that most mazes are either too open and simple, or too dense and complex. However, recently we came across the Amaze from ThinkFun. This is a maze with a difference: it’s quite open, but it’s not immediately apparent how to complete it. This is due to four rows of movable barriers on every third line. These barriers can be pushed in the direction that your maze-following pen allows, so the path from start to finish is not initially visible.

The full article can be found in The MagPi 39 and was written by Mike Cook

The game is purely mechanical, but when we got it home we saw that by interfacing it to a Raspberry Pi we could add some fun to the game, both in setup and play. Basically, with four sliders that can be set either left or right, there are 16 possible ways to configure the maze. The instruction leaflet shows each combination of left and right for an increasingly complicated maze. Furthermore, there is a table telling you which slider you have to push, and in what order, to complete the maze. Of course, even if you got the correct order of pushing, there’s no guarantee that you could finish the maze because it matters where in the barrier you pushed it, and they aren’t telling you that. What makes this table a bit messy is that you can see all the solutions at once; with a computer interface, not only could you simply select the maze’s complexity, but also tailor the sort of help you’re given. Add to that the inclusion of sound effects, and the magic of seeing the on-screen graphics reflect the real-life hardware, and you have all the ingredients for a worthy Bakery project.

You'll need

  • Amaze game by ThinkFun
  • 4× SFH3410 light sensors
  • 4× pieces of 3- by 4- hole stripboard
  • An 8-pin header socket
  • 5× 300mm wires with crimped female header sockets
  • Insulating tape & hot-melt glue

The project

We needed a way to interface the Raspberry Pi to the game so that it could read the position of each of the sliders; when you move them, the Pi should be able to read the new position and reflect that on the screen. A careful examination of the sliders showed that the round spots at the end covered up or revealed the plastic for the lower half of the case. We thought that a strategically placed phototransistor could detect the light difference between the two states of the slider, especially if a hole was drilled in the lower side. To increase the contrast we placed a piece of black insulating tape on the underside of the slider, because it was a bit translucent. To simplify the electronics circuitry even further, we used a phototransistor attached directly into a digital input and allowed the internal pull-up resistor to act as the load. The only downside to this was that we had to ensure there was sufficient light reaching the phototransistor down a rather narrow hole. If there is insufficient light to register a logic low on the GPIO pin, then a small anglepoise lamp can be aimed at the sliders. The schematic of the sensor interface is shown below; we chose the small phototransistor SFH3410 to use here because it was cheap and flat enough to sit in the underside well of the game.

 The schematic of the slide position sensors

Making the interface

Start off by drilling a hole in the middle of each slider position. Move all the sliders to the right, exposing the base of the box through the slot. Then take a 2mm drill and drill a hole in the middle of the slot; the hole will emerge through the base on the underside. On the reverse, drill a similar-sized blind hole about 1cm away from the through hole. This is to act as a securing hole for the hot-melt glue you will use later.

 Drilling the sensor holes

Dismantle the Amaze by removing the four self-tapping screws, clean out any swarf created by the drilling, and fix a small length of black masking tape inside the back of the slider at the end you have drilled the hole. This reduces the light through a closed hole. You could use acrylic paint here if you like. Reassemble the box, taking care not to force the self-tapping screws back into the holes – if it feels stiff, then back off until you feel it click and then screw in again. You have to be careful not to strip the thread in the plastic.

 Fitting light baffles

Make up four sensor boards using small pieces of stripboard, and wire them up as shown in the diagram. We used a single-width 8-pin header socket to connect these wires to the Raspberry Pi’s GPIO connector PL1. The first three pin connections are empty, and the GPIO pins we used followed on from that. We marked the end of this connector with typing correction fluid to make sure we always connected it the correct way round to the Pi’s port. You could use a blob of white paint if you haven’t got any corrector fluid.

 Wiring up the sensors

Fix the boards to the back of the Amaze case with hot-melt glue. Make sure that you can see the black spot of the sensor through the hole from the other side before letting the glue set. Tack the board on at first to get the position correct, and then fill in the remaining spaces with glue. Make sure you do this in stages so as not to melt and disturb the initial positioning spot of glue. When set, cover all the sensor boards with a strip of black insulation tape to ensure a light, tight fitting for the back.

 Fixing the sensors

The screen display

Now to work on the screen display. We started off with a photograph of the Amaze and, using a photo-editing package, removed all the red partitions and slider indicator with the clone tool. We also removed the cord of the pen and this was then used as the basic background image, stored in an images directory at the same level as the main code. Then the program could draw in the red barriers in the appropriate place, depending on the position of the sliders. However, this looked a little jerky going from one position to the other, so we decided to animate the change in position so that it looked like a smooth movement. The results were quite impressive and certainly better than we were expecting. There are a lot of magic numbers involved here for the positions of the red barriers, but these were easily gathered by the program itself by getting it to print out the coordinates of every mouse click. This is commented out in the final code, but you can easily uncomment if you want to see them. The space for the pen holder in the image was used to show user messages, and the ‘Start’ and ‘Finish’ labels were used as clickable areas or buttons.

Testing the sensors

The first thing you want to do is to check out the sensors to see if you are getting enough light down through the holes when the slider uncovers them. For this you can use the Photo_test.py code:

# photo transistor input test
# for the Amaze game - Mike Cook September 2015
import time, os
import wiringpi2 as io

pinList = [22,27,17,4] # GPIO pins for sensor switches

def main():
   initGPIO()
   print"Amaze sensor switch test"
   while True:
      for i in range(0,4):
         print io.digitalRead(pinList[i])," ",
      print" "
      time.sleep(1)
      
def initGPIO():
   try :
      io.wiringPiSetupGpio()
   except :
      print"start IDLE with 'gksudo idle' from command line"
      os._exit(1)
   for pin in range (0,4):
      io.pinMode(pinList[pin],0)
      io.pullUpDnControl(pinList[pin],2) # input enable pull up

# Main program logic:
if __name__ == '__main__':    
    main()

This simply initialises the four GPIO pins as inputs, reads them at one-second intervals and prints out the value. Note here that a logic 1 indicates that there’s no light or not enough reaching the sensor, and a logic 0 shows that the sensor is detecting enough light to pull the pin low. For the test, expose all the sensors by moving all the sliders to the right, adjust the lighting so that all the sensors read zero, and then push the sliders to the left, making sure that each one goes to a logic 1.

Using the program

With the sensors in place and the light adjusted, it’s time to run the Amaze.py code listing. It’s a Pygame program, so clicking the close box or pressing ESC will quit the program. There’s a startup message printed to the Python console, but after that all communication is through the graphic display. The first thing to do is to select the maze number; these go from 1 to 16 and the bigger the number, the more complex the maze is. When you have selected the one you want, click on the Start label; the display will then move the sliders into the start position and you have to physically push the sliders to match this. When you have done this, you will be asked to set a help level; there are three of them. First, there is no help at all. Next, there is the validation of a slider move; that means if you move a slider, then you will be told if this was the correct slider to move. The final level of help tells you which slider is the next one to move; however, there is no indication of where in the slider you must push it, so it is still possible to trap yourself even if you move the correct slider. When you have finished or want to give up, click the on-screen Finish label and the whole process will start again. Let’s look at the code and see how this magic is worked.

How the code works

After the normal Pygame initialisation stuff there are four lists defined, one for each slider, containing a tuple with the x and y coordinate of the slide indicator and the start of each of the barriers. These lists are then combined into a list of lists. The same sort of thing is done with the maze solutions. For each initial starting slider configuration of a maze, there is a list of sliders to push, and this list is combined into a list of lists. Note here that while the sliders are numbered for the user as being 1 to 4, in the code these will be given the numbers 0 to 3, so when indicating the next slider to move a 1 must be added to the number in the list. The same goes for maze starting numbers, 1 to 16. This time the problem is resolved by putting a blank list as the first item in the list of lists. Next, the sounds are loaded in from a sounds directory.

The main function is mainly one infinite while loop; the first part calls the functions that set up the game, and the final while loop runs until the finish is indicated. The program only responds to a slider move once it’s running, and this is done by the updateSensors function. This function checks to see if any of the sensors indicate a different slider condition than the program has displayed; if so, then that slider is updated with the toggleSlider function. It first looks at the old slider state to see what direction it needs to move to. Then it performs the animation of moving the sliders; after that, it determines and displays any feedback messages. This function is also responsible for playing most of the feedback sounds. The checkForEvent function handles all the mouse clicks; there is a section commented out that will ‘push’ the sliders from the keyboard – useful for testing, but not for running the game.

Customisation

So, what can you do to add your own twist to this project? Well, the observant will have noticed that the clickable areas to set the maze number and help levels remain active at all times; you could make the program more robust by only allowing those clicks to affect the numbers at the correct time. You can do this simply by using a global Boolean variable in the click condition, and only setting those variables when the appropriate function is being executed. Also, when clicking the Start and Finish labels, it would be good to invert or highlight those areas to give some feedback. You might want to add white LEDs above each sensor so that the shadow of your hand doesn’t accidentally trigger the slide sensors. However, one big improvement you could make is to give help as to which barrier on the slider to push, but that would require quite a bit more work analysing the maze. Whatever you do, have fun.

Code listing

The full code for this project is quite long, so we suggest heading over to the GitHub page for it and downloading it!

From The MagPi store

Subscribe

Subscribe to the newsletter

Get every issue delivered directly to your inbox and keep up to date with the latest news, offers, events, and more.