I took a break from the intense book schedule this weekend (don’t worry everything is on schedule). Was reading about Commodore’s one-liner maze when it struck me.
I wondered - why not make some one-liner games in Python? And just to make it insanely hard, I would try to make it fit a tweet i.e. 140 characters. Let’s see what we could manage.
NOTE: All the one-liners below work only in Python 3. Depending on your platform, you might want to change the code by replacing python
with python3
.
Maze
python -c "while 1:import random;print(random.choice('|| __'), end='')"
Create an infinite maze with this deceptively short one-liner. It is quite easy to understand too. The while
loop is infinite. The import
statement had to move inside the loop but Python takes care not to re-import it each time.
A random character is picked from one of the maze drawing characters and printed. An alternate version below has better maze drawing characters. But this version used characters which were displayable on the Windows shell (and possibly portable to other operating systems).
Prettier Version
python -c "while 1:import random;print(random.choice('╱╲'), end='')"
This version uses two Unicode characters. The maze walls look more connected in this version and the viewing angle is interestingly skewed.
If you are more interested in the history and phenomenon of these one-liner mazes, then I suggest you check out the book 10 PRINT, which can be freely downloaded.
Crash!
Crash is a homage to the BASIC era games like Lunar Lander. Watch an out-of-control spaceship fall into earth. You need to freeze time (i.e. Ctrl+Break) just before it hits the cliff walls.
python -c "while 1:locals().setdefault('i',60);import time,random;print(' '*i+'<>'+' '*(80-i-1)+'|');time.sleep(.1);i+=random.randint(-2,2)"
Once again, we rely on while
to create an infinite loop. Since the whole code is wrapped in a loop, we cannot initialise the spaceship position i
. Unless, of course, we setdefault
the locals()
dictionary directly.
The print
statement pads spaces i
times to offset the ship’s symbolic representation. Then a slight delay is introduced for a convincing animation and the ship’s position is randomly shifted left or right. This put together gives the mesmerising effect of a swerving ship.
Slot Machine
Back when we were kids, we had a handheld toy slot machine with plastic rollers. We used to love spinning it until the three 7s aligned and everyone used to yell - Jackpot!
python -c "import random;p=lambda:random.choice('7♪♫♣♠♦♥◄☼☽');[print('|'.join([p(),p(),p()]),end='\r') for i in range(8**5)]"
This is one of the most fun games here. Essentially it needs three independent random number generators. Using a lambda
function was the obvious choice for the generator so that you could invoke it thrice.
I used a variety of fun-looking Unicode characters that rendered correctly even on a Windows shell. Using the \r
(carriage return) terminator for print
makes it overwrite the same line; giving the illusion of animation. Finally, 8**5
was chosen as a compact large number that completes looping in a reasonable time.
Slightly Longer Version
python -c "import random,time;p=lambda:random.choice('7♪♫♣♠♦♥◄☼☽');[print('[{}|{}|{}]'.format(p(),p(),p(),t=time.sleep(.1)),end='\r') for i in range(20)]"
This version is slightly more satisfying since you can actually see the symbols as they change. The printed representation is also slightly better. However, these changes made it exceed the length of a tweet.
100 Feet Golf
Inspired by Pingu Throw (and possibly Angry Birds), this game allows you to choose the angle and velocity of a golf ball. The objective is to make it fall exactly in a hole at the hundredth feet, no more no less.
python -c "import math as m;a,v=eval(input());[print('%03d'%x+' '*m.floor(0.5+x*m.tan(a)-x*x/(v*m.cos(a)))+'o') for x in range(102)]"
Entering the two values is slightly clumsy due to the length restrictions. You need to input a tuple having two numbers like (0.9,120)
- the first number is the angle in radians and the second number is the velocity (in some arbitrary unit). Due to the use of the infamous eval
statement and subsequent tuple unpacking, input in any other form will not work.
The remaining list comprehension is basically a for
loop with a print
function. The ‘height’ of the golf ball is calculated by a simplified form of the actual physics formula to compute projectile trajectories.
The range is chosen to be slightly more than, the expected, 100 to give an idea of the trajectory in case you overshoot.
Slightly Longer Version
python -c "import math as m;a,v=m.radians(float(input())),float(input());[print('{:03}:'.format(x)+' '*m.floor(0.5+x*m.tan(a)-x*x/(v*m.cos(a)))+'o') for x in range(102)]"
This version has a more sane method of entering values. The first input is the angle in degrees (thank god!) and the next input is the velocity. However, it exceeds the length of a tweet.
Number Guess
This is a classic game for new programmers. Rules are easy to understand - I am thinking of a number between 1 and 99. You can make a guess and I will tell if your guess is higher (‘H’) or lower (‘L’) than my number. You can make up to six guesses.
python -c "import random;n=random.randint(1,99);[(lambda a:print('Y' if a==n else 'H' if a>n else 'L'))(int(input())) for i in range(6)]"
Most of the techniques used here should look familiar - list comprehensions, lambdas and random integers. The lambda is needed since the input variable needs to be assigned (when the lamda gets called). The if else
short form is used as a ternary operator.
Upon a successful guess the game prints a ‘Y’. However, it doesn’t stop which is a possible drawback of this implementation.
As you might know, the best strategy is a binary search. To make the game more interesting, I have chosen the maximum number of guesses to be one less than the ideal to span the range.
How to Write One-liners in Python?
One-liners are notoriously hard to write in Python. You would be hard pressed to find examples of one-liners with the exception of the Python wiki.
What makes it so hard? Well, there are a couple of reasons:
- Whitespace-significance: This makes is quite hard to include block statements like
while
orfor
. Often the entire program is wrapped in one loop statement. - Verboseness: Unlike languages like Perl there are no short hand symbols say for commandline arguments or regular expressions
But Python is not devoid of merit for creating one-liners. Thanks to some great functional programming features it does have some advantages like:
- Lamdas: Defining functions in a line does come handy despite its limitations.
- List comprehensions: Readable yet terse constructs.
- Reflectiveness: Ability to edits its own local variables for instance is quite handy.
Overall, I am quite surprised by the kinds of games I could manage. My daughter and I had lots of fun playing and tweaking some of these games. They are probably the most fun I could get from one line of code.