Picture Puzzle: Name the City

A tricky little picture puzzle to test your decryption skills and a simple question: name the city.

Click on the picture for a larger version.

If that isn’t enough fun, this post includes some of the code used to generate the picture. If you understand the code, it will give you a big hint for solving the puzzle.

The image was created using the free POV-Ray raytracer. Generating raytraced images involves creating a virtual 3D world with objects and light sources and a camera. POV-Ray then calculates how light travels around the virtual world, bouncing off the objects, and creates the view that would be seen by the camera. The usual aim of raytacing calculations is to mimic real-world physics as much as possible to try to create a photo-realistic image.

I’ve been using POV-Ray since I was a teenager. The program has been around since 1992, and the original code dates back to 1986. It has long been surpassed by other free programs with many more features such as Blender.

The reason I still use POV-Ray for projects like this is its simplicity. Once you know the fundamentals, it is really easy to write a few lines of code to generate complex structures made up of basic objects like cubes and spheres. You’re always working directly with the guts of the program, which makes it a wonderfully easy way to create procedurally generated images.

The basic code for encrypting the city name and creating stacks of blocks was very quick to write. Making the image look nice took a lot more effort. I stole plenty of resources from tutorial projects packaged with POV-Ray. Another advantage of the program is how simple this is to do. Then I played around with lighting until I got something I liked.

A simplified version of my code is included below. The simplified version just uses plain white boxes with a single black letter rather than the colourful cubes of the main image. I’ve also left out the lighting and the camera so, if you want to recreate the image yourself, you’ll need to add those in.

// declare code and create variables
//declare a 10 letter codeword
#declare codeword="abcdefghij";
//put it in upper case
#declare codeword=strupr(codeword);
//declare the codeword length as a variable
#declare codelength=10;
//create an empty array
#declare codearray=array[codelength];
//loop through the codeword and turn each character into an ASCII representation,
//A=65, Z=90
//store the numbers in the array
#for(n,0,codelength-1,1)
#declare codearray[n]=asc(substr(codeword,n+1,1));
#end
// ------------------------------
// macros
// ------------------------------
// center the text using built-in functions
#macro centertext(Text)
#local MinText=min_extent(Text);
#local MaxText=max_extent(Text);
translate -(MinText+(MaxText-MinText)/2)
#end
//draw a box and write the letter "txt" on the front
#macro unitbox(txt)
#local Font="cyrvetic"
#local sFont=<0.76,0.76,0.05>;
#local s1=text { ttf Font txt 1, 0 scale sFont}
union{
box{,<0.49,0.49,0.49>
texture{pigment{rgb 0.95} finish{specular 0.2 roughness 0.1 diffuse 0.9}}
}
object{s1 centertext(s1) translate -0.5*z
texture{pigment {rgb 0.05} finish{specular 0.9 roughness 0.001 diffuse 0.6}}
}}}
#end
// ------------------------------
// create encryption and stack the cubes
// ------------------------------
//declare a maximum height for each stack
#declare maxheight=7;
//initialise a random number generator for the height of each stack
#declare codernd=seed(10);
//declare an array to store the height of each stack
#declare towerheightarray=array[codelength];
//declare an array to store a number representing the letter at the top of each stack
#declare topblockarray=array[codelength];
//loop through each letter of the codeword in turn and encrypt it
#for(i,0,codelength-1,1)
//randomly choose number of blocks to have in each stack, min of 2, max of maxheight
#declare towerheightarray[i]=floor(rand(codernd)*(maxheight-1)+1);
//encrypt codeword and assign a number to the top block of the stack
#declare topblockarray[i]=codearray[i]-2*towerheightarray[i]-1;
//check whether top letter is "less than" A, and cycle round to Z if so
#if(topblockarray[i]<65)
#declare topblockarray[i]=topblockarray[i]+26;
#end
#end
//create each stack based on the encryption
//loop through the codeword from left to right
#for(nx,0,codelength-1,1)
//loop though the stack vertically, placing cubes
#for(ny,0,towerheightarray[nx],1)
//check whether letter is "greater than" Z and cycle round to A if so
#if(topblockarray[nx]+ny>90)
#local chroffset=26;
#else
#local chroffset=0;
#end
//add a cube
object{
//create box with the correct letter written on the front
unitbox(chr(topblockarray[nx]-chroffset+ny))
//move the box to the correct place in the stack
translate
}
#end
#end