# Incremental Cipher

This task is rather simple, and makes use of three distinct "operator" characters. Your task is, given a simple sequence of letters, perform the following task to encode it using <,>,*. You may choose to use either upper or lowercase letters, you do not have to handle both.

# Cipher Explanation

The cipher is simple, you're using increment and decrement operations to traverse from letter 1 to the end letter, with * being your "submit" function. The operator for "increment" will be > and "decrement" will be <.

An example using the word adbc:

• Start with the first letter of the word, output that letter. a
• Next, use > and < (like brainfuck) to "navigate" the current letter to the next one. a> would result in 'raising' a by 1 to the letter b. a< would result in z because you're lowering the letter (it wraps, you must always choose the direction resulting in the LEAST number of operations).
• After outputting the correct minimalized combination of < and > output a * to denote that we've reached the next letter.

The steps to encode adbc would be:

a          # a


# Examples

The steps to encode aza would be:

a       # a
a<*     # az
a<*>*   # aza


More examples:

"abcdef"    =  "a>*>*>*>*>*"
"zyaf"      =  "z<*>>*>>>>>*"
"zzzzzz"    =  "z*****"
"z"         =  "z"
"zm"        =  "z<<<<<<<<<<<<<*" or "z>>>>>>>>>>>>>*" (equidistant)
"zl"        =  "z>>>>>>>>>>>>*"
"alphabet"  =  "a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<*"
"banana"    =  "b<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*" OR "b<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>*"
"abcdefghijklmnopqrstuvwxyz" = "a>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*>*"
"abcdefz"   =  "a>*>*>*>*>*<<<<<<*"


# Rules

• We are encoding not decoding, so don't mess that up.
• You may assume the message will contain letters [A-Z] or [a-z], your choice.
• You may use any non-letter/numeric/reserved character to denote * (E.G. $). • You must have the ending *, it isn't implicit on repeats. • You may assume no empty strings, but a single character is possible. • If it is equidistant either way to the next letter, you may choose a direction. • This is , lowest byte-count wins. Please explain your answer, it helps others learn this way. • Just to be clear, the last test case represents abcdefghijklmnopqrstuvwxyz and is not its own input? Commented Apr 17, 2017 at 19:55 • @NickClifford yes. Commented Apr 17, 2017 at 19:57 • I think zl should use >. – xnor Commented Apr 17, 2017 at 21:11 • Could you please check the examples? alphabet is in my opinion a>>>>>>>>>>>*>>>>*<<<<<<<<*<<<<<<<*>*>>>*<<<<<<<<<<<* and zl should be z>>>>>>>>>>>>* and for banana should a second solution exists b<*<<<<<<<<<<<<<*>>>>>>>>>>>>>*<<<<<<<<<<<<<*>>>>>>>>>>>>>* Commented Apr 17, 2017 at 21:41 • @xnor correct, was a manual typo from zm. @jorg good catches, fixed all of them, was a manual effort. Commented Apr 18, 2017 at 13:19 ## 16 Answers # 8086 machine code, 70 68 67 bytes 00000000 be 82 00 bf 43 01 57 31 d2 ac 3c 0d 74 2c 89 d1 |....C.W1..<.t,..| 00000010 88 c2 aa e3 f4 4f 28 c1 9f 88 e7 79 02 f6 d9 83 |.....O(....y....| 00000020 f9 0d 9f 76 05 83 e9 1a f6 d9 30 fc 9e b0 3c 78 |...v......0...<x| 00000030 02 b0 3e f3 aa b0 2a aa eb cf c6 05 24 b4 09 5a |..>...*.....$..Z|
00000040  cd 21 c3                                          |.!.|
00000043


How it works:

            |   org 0x100
|   use16
be 82 00    |       mov si, 0x82        ; source = command line arguments
bf 43 01    |       mov di, result      ; destination = result
57          |       push di
31 d2       |       xor dx, dx          ; clear dx
ac          |   n:  lodsb               ; al = *si++
3c 0d       |       cmp al, 0x0d        ; end of input reached? (newline)
74 2c       |       je q                ; jump to exit in that case
89 d1       |   @@: mov cx, dx          ; store last char in cl
88 c2       |       mov dl, al          ; and store the current char in dl
aa          |       stosb               ; *di++ = al
e3 f4       |       jcxz n              ; skip encoding this char if cx == 0 (only happens for the first char)
4f          |       dec di              ; move di pointer back
28 c1       |       sub cl, al          ; take the difference between this char and the last one
9f          |       lahf                ; store flags from last subtraction in bh
88 e7       |       mov bh, ah
79 02       |       jns @f
f6 d9       |       neg cl              ; make sure cl is positive
83 f9 0d    |   @@: cmp cl, 13          ; which way is shorter?
9f          |       lahf                ; also store these flags
76 05       |       jbe @f
83 e9 1a    |       sub cl, 26          ; invert cl if we're going backwards
f6 d9       |       neg cl
30 fc       |   @@: xor ah, bh          ; xor saved flags together
9e          |       sahf                ; load flags register with the result
b0 3c       |       mov al, '<'
78 02       |       js @f               ; now the sign flag tells us which operator to use
b0 3e       |       mov al, '>'
f3 aa       |   @@: rep stosb           ; while (cx--) *di++ = al
b0 2a       |       mov al, '*'         ; mark the end with an asterisk
aa          |       stosb
eb cf       |       jmp n               ; repeat
c6 05 24    |   q:  mov byte [di], '$' ; mark end of string b4 09 | mov ah, 0x09 ; dos function: print string 5a | pop dx ; dx = string pointer cd 21 | int 0x21 ; syscall c3 | ret | result rb 0  • This. This is beyond cool. You did this REALLY quickly too, dang. Commented Apr 19, 2017 at 17:28 • Thanks. It's pretty much the trivial solution though. Just happens to be quite short in 8086. Commented Apr 20, 2017 at 1:05 # Python 3, 87 bytes r,*s=input();p=r for c in s:d=(ord(p)-ord(c)-13)%26-13;r+='<'*d+'>'*-d+'*';p=c print(r)  Try it online! Works with either lowercase or uppercase. The program builds the output string r as it iterates over the characters in the input string. It stores the previous character as p, and computes the incrementing operation to get from p to the new character c. The interval between the characters is ord(c)-ord(p), and (ord(c)-ord(p)-13)%26-13 takes it modulo 26 to the interval [-13..12]. A negative result means it's shorter to step down, and a positive result means to step up. This needs to be converted to a string of > or < depending on the sign. Rather than using abs or a conditional, we take advantage of Python's string multiplication s*n giving the empty string when n is negative. In the expression '<'*-d+'>'*d, the wrong-signed part does not contribute. The initial state is handled by splitting the input into its first character and the rest with Python 3's unpacking r,*s=input(). The initial character is used to start building the string, as well as the initial "previous" char. Thanks to ovs for suggesting switching to Python 3 to do this unpacking. # Python 3, 110 93 bytes r,*s=input() b=r for a in s:d=(ord(a)-ord(b))%26;r+=['>'*d,'<'*(26-d)][d>13]+'*';b=a print(r)  Try it online! • Ooo... Works for both lower and uppercase, nice one (but I think you can shave off bytes by assuming one or the other). Commented Apr 17, 2017 at 20:08 • Explanation please? Commented Apr 17, 2017 at 21:47 ## JavaScript (ES6), 118109 107 bytes The input string is case insensitive. s=>s.replace(/./g,(c,i)=>(d=~~s-(s=parseInt(c,36)),i)?'<><>'[k=d/13+2|0].repeat([d+26,-d,d,26-d][k])+'*':c)  ### How it works Unlike Python, the JS modulo operator returns a number having the same sign as the dividend rather than the divisor. Also, the JS repeat() method throws an error when given a negative number, rather than returning an empty string (and it's significantly longer than a simple * anyway). These are rather unfavorable behaviors for this challenge. So, we'd better identify in which exact case we are rather than relying on math tricks. (Which doesn't mean that such tricks do not exist, but rather that I failed to find them.) Below is a table describing the 4 possibles cases, where d is the signed distance between the current character and the previous one: d | floor(d / 13) + 2 | direction | repeat ------------+-------------------+-----------+------- -25 ... -14 | 0 | < | d + 26 -13 ... -1 | 1 | > | -d +0 ... +12 | 2 | < | +d +13 ... +25 | 3 | > | 26 - d  ### Test cases let f = s=>s.replace(/./g,(c,i)=>(d=~~s-(s=parseInt(c,36)),i)?'<><>'[k=d/13+2|0].repeat([d+26,-d,d,26-d][k])+'*':c) console.log(f("abcdef")); console.log(f("zyaf")); console.log(f("zzzzzz")); console.log(f("z")); console.log(f("zm")); console.log(f("zl")); console.log(f("alphabet")); console.log(f("banana")); console.log(f("abcdefghijklmnopqrstuvwxyz")); console.log(f("abcdefz")); # Jelly, 17 bytes OIżN$ẋ"@€⁾><;€⁶ṭḢ


Uses a space character in place of * (a space, ⁶, or a newline, ⁷, saves one byte over ”*).

Works with either uppercase-only or lowercase-only input.

Try it online! or see a test suite (where those spaces are post-replaced by * for reading ease).

### How?

OIżN$ẋ"@€⁾><;€⁶ṭḢ - Main link: string s e.g. "adbc" O - cast s to ordinals [97,100,98,99] I - incremental differences [3,-2,1]$             - last two links as a monad:
N              -     negate                        [-3,2,-1]
ż               -     zip together                  [[3,-3],[-2,2],[1,-1]]
⁾><      - literal ['>','<']                 "><"
"@€         - using reversed @arguments for €ach zip with("):
ẋ            -     repeat (-n are like zeros)    [[">>>",""],["","<<"],[">",""]]
;€    - concatenate €ach with:
⁶   -     literal ' '                   [[">>>","",' '],["","<<",' '],[">","",' ']]
ṭ  - tack to:
Ḣ -     head of s (1st char)          [['a'],[">>>","",' '],["","<<",' '],[">","",' ']]
- implicit print   (" not printed:) "a>>> << > "


# PHP, 127 Bytes

for($l=ord($r=($s=$argn)[0]);$x=ord($s[++$i]);$l=$x)$r.=str_pad("",($a=abs($n=$l-$x))<14?$a:26-$a,"><"[$n>0^$a>13])."*";echo$r;  Testcases ## PHP, 137 Bytes for($l=$r=($s=$argn)[0];$s[++$i];$l=$s[$i])$r.=str_pad("",$d=min($a=abs(ord($l)-ord($s[$i])),$b=26-$a),"><"[$d<$b^$l<$s[$i]])."*";echo$r;


Testcases

## JavaScript (ES6), 111 103 bytes

f=
s=>s.replace(/./g,(c,i)=>(p=(n+26-(n=parseInt(c,36)))%26,i?'<>'[p+3>>4].repeat(p>13?26-p:p)+'*':c),n=0)
<input oninput=o.textContent=f(this.value)><pre id=o>

s=>[...s].map(c=>(n=parseInt(c,36),p&&(p=(n+26-p)%26,s+='><'[p+3>>4].repeat(p>13?26-p:p)+'*'),p=n),s=s[p=0])&&s


Originally version that took 111 bytes before I adapted @Arnauld's trick of setting n while computing p, I think there's probably another trick using s instead of n but it's getting late so I won't bother.:

## Haskell (lambdabot), 161 153 bytes

w(s:n)=s:(join.snd$mapAccumL(ap(,).g)s n);g c n|q<-[c..'z']++['a'..c],(Just l,s)<-minimum$first(elemIndex n)<$>[(q,'>'),(reverse q,'<')]=(s<$[1..l])++"*"


Try it online!

Explanation:

-- Encode a single letter
g c n | q          <- [c..'z']++['a'..c]        -- The alphabet starting from letter c, looping around
, (Just l,s) <- minimum                   -- Choose the smallest of ..
$first(elemIndex n) -- the index of the letter n .. <$> [(q,'>'),(reverse q,'<')] -- from the alphabet q and its reverse

= (s<$[1..l]) -- Repeat < or > the same number of times as the index of n .. ++ "*" -- and append * -- Encode the whole string w (s:n) = s -- Yield the first char of the input : ( join . snd -- Concatinate the result of ..$ mapAccumL (\a b->(b,g a b))s n -- executing the g function on each letter of the input string ..
-- except the first, passing the previous letter as the 'c' ..
-- argument on each iteration
)


## EXCEL VBA 130 bytes

s="":p=Mid(s,1,1):For i=1 To Len(s)-1:b=Asc(Mid(s,i+1,1)):a=Asc(Mid(s,i,1)):p=p &String(abs(b-a),IIf(b>a,">","<"))&"*":Next:[a1]=p


Run it from Excel VBA Immediate window.

Explanation:

Simple for loop that with String function to repeat the ">" or "<" n number of times where n is the ascii difference between the i and i+1 character string.

# Java 7-, 232 bytes

class C{static void main(String[]a)throws Exception{int i=System.in.read(),j,d,c;p(i);while((j=System.in.read())>10){d=(j-i+26)%26;c=d>13?-1:1;while(d%26>0){d-=c;p(61+c);}p(42);i=j;}}static void p(int k){System.out.print((char)k);}}


Pretty much the trivial solution. Ungolfed and commented:

class C {
static void main(String[] a) throws Exception {
int i = System.in.read(), j, d, c; // i is the last character. j is the current character. d is the difference. c is the direction (-1 is left, 1 is right)
p(i); // print the starting character first
while ((j = System.in.read()) > 10) { // keep going until a newline is hit (or an EOF/EOL for -1)
d = (j - i + 26) % 26; // get the difference (always positive) by wrapping around
c = d > 13 ? -1 : 1; // get the direction by finding which way is shorter, going right when it's a tie
while (d % 26 > 0) { // keep going until the current character is reached
d -= c; // reduce d in the right direction
p(61 + c); // < is 60 = 61 + (-1), > is 62 = 61 - (-1)
}
p(42); // print an asterisk
i = j; // set the current character to the new reference point
}
}

static void p(int k) {
System.out.print((char) k);
}
}


# C, 170 bytes

e(c){putchar(c);}i;m(a,b){i=b-a?a>b?b-a<14?b-a:-(a+26-b):a-b<14?-(a-b):b+26-a:0;while(i>0)e(62),i--;while(i<0)e(60),i++;}f(char*l){e(*l);while(l[1])m(*l,l[1]),e(42),l++;}


Detailed Live

e(c){ putchar(c); } // encode

g(a,b) // obtain required transition
{
return (b-a) // calculate distance

? (a > b // distance is non-zero

// if b comes after a
? (b-a < 14 // if forward is a shorter path
? b-a // go forward
: -(a+26-b)) // otherwise go backward

// if b comes before a
: (a-b < 14 // if backward is a shorter path
? -(a-b) // go backward
: b+26-a)) // otherwise go forward

: 0; // if distance is 0
}

// transition
i;m(a,b)
{
// obtain required transition
i=g(a,b);

// encode forward transition
while(i>0)e('>'), i--;

// encode backward transition
while(i<0)e('<'),i++;
}

// incremental cipher function
f(char*l)
{
e(*l); // encode first character

while(*(l+1)) // while next character is not END-OF-STRING
m(*l,*(l+1)), // do transition from current to next character
e('*'), // encode
l++; // next
}

• Cool solution. The following is probably easier to understand, but 1 byte longer: #define x q<14?q:q+26 e(c){putchar(c);}i,q;m(a,b){q=b-a;i=q?(a>b?x:-x):0;while(i>0)e('>'),i--;while(i<0)e('<'),i++;}f(char*l){e(*l);while(*(l+1))m(*l,*(l+1)),e('*'),l++;} Commented Apr 19, 2017 at 21:41
• @Moreaki Thx, but this is a code-golf, so we always aim to reduce byte count, anyway I have added detailed explanation on how my code works. Commented Apr 20, 2017 at 9:03

C++ ,210 190 bytes

My First Try At Golfing !

#include<iostream>
int g(char*a){char k,j,d;std::cout<<*a;a++;for(;*a;a++){for(j=*(a-1),d=j-*a,k=d>0?d>13?62:60:d<-13?60:62;j!=*a;j+=k-61,j=j<97?122:j>122?97:j)std::cout<<k;std::cout<<'*';}}


k stores which of < , > or * to print .At first it simply prints the first element of array then runs a loop for a from first to last element of array . j stores the previous element and then by comparing if j closer to *a by < or > set k to < ,> respectively and then print k then run this loop until j becomes equal to p . Then after every ending of second loop print * .

• Welcome to the site! If I recall correctly *p!=0 can be replaced with *p. I'm pretty sure the space in char *a is also unnecessary. You will also need to #include <iostream> and using namespace std; (although I think it might be cheaper to just add std::) to make this a complete answer. Commented Apr 19, 2017 at 17:23
• Welcome to the site! I think you need to include std:: or using namespace std; You'll probably also need #include <iostream> in your byte count. Commented Apr 19, 2017 at 17:23
• +1, but do fix the two aforementioned things, welcome to PPCG ;). Checkout some of the languages around the TIO Nexus ( tio.run/nexus ) when you get a chance! Maybe introduce yourself to Dennis, he's a key dude floating around here. Commented Apr 19, 2017 at 17:26
• Thanks everyone for suggestions and pointing out the mistakes. I will update the code shortly. Commented Apr 20, 2017 at 9:18

# 05AB1E, 17 bytes

¬sÇ¥v„<>y0›èyÄ×ðJ


Try it online!

Explanation

Uses >, < and <space> to denote increment, decrement, submit

¬                  # get the first letter of the input string
sÇ¥               # push a list of delta's of the character codes in the input string
v              # for each delta
„<>           # push the string "<>"
y0›        # check if the delta is positive
è       # use this to index into the string
yÄ×    # repeat it abs(delta) times
ðJ  # join to string with a space

• And lost this one by 3 hours 😉. Commented Aug 17, 2017 at 21:49

f=fromEnum
r=replicate
a?b=mod(f a-f b-13)26-13
c#x=r(c?x)'<'++r(-c?x)'>'
s(c,s)x=(x,s++c#x++"*")
e(x:y)=x:snd(foldl s(x,[])y)


Now using xnor's arithmetic solution. Call with e str where str :: String is the string to be encoded.

a#b=mod(a-b-13)26-13
r=replicate
h(a:b:s)=r(a#b)'>'++r(-a#b)'<'++'*':h(b:s)
h e=""


Try it online! Uses xnor's approach. Call with f "somestring".

# JavaScript (ES6), 140128129111 113 bytes

I went down a different route to the other JS solutions but it didn't work out too well - here's what I have so far:

f=

([x,...s])=>x+s.map(y=><><>[r=(d=y[c=charCodeAt]()-x[c](x=y))/13+2|0].repeat([d+26,-d,d,26-d][r])+*).join

console.log(f("aza"))
console.log(f("abcdef"))
console.log(f("zyaf"))
console.log(f("zzzzzz"))
console.log(f("z"))
console.log(f("zm"))
console.log(f("zl"))
console.log(f("alphabet"))
console.log(f("banana"))
console.log(f("abcdefghijklmnopqrstuvwxyz"))
console.log(f("abcdefz"))
<input id=i>
<pre id=o>

• Saved 12 bytes thanks to a suggestion from Luke on destructuring the string.
• Added 1 byte fixing a misreading of the challenge, which I thought allowed for an implicit final print character.
• Saved another 18 bytes thanks to an extensive rewrite by Luke.
• Added 2 bytes as it seems numbers are not valid print characters.

## Original, 131 bytes

f=

([x,...s])=>x+s.map(y=>(t=(d=y[c=charCodeAt]()-x[c](x=y))<0?-d:d,<>[+((r=t<13)&&d>0)||+(!r&&d<0)].repeat(r?t:26-t)+*)).join

console.log(f("aza"))
console.log(f("abcdef"))
console.log(f("zyaf"))
console.log(f("zzzzzz"))
console.log(f("z"))
console.log(f("zm"))
console.log(f("zl"))
console.log(f("alphabet"))
console.log(f("banana"))
console.log(f("abcdefghijklmnopqrstuvwxyz"))
console.log(f("abcdefz"))
<input id=i>
<pre id=o>

• ([x,...s])=>x+s.map(...) saves 12 bytes. Note that you should append a print character to the end as well. I suggest using a number, which will only cost 2 bytes 1+1 instead of *.
– Luke
Commented Apr 18, 2017 at 15:48
• Thanks, Luke; I'd forgotten I could destructure a string input like that. I must have misread the challenge last night; I could've sworn it said the last print character was implicit. Unfortunately, simply tacking it on after the join would have resulted in an invalid output for single letter inputs. However, moving the print character within the map method only cost 1 byte. Commented Apr 18, 2017 at 16:05
• ([x,...s])=>x+s.map(y=>'<><>'[r=(d=y[c='charCodeAt']()-x[c](x=y))/13+2|0].repeat([d+26,-d,d,26-d][r])+0).join for 111 bytes
– Luke
Commented Apr 18, 2017 at 17:25
• Thanks, again, @Luke. Before I edit it in, would you prefer to post the above as your own answer? I feel it differs sufficiently from mine (almost a hybrid of it and Arnauld's) for that to be OK. Commented Apr 18, 2017 at 17:57
• Nah, you can edit it in. I tried golfing a reduce solution, but that turned out to be 115 bytes.
– Luke
Commented Apr 18, 2017 at 18:19