# Obfuscating text by cycling ternary digits

The goal of this challenge is the write the shortest function/program to take input text, encrypt it using the method below, and return the result.

As an example, I will use the string hello world.

First, get the input text.

hello world


Second, convert the string into ternary (base 3). Use this key:

a = 000
b = 001
c = 002
d = 010
e = 011
f = 012
g = 020

...

w = 211
x = 212
y = 220
z = 221
[space] = 222


With this key, hello world becomes 021011102102112222211112122102010, as seen below.

 h   e   l   l   o       w   o   r   l   d
021 011 102 102 112 222 211 112 122 102 010


Third, move the first digit to the end.

021011102102112222211112122102010
becomes
210111021021122222111121221020100


Fourth, convert the number back into a string using the same key.

210 111 021 021 122 222 111 121 221 020 100
v   n   h   h   r       n   q   z   g   j


Lastly, return the encrypted text.

vnhhr nqzgj


Here are some sample text and their output:

the turtle ==> dvo fh ego

python ==> uudwqn

code golf ==> hpjoytqgp

As this is code golf, the shortest entry in bytes wins. Errors are allowed if some of the characters are not lowercase letters or space. This is my first challenge, so any suggestions would be more than helpful.

Good luck!

var QUESTION_ID=54643;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),e.has_more?getAnswers():process()}})}function shouldHaveHeading(e){var a=!1,r=e.body_markdown.split("\n");try{a|=/^#/.test(e.body_markdown),a|=["-","="].indexOf(r[1][0])>-1,a&=LANGUAGE_REG.test(e.body_markdown)}catch(n){}return a}function shouldHaveScore(e){var a=!1;try{a|=SIZE_REG.test(e.body_markdown.split("\n")[0])}catch(r){}return a}function getAuthorName(e){return e.owner.display_name}function process(){answers=answers.filter(shouldHaveScore).filter(shouldHaveHeading),answers.sort(function(e,a){var r=+(e.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0],n=+(a.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0];return r-n});var e={},a=1,r=null,n=1;answers.forEach(function(s){var t=s.body_markdown.split("\n")[0],o=jQuery("#answer-template").html(),l=(t.match(NUMBER_REG)[0],(t.match(SIZE_REG)||[0])[0]),c=t.match(LANGUAGE_REG)[1],i=getAuthorName(s);l!=r&&(n=a),r=l,++a,o=o.replace("{{PLACE}}",n+".").replace("{{NAME}}",i).replace("{{LANGUAGE}}",c).replace("{{SIZE}}",l).replace("{{LINK}}",s.share_link),o=jQuery(o),jQuery("#answers").append(o),e[c]=e[c]||{lang:c,user:i,size:l,link:s.share_link}});var s=[];for(var t in e)e.hasOwnProperty(t)&&s.push(e[t]);s.sort(function(e,a){return e.lang>a.lang?1:e.lang<a.lang?-1:0});for(var o=0;o<s.length;++o){var l=jQuery("#language-template").html(),t=s[o];l=l.replace("{{LANGUAGE}}",t.lang).replace("{{NAME}}",t.user).replace("{{SIZE}}",t.size).replace("{{LINK}}",t.link),l=jQuery(l),jQuery("#languages").append(l)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",answers=[],page=1;getAnswers();var SIZE_REG=/\d+(?=[^\d&]*(?:&lt;(?:s&gt;[^&]*&lt;\/s&gt;|[^&]+&gt;)[^\d&]*)*)/,NUMBER_REG=/\d+/,LANGUAGE_REG=/^#*\s*([^,]+)/; body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px} <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"><div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table></div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table></div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table><table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table> • Note that this technically is obfuscation, not encryption. There is no encryption key here. – John Dvorak Aug 14 '15 at 8:43 • @JanDvorak Will "cipher" work? – The Turtle Aug 14 '15 at 13:55 • To build on @JanDvorak's comment, I would describe this as an "encoding," which is a standard way of expressing data in a different format (e.g., you can express a bit string with hexadecimal encoding, or base64 encoding). – apsillers Aug 14 '15 at 19:26 • @JanDvorak Agreed -- I'd be more likely to call ROT13 "obfuscation" rather than "encoding" (even though it satisfies both definitions). Probably the most precise title would be "Obfuscate text by..." – apsillers Aug 14 '15 at 19:54 • @TheTurtle The idea was to pack the characters into a large integer (uint64) using increasing powers of 27. The displacement by one digit would then be equivalent to multiplying this large integer by 3, and the introduction of the first digit on the other end would simply be an addition. But there are complications, such as discarding the last "carry" (perhaps via a mod operation), and I couldn't get it to work with few bytes – Luis Mendo Aug 14 '15 at 23:29 ## 20 Answers # Pyth, 23 22 bytes sXc.<sXz=+GdJ^UK3K1KJG  Try it online: Regular Input / Test Suite Thanks to @isaacg for one byte. ### Explanation: sXc.<sXz=+GdJ^UK3K1KJG =+Gd append a space the G (preinitialized with the alphabet) K3 assign 3 to K J^UK K assign all 3-digit ternary numbers [[0,0,0], [0,0,1],...,[2,2,2]] to J Xz G J translate input from G to J s sum (join all ternary numbers to one big list) .< 1 rotate by 1 c K split into lists of size 3 X JG translate from J to G s join chars to string and print  • We had the same idea. I wrote a Pyth port of my CJam, then scrolled down and saw your answer :/ – Andrea Biondo Aug 14 '15 at 8:22 • You can save a byte by doing an augmented assignment to G instead of using N, e.g. =+Gd. – isaacg Aug 14 '15 at 8:43 • @isaacg thanks. – Jakube Aug 14 '15 at 8:47 # Pyth, 26 bytes J+Gds@LJiR3c.<s.DR9xLJz1 2  Try it online in the Pyth Compiler/Executor: demo | test cases ### Idea Assume all input characters have already been mapped to the integers that step 2 specifies. For every 3-digit ternary number, we have that xyz3 = 9x + 3y + z, so modular division by 9 yields quotient x and residue 3y + z. If the input is abc3 def3 ghi3, applying modular division to each yields a, 3b + c, d, 3e + f, g, 3h + i. After rotating the list from above one unit to the left, we can group the integers into pairs. This yields the list (3b + c, d), (3e + f, g), (3h + i, a). Now, if we convert (3y + z, w) from base 3 to integer, we obtain 3(3y + z) + w = 9y + 3z + w = zyw3. Thus, applying base conversion to the list of pairs gives us bcd3 efg3 hia3, which is precisely the result of rotating the concatenated ternary digits one unit to the left. All that's left to do is mapping the resulting integers back to characters. ### Code J+Gd Concatenate "a...z" (G) with " " (d) and save in J. L z For each character in the input(z): x J Compute its index in J. R For each index I: .D 9 Compute (I / 9, I % 9). s Concatenate the resulting pairs. .< 1 Rotate the resulting list one unit to the left. c 2 Split it back into pairs. R For each pair: i 3 Perform conversion from base 3 to integer. L For each resulting integer: @ J Select the element of J at that index. s Concatenate the resulting characters.  • Yeesh, in a few hours I got beaten by CJam and Pyth. :/ – kirbyfan64sos Aug 13 '15 at 21:05 • Wow! Can you write an explanation of how it works? I'm curious. :) – The Turtle Aug 13 '15 at 23:13 • @TheTurtle I've edited my answer. – Dennis Aug 14 '15 at 3:07 # Python 2, 96 s=input() r=y='' for c in s+s[0]:x=(ord(c)-97)%91;r+=y and chr((y%9*3+x/9-26)%91+32);y=x print r  Converts a character c to a value x as x=(ord(c)-97)%91, with the modulo affecting only space to convert it to 26. The reverse conversion is i to chr((i-26)%91+32), with the modulo only affecting i=26 to make it become spaces. We loop through the characters, noting the current value x and the previous value y. We use the last two ternary digits of y, found as y%9, and the first ternary digit of x, found as x/9. The value of the concatenation is y%9*3+x/9. There's probably some optimizations combining this arithmetic with the shifting by 97 and fixing of space. We make this loop around, we return to the first character of the string at the end. We also do one preparation loop to write in a previous value y, suppressing the character for the first loop when y has not yet been initialized. # CJam, 39 29 bytes The cool thing about this one is that it doesn't even use base conversion. q'{,97>S+:XZZm*:Yere_(+3/YXer  I just realized I had exactly the same idea as Jakube's Pyth answer. I actually ported this CJam code to Pyth before seeing his post, ending up with 25 bytes. Given it was my first Pyth golf I guess it's not too bad. # Explanation  e# Z = 3 q e# Push input string '{, e# Push ['\0' ... 'z'] 97> e# Keep ['a' ... 'z'] S+ e# Append space :X e# Assign "a...z " to X ZZm* e# Push 3rd cartesian power of [0 1 2] e# i.e. all 3-digit permutations of 0, 1, 2 e# (in lexicographical order) :Y e# Assign those permutations to Y er e# Translate input from X to Y e_ e# Flatten resulting 2D array (+ e# Rotate first element to the end 3/ e# Split back into 3-digit elements YXer e# Translate from Y to X  # CJam, 3029 27 bytes q'{,97>S+:Af#9fmd(+2/3fbAf=  Try it online in the CJam interpreter. The approach is the same as in my other answer, which is a port of this code to Pyth. ### How it works q e# Read from STDIN. '{, e# Push ['\0' ... 'z']. 97> e# Remove the first 97 elements (['\0' - '']). S+:A e# Append a space and save in A. f# e# Find the index of each input character in A. 9fmd e# Apply modular division by 9 to each index. (+ e# Shift out the first quotient and append it. 2/ e# Split into pairs. 3fb e# Convert each pair from base 3 to integer. Af= e# Select the corresponding elements from A.  # Pyth, 30 29 bytes K+Gdsm@Kid3c.<sm.[Z3jxKd3z1 3  Saved 1 byte thanks to @Jakube. Live demo and test cases. # Javascript (ES6), 175 bytes A one-liner! "Overuse of variable v award, anyone?" update: Now only uses variables called v, for total confusion! Thanks @vihan for saving 6 bytes! Thanks @Neil for saving 27 bytes!! v=>(([...v].map(v=>(v<"V"?53:v.charCodeAt()-70).toString(3).slice(1)).join)+v[0]).slice(1).match(/..?.?/g).map(v=>(v=String.fromCharCode(parseInt(v,3)+97))>"z"?" ":v).join  Defines an anonymous function. To use, add v= before the code to give the function a name, and call it like alert(v("hello world")) • You can use .slice(-3) to save 6 bytes, at which point you can use "00"+v to save another byte. (You could concatenate with a template but the resulting length is the same.) – Neil Aug 14 '15 at 20:20 • Actually, you can save a whole bunch of bytes by adding 27 to your values before converting them to base three, as that guarantees enough digits. .map(v=>(v<"V"?26:v.charCodeAt()-97).toString(3)).map(v=>("000"+v).slice(v.length)) then becomes .map(v=>(v<"V"?53:v.charCodeAt()-70).toString(3).slice(1)). – Neil Aug 14 '15 at 20:22 • @Neil Wow, that really shortened the code! It also made it a true 'one-liner', by removing the only intermediate variable. Thanks! – jrich Aug 14 '15 at 22:51 # Julia, 149 137 bytes My first golf! s->(j=join;b=j([base(3,i==' '?26:i-'a',3)for i=s]);r=b[2:end]*b[1:1];j([i==26?" ":i+'a'for i=[parseint(r[i:i+2],3)for i=1:3:length(r)]]))  (partially) ungolfed: f = s -> ( # join the ternary represenations: b = join([base(3, i == ' ' ? 26 : i - 'a',3) for i = s]); # rotate: r = b[2:end] * b[1:1]; # calculate the new numbers: n = [parseint(r[i:i+2],3) for i = 1:3:length(r)]; # convert back to characters: join([i == 26 ? " " : 'a' + i for i = n]) ) assert(f("hello world") == "vnhhr nqzgj") assert(f("the turtle") == "dvo fh ego") assert(f("python") == "uudwqn") assert(f("code golf") == "hpjoytqgp")  • You can use = rather than in for loops and you can use b[1] in place of b[1:1]. You also don't need a space between closing parens and for. – Alex A. Aug 13 '15 at 18:52 • @AlexA. Cheers for =, but b[1] returns a character, which can't be appended to a string with *. – kevinsa5 Aug 13 '15 at 18:53 • Oh right, forgot about that. – Alex A. Aug 13 '15 at 18:54 • @AlexA. The for trick is nifty. You can also have it directly after a close quote. I didn't realize the parser was that flexible. – kevinsa5 Aug 13 '15 at 19:01 • It can also directly follow a numeric literal, as can end. – Alex A. Aug 13 '15 at 19:02 # Javascript (ES6), 178, 172, 170 p=>{p=p.replace(' ','{');c="";l=p.length;for(i=0;i<l;){c+=String.fromCharCode(((p.charCodeAt(i)-97)%9)*3+(((p.charCodeAt((++i)%l)-97)/9)|0)+97)}return c.replace('{',' ')}  Replaced Math.floor with a bitwise or. Created an anonymous function. If I'm understanding correctly, this should fix my noobishness somewhat (thanks Dennis!) and get me another 2 bytes down. # Julia, 169 166 bytes s->(J=join;t=J(circshift(split(J([lpad(i<'a'?"222":base(3,int(i)-97),3,0)for i=s]),""),-1));J([c[j:j+2]=="222"?' ':char(parseint(c[j:j+2],3)+97)for j=1:3:length(t)]))  Ungolfed + explanation: function f(s::String) # Convert the input into a string in base 3, with space mapping to 222 b = join([lpad(i < 'a' ? "222" : base(3, int(i) - 97), 3, 0) for i = s]) # Split that into a vector of single digits and shift once p = circshift(split(b, ""), -1) # Join the shifted array back into a string t = join(p) # Convert groups of 3 back into characters c = [t[j:j+2] == "222" ? ' ' : char(parseint(t[j:j+2], 3) + 97) for j = 1:3:length(t)] # Return the joined string join(c) end  # Haskell, 160 bytes a!k|Just v<-lookup k a=v x=['a'..'z']++" " y="012";z=mapM id[y,y,y] m(a:u:r:i:s)=[u,r,i]:m(a:s) m[e,a,t]=[[a,t,e]] main=interactmap(zip z x!).m.(>>=(zip x z!))


Ugh, this feels way too lengthy, but at least I'm... beating Python somehow. And Ruby.

# Javascript (ES6), 141124 120 bytes

Believe it or not.... :-)

(t,i=0,c=w=>(t.charCodeAt(w)-123)%91+26)=>String.fromCharCode(...[...t].map(k=>(c(i)%9*3+c(++i%t.length)/9+65|0)%91+32))


As with my other answer, this is an anonymous function, and needs to be assigned to a variable before it can be used. Try it here:

e=(t,i=0,c=w=>(t.charCodeAt(w)-123)%91+26)=>String.fromCharCode(...[...t].map(k=>(c(i)%9*3+c(++i%t.length)/9+65|0)%91+32));

input=document.getElementById("input");
p=document.getElementById("a");
setTimeout(function(){p.innerHTML = e(input.value);},10);
})
<form>Type your text here: <input type="text" id="input" value="hello world"/><br>
Only space and lowercase letters are allowed.</form>

<h3>Output:</h3>
<p id="a">vnhhr nqzgj</p>

I thought I might be able to shave a couple bytes off my previous answer by using a different technique, so I started out with one similar to Tekgno's and golfed my head off from there. I initialized some variables in the function's argument section, and again stuffed everything into a .map function. Then I realized the String.fromCharCode would be much more efficient outside the .map. After all was said and done, I had shaved off more than 30 45 bytes!

Edit 1: Saved 17 bytes by getting rid of the .replaces, using a technique similar to xnor's Python solution.

OK, maybe it's time to move onto another challenge....

# Python 2, 182 180 Bytes

This solution is not ideal, due to the replace being very costly.. Trying to figure out how to avoid that.

b=lambda k:k and b(k/3)*10+k%3
s=''.join('%03d'%b(ord(x)-6-91*(x>' '))for x in input())
print[chr(int((s[1:]+s[0])[i:i+3],3)+97)for i in range(0,len(s),3)][2::5].replace('{',' ')


Input is like "hello world".

• You need to count 2 bytes for required quotation marks in the input, right? – mbomb007 Aug 13 '15 at 19:51
• @mbomb007 That's what I had thought previously, but multiple people have told me I don't need to account for that. – Kade Aug 13 '15 at 20:10

# Mathematica, 162 bytes

r=Append[#->IntegerDigits[LetterNumber@#-1,3]~PadLeft~3&/@Alphabet[]," "->{2,2,2}];StringJoin[Partition[RotateLeft[Characters@#/.r//Flatten,1],3]/.(#2->#1&@@@r)]&


(Re)Using a Rule to convert the digit lists to characters and back.

# Javascript (ES6), 179 bytes

s=>[...s+s[0]].map(q=>00${(q<'a'?26:q.charCodeAt(0)-97).toString(3)}.slice(-3)).join.slice(1,-2).match(/..?.?/g).map(q=>q>221?' ':String.fromCharCode(parseInt(q,3)+97)).join  Props to vihan for the .match regex. # Ruby, 177 Needs at least Ruby 1.9 for the each_char method l=[*('a'..'z'),' '];n=(0..26).map{|m|m=m.to_s(3).rjust 3,'0'};s='';gets.chomp.each_char{|x|s+=n[l.index x]};puts("#{s[1..-1]}#{s[0]}".scan(/.../).map{|i|i=l[n.index i]}.join '')  ## Java, 458 449 bytes It made me a little sad to determine that I could shave off 10 bytes by not using Java 8 streams and the map() method. Here is the golfed version: import org.apache.commons.lang.ArrayUtils;class A{public static void main(String[]a){int b=0;String[] c=new String[27];for(;b<27;++b)c[b]=String.format("%03d",Integer.valueOf(Integer.toString(b,3)));String d=a[0],e="abcdefghijklmnopqrstuvwxyz ",f="",g="";for(b=0;b<d.length();++b)f+=c[e.indexOf(d.substring(b,b+1))];f=f.substring(1)+f.charAt(0);for(b=0;b<f.length();b+=3)g+=e.charAt(ArrayUtils.indexOf(c,f.substring(b,b+3)));System.out.println(g);}}  Here is a much less golfed version. It is intended to be readable, but I make no guarantees. import org.apache.commons.lang.ArrayUtils; class A { public static void main(String[] a) { int b=0; String[] c = new String[27]; for (; b < 27; ++b) c[b] = String.format("%03d", Integer.valueOf(Integer.toString(b, 3))); String d = a[0], e = "abcdefghijklmnopqrstuvwxyz ", f = "", g = ""; for (b = 0; b < d.length(); ++b) f += c[e.indexOf(d.substring(b, b + 1))]; f = f.substring(1) + f.charAt(0); for (b = 0; b < f.length(); b += 3) g += e.charAt(ArrayUtils.indexOf(c, f.substring(b, b + 3))); System.out.println(g); } }  This program takes the string to convert as a command-line argument. If you want to have spaces in your input, you have to surround it with double quotes. I wanted to provide an example of using this from the command line, but I was unable to get this code to work outside of Eclipse. I never learned to use Java from the command line ^_^; You can probably get this running inside the IDE of your choice without too much trouble. • if you only use the ArrayUtils once using the fully qualified name inside the code is shorter than that import statement. see: codegolf.stackexchange.com/a/16100/10801 (bottom half of linked answer) – masterX244 Sep 28 '15 at 11:40 # Javascript (ES6), 181 180 bytes t=>((x=[...t].map(k=>00${(k<'!'?26:k.charCodeAt(0)-97).toString(3)}.slice(-3)).join).slice(1)+x[0]).match(/.../g).map(j=>j>221?' ':String.fromCharCode(parseInt(j,3)+97)).join


This is an anonymous function, so it needs to be given a name before it can be used. (E.g. encrypt=t=>...) Try it out here:

e=t=>((x=[...t].map(k=>00\${(k<'!'?26:k.charCodeAt(0)-97).toString(3)}.slice(-3)).join).slice(1)+x[0]).match(/.../g).map(j=>j>221?' ':String.fromCharCode(parseInt(j,3)+97)).join;

input=document.getElementById("input");
p=document.getElementById("a");
setTimeout(function(){p.innerHTML = e(input.value);},10);
})
<form>Type your text here: <input type="text" id="input" value="hello world"/><br>
Only space and lowercase letters are allowed.</form>

<h3>Output:</h3>
<p id="a">vnhhr nqzgj</p>

I started out using multiple variables and for loops instead of .map. I then golfed it in every possible way without changing the algorithm, which put me somewhere around 217 bytes. After taking a look at UndefinedFunction's answer, I managed to get it down to 195, and some inspection of Dendrobium's answer resulted in another 14 golfed off.

As far as I'm aware, I can't go any further or my result would be practically identical to Dendrobium's (except for being one character shorter!). Can anyone find the place where I saved one char? :-)

As usual, suggestions are gladly welcome!

• Thanks for the regex tip! I'm not sure how exactly the for-of loop could be worked into this one-line function, but perhaps it would save some space anyway. You can post your version if you like. – ETHproductions Aug 14 '15 at 15:09

## Matlab, 113 bytes

x=dec2base(strrep(input('','s'),' ','{')-97,3)';strrep(char(base2dec(reshape(x([2:end 1]),3,[])',3)+97)','{',' ')


Input is through stdin.

Example:

>> x=dec2base(strrep(input('','s'),' ','{')-97,3)';strrep(char(base2dec(reshape(x([2:end 1]),3,[])',3)+97)','{',' ')
hello world
ans =
vnhhr nqzgj


# Julia - 928761 54 bytes

s->join(32+(3(i=[s...]%91+579)%27+i[[2:end,1]]÷9)%91)


Ungolfed:

function f(s)
t=[s...];       # Convert the string into a char array
#
i=t%91+579          # Mod 91 drops the alpha characters to sit just
# below space, then 579 is added as a trick,
# equivalent to subtracting 6 and adding 9*65
v1=3i%27            # This shifts the bottom two ternary digits up
# and removes the first ternary digit
v2=i[[2:end,1]÷9    # This shifts the first ternary digit down and
# removes the bottom two ternary digits. [2:end,1]
# rotates the array to put the first value at the end
N=(v1+v2)%91+32     # this combines the ternary digits, then returns
# the values to the correct ASCII values
j=join(N)           # join the char array back to a string
return j
end


The trick may confuse you. Subtracting 6 moves 'a' down to zero after the mod. Adding 9*65 is equivalent to adding 65 to v1+v2, which is part of the process of restoring the values to their ascii values. You could replace i=t%91+579 with i=t%91-6, and then replace N=(v1+v2)%91+32 with N=(v1+v2+65)%91+32` to get the same result, but it requires one extra character.