# Tic Tac Toe encoder/decoder

James Bond is about to start a new mission and you are his computer scientist friend. As Tic Tac Toe is becoming more and more popular you decide that nothing would be more underhanded than a Tic Tac Toe encoder/decoder™.

For each line the decoder will follow the following steps:

• Convert from 'O','X' and ' ' [space] to trinary

• ' ' -> 0

• 'O' -> 1

• 'X' -> 2

• Convert from trinary to decimal

• Convert from decimal to letter

Example: "XO "

• 210

• 21

• v

The encoder will do the reverse.

As code is much more precise than words, see the reference answer below in which I give an example (very long) implementation of the problem in Python:

Your decoder should be able to decode all the messages encoded with my encoder correctly and my decoder should be able to decode all the messages encoded with your encoder.

This is code-golf, the shortest wins.

• 0 must be converted to a, the alphabet ends with a whitespace, so 26-> ' ' [whitespace]

• "XXX" is the max, it translates to "222" that translates to 26.

• As in Tic Tac Toe the max line lenght is 3.

• X -> 2 means X should be replaced by 2

• Encoder/Decoder

• The encoder goes from plaintext to code.
• The decoder goes from code to plaintext.
• What happens when the result of the third step in encoding is grater than 26 ? – Optimizer Dec 10 '14 at 19:19
• @optimizer It can't be: "OOO" is the max, it translates to "222" that translates to 26. – Caridorc Dec 10 '14 at 19:21
• Also, should 1 mean a or 0 mean a ? because if 0 means a, then XXX, i.e. 26 means } – Optimizer Dec 10 '14 at 19:37
• @Optimizer 0 means a – Caridorc Dec 10 '14 at 20:01
• You have to put all these things in the questions as the spec. Do you believe that people will read the comments for sure ? – Optimizer Dec 10 '14 at 20:08

## BRAINFUCK, 393 bytes (encoder only)

Guys, we're making something for James Bond. Languages like javascript and C are way too readable! If you want something that the russians will never understand, brainfuck is the only option. It's surly not the shortest or fastest option, but no-one will understand it (and, let's be honest, everyone loves brainfuck)

The code has a couple of limitations though, It only encodes and only one character at a time. Also it doesn't manually stop, you have the stop it after it spits out the output. But hey, it works. This is the code:

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


If you want to try it: just run the code with one capital letter as input.

If you want it commented just ask me nicely. A lot of things can be done better but I don't feel like optimizing it now (because brainfuck). Maybe I'll make a decoder too as reversing the process probably isn't that difficult.

• Bit late to the party, but pretty please comment it? – aaaaaaa Jun 28 '16 at 6:22

# C++, 168 + 135 = 303 bytes

EDIT: saved one byte by requiring uppercase input

I like doing these in C++ because I get to do all sorts of fun nastiness I would never ever do in C++ code.

Encoder (168):

Takes a string of uppercase letters and spaces as an argument.

#include<cstdio>
int main(int h,char**c){c[0][3]=0;for(c++;h=**c;c[0]++){h=h&32?26:h-65;for(int d=2,e;d+1;d--){h=(h-(e=h%3))/3;c[-1][d]=e&2?88:e*47+32;}printf(c[-1]);}}


#include<cstdio>
int main(int h,char**c)
{
c[0][3]=0;
for(c++;h=**c;c[0]++)
{
h=h&32?26:h-65;
for(int d=2,e;d+1;d--)
{
h=(h-(e=h%3))/3;
c[-1][d]=e&2?88:e*47+32;
}
printf(c[-1]);
}
}


Decoder (135):

Takes a string of X, O, and space as an argument.

#include<cstdio>
int b=9,v;int main(int h,char**c){for(c++;h=**c;c[0]++){v+=(h&16?2:h&1)*b;b/=3;if(!b)putchar(v==26?32:v+97),v=0,b=9;}}


#include<cstdio>
int b=9,v;
int main(int h,char**c)
{
for(c++;h=**c;c[0]++)
{
v+=(h&16?2:h&1)*b;
b/=3;
if(!b)putchar(v==26?32:v+97),v=0,b=9;
}
}


# CJam, 24 + 25 = 49 bytes

Encoder

qN/{:i40f/3b'a+_'{=S@?}%


Decoder

q{_Sc=26@'a-?Zb" OX"f=N}%


Try it online here

## Javascript, ES6, 157 chars

### Only encoder, 83

f=s=>s=="XXX"?" ":(parseInt(s.replace(/./g,x=>" OX".indexOf(x)),3)+10).toString(36)


### Only decoder, 77

g=s=>(parseInt(10+s,36)-10).toString(3).substr(-3).replace(/./g,x=>" OX"[x])


### Both, 157

p=parseInt;f=s=>s=="XXX"?" ":(p(s.replace(/./g,x=>" OX".indexOf(x)),3)+10).toString(36);g=s=>(p(10+s,36)-10).toString(3).substr(-3).replace(/./g,x=>" OX"[x])


### Test

console.log(x=["   ", "XO ", "XXX"], x=x.map(f), x.map(g))


PS: Tried to perform some optimization, but failed: resulting code was longer then just concatenation. I don't publish it as it also contains a bug, which had already been fixed.

• Your encoder/decoder fail for space/XXX – Optimizer Dec 10 '14 at 20:23
• @Optimizer I've fixed this bug. I have to read the task more carefully before posting an answer... – Qwertiy Dec 10 '14 at 20:45
• Not your fault. The spec kept on revealing itself in parts. – Optimizer Dec 10 '14 at 20:49
• Maybe my stupid actions will inspire you to improve something else: n=[36,3];r=s=>s.replace(/./g,x=>" OX"[x]||" OX".indexOf(x));f=(s,t,p=a=>(parseInt(a,n[1-t])+10-20*t).toString(n[t]))=>t?r(p(10+s).substr(-3)):s=="XXX"?" ":p(r(s)) usage: console.log(x=[" ", "XO ", "XXX"], x=x.map(z=>f(z,0)), x.map(z=>f(z,1))) – Mihail Malostanidis Sep 15 '18 at 23:24

## R, 121 + 115 = 236

I think I got the spec correct

Decoder Function 121

d=function(s){i=rev(as.integer(unlist(strsplit(chartr('XO ','210',s),''))));c(letters,' ')[sum(3^(0:(length(i)-1))*i)+1]}


Encoder Function 115

e=function(s){i=which(c(letters,' ')==s)-1;paste(chartr("210","XO ",c(i%/%9%%3,i%/%3%%3,i%%3)),sep='',collapse='')}


This only works on lower case characters. Is that a requirement?

Quick Test

> mapply(d,c("OO "," OO"," OO","X O","XXX"))
OO   OO  OO X O XXX
"m" "e" "e" "t" " "
> mapply(e,unlist(strsplit('meet ','')))
m     e     e     t
"OO " " OO" " OO" "X O" "XXX"


# Tic-Tac-Toe code encoder

def from_letter_to_decimal(letter):
alphabet = "abcdefghijklmnopqrstuvwxyz "
return alphabet.index(letter)

def from_decimal_to_trinary(decimal):
digits = []
while decimal:
digits.append(str(decimal % 3))
decimal //= 3
return ''.join(list(reversed((digits))))

def from_trinary_to_line(trinary):
replace_dict = {"0": " ",
"1": "O",
"2": "X"}
for char in replace_dict:
trinary = trinary.replace(char,replace_dict[char])
return trinary

def encode_letter(letter):
decimal = from_letter_to_decimal(letter)
trinary = from_decimal_to_trinary(decimal)
line = from_trinary_to_line(trinary)
return line

def encode_text(text):
return '\n'.join([encode_letter(letter) for letter in text])

print(encode_text("meet me under the red bridge"))


# Tic-Tac-Toe code decoder

boards = """
OO
OO
OO
X O
XXX
OO
OO
XXX
X X
OOO
O
OO
OXX
XXX
X O
XO
OO
XXX
OXX
OO
O
XXX
O
OXX
XX
O
X
OO

"""

def from_line_to_trinary(line):
replace_dict = {" ": "0",
"O": "1",
"X": "2"}
for char in replace_dict:
line = line.replace(char,replace_dict[char])
return line

def from_trinary_to_decimal(n):
result = 0
for position,i in enumerate(reversed(n)):
result += int(i) * 3**position
return result

def from_decimal_to_letter(n):
alphabet = "abcdefghijklmnopqrstuvwxyz "
return alphabet[n]

def decode_line(line):
trinary = from_line_to_trinary(line)
decimal = from_trinary_to_decimal(trinary)
letter = from_decimal_to_letter(decimal)
return letter

def decode_boards(boards):
return ''.join([decode_line(line) for line in boards.splitlines() if not line==""])

print(decode_boards(boards))

• I think you lost the leading spaces in the boards string in your decoder. – marinus Dec 10 '14 at 19:41
• @optimizer: over here the first few lines show up as OO_ OO OO X_O, which would be mmmt. – marinus Dec 10 '14 at 19:48
• @optimizer: oh wait, they're supposed to be right-aligned. duh. – marinus Dec 10 '14 at 19:49