02 Jan 2017
Cracking the BBC's GCHQ Puzzlebook Challenge, Revisited
“This time with Go”
gchqgo01
image credit: quapona.com
  1. just to show I can code badly in more than one language!

This post is a follow up to my smash hit Cracking The BBC’S GCHQ Puzzlebook Challenge With Python

I made an abortive attempt to learn Go / Golang last year but never really got anywhere with it. Mainly, I think, because I tried to do too much fancy stuff too soon and got right in over my head, in a morass of package imports and more syntax than I could take on board at once.

Well, anyway, flushed with my success in managing to hack together some creaky Python code which actually worked to solve the aforementioned challenge —and what’s more, did so without relying on any external Python packages, I thought I might have another bash at Go and try and do the same in that language.

I’ll not walk through all the thinking behind what I was trying to do, as that’s all been covered in the previously mentioned post. This is pretty much just a record of me taking that Python code [at least the bits which were relevant to actually solving the puzzle] and translating them into Go, in my usual cack-handed fashion.

Let’s just make do with a quick recap of the coded message. As I said, if you want to know what this is all about, you can check out the previous Cracking The BBC’S GCHQ Puzzlebook Challenge With Python post for the nitty and the gritty.

gchqpuzzle02
image credit: BBC

Let’s go!…​

Those of you Gophers, who don’t like to see your favourite language being mutilated by a rank amateur may want to look away now!

1: Load up the coded message lines and Morse and Braille 'dictionaries'

Here’s the original Python version:

PYTHON

#coded message
messageline01 = ("IN AAAAIAN INAAANAIA IA IAINA AI AA IAIIA IAA AAIAAINN AA IAAANN IAINANI")
messageline02 = ("NA ANNNNMA NAANIANMN NN ANNAN NN AM MNNNN ANI MAAINNIA AM NNAMIA NNAANIN")
messageline03 = ("AM MMIAAMA MMIMAAMMA MM AMAAA MA AM AAAMA AAA MAMAAAAM AM AAIMMM MMMMAMA")


#braille alphabet
braille = {
'A':'100000',
'B':'101000',
'C':'110000',
'D':'110100',
'E':'100100',
'F':'111000',
'G':'111100',
'H':'101100',
'I':'011000',
'J':'011100',
'K':'100010',
'L':'101010',
'M':'110010',
'N':'110110',
'O':'100110',
'P':'111010',
'Q':'111110',
'R':'101110',
'S':'011010',
'T':'011110',
'U':'100011',
'V':'101011',
'W':'011101',
'X':'110011',
'Y':'110111',
'Z':'100111'
}

#morse code
morse = {
'A':'10',
'I':'11',
'M':'00',
'N':'01',
}

The Go version was pretty similar apart from we have to stick everything inside a main function and import the fmt package [the only one I allowed myself to use, as it’s needed for printing formatted strings to screen]. dictionariesin Go are called maps. In this case I’m making maps of strings to strings, to hold my Morse and Braille codes.

The syntax isn’t all that different from Python, but look out for the sneaky comma on the last item, which Python doesn’t need:

GO

package main

import (
"fmt"
)

func main() {

//coded message
messageline01 := "IN AAAAIAN INAAANAIA IA IAINA AI AA IAIIA IAA AAIAAINN AA IAAANN IAINANI"
messageline02 := "NA ANNNNMA NAANIANMN NN ANNAN NN AM MNNNN ANI MAAINNIA AM NNAMIA NNAANIN"
messageline03 := "AM MMIAAMA MMIMAAMMA MM AMAAA MA AM AAAMA AAA MAMAAAAM AM AAIMMM MMMMAMA"

//print to stop Go whingeing about unused vars
fmt.Println("\nMESSAGE:\n\n", messageline01, "\n", messageline02, "\n", messageline03)

//braille alphabet map
braille := map[string]string{
	"A": "100000",
	"B": "101000",
	"C": "110000",
	"D": "110100",
	"E": "100100",
	"F": "111000",
	"G": "111100",
	"H": "101100",
	"I": "011000",
	"J": "011100",
	"K": "100010",
	"L": "101010",
	"M": "110010",
	"N": "110110",
	"O": "100110",
	"P": "111010",
	"Q": "111110",
	"R": "101110",
	"S": "011010",
	"T": "011110",
	"U": "100011",
	"V": "101011",
	"W": "011101",
	"X": "110011",
	"Y": "110111",
	"Z": "100111",
}
//end braille alphabet map

//print to stop Go whingeing about unused vars
fmt.Println("\nBRAILLE MAP:\n\n", braille)

//morse code map
morse := map[string]string{
	"A": "10",
	"I": "11",
	"M": "00",
	"N": "01",
}
//end morse code map

//print to stop Go whingeing about unused vars
fmt.Println("\nMORSE MAP:\n\n", morse)

}//end main

One annoying [although probably well-intentioned] quirk of Go is that, if you declare a variable, you have to use it, otherwise your programme won’t compile. This makes it a bit tricky to incrementally add new stuff bit-by-bit. Hence my use of a lot of fmt.Println(<some variable>) lines, as I went along, just so the variables would be 'used' and the compiler would shut the fuck up and give me a chance to think.

2: Read the coded message in vertical 'triplets'

My next step in the Python version was to loop along the length of the line[s] in the coded message, reading vertically through the top, middle and bottom lines and adding each 'triplet' of letters thus derived into a vertmessage array:

PYTHON

#try building vertically
print("\n===========================================================")
print("MESSAGE - VERTICAL READING")
print("===========================================================\n")
vertmessage = []
for index in enumerate(messageline01):
#print("index --> ",index[0])
#take letters at a time from each line and group in threes
brailleletter = (messageline01[index[0]]+messageline02[index[0]]+messageline03[index[0]])
#print(brailleletter, end=" ")
vertmessage.append(brailleletter)

print("vertical message = ",vertmessage)

Although I’d set myself the challenge of keeping the Go code as similar as possible to my original Python wranglings, I had to do things a bit differently here and there. After initially fumbling about trying to build vertmessage as an array [or more exactly a slice] in Go, as I had in Python, I ended up just making it a string, as it turned out easier for me to work with, at my current level of incompetence.

GO

//try building vertically
fmt.Println("\n===========================================================")
fmt.Println("MESSAGE — VERTICAL READING")
fmt.Println("===========================================================\n")

//string to hold vertmessage
vertmessage := ""

//loop through length of message line
for i := 0; i < len(messageline01); i++ {
//if we're on a blank, add a space to the string
if string(messageline01[i]) == " " {
	vertmessage += " "
} else {
	//build morse triplet from vert letters
	morsetriplet := string(messageline01[i]) + string(messageline02[i]) + string(messageline03[i])
	//add to vertmessage
	vertmessage += morsetriplet
}
}
//end loop through length of message line

fmt.Println("VERTMESSAGE:\n\n", vertmessage)

Running and comparing the results of the code so far, Python gave me this:

Python

===========================================================
MESSAGE - VERTICAL READING
===========================================================

('vertical message = ', ['INA', 'NAM', '   ', 'AAM', 'ANM', 'ANI', 'ANA', 'INA', 'AMM', 'NAA', '   ', 'INM', 'NAM', 'AAI', 'ANM', 'AIA', 'NAA', 'ANM', 'IMM', 'ANA', '   ', 'INM', 'ANM', '   ', 'IAA', 'ANM', 'INA', 'NAA', 'ANA', '   ', 'ANM', 'INA', '   ', 'AAA', 'AMM', '   ', 'IMA', 'ANA', 'INA', 'INM', 'ANA', '   ', 'IAA', 'ANA', 'AIA', '   ', 'AMM', 'AAA', 'IAM', 'AIA', 'ANA', 'INA', 'NIA', 'NAM', '   ', 'AAA', 'AMM', '   ', 'INA', 'ANA', 'AAI', 'AMM', 'NIM', 'NAM', '   ', 'INM', 'ANM', 'IAM', 'NAM', 'ANA', 'NIM', 'INA'])

and Go gave me this:

Go

===========================================================
MESSAGE — VERTICAL READING
===========================================================

VERTMESSAGE:

INANAM AAMANMANIANAINAAMMNAA INMNAMAAIANMAIANAAANMIMMANA INMANM IAAANMINANAAANA ANMINA AAAAMM IMAANAINAINMANA IAAANAAIA AMMAAAIAMAIAANAINANIANAM AAAAMM INAANAAAIAMMNIMNAM INMANMIAMNAMANANIMINA

As I went along, it was actually helpful to be able to compare what Go was outputting with the already working Python code, because I made a few cock-ups along the way with the Go code, especially when iterating over strings in steps, later on.

All of which I’ve neatly air-brushed out ot history, here.

Right. So that’s the vertmessage created and, allowing for slight differences between it being an array in the Python version and a string in the Go version, the basic content was pretty much the same.

3: Look up the Morse and Braille codes

At this point in the Python version, I looped through the vertmessage array, taking each group of three letters in turn and and looking up the morse code for each one. Joining those three Morse codes together gave me a six digit 'Braille code' which I then looked up in the braille dictionary to find which letter of the alphabet it corresponded to.

I then added each of those letters into an esperanto string, finally printing this to screen. [If the selected group of three 'letters' in the vertmessage array turned out to be three spaces, I added a single space to the esperanto string, instead]

Python

print("\n===========================================================")
print("VERTICAL MESSAGE DECODING:")
print("===========================================================\n")
esperanto = ""
for section in vertmessage:
 #take 3 letters at a time and convert to morse
 #join 3 morse letters together to create braille letter
 #if the 'section' consists of 3 spaces, then interpret it s a single space between words'
 #yes. I know this is a bit clunky but it doesn't need regex!
 if section == "   ":
     esperanto += " "
 # 'section' wasn't a triple space, so look it up as a braille letter...
 # using the previous method
 else:
     brailleletter = (morse[section[0]]+morse[section[1]]+morse[section[2]])
 #lookup braille letter
     try:
         #if it exists, add it to the esperanto string
         esperanto += (list(braille.keys())[list(braille.values()).index(brailleletter)])
         #if it doesn't exist, print '?'
     except:
         esperanto += "?"
# print the constructed esperanto string
print(esperanto)
print("\n===========================================================\n")

For the Go version, I looped over the vertmessage string in steps of four, grabbing the next three letters from the string on each loop and then looking up the morse code for each one [just as I’d done with each group of three letters from the Python vertmessage array].

Exactly as before; joining those three Morse codes together gave me a six digit 'Braille code' which I then looked up in the braille dictionary to find which letter of the alphabet it corresponded to.

Again, I added each of those letters into an esperanto string, finally printing this to screen. [If the first letter I grabbed on any iteration through the loop was a space, I added a space to the esperanto string and then skipped forward one 'character' to grab the next letter]

GO

fmt.Println("\n===========================================================")
fmt.Println("VERTICAL MESSAGE DECODING:")
fmt.Println("===========================================================\n")

//create var to hold Esperanto string
esperanto := ""

//loop through length of vertmessage 3 at a time to select each morsetriplet
for i := 0; i < len(vertmessage); i += 3 {

	//if it's a blank, add a space and increment counter [ie. skip to next letter]
	if string(vertmessage[i]) == " " {
		esperanto += " "
		i += 1
	}

	//build a braille code to lookup from the morse triplets
	braillecode := morse[string(vertmessage[i])] + morse[string(vertmessage[i+1])] + morse[string(vertmessage[i+2])]

	//look up the braillecode in braille map
	for key, value := range braille {
		if value == braillecode {
			esperanto += key
		}
	}
	//end look up braillecode in braille map

}
//end loop through length of vertmessage 3 at a time

//print the constructed esperanto string
fmt.Println(esperanto)
fmt.Println("\n===========================================================\n")

It took me a while to get that last bit working, what with my still not quite having got my head around the fact that sometimes Go treats [what I think are] strings as arrays of bytes and at other times as strings. Hence why I’m having to cast vertmessage[i] to a string up there, in order to be able to look it up in the morse map.

Anyway, after all that, the results from each version output the same answer, so I knew that, reek of rancid haddock though it may well do, my Go code does what it’s supposed to.

4: Results

Python

===========================================================
VERTICAL MESSAGE DECODING:
===========================================================

NI BEZONAS DIVERSECO DE PENSO EN LA MONDO POR ALFRONTI LA NOVAJI DEFIOJN

===========================================================

Go

===========================================================
VERTICAL MESSAGE DECODING:
===========================================================

NI BEZONAS DIVERSECO DE PENSO EN LA MONDO POR ALFRONTI LA NOVAJI DEFIOJN

===========================================================

SNAP!

The astute Gopher will notice through his/her self-administered "eye bleach" that I didn’t build any error checking at all into the Go version. Lazy I know but, seeing as I already knew the code would do the job, if I could just work out how to translate my crappy Python into crappy Go, I allowed myself to commit the cardinal sin of not bothering to check for errors.

As with last time, anyone who wants to point and laugh at the code in its entirety can find it in this snippet on Bitbucket

Ciao!

Back to Top