There’s an old joke about the evolution of a programmer. It starts with the programmer in their infancy and typing:
Print “Hello World” and so the output returns:
The programmer continues to evolve. His coding knowledge increases and his code in the end of his evolution becomes a script of 5000 to 10,000 lines. What does the output return? You guessed it:
I often joked that I’d make a terrible developer. I over think everything, but the truth is, I may have just evolved too much and need to devolve to improve. There used to be a sign up on my door of my office years ago, put there by an Operations Manager that read-
Go away before I write an efficient script to replace you.
It wasn’t far off from the truth. My shell scripts made the world go round, but they also were built with a certain mindset design. There was almost always a wrapper shell script that called subsequent scripts to perform different tasks and arguments to do what was expected. This was the design and mindset of shell scripting I’d been taught by a great scripting teacher.
Now that I’ve been working in Python for the last four months, I’ve had to admit to myself that my mindset has to change. I need to move to the Pythonic way of thinking. What is Pythonic thinking? It is the particular style that has emerged over time trhough experience using the language by those that know it best. This challenge is also quite normal for anyone coming to Python. Doesn’t matter if the programmer is skilled at Java, C++ or Ruby Rails, they all go through it. Python is very efficient, but below, you’ll find a perfect example of how one can really work hard instead of smart, i.e. the Pythonic way.
Coding Hard, Not Coding Smart
For my latest project, after noting the lights and built in sounds for the Pibrella board add-on for the Raspberry Pi, I decided I wanted to create a gaming script that when combined with kids imagination, could be used in a variety of ways. The game, “Red Light, Green Light” was the source of the inspiration.
The requirements were as follows:
- Use the lights on the board to have different variations and times lit to mark movement.
- Use different sounds in conjunction with the lights to signal a change or an alarm when the game play must stop, (i.e. red light.)
- The game play must be random so that the players wouldn’t know which light would execute, (green for go, yellow for slow motion and red for stop movement) without human intervention.
Now I created the initial script to test the process without issue. I used the Pibrella and time modules-
import pibrella import time #start game with success and green light. During green, (25 seconds) people will move as fast as want. pibrella.buzzer.success() time.sleep(3) pibrella.buzzer.off() pibrella.light.green.on() time.sleep(25) pibrella.light.green.off() pNow lets go in slow motion. Signal the yellow alarm and then light for 15 seconds of slow motion movement. pibrella.buzzer.buzz( frequency ) pibrella.buzzer.note( 1 ) #this is the frequency for the Note A time.sleep(2) pibrella.buzzer.off() pibrella.light.yellow.on() time.sleep(15) pibrella.light.yellow.off() #Now for a stop movement or red light in the game. pibrella.light.red.pulse(2,4,2,1) #we’ll make the light pulse instead of just light up pibrella.buzzer.fail() time.sleep(2) pibrella.buzzer.off() pibrella.light.red.off()
Now this seems pretty straight forward, but now I wanted to add in the logic to have random runs on times and variations of colored light sequence. I started by duplicating the script and adding in different rotations and time. I planned on six different scripts with different amount of time included in it and rotations…about 150 lines of code when I finished.
Why? Because this is how I would have built in the logic to Shell scripts. I would have had a wrapper script that would call the other scripts to run different rotations to keep the players on their toes.
What’s the problem with this logic? It’s not the Pythonic way of doing things- secondary scripts called from a main script and adds to complexity that doesn’t belong in the code. It’s also the wrong way to teach python coding and would have added confusion to the class.
So how should these requirements be coded?
Pythonic Smart Instead of Coding Hard
The latest Python script looks very different from the first and it includes everything in one script, using three modules. I’ve added the Random module, which allows me to build out a random number generator that acts like a throw of a dice. Depending on the results, a different light and duration occurs. I chose six variations, three green, two yellow and one red. With the red, (throw on a six) there is a break to leave the execution of the script, but the code is built to run for 30 times as is.
import random import pibrella import time for x in range(1, 31): #run for 30 iterations dice_1 = random.randint(1, 6) #options, just like a die. if dice_1 == 1: pibrella.buzzer.success() time.sleep(3) pibrella.buzzer.off() pibrella.light.green.on() time.sleep(25) #green for 25 seconds pibrella.light.green.off() if dice_1 == 2: pibrella.buzzer.success() time.sleep(3) pibrella.buzzer.off() pibrella.light.green.on() time.sleep(15) #green for 15 seconds pibrella.light.green.off() if dice_1 == 3: pibrella.buzzer.success() time.sleep(3) pibrella.buzzer.off() pibrella.light.green.on() time.sleep(10) #green for 10 seconds pibrella.light.green.off() if dice_1 == 4: pibrella.buzzer.note( 1 ) #solid note for tone time.sleep(2) pibrella.buzzer.off() pibrella.light.yellow.on() time.sleep(25) #yellow for 25 seconds pibrella.light.yellow.off() if dice_1 == 5: pibrella.buzzer.note( 1 ) #solid note for tone time.sleep(2) pibrella.buzzer.off() pibrella.light.yellow.on() time.sleep(15) #yellow for 15 seconds pibrella.light.yellow.off() if dice_1 == 6: pibrella.light.red.pulse(2,4,2,1) #red, you’re done! pibrella.buzzer.fail() time.sleep(2) pibrella.buzzer.off() pibrella.light.red.off() break #escape out of the loop
What the Code Does
This code now randomly runs different variations of green and yellow with their notifying buzzer, up to 30 times or until it results in a “6”, which then will alarm, pulse the red light and exit out of the script. No other scripts or logic is required because I coded it with the Pythonic way of thinking.
To execute the code, looks like this:
sudo python <script_name>.py
Playing a Game with the Code
So what does this code look like when I remove the extended times in the lights so the random generations goes at an accelerated rate of change between each?
Just like this video…
Now I want you to imagine playing the game of Musical Chairs to this. Green means go fast for the time elapsed, (10, 15, 20 or 25 seconds…) Yellow requests all the players must go in slow motion, (which is also amusing for the spectators… :)) and then the red light, (and alarm) signifies everyone tries to immediately find a seat before there isn’t one left!
In a larger room, you could use it to play “Red Light, Green Light”. You could still expect the players to go in slow motion during the yellow iterations and just as in the standard game, anyone still moving when the alarm and red light go off, must return to the starting line.
The completion of the project, after working with the kids to create the code, test and verify, is then to ask them to use their imagination on how they would use the code or enhance it to play other games. The random libraries could easily be used for dice games, displaying the role and even incorporate more than one die for the game.
Until next time…