The India Map C Program – Explained
Few months back, I came across an interesting piece of code:
#include <stdio.h> main() { int a,b,c; int count = 1; for (b=c=10;a="- FIGURE?, UMKC,XYZHello Folks,\ TFy!QJu ROo TNn(ROo)SLq SLq ULo+\ UHs UJq TNn*RPn/QPbEWS_JSWQAIJO^\ NBELPeHBFHT}TnALVlBLOFAkHFOuFETp\ HCStHAUFAgcEAelclcn^r^r\\tZvYxXy\ T|S~Pn SPm SOn TNn ULo0ULo#ULo-W\ Hq!WFs XDt!" [b+++21]; ) for(; a-- > 64 ; ) putchar ( ++c=='Z' ? c = c/ 9:33^b&1); return 0; }
This odd looking obfuscated C program has the following output:
!!!!!! !!!!!!!!!! !!!!!!!!!!!!!!! !!!!!!!!!!!!!! !!!!!!!!!!!!!!! !!!!!!!!!!!! !!!!!!!!!!!! !!!!!!!!!!!! !!!!!!!! !!!!!!!!!! !!!!!!!!!!!!!! !!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!! !!!!! !!!!!!!!!!!!!!!!!!! !!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!! ! !!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!! !!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!! !!!!!!!!!!!!!!! !!!!!!!!!!!!!! !!!!!!!!!!!! !!!!!!!!!!!! !!!!!!!!!!!! !!!!!!!! !!!!!! !!!!
Yes! That wired looking code prints the map of India. But a first look at the program did not reveal much as to how that is happening. So I decided to go ahead and do my own map of India program. And as always I had a lot of fun and a few new things to learn.
Here is my primary analysis of the program:
- This is a binary image (Just like a series of zeroes and ones). So it will take much less storage space than a conventional image. I don’t have to store each pixel color value. I need to somehow store how many pixels are on and how many are off.
- Looking at the program, one can clearly tell that the image data is somehow stored in this string:
"- FIGURE?, UMKC,XYZHello Folks,\ TFy!QJu ROo TNn(ROo)SLq SLq ULo+\ UHs UJq TNn*RPn/QPbEWS_JSWQAIJO^\ NBELPeHBFHT}TnALVlBLOFAkHFOuFETp\ HCStHAUFAgcEAelclcn^r^r\\tZvYxXy\ T|S~Pn SPm SOn TNn ULo0ULo#ULo-W\ Hq!WFs XDt!"
- The code is deliberately obfuscated. Better try and do this afresh.
Part 1: Creating the map data
At first I had to find a India map and get its binary data.
I got this India political map and converted it to a binary (black and white) image in Photoshop:
Now comes the interesting part. After 2 days of scratching my head, I realize that this can be achieved by something called as Run Length Encoding. This was already mentioned by someone in the original link but sadly I overlooked and wasted 2 days figuring it out myself. 😡 It works something like this:
The image is composed of several lines of pixels. Now if you pick up any line it will look something like this:
To store data corresponding to this line of the image, you do not need to store several pixels rather just the number of consecutive 1s and consecutive 0s. So this line of image data can be simply written as B7,3,3,2,1,1,14,2,10. Notice that we do not specify which number represents what color. That is because the colors appear alternatively in the sequence. We just mention the starting color, black in this case, as a prefix B. We can use W for white. So the code can be interpreted as
7 Blacks followed by 3 Whites followed by 3 Blacks followed by 2 Whites and so on.
So our image data will look something like this:
B7,3,3,2,1,1,14,2,10
W5,7,2,22,3,4
B2,20,21
B2,2,2,2,2,2,7,24
But can this be simplified further?
Yes. I did more simplifications to this:
- I wanted my code to have just alphanumeric characters (a-z,A-Z,0-9). The use of alphanumeric characters can reduce the data further so that I can write two decimal digits like ’14’ in one character only like, lets say, ‘M’. To do so, I re-sampled the image so that the total output width is less than 62, which is the total number of alphanumeric characters (26+26+10 = 62). This way, I can now represent each width by only 1 character. Another benefit of this is that I don’t have to use the comma (,) separator.
- I also wanted to remove the first color (B or W) from each line. I modified the image in such a way that each line always started with a B. So no need to mention that either.
This is the character encoding that I created for this purpose:
Width | Character | Width | Character | Width | Character | Width | Character |
1 | A | 21 | U | 41 | o | 61 | 9 |
2 | B | 22 | V | 42 | p | 62 | 0 |
3 | C | 23 | W | 43 | q | ||
4 | D | 24 | X | 44 | r | ||
5 | E | 25 | Y | 45 | s | ||
6 | F | 26 | Z | 46 | t | ||
7 | G | 27 | a | 47 | u | ||
8 | H | 28 | b | 48 | v | ||
9 | I | 29 | c | 49 | w | ||
10 | J | 30 | d | 50 | x | ||
11 | K | 31 | e | 51 | y | ||
12 | L | 32 | f | 52 | z | ||
13 | M | 33 | g | 53 | 1 | ||
14 | N | 34 | h | 54 | 2 | ||
15 | O | 35 | i | 55 | 3 | ||
16 | P | 36 | j | 56 | 4 | ||
17 | Q | 37 | k | 57 | 5 | ||
18 | R | 38 | l | 58 | 6 | ||
19 | S | 39 | m | 59 | 7 | ||
20 | T | 40 | n | 60 | 8 |
So using this new encoding, our code now looks like this:
GCCBAANB
EGBVCD
BTU
BBBBBBGX
And just one more thing:
I used ‘9’ as a line separator. Because that character will never be used since total width will never exceed 60. So finally the code looks something line this:
GCCBAANB9EGBVCD9BTU9BBBBBBGX
Part 2: Decoding the code to the map output
I think this part is pretty straightforward.
Given the map data (like GCCBAANB9EGBVCD9BTU9BBBBBBGX…) You simply loop through the map data to print the map back. That is exactly what this program does:
#include<stdio.h> main() { int c,m,i,j; for(i=0,m=1<<5|1;c="MBs9KFq9MMh9MKj9MJk9OGAAj9NIk9MLi9LNbAA" "BB9JOaHA9EABTMBEL9CeGCEGD9EkBLD9FkGEE9Ap" "FFE9ApEBABG9DnGBG9ClS9EBCdT9IcV9IZY9JXZ" "9JUc9JTd9KOh9LMi9MLi9MMh9NKi9OJi9PIi9PGk9RCm9" [(!(c-57)?(m=1<<5, printf("\n")):(m^=1)), i++];){for(j=0;(c-57) && (j++-c-(c<64?5:(c>90?-70:-64))); printf("%c",m)); } }
The output of my code is something like this:
!! !!!!!! !!!!!!!!!!!!! !!!!!!!!!!! !!!!!!!!!! !!!!!!! ! !!!!!!!!! !!!!!!!!!!!! !!!!!!!!!!!!!! ! !! !!!!!!!!!!!!!!! !!!!!!!! ! !!!!!!!!!!!!!!!!!!!! !! !!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! !!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!! !!!!!!!!!!!!! !!!!!!!!!!!! !!!!!!!!!!!!! !!!!!!!!!!! !!!!!!!!!! !!!!!!!!! !!!!!!! !!!
I will leave you to guess how the rest of it works. Thanks for reading so far 🙂
Let’s Connect!