| Bytes | Lang | Time | Link |
|---|---|---|---|
| nan | APL Dyalog Unicode | 230726T170532Z | Adá |
| nan | Nibbles | 230726T125941Z | xigoi |
| nan | Scala | 230725T070134Z | 138 Aspe |
| nan | Excel | 230725T062716Z | Jos Wool |
| nan | Japt v1.4.5 | 221019T212558Z | Kamil Dr |
| nan | Ruby | 221019T211428Z | Jordan |
| nan | 221019T203308Z | bigyihsu | |
| 393 | BRAINFUCK | 141213T095156Z | Def |
| nan | C++ | 141211T073047Z | BMac |
| nan | R | 141210T220653Z | MickyT |
| 157 | Javascript | 141210T195018Z | Qwertiy |
| nan | CJam | 141210T194749Z | Optimize |
| nan | Reference answer | 141210T193250Z | Caridorc |
Nibbles, 12 + 14 = 26 bytes
Encoder, 12 bytes
.@.`@3%-$6 91=$"OX "
-1 byte thanks to Dominic van Essen
.@.`@3%-%$32~27=$"OX "
. For each character c in
@ the input as a string
. for each digit d in
`@3 convert to base 3
%$32 ord(c) mod 32
- ~ minus 1
% 27 mod 27
=$ take the d-th character (1-indexed, wrapping)
"OX " from "OX "
Decoder, 14 bytes
*" "`%.;@+`@3.$%/$10 3'a'"{"
*" "`%.;@+`@3.$%/$10 3'a'"{"
*" " Join by spaces
`% "{" split on '{' characters
. for each line l in
;@ the input as a list of lines
+ 'a' add the character code of 'a' to
`@3 convert from base 3
. for each character c in
$ l
/$10 ord(c) divided by 10
% 3 modulo 3
I realized later that I could've simply used ?"OX"$ instead of %/$10 3. The byte count is equal.
Scala, 90+107=197 bytes
Port of @Jordan's Ruby answer in Scala.
Encoder
Golfed version. Attempt This Online!
s=>(('A'to'Z')++Seq(' '))(Integer.parseInt(s.map{case'O'=>'1'case'X'=>'2'case' '=>'0'},3))
Ungolfed version. Attempt This Online!
object Main {
def main(args: Array[String]): Unit = {
def f(s: String): Char = {
val alphabet = ('A' to 'Z') ++ Seq(' ')
val mapped = s.map {
case 'O' => '1'
case 'X' => '2'
case ' ' => '0'
}
val idx = Integer.parseInt(mapped, 3)
alphabet(idx)
}
println("["++f("XO ").toString++"]")
println("["++f("XXX").toString++"]")
}
}
Decoder
Golfed version. Attempt This Online!
c=>{val n=if(c<'A')26 else c-'A';Integer.toString(n,3).map{case'0'=>' ';case'1'=>'O';case'2'=>'X'}.reverse}
Ungolfed version. Attempt This Online!
object Main {
def F(c: Char): String = {
val n = if (c < 'A') 26 else (c - 'A').toInt
val base3 = Integer.toString(n, 3)
base3.map {
case '0' => ' '
case '1' => 'O'
case '2' => 'X'
}.reverse
}
def main(args: Array[String]): Unit = {
println(F('V'))
println(F(' '))
}
}
Excel, 81 + 87 = 168 bytes
Encoder:
=CONCAT(SWITCH(0+MID(BASE(TEXT(CODE(A1)-97,"[=63]26"),3,3),{1,2,3},1),2,"X",1,"O"," "))
Decoder:
=CHAR(97+TEXT(MMULT(SWITCH(MID(A1,{1,2,3},1),"X",2,"O",1,),3^{2;1;0}),"[=26]63"))
Input in cell A1 in both cases.
Japt v1.4.5, 12 + 17 = 29 bytes
Encoder
;C+S gUn" OX
Decoder
;C+S aU s" OX" ù3
I tried some options that worked with codepoints rather than indexing into C+S, but they always ended up being longer in order to handle the space.
Explanations:
;C+S gUn" OX
; # C = "abcdefghijklmnopqrstuvwxyz"
C+S # Add a space to the end of C
g # Get the character at index:
U # Input string
n" OX # Converted to base 10 from base " OX"
;C+S aU s" OX" ù3
; # C = "abcdefghijklmnopqrstuvwxyz"
C+S # Add a space to the end of C
aU # Find the index of the input string
s" OX" # Convert to base " OX"
ù3 # Left pad with spaces to length 3
Ruby, 44 + 54 = 98 bytes
Encoder
->s{[*?A..?Z," "][s.tr(" OX","012").to_i 3]}
Decoder
->c{((c<?A??[:c).ord-65).digits(3).join.tr"012"," OX"}
Go, 372 bytes \$= 29 + 171 + 170\$
- Imports = 29 bytes
- Decoder = 171 bytes
- Encoder = 170 bytes
import(."strings";."strconv")
func d(s string)(k string){for _,l:=range Split(s,"\n"){i,_:=ParseInt(NewReplacer(" ","0","O","1","X","2").Replace(l),3,64)
k+=string('A'+i)}
return ReplaceAll(k,"["," ")}
func e(s string)(k string){q:=ReplaceAll(s," ","[")
for _,r:=range q{k+=NewReplacer("0"," ","1","O","2","X").Replace(FormatInt(int64(r-'A'),3))+"\n"}
return Trim(k,"\n")}
Explanation
Decoder
import(."strings";."strconv")
func d(s string)(k string){
for _,l:=range Split(s,"\n"){ // for each line...
i,_:=ParseInt( // turn the string into an int
NewReplacer(" ","0","O","1","X","2") // define the replacements
.Replace(l), // replace the chars
3,64) // turn it into trinary
k+=string('A'+i)} // append to the output string
return ReplaceAll(k,"["," ")} // replace `[` with spaces
Encoder
import(."strings";."strconv")
func e(s string)(k string){
q:=ReplaceAll(s," ","[") // replace `[` with spaces
for _,r:=range q{ // for each character...
k+=NewReplacer("0"," ","1","O","2","X") // define the replacements...
.Replace( // and apply onto...
FormatInt(int64(r-'A'),3)) // the character, turned into trinary
+"\n"} // and add a newline
return Trim(k,"\n")} // trim the final newline
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.
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;
}
}
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"
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.
CJam, 24 + 25 = 49 bytes
Encoder
qN/{:i40f/3b'a+_'{=S@?}%
Decoder
q{_Sc=26@'a-?Zb" OX"f=N}%
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))