Incremental Cipher
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
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!