14
\$\begingroup\$

Context

We're at war! You need to transfer an important message to your general to inform them from an imminent assault. The thing is, your enemy knows a lot about cryptography : you will need to be more creative in order to encode your message...

Task

Create a program that accepts an ascii message as input, and outputs the encoded message. The message should be encoded this way : each character should get its ascii value shifted by its position in the message.

For example, let's encode the message "Hello, world!"

H   e   l   l   o   ,       w   o   r   l   d   !     Original message

72  101 108 108 111 44  32  119 111 114 108 100 33    ASCII value

0   1   2   3   4   5   6   7   8   9   10  11  12    Place in the message

72  102 110 111 115 49  38  126 119 123 118 111 45    Encoded ascii (line 1 + line 2)

H   f   n   o   s   1   &   ~   w   {   v   o   -     Encoded message

The message Hello, world! should be encoded as Hfnos1&~w{vo-.

Sometimes the encoded ascii can go beyond printable character. In that case, the value loop back to 32 (read the rules for additionnal informations)

T   h   e       r   a   n   d   o   m       g   u   y      Original message

84  104 101 32  114 97  110 100 111 109 32  103 117 121    ASCII value

0   1   2   3   4   5   6   7   8   9   10  11  12  13     Place in the message

84  105 103 35  118 102 116 107 119 118 42  114 129 134    Encoded ascii (line 1 + line 2)

84  105 103 35  118 102 116 107 119 118 42  114 34  39    Corrected encoded ascii (looped back to 32)

T   i   g   #   v   f   t   k   w   v   *   r   "   '

The random guy is then converted into Tig#vftkwv*r"'

Using the same strat, zzzzzzzzz will be converted into z{|}~ !"# (ascii values converted into 122 - 123 - 124 - 125 - 126 - 32 - 33 - 34 - 35)

Rules

  • The input message will be composed of printable ascii character (between 32 and 126)

  • The message should be encoded as described before.

  • The ascii values of the encoded message should be set between 32 and 126.

  • The first character of the message should be at position 0.

  • If the new ascii value goes beyond the limit, it should loop back to 32.

  • Every character should be encoded. This includes punctuation, spaces etc.

  • No standard loopholes allowed.

  • This is codegolf, so the shortest code wins.

\$\endgroup\$
  • \$\begingroup\$ Meta \$\endgroup\$ – The random guy Jun 3 at 7:44
  • 2
    \$\begingroup\$ Suggested test case: 'zzzzzzzzz', to catch the correct wrapping point \$\endgroup\$ – PaMu Jun 3 at 8:11
  • \$\begingroup\$ @Adám yes, every character in the input message will be set between 32 and 126 \$\endgroup\$ – The random guy Jun 3 at 8:15
  • 2
    \$\begingroup\$ You may want to spell out that your positions are 0-based. \$\endgroup\$ – Adám Jun 3 at 8:15
  • 11
    \$\begingroup\$ "Your enemy knows a lot about cryptography" Evidently not if this simple code is enough to confound them. ;-p \$\endgroup\$ – Darrel Hoffman Jun 3 at 17:39

29 Answers 29

7
\$\begingroup\$

Charcoal, 9 bytes

⭆S§γ⁺κ⌕γι

Try it online! Link is to verbose version of code. Explanation:

 S          Input string
⭆           Map over characters and join
        ι   Current character
      ⌕     Find position in
       γ    Printable ASCII
    ⁺       Plus
     κ      Current index
  §         Cyclically indexed into
   γ        Printable ASCII
            Implicitly print
| improve this answer | |
\$\endgroup\$
7
\$\begingroup\$

Python 3.8, 55 54 bytes

Output is a list of characters.

lambda s,d=33:[chr((ord(c)-(d:=d-1))%95+32)for c in s]

Try it online!

| improve this answer | |
\$\endgroup\$
5
\$\begingroup\$

J, 22 bytes

(95|<:+#\)&.(_32+3&u:)

Try it online!

Almost word-to-word translation of my dzaima/APL solution.

How it works

(95|<:+#\)&.(_32+3&u:)  NB. Input: string S
(   X    )&.(   Y    )  NB. The "Under" operator; do Y, do X and undo Y
             _32+3&u:   NB. Convert chars to codepoints and subtract 32
       #\               NB. One-based index
    <:+                 NB. Add to the codepoints minus 1
 95|                    NB. Modulo 95
             _32+3&u:   NB. Undo this: add 32 and convert to chars
| improve this answer | |
\$\endgroup\$
5
\$\begingroup\$

R, 56 57 bytes

function(s)intToUtf8((utf8ToInt(s)-33+1:nchar(s))%%95+32)

Try it online!

Edit: thanks to Giuseppe for bug-spotting!

I am beginning to despise string manipulations in R, and the intToUtf8() / utf8ToInt() function names in particular...

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ this will fail for a single character input "a" for instance. You can save it at a cost of 2 bytes -- wasn't sure if that would actually work until I tried it! \$\endgroup\$ – Giuseppe Jun 3 at 18:03
  • 2
    \$\begingroup\$ and yes, R's string manipulation is abysmal. \$\endgroup\$ – Giuseppe Jun 3 at 18:03
  • 1
    \$\begingroup\$ There's also a 57 byte solution if you get rid of seq \$\endgroup\$ – Giuseppe Jun 3 at 18:07
  • \$\begingroup\$ Aargh! Well-spotted for the single-character-input bug, and thanks for the suggestion (that's a nice 4-byte shortcut for seq_along that I didn't know about!). \$\endgroup\$ – Dominic van Essen Jun 3 at 19:11
  • \$\begingroup\$ The 57-byte solution is what I originally had... I was smugly thinking how cleverly I'd saved a byte until you pointed-out that it didn't actually work! \$\endgroup\$ – Dominic van Essen Jun 3 at 19:12
4
\$\begingroup\$

APL (dzaima/APL), 21 bytes

{95|⍵+⍳≢⍵}⍢(¯32+⎕UCS)

Try it online!

Just trying out the experimental Under operator because the task is screaming for it.

How it works

{95|⍵+⍳≢⍵}⍢(¯32+⎕UCS)  ⍝ Input: string S
          ⍢(¯32+⎕UCS)  ⍝ Convert S to Unicode codepoints and subtract 32
{   ⍵+⍳≢⍵}             ⍝ Add the index to each char
 95|                   ⍝ Modulo 95
          ⍢(¯32+⎕UCS)  ⍝ Undo the operation:
                       ⍝ Add 32 and convert back to Unicode chars
| improve this answer | |
\$\endgroup\$
  • 4
    \$\begingroup\$ That operator looks like it is really happy to be used \$\endgroup\$ – The random guy Jun 3 at 8:56
4
\$\begingroup\$

05AB1E, 16 10 9 bytes

žQDIkā<+è

-1 byte by porting @Neil's Charcoal answer, so make sure to upvote him!

I/O as a list of characters.

Try it online or verify all test cases.

Explanation:

žQ          # Push the printible ASCII string builtin
  D         # Duplicate it
   I        # Push the input-list of characters
    k       # Get each index in the ASCII string
     ā      # Push the list [1, length] (without popping)
      <     # Decrease it by 1 to make it a 0-based range [0, length)
       +    # Add the values at the same positions in the lists together
        è   # Index each into the ASCII string (0-based and with automatic wraparound)
            # (after which the resulting list of characters is output implicitly)
| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

Perl 5 (-p), 32 bytes

-1 byte thanks to @Abigail

s/./chr 32+($x++-32+ord$&)%95/ge

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ from the test case it seems it's 94 \$\endgroup\$ – Nahuel Fouilleul Jun 3 at 9:07
  • 1
    \$\begingroup\$ you're correct the post was updated 41 min ago \$\endgroup\$ – Nahuel Fouilleul Jun 3 at 9:18
  • 2
    \$\begingroup\$ Save a byte by using ($x++-32+ord$&) instead of (-32+$x+++ord$&). \$\endgroup\$ – Abigail Jun 3 at 9:51
  • 1
    \$\begingroup\$ @Abigail +++ looks cooler though! \$\endgroup\$ – Neil Jun 3 at 18:49
4
\$\begingroup\$

C (gcc), 48 47 46 bytes

Saved a byte thanks to 640KB!!!

Saved a byte thanks to dingledooper!!!

i;f(char*s){for(i=32;*s;)*s++=(*s-i--)%95+32;}

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @dingledooper Nice one - thanks! :-) \$\endgroup\$ – Noodle9 Jun 4 at 8:13
4
\$\begingroup\$

APL (Dyalog Unicode), 28 24 22 bytes SBCS

-4 bytes thanks to @Adám; -2 bytes thanks to @ngn;

Monadic function expecting a string:

⎕ucs 32+95|⎕ucs-32-⍳∘≢

Try it online! Assumes ⎕IO←0. How the 24-byter works:

32(⎕ucs⊣+95|⊢--∘⍳∘≢)⎕ucs  ⍝ monadic function taking a character vector on the right
                     ⎕ucs  ⍝ convert to unicode code points
32(                 )      ⍝ and then evaluate the expression with 32 as left argument and the code points as right arg
               -∘⍳∘≢        ⍝ do 32 minus (-) the range 0 1 ... [length of input string] (⍳∘≢)
            ⊢-            ⍝ take the right argument (⊢) [the codepoints] and subtract the previous calculation from those [effectively adding the positions and subtracting 32]
         95|               ⍝ and take those numbers modulu 95.
      ⊣+                  ⍝ Take the left (⊣) argument [32] and add it to the numbers we just did mod 95
  ⎕ucs                     ⍝ and convert the new code points to characters.

@Bubbler has a similar answer but making use of an operator that hasn't been implemented in Dyalog APL yet, check it out.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Yours actually consumes 42 bytes (UTF-8) \$\endgroup\$ – John Brookfields Jun 3 at 8:28
  • \$\begingroup\$ @JohnBrookfields I know, I'm on my mobile so I took a bit longer to link the appropriate encoding. C.f. my edited answer \$\endgroup\$ – RGS Jun 3 at 8:30
  • 1
    \$\begingroup\$ 24: 32(⎕ucs⊣+95|⊢--∘⍳∘≢)⎕ucs \$\endgroup\$ – Adám Jun 3 at 8:37
3
\$\begingroup\$

Retina 0.8.2, 19 bytes

{*\M!`^.
^.

T`~p`p

Try it online! Link includes test cases. Explanation:

{

Repeat until the input is empty.

*\M!`^.

Output the first character.

^.

Remove the first character.

T`~p`p

Cyclically increment the remaining characters.

12 bytes in Retina 1:

1,Tv`~p`p`.+

Try it online! Link includes test cases. Explanation:

v`.+

Create overlapping matches that start at each character and end at the end of the string.

1,

Ignore the match of the whole input.

T`~p`p`

Cyclically shift each character according to the number of times it was matched.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

K (oK), 19 bytes

{`c$32+95!x-32-!#x}

Try it online!

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Java (OpenJDK 8), 80 60 bytes

s->{int i=0;for(char n:s)s[i]+=i-(n+i++>126?95:0);return s;}

Try it online!

Thanks for help from Kevin Cruijssen

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Looks like this gives the wrong output for "The random guy" (should be Tig#vftkwv*r"') -- I think your 94 should be 95, that seems to fix it \$\endgroup\$ – math junkie Jun 4 at 3:46
  • 1
    \$\begingroup\$ -1 by combining the s[i]+= with the s[i]-= like this: s[i]+=i-(i+s[i++]>126?95:0). Also, you can use a lambda in Java 8+, so the char[]a(char[]s) can be s->: try it online - 64 bytes \$\endgroup\$ – Kevin Cruijssen Jun 4 at 14:43
  • 1
    \$\begingroup\$ If you've never used lambdas before in Java, here are some brief examples of different lambdas and how to use it in codegolf. In general, you almost always want to use lambdas in Java codegolfing, unless you need a recursive function, which would still be a regular method. \$\endgroup\$ – Kevin Cruijssen Jun 4 at 14:46
  • 1
    \$\begingroup\$ 48 bytes \$\endgroup\$ – Olivier Grégoire Jun 5 at 13:27
  • 1
    \$\begingroup\$ The input object is the output object. It happens all the time in programming. Not every function is pure. And yes, we accept it as is here on Code Golf. \$\endgroup\$ – Olivier Grégoire Jun 5 at 13:35
3
\$\begingroup\$

Haskell, 55 bytes

g '~'=' '
g c=succ c
i!c=iterate g c!!i
zipWith(!)[0..]

Try it online!

The TIO link has f=, but that doesn't contribute to the byte count because I defined it point-free. It's mostly there so that the code compiles.

I didn't play around much with using a point-free definition instead of !, so that might be a place where some bytes can be shaved off. I just figured that the parens and dots would add up. I also want to get rid of the call to iterate, but I'm not sure how. I want something like mtimes...

Haskell + -XParallelListComp, 55 bytes

g '~'=' '
g c=succ c
f s=[iterate g c!!i|c<-s|i<-[0..]]

Try it online!

Unfortunately this isn't any shorter, but I thought it was a cool usage of a pragma. It seems most of the time that pragmas aren't too helpful in golfing.

Explanation

-- g gives the successor of each character according to the specification
g :: Char -> Char
-- the successor of '~' is ' ' (wrap around)
g '~'=' '
-- all other characters have their normal successor
g c=succ c

-- (!) is an infix function that enciphers a character, given an int
(!) :: Int -> Char -> Char
-- iterate produces an infinite list of 'g' applied to 'c' repeatedly,
-- and '!!' indexes into that list at index 'i'. This has the effect
-- of applying 'g' to 'c' 'i' times.
i!c=iterate g c!!i

-- Point-free definition that applies '!' to each character of the input along with its index
zipWith(!)[0..]
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Nice idea to try a pragma to substitute zipWith. I did find two shorter approaches, though using ParallelListComp results in the same byte count for those as well. \$\endgroup\$ – Laikoni Jun 17 at 16:00
3
\$\begingroup\$

x86-16 machine code, IBM PC DOS, 17 16 bytes

Binary:

Build STL.COM using xxd -r:

00000000: b120 b408 cd21 2ac1 d45f 0420 cd29 e0f2  . ...!*.._. .)..

Listing:

B1 20       MOV  CL, 32         ; set up offset / position counter 
        CLOOP: 
B4 08       MOV  AH, 8          ; use DOS API get char from STDIN function 
CD 21       INT  21H            ; read input char into AL 
2A C1       SUB  AL, CL         ; subtract offset 
D4 5F       AAM  95             ; AL = AL % 95 
04 20       ADD  AL, 32         ; restore ASCII offset 
CD 29       INT  29H            ; output AL to console 
E0 F2       LOOPNZ CLOOP        ; keep looping until break, decrement CL

Standalone IBM PC DOS executable program. Input via STDIN, output to console.

Runtime:

enter image description here

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Haskell, 52 51 bytes

zipWith(%)[-32..]
n%c=toEnum$32+mod(fromEnum c+n)95

Try it online!


Haskell, 52 bytes

zipWith(%)[0..]
n%c=snd(span(<c)$cycle[' '..'~'])!!n

Try it online!

Explanation

  • zipWith(%)[0..] calls the infix function % on each character of the input string along with its index.
  • cycle[' '..'~'] builds a list where the ASCII chars are repeated infinitely.
  • span(<c) partitions this list into a prefix of chars smaller than the current character c and a remainder.
  • snd drops the prefix, so only the list of ASCII chars starting with c remains.
  • !!n returns the nth element from that list.
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Ruby, 42 bytes

->s{i=33;s.map{((_1.ord-i-=1)%95+32).chr}}

Takes input and returns output as an array of characters.

44 byte version because TIO doesn't support ruby 2.7's _1 syntax

->s{i=33;s.map{|c|((c.ord-i-=1)%95+32).chr}}

Try it online!

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

APL (Dyalog Extended), 22 bytes (SBCS)

Full program. Requires ⎕IO←0

⍞(⊢⊇⍨95|⍳⍨+~⍋⊣)' '…'~'

Try it online!

' '…'~' the printable ASCII range

⍞() with the input as left argument, apply the following tacit function to that:

 the left argument (the input)

 the sorting permutation to sort according to the following order:

  ~ the input without any printable ASCII, i.e. an empty string (this means leave all in current positions)

⍳⍨ the indices of the input characters in the printable ASCII

95| division remainder when divided by 95

⊇⍨ use those indices to select from:

   the printable ASCII

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Befunge-93, 25 bytes

:~:1+!#@_" "-+"_"%" "+,1+

Try it online!

Keeps the character count on the bottom of the stack. Then in a loop, reads a character at the time, subtracts 32 to the character, adds the character count, mods it with 95, adds 32 again, then prints the character. Finally, it adds 1 to the character count.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

T-SQL, 100 bytes

Added some line changes to make it readable

DECLARE @x INT=0
WHILE @x<len(@)
SELECT
@=substring(@,2,999)+char((ascii(@)+@x-32)%95+32),
@x+=1
PRINT @

Try it online

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Ly, 25 bytes

ir84*sp[l-l,sp(95)%84*+o]

Try it online!

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

JavaScript, 77 bytes

Iterative!

s=>[...s].map((c,i)=>String.fromCharCode((c.charCodeAt()+i-32)%95+32)).join``

Try it online!


JavaScript, 77 bytes

Outer recursive!

f=(s,i=0)=>s[i]?String.fromCharCode((s.charCodeAt(i)+i-32)%95+32)+f(s,i+1):''

Try it online!


JavaScript, 77 bytes

Inner recursive!

s=>(F=i=>s[i]?String.fromCharCode((s.charCodeAt(i)+i-32)%95+32)+F(i+1):'')(0)

Try it online!

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

JavaScript (Node.js), 42 bytes

s=>Buffer(s).map((c,i)=>(c+i-32)%95+32)+''

Try it online!

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Jelly, 9 bytes

O+J_32ịØṖ

Try it online!

How?

O+J_32ịØṖ - Link: list of characters, S  - e.g. "zzzzzzzzz"
O         - cast (S) to ordinal values          [122,122,122,122,122,122,122,122,122]
  J       - range of length (S)                 [  1,  2,  3,  4,  5,  6,  7,  8,  9]
 +        - add (vectorises)                    [123,124,125,126,127,128,129,130,131]
    32    - thirty-two                          32
   _      - subtract                            [ 91, 92, 93, 94, 95, 96, 97, 98, 99]
       ØṖ - printable ASCII characters          " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
      ị   - index into (1-based & modular)      "z{|}~ !"#"
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

C (gcc), 46 50 48 bytes

x;f(char*s){*s?*s=(*s+x++-32)%95+32,x=f(s+1):0;}

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ This isn't legal, you can't depend on a variable being externally set outside of the function. \$\endgroup\$ – Noodle9 Jun 3 at 11:13
  • \$\begingroup\$ I don't depend on it for the 1st iteration, only subsequent ones... (proof), is that also illegal? \$\endgroup\$ – Asone Tuhid Jun 3 at 11:41
  • 2
    \$\begingroup\$ No, it is not legal. It has to work independently for any run, not just the first. In C this means, for instance, a function can't depend on global variables being set to 0 at the start of a program run. \$\endgroup\$ – Noodle9 Jun 3 at 12:12
  • \$\begingroup\$ Can I say the function takes an extra argument that must always be 0 or is that illegal too? \$\endgroup\$ – Asone Tuhid Jun 3 at 12:24
  • \$\begingroup\$ @Noodle9 Do you have a link to the rules thread? I can't seem to find it. \$\endgroup\$ – Asone Tuhid Jun 3 at 12:35
1
\$\begingroup\$

Erlang (escript), 68 bytes

f(I,[H|T])->[(H+I-32)rem 95+32]++f(I+1,T);f(_,[])->[].
f(I)->f(0,I).

Try it online!

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Stax, 9 bytes

éñÇöo♣j0♦

Run and debug it

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Wolfram Language, 68 bytes

FromCharacterCode@Mod[#&~Array~Length@#+#-1,95,32]&@*ToCharacterCode

Uses a little function composition to make it shorter, but other than that, does pretty much what it says on the tin. Converts the string to character codes, adds the proper offset to each, wraps around if needed using Mod (there's an optional argument for offset that I use here), then converts back to a string.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I believe #&~Array~Length@# can be replaced with Range@Length@# for a 3-byte improvement. \$\endgroup\$ – LegionMammal978 Jun 6 at 4:34
0
\$\begingroup\$

Keg, 19 bytes

0&(⑻+:\~>[\~% +;],⑹

Try it online!

Woooo! I managed to beat APL somehow! This is a very literal interpretation of the challenge, except for the part where overflow values are decremented after modulusing.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Befunge-98 (FBBI), 20 bytes

'!v
-1<,+ '%_'-\~@#:

Try it online!

Initially pushes d=33 on the stack. On every iteration, d is reduced by one and (input-d)%95+32 is printed.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.