# Decode Polybus Square/Tap Code/Prison Code

The code has a lot of names, but is very simple:

  1 2 3 4 5
1 A B C D E
2 F G H I J
3 L M N O P
4 Q R S T U
5 V W X Y Z


A letter is coded by its coordinates, with the row first, then the column. Ex:

M = 3, 2
V
1 2 3 4 5
1 A B C D E
2 F G H I J
>3 L M N O P
4 Q R S T U
5 V W X Y Z


Note the letter 'K' is missing, as a letter needs to be removed to make the alphabet fit in the grid. In some versions, the letter 'J' is removed but K is easier to remove because every line stays in order.

More info here on Wikipedia.

Challenge: Make a program that takes in a message encoded in this way, that outputs the decoded message. Input can be in any reasonable format.

23 15 31 31 34 52 34 42 31 14
23153131345234423114
etc


Are all reasonable input formats. Standard loopholes apply.

## Test Cases

23 15 31 31 34 52 34 42 31 14 => HELLOWORLD
24 25 31 32 => IJLM
11 22 33 44 55 => AGNTZ

• Can we take the input 0-based? Mar 27 at 21:36
• @Jonah I'm going to say no, as the purpose of the tap code is that the numbers can be tapped, which 0 cannot. Mar 28 at 2:48
• it's Polybius
– ngn
Jun 18 at 5:51

# Python 2,  40  39 bytes

-1 thanks to kops! (Multiply before integer division)

lambda a:[chr(r*16/3+c+59)for r,c in a]


An unnamed function accepting an iterable of pairs which returns a list of characters.

Try it online!

• 39 bytes by unapplying the distributive property.
– kops
Mar 27 at 20:19
• Nicely done @kops, thanks! Mar 27 at 20:38

# J, 22 bytes

65(u:@+>&74)@+[:5&#.<:


Try it online!

• [:5&#.<: Decrement each input value <: and interpret every resulting 2-element pair as a base 5 number 5&#..
• 65...@+ Add 65 to each (to make it an ascii value), and...
• u:@+>&74 Add 1 more to each number greater than 74 +>&74 to adjust for the missing K. Finally, convert the result to a character u:@.

# Jelly, 10 bytes

ḅ5<⁴ạƊ+60Ọ


Try it online!

A completely different approach.

## Explanation

ḅ5<⁴ạƊ+60Ọ   Main monadic link
All following operations are automatically vectorized.
ḅ5           Convert from base 5
ạƊ       Absolute difference with
<⁴           1 if it's less than 16, else 0
+60    Add 60
Ọ   Convert to character


# brainfuck, 85 bytes

,[>++++++++[<------>-],<[>+++++>>[>]+[<]<<-]>+++++++++++>>>>[<<<<+>>>>-]<<<<.>>>>>>,]


Try it online!

## Explanation

,  Read a character
[  While not at the end of input
>++++++++[<------>-]  Subtract 48 to get the actual number
,  Read another character
<[>+++++>>[>]+[<]<<-]  Add 5 times the number to the character and also expand the number into a group of 1s
>+++++++++++  Add 11 to the character to turn it into a letter
>>>>  Go to the third item in the group of 1s
[<<<<+>>>>-]  If it's a 1 then add 1 to the character
<<<<.  Print the character
>>>>>>  Skip past the dirty memory cells
,  Read a new character
]


# Jelly, 10 bytes

ØAḟ”Ks5⁸œị


Try it online!

-1 byte thanks to Jonathan Allan!

## How it works

ØAḟ”Ks5⁸œị - Main link. Takes a list of pairs P on the left
ØA         - Yield the uppercase alphabet
ḟ”K      - Filter out "K"
s5    - Split into a 5x5 matrix, S
⁸   - Yield P
œị - For each pair [A, B] in P,
get the B'th element of the A'th row of S

• I had ØAḟ”Ks5⁸œị Mar 27 at 19:52
• @JonathanAllan Ah, clever use of dyad-nilad pairs! Mar 27 at 19:53

# brainfuck, 78 bytes

,[<<-[----->+>-<<]>>+>,<[>+>]<<[<]>>+[>+>]<<[<]>[--->>+<<]>[->+++++<]>--.>>>,]


Try it online!

Takes input for each letter as 2 ascii encoded digits.

Explanation

Essentially the formula is 65+[Row ASCII - 49]*5+[Column ASCII -49]+[1 if row >2] .

The row ASCII value is reduced by 49, but the column ASCII offset is calculated as

 65-49 = 16 = 17-2+1 plus an additional 1 if in row 3 onwards.


The approach is quite different to the existing brainfuck answer.

,[<<             Take an input for row value into cell 0 to get started then move to cell minus 2
-[----->+>-<<]   make cell minus 1 equal 255/5=51 and also subtract this number from input
>>+>,<           add 1 to row value in cell 0 and input column value into cell 1
[>+>]<<[<]       if cell 0 not 0  row input was not 2 so add 1 to column value
>>+              add 1 to row value in cell 0 so now it is 49 minus the input / note ASCII 49 is 1
[>+>]<<[<]       if cell 0 not 0 row input was not 1 so add 1 to column value
>[--->>+<<]      add 51/3=17 to column value
>[->+++++<]      add 5 times row value to column value
>--.             subtract 2 from column value and output letter
>>>,]            skip 3 dirty cells and take next row input


# Haskell, 39 37 bytes

map(\(r,c)->[';'..]!!(r*5+c+rdiv3))


Try it online!

• saved 2 thanks to @cole
• I think you can leave off the g= because it’s a valid function without a binding.
– cole
Mar 28 at 18:51

# JavaScript (Node.js), 42 bytes

a=>Buffer(a.map(([y,x])=>+x+y*16/3+59))+''


Try it online!

Takes an array of strings.

# convey, 568 bytes

{:v
1v
v#<   0
v^<<<<(<
v9     ^9
v+2v'A'^+2
"=>!}  ^*5v'Z'
v9     "=>!}
v+3v'B'^9
"=>!}  ^*6v'Y'
v9     "=>!}
v+4v'C'^9
"=>!}  ^*6
v9     ^-1v'X'
v+5v'D'"=>!}
"=>!}  ^9
v9     ^+4
v+6v'E'^*4v'W'
"=>!}  "=>!}
v7     ^9
v*3v'F'^+8
"=>!}  ^*3v'V'
v9     "=>!}
v+2    ^9
v*2v'G'^*5v'U'
"=>!}  "=>!}
v9     ^9
v+9    ^+2
v+5v'H'^*4v'T'
"=>!}  "=>!}
v6     ^9
v*4v'I'^*4
"=>!}  ^+7v'S'
v5     "=>!}
v*5v'J'^7
"=>!}  ^*6v'R'
v9     "=>!}
v*3    ^9
v+4v'L'^*4
"=>!}  ^+5v'Q'
v8     "=>!}
v*4v'M'^5
"=>!}  ^*7v'P'
v9     "=>!}
v+2    ^9
v*3v'N'^+8
"=>!}  ^*2v'O'
>>>>>>>"=>!}


And here's a picture of the factory (the gif thing kept crashing):

The basic idea is that there is a massive loop which lets one value through at a time. It goes through every letter. Note: Some things which appear to be golfable aren't due to interpreter glitches.

Try it online!

I can't believe Brainfuck is beating this :( - Convey has terrible string handling, so this is the only answer where it implicitly checks every single letter...

# Scala, 37 36 bytes

Saved 1 byte thanks to @xigoi, who suggested applying @kops's suggestion to Jonathan Allan's answer.

_.map{case(r,c)=>r*16/3+c+59 toChar}


Try it online!

Now simply a port of Jonathan Allan's Python answer, which you should upvote!

Outputs a list of characters.

• The Python answer was golfed by one byte, which can also apply to your answer: Try it online! Mar 28 at 7:42
• @xigoi Thanks, I've added it
– user
Mar 28 at 15:58

# 05AB1E, 13 12 bytes

<ε5β}Au'Kмsè


Try it online!

-1 byte thanks to Makonede. Outputs as a list of characters

## How it works

<ε5β}Au'Kмsè - Program. Takes an input of a list of pairs P
<            - Decrement to use 0-indexing
ε  }        - Over each pair [A, B]:
5β         -   Convert from base 5, yielding 5A+B
Au      - Push the uppercase alphabet
'K    - Push "K"
м   - Remove "K" from the alphabet
sè - Index into this modified alphabet

• -1 without the J, as a list of characters is technically a string and therefore is acceptable. Also, м can be K if you want Mar 28 at 23:05
• @Makonede Nice, I wasn't sure if outputting as a list of characters was allowed or not Mar 28 at 23:07
• Yeah, it's also what saved me one byte here Mar 29 at 0:22

# Charcoal, 14 bytes

⭆⪪⭆Ｓ⊖ι²§⁻αK⍘ι⁵


Try it online! Link is to verbose version of code. Explanation:

   Ｓ            Input string
⭆             Map over characters and join
ι          Current character
⊖           Decremented
⪪    ²         Split into pairs of digits
⭆               Map over pairs and join
ι   Current pair
⍘ ⁵  Convert from base 5
§        Index into
α      Predefined variable uppercase alphabet
⁻       Minus
K     Literal string K
Implicitly print


# K (ngn/k), 20 bytes

c${x+74<x}65+5/'-1+  Try it online! Uses @Jonah's method - don't forget to upvote him! # Jelly (fork), 10 bytes ’ḅ5ịØȦḟ”K¤  Try it online! (or rather, don't) ## How it works ’ḅ5ịØȦḟ”K¤ - Main link. Takes a list of pairs P on the left ’ - Decrement each integer to use 0-indexing ḅ5 - For each pair [A, B], yield 5A+B (convert from base 5) ¤ - Group the previous links into a nilad: ØȦ - Shifted alphabet; Yield "BCDE...XYZA" ḟ”K - Filter out "K" ị - Index into this modified alphabet  • Indexing from 0 is not allowed for this challenge. Mar 28 at 6:54 • @xigoi Frustrating, but fixed Mar 28 at 11:09 • the TIO link is only showing a 0 as output. Is something wrong? Mar 28 at 12:13 • @LevelRiverSt Yes, the (fork) in the header accidentally got removed when I updated the answer. This is a fork of Jelly, so isn't currently on TIO (has to be run locally) Mar 28 at 12:31 # Excel, 42 bytes =CONCAT(REPT(CHAR(A:A*16/3+B:B+59),A:A>0))  Another port of Johnathan Allan's Python Answer Input is 2 columns of cells. # Stax, 10 bytes ▄πKñ╜╓♥F⌂F  Run and debug it takes inputs as [column, row]. Based on Jonathan Allan's answer. # Befunge-93, 31 bytes ~:1+!#@_"0"-:2\5*+~"0"-+";"+,~  Try it online! ### Explanation ~ Get a char :1+!#@_ If at the end of the string, stop the execution (see if the char is -1) "0"- Get the row number :2\ If greater than 2, push a 1, otherwise a zero, swap the top two in the stack 5*+ Multiply by 5 and sum the 0/1 ~"0"-+ Get the col number and sum everything ";"+, Sum 59 to get the ASCII value of the char ~ Remove the space  # R, 37 bytes function(a)intToUtf8(a$x*16/3+a$y+59)  Try it online! Port of Jonathan Allan's Python answer. Takes input as a data frame with first digit in first column and second digit in second column. • I've been totally outgolfed!! That'll teach me not to look at the other answers... Well done... Mar 28 at 9:19 • 34 bytes if you don't mind outputting a list of letters... Mar 28 at 9:29 • @DominicvanEssen hmm, nice approach, but I'll pass. It seems that all answers output strings and the question allows flexible input, but doesn't mention flexible output :/ Mar 29 at 5:43 # Ruby, 34 bytes (31 bytes with Ruby 2.7) ->x{x.map{|i,j|(i*16/3+j+59).chr}}  A direct port of Johnathan Allan's Python answer. This lambda accepts an array of pairs and returns an array of characters. Try it online! ->x{x.map{(_1*16/3+_2+59).chr}} is written in 31 bytes and also works fine, but it requires Ruby 2.7 (not yet supported by TIO). # PowerShell 5+, 47 bytes Tribute to Metal gear 2: Solid Snake -join($args|%{(';'..'_'-ne'K')[5*$_[0]+$_[1]]})


Try it online!

# Perl 5-p, 34 bytes

s/(.)(.)/(A..J,L..Z)[5*$1-6+$2]/ge


Try it online!

# C (gcc), 75 bytes

main(int a,char**b){for(b++;**b;++*b)putchar(16+(a=**b-49)*5+(a>1)+*++*b);}


Try it online!

In the end, this is pretty straightforward and just uses C's willingness to be fluid about treating characters as integers. It runs through the characters in the first commandline argument, then uses a golfed version of this logic to map each one to the desired character.

'A' + (char1-'1')*5 + (char1-'1'>1) + (char2-'1')


The only trickery here is using the using the storage provided by the arguments to the main() call to avoid having to declare local variables. And the operator precedence in C means this jumble of punctuation,

+*++*b


does a number of things with just a few characters. That fragment, increments the pointer to the "current character" *b, then dereferences that location as a single character, implicitly converts it to an integer and adds it to the rest of the expression. The fact that +*++*, which looks more like Morse Code than C code, does something useful is pretty much why I decided to post this entry. :)

# APL (Dyalog Unicode), 33 15 bytes

Saved 18 bytes thanks to Razetime! (they also pointed out the answer was invalid)

⌷∘(5 5⍴⎕A~'K')¨


Try it online!

Takes a vector of pairs of numbers.

⌷∘(5 5⍴⎕A~'K')¨
¨ ⍝ For each pair in the input
⌷                ⍝ Index into:
⎕A        ⍝ Capital letters
~'K'   ⍝ Without 'K'
5 5⍴          ⍝ Reshaped into a 5x5 matrix

• are you sure this can handle multiple coordinates? Apr 8 at 5:58
• you can substitute the string for ⎕A~'K' Apr 8 at 5:59
• @Razetime You're right, it couldn't. Let that be a lesson to me to not golf after midnight on mobile :P Thanks for the tip!
– user
Apr 8 at 13:17

# Retina 0.8.2, 37 bytes

T d__9\EKPU |\b\d
+TdL__1-7L.\d


Try it online! Link includes test cases. Explanation:

T d__9\EKPU |\b\d


This does two things; it deletes all the spaces, and it replaces the first of each pair of digits with the characters 9EKPU respectively, these being the characters in the translation string below that precede the letters from the first column of the code.

+TdL__1-7L.\d


Repeatedly decrement the remaining digits and increment the preceding letter until the digits become zero, at which point they are deleted. Note that on the first pass the "letter" might actually be a 9, but this works because on the first pass of this loop all the "letters" will be paired with a digit.

# R, 62 bytes

function(x)for(i in x)cat(letters[(y=(i-1)%*%c(5,1)+1)+(y>9)])


Try it online!

Aaargh! I clicked submit and then saw pajonk's much shorter answer waiting for me! Upvote that one (and Jonathan Allan's one that it's based-on)!

# GolfScript, 22 bytes

~]2/{~\16*3/+59+}/]''+


Try it online!

Another port of @Jonathan Allen’s answer, and my first time trying out GolfScript. Input is just a series of numbers, separated by spaces, but you can separate number pairs with extra spaces for readability.

# PowerShell, 60 bytes

($a|%{[char][int][math]::floor($_[0]*16/3+\$_[1]+59)})-join''
`

Try it online!

Thanks to @JonathanAllan