Tic Tac Toe encoder/decoder

6

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.

Additional informations

  • 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.

Caridorc

Posted 2014-12-10T19:15:02.800

Reputation: 2 254

This is a code-golf. Which means that the code with the smallest bytes is the winner. Instead, you chose the one with the largest bytes. What's wrong with you ? – Optimizer – 2014-12-20T23:17:39.273

What happens when the result of the third step in encoding is grater than 26 ? – Optimizer – 2014-12-10T19:19:55.270

@optimizer It can't be: "OOO" is the max, it translates to "222" that translates to 26. – Caridorc – 2014-12-10T19:21:47.850

Oh, we only get 3 characters at a time ? Nobody mentioned that :) – Optimizer – 2014-12-10T19:22:14.370

Yes, as in Tic Tac Toe the max line lenght is 3. – Caridorc – 2014-12-10T19:23:36.790

X -> 1 but XO -> 210 ? instead of 120 ? – Optimizer – 2014-12-10T19:31:43.507

Also, 210 in trinary is 21 in decimal, not 19. – marinus – 2014-12-10T19:32:42.817

Wow acc. to his code, X -> 2. Totally unclear what he means here.. – Optimizer – 2014-12-10T19:34:09.263

X -> 2 means X should be replaced by 2 – Caridorc – 2014-12-10T19:35:49.453

1Also, should 1 mean a or 0 mean a ? because if 0 means a, then XXX, i.e. 26 means } – Optimizer – 2014-12-10T19:37:40.577

1@Optimizer 0 means a – Caridorc – 2014-12-10T20:01:14.093

@Optimizer The alphabet ends with a whitespace, so 26-> ' ' [whitespace] – Caridorc – 2014-12-10T20:03:11.243

1You have to put all these things in the questions as the spec. Do you believe that people will read the comments for sure ? – Optimizer – 2014-12-10T20:08:29.827

Answers

4

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.

Def

Posted 2014-12-10T19:15:02.800

Reputation: 602

Bit late to the party, but pretty please comment it? – aaaaaaa – 2016-06-28T06:22:28.357

4

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]);}}

Readable:

#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;}}

Readable:

#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;
    }
}

BMac

Posted 2014-12-10T19:15:02.800

Reputation: 2 118

3

CJam, 24 + 25 = 49 bytes

Encoder

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

Decoder

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

Try it online here

Optimizer

Posted 2014-12-10T19:15:02.800

Reputation: 25 836

3

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.

Qwertiy

Posted 2014-12-10T19:15:02.800

Reputation: 2 697

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 – 2018-09-15T23:24:08.453

Your encoder/decoder fail for space/XXX – Optimizer – 2014-12-10T20:23:43.557

@Optimizer I've fixed this bug. I have to read the task more carefully before posting an answer... – Qwertiy – 2014-12-10T20:45:19.100

3Not your fault. The spec kept on revealing itself in parts. – Optimizer – 2014-12-10T20:49:05.320

1

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" 

MickyT

Posted 2014-12-10T19:15:02.800

Reputation: 11 735

0

Reference answer, completely ungolfed:

# 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))

Caridorc

Posted 2014-12-10T19:15:02.800

Reputation: 2 254

I think you lost the leading spaces in the boards string in your decoder. – marinus – 2014-12-10T19:41:40.470

@optimizer: over here the first few lines show up as OO_ OO OO X_O, which would be mmmt. – marinus – 2014-12-10T19:48:02.620

@optimizer: oh wait, they're supposed to be right-aligned. duh. – marinus – 2014-12-10T19:49:32.303