99 Bottles of Beer

2016-10-22, post № 144

art, codegolf, poetry, programming, Pygame, #character-sparse code, #characters, #space-efficient, #StackExchange

I recently [1] found a five year old StackExchange thread talking about a programming challenge to recreate the marvelously imaginative lyrics of ‘99 Bottles of Beer’. The song goes as follows (whole lyrics can be viewed below).

99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 98 bottles of beer on the wall.
98 bottles of beer on the wall, 98 bottles of beer.
Take one down and pass it around, 97 bottles of beer on the wall.
97 bottles of beer on the wall, 97 bottles of beer.
Take one down and pass it around, 96 bottles of beer on the wall.
3 bottles of beer on the wall, 3 bottles of beer.
Take one down and pass it around, 2 bottles of beer on the wall.
2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.
1 bottle of beer on the wall, 1 bottle of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.

Of course, the real challenge is not to build a program that generates the lyrics but rather to do it with the least amount of characters [2]. To achieve this goal, I tried out various strategies, all written in Python.

The first strategy is to join a string generated by a for loop (𝟤𝟨𝟥 characters).

99-bottles-of-beer_d...-function.py; Python2, 264 bytes, 3 lines
a,b=" bottles of beer"," on the wall"
print"\n".join([str(n)+a+b+", "+str(n)+a+"."+"\nTake one down and pass it around, "+str(n-1)+[a,c][n<3]+b+".\n"for n in range(99,1,-1)])+"\n1"+c+b+", 1"+c+".\nGo to the store and buy some more, 99"+a+b+"."

The second, less efficient strategy is to use a function and recursion (𝟤𝟩𝟦 characters).

99-bottles-of-beer_d...-function.py; Python2, 275 bytes, 8 lines
a,b=" bottles of beer"," on the wall"
def f(n):
	if n>1:
		s="%d"%n+a+b+", %d"%n+a+".\nTake one down and pass it around, "+str(n-1)+[c,a][n>2]+b+".\n\n"+f(n-1)
	return s
print f(99)+"1"+c+b+", 1"+c+".\nGo to the store and buy some more, 99"+a+b+"."

The third is a bit more character-efficient, using lambda functions and recursion (𝟤𝟩𝟢 characters).

99-bottles-of-beer_d...gy-lambda.py; Python2, 271 bytes, 6 lines
a="%d bottle%s of beer"
b=" on the wall"
f=lambda i:a%(i,c[i>1])+b+", "+a%(i,c[i>1])+".\nTake one down and pass it around, "+a%(i-1,c[i>2])+b+".\n\n"
F=lambda i:f(i)+F(i-1)if i>0 else ""
print F(99)[:-65]+"Go to the store and buy some more, "+a%(99,"s")+b+"."

The fourth, final and most space-efficient [3] strategy is to use a while loop (𝟤𝟧𝟢 characters).

99-bottles-of-beer_d...egy-while.py; Python2, 251 bytes, 7 lines
a="%d bottle%s of beer"
b=" on the wall"
c=a+b+", "+a+"."
while i>1:s+=c%((i,"s")*2);i-=1;s+="\nTake one down and pass it around, "+a%(i,["","s"][i>1])+b+".\n\n"
print s+c%(1,"",1,"")+"\nGo to the store and buy some more, "+a%(99,"s")+b+"."

Menger Sponge II

2016-10-08, post № 143

Processing 3, programming, Python, #3D, #fractal, #three dimensions, #three-D, #three-dimensional

In July of 2015 I published my Menger Sponge post. As I said there, the true Menger Sponge is a three-dimensional object, but due to the lack of 3D-integration in Pygame, I only showed one of the six cube’s faces. The two-dimensional fractal is officially called Sierpiński carpet while the three-dimensional object is really called a Menger sponge.
To achieve the three-dimensional cube, I used Processing 3 together with its Python Mode.
The actual fractal is colored with a pseudo-randomly chosen color. All its smaller cubes then get a slight color shift. The cube rotates slowly, with a different speed on each of the three axes.


  • ‘Space’will advance the cube’s fractalness,
  • ‘q’ will save an image of the current fractal’s state.
Source code: menger-sponge-ii.pyde


2016-09-24, post № 142

MicroPython, programming, Python 3, #micro, #microcontroller, #pyboard

Being a big fan of Python [1], I recently got a MicroPython Board.
MicroPython is a simple to use micro controller which runs Python 3. To put code onto it, you simple mount it as you would do with a USB flash drive, copy your main.py to it and restart your MicroPython.
As a simple “Hello world.”-program, I wrote this counting script. Every time you press the built-in [2] button, it counts up by one. Using the four built-in LEDs and binary number representation, this counter can count from 𝟢 to 𝟣𝟧 and then wraps back.

Source code: microcounter.py


2016-09-10, post № 141

curses, programming, Python, #animation, #bit, #bits, #falling bits, #hacker, #hacking, #Matrix, #screensaver

Recreating the famous falling bit effect from Matrix using python and curses.The individual bit strips are separate entities, falling to the bottom and then being moved up again with a different 𝑥 value. They also get a random speed between one and five deciseconds.

Source code: j-trix.py

Collatz Conjecture

2016-09-03, post № 140

mathematics, programming, Pygame, Python, #3n+1, #three n plus one

The Collatz conjecture states that every positive integer 𝑘 > 𝟢 will — if you iteratively set 𝑘 to 𝑓 (𝑘) — result in 𝟣 (function shown beneath).
The graph beneath shows the path length of numbers from 𝟣 to 𝟣𝟢 𝟢𝟢𝟢. In this range, 𝟨 𝟣𝟩𝟢 is the number with the most steps, 𝟤𝟨𝟣.

f(k)={\begin{cases}\frac{k}{2}&{\text{if }}k\mod 2=0\\3\cdot k+1&{\text{if }}k\mod 2=1\end{cases}}
Source code: collatz-conjecture.py

Curses Cam

2016-08-27, post № 139

curses, programming, Pygame, Python, #camera, #color depth, #low resolution, #shell image, #.si, #text-based images

Normally a shell lets you input via a text command and outputs via a text message [1]. When using curses you can extend its capabilities and program for example games with limited graphics.
I wanted to go even further and built a Python script that — using Pygame’s camera module and curses — captures an image from an attached webcam (USB or built-in), transforms it and displays it on the shell.
Although both the resolution and the color depth are shrunk immensely, the resulting colored text on the shell often resembles the scene caught and has a nice visual effect.
There are two modes, camera and file viewer, which can be toggled by pressing ‘F1’. In camera mode you can see what the camera is seeing and snap a photo, which then will be saved to disk. In file viewer mode you can view the photos you took. The files will be saved in an out/ directory located in the current Python file’s directory. Saved photos have the file extension .si (“shell image”).
Unfortunately, Pygame’s camera module does neither work on Mac OS X nor on Windows. Thus this program is only properly usable under Linux [2] systems. You obviously also need a webcam or else you will not be able to take a picture.


  • ‘F1’ switches between camera and file viewer mode,
  • ‘Space’ saves the current photo as a .si file (only in camera mode),
  • Left or down arrow key decreases current file’s id (only in file viewer mode),
  • Right or up arrow key increases current file’s id (only in file viewer mode).
Source code: curses-cam.py

Jetris CE

2016-08-20, post № 138

curses, games, programming, Python, #bag, #bag method, #Tetris

This game’s challenge is
to arrange the falling blocks.
Stay alive forever.

Jetris Console Edition is my second Tetris clone (see Jetris for the first one). It is programmed in Python and uses the curses module to display all its graphics on the shell.
Despite it running purely on the shell, I managed to eliminate any noticeable graphics update bugs. Furthermore the code to clear lines differs immensely from Jetris and actually works properly.
To enhance gameplay I implemented the so-called bag method. Instead of choosing pieces at random, a bag gets filled with all seven possible pieces. Each time you get a new piece, that piece gets randomly chosen out of the bag. If the bag is empty, it gets refilled. That way it is ensured that there will be no more than twelve pieces between two identical pieces (worst-case scenario). Also there will no more than four ‘S’ or ‘Z’ pieces in a row which makes the game fairer.
The pieces initially fall at one pps (pixel per second) and the game runs at twelve tps (ticks per seconds). Every ten cleared lines the speed increases by one tick or one twelfth of a second until it stays at the minimum speed, one twelfth of a second. [1]
The game’s clock is handled by a thread and graphics updates are made when they are needed (there are no fps).
To achieve the pieces blocky look I used two spaces and a color pair whose background color is the piece’s color. On the shell two fully filled characters look like a square.
You also have the option to change your key bindings — which get saved on disk —, pause the game and there is a high score list — which also gets saved on disk. The files are located where the Python code file resides.

Source code: jetris-ce.py

Web Sudoku Solver

2016-08-13, post № 137

Auto Hotkey, games, programming, Python, #AHK, #automatic, #fast times, #good times, #web, #Web Sudoku

In my last post I used Web Sudoku to get a Sudoku as an example for my solver.

After that I wanted to automate the process of looking up a Sudoku, solving it and typing it in. But while trying to get the Sudoku’s numbers, I noticed that the whole, solved Sudoku was stored in plaintext! (Look at this page’s source code.)
So I just needed to get that information, open the Web Sudoku page in a browser and type in the already solved Sudoku.

To accomplish said goal I used the python module urllib to get the Web Sudoku page’s source code and the module webbrowser to open the page in a browser. To type in the Sudoku I used AutoHotkey.

The finished program takes a level (easy, medium, hard or evil) and an id (the Sudoku’s identification number) to get a Sudoku, create an AHK file, execute it and open a web browser.
All you have to do is to click into the first box, press a key (‘F1’ in this case) and the Sudoku gets solved! You then just need to wait a minute, which is the minimum time Web Sudoku wants you to take to solve a Sudoku, and the AHK script hits enter.

You can get really good times with this:

Source code: web-sudoku-solver.py
Jonathan Frech's blog; built 2024/07/06 12:42:51 CEST