Given an input, move it along the keyboard by N characters

19

3

The Challenge:

Given any input that can be typed on a keyboard, move the text along by N chars.

Here is the QWERTY keyboard to be used. You can ignore the modifier keys (Shift, Caps, Enter, Delete and Tab). Once you reach one side (for example |) loop back round, so | goes to Q if N = 1.

enter image description here

Spaces do not have to be moved along (they go back round to space as you skip modifiers). If shift was used to type the character (e.g. ! and @) the changed character should also be typed using shift (i.e. ! goes to @ not 2 if N = 1).

UK keyboards are different to this, but please use this so that we can compare.

Input:

Any sentence that can be typed on the above keyboard followed by a positive integer. There is no maximum to the size of this integer.

Output:

The same sentence, shifted along by N.

Examples:

My name is Tim 3
?o .f/y [g I[/
Hello World 7
Spgge Oe[g;
I Wi5h I h4d b3773r C@d3ing ski{{s 3
{ T[8l { l7h ,6006u N%h6[.k g'[QQg

This is code golf, so shortest code wins.

Tim

Posted 2015-05-17T09:38:12.090

Reputation: 2 789

Can we assume that N<= 13 as you will need to shift at most 13 in order to return to the original character? – flawr – 2015-05-17T10:30:16.547

1@flawr nope, sorry. It can be any positive value. – Tim – 2015-05-17T10:31:08.617

Shouldn't the "Hello World 7" example be "Spggr Oe[g;"? – James Williams – 2015-05-17T16:16:42.667

Shouldn't the Hello World 7 example be Spgge Oe[g;? The two o should map to the same character – edc65 – 2015-05-17T20:17:03.033

Answers

2

05AB1E, 61 bytes

-1 byte thanks to Kevin Cruijssen

žVDu«1ú`žhÀ“~!@#$%^&*()_+ `ÿ-=ÿ<>?ÿ:"ÿ{}|ÿ,./ÿ;'ÿ[]\“#vyy¹._‡

Try it online!

Grimmy

Posted 2015-05-17T09:38:12.090

Reputation: 12 521

2

C, 217 bytes

char*t=" @A$%^*a)_(~.=/z-234567890\"'>`?Z#SNVFRGHJOKL:<MP{WTDYIBECUX]q\\&=1snvfrghjokl;,mp[wtdyibecux}Q|!";l,d,k;f(char*s){for(l=strlen(s);s[--l]-32;);d=atoi(s+l);for(s[l]=0;d--;)for(k=l;k--;s[k]=t[s[k]-32]);puts(s);}

Readable version with whitespace, includes, etc:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

char* t = " @A$%^*a)_(~.=/z-234567890\"'>`?Z#SNVFRGHJOKL:<MP{WTDYIBECUX]q\\&=1snvfrghjokl;,mp[wtdyibecux}Q|!";
int l, d, k;

void f(char* s) {
    l = strlen(s);
    for( ; s[--l] - 32; );
    d = atoi(s + l);
    s[l] = 0;
    for ( ; d--; ) {
        for (k = l; k--; s[k] = t[s[k] - 32]);
    }
    puts(s);
}

The code pretty much speaks for itself. Just a lookup table that maps from each character to the next character, which is applied the given number of times. Much of the code is actually for parsing the number out of the input.

Reto Koradi

Posted 2015-05-17T09:38:12.090

Reputation: 4 870

@Ypnypn You can use undeclared functions in C. So the includes are not needed for it to build. It typically gives compiler warnings, but I've been told that this is allowed as long as it builds and runs. – Reto Koradi – 2015-05-17T23:39:55.247

1

Pyth, 126 bytes

XjdPczdsJc"~!@#$%^&*()_+ `1234567890-= qwertyuiop[]\ QWERTYUIOP{}| asdfghjkl;, ASDFGHJKL:\" zxcvbnm,./ ZXCVBNM<>?")sm.<dvecz)J

Try it online: Demonstration or Test Suite

Explanation:

    czd                       split input by spaces
   P                          remove the last element
 jd                           join by spaces (=#1)

          "..."               string with the chars of each row
         c     )              split by spaces
        J                     assign to J
       sJ                     sum of J (=#2)

                       cz)    split input by spaces
                      e       take the last element
                     v        and evaluate it 
                 m        J   map each row d of J to:
                  .<d           rotate the row d by value
                s             sum (=#3)

X                             Take #1, and replace the chars in #2 by the chars in #3

Jakube

Posted 2015-05-17T09:38:12.090

Reputation: 21 462

1

Python 3, 311 bytes

*i,s=input().split()
r=["`1234567890-=","qwertyuiop[]\\","asdfghjkl;'","zxcvbnm,./","~!@#$%^&*()_+","QWERTYUIOP{}|",'ASDFGHJKL:"',"ZXCVBNM<>?"]
print("".join([[x[int(s):]+x[:int(s)]for x in r][r.index([x for x in r if c in x][0])][([x for x in r if c in x][0]).index(c)]if c!=" "else " " for c in " ".join(i)]))

James Williams

Posted 2015-05-17T09:38:12.090

Reputation: 1 735

Remove the unnecessary spaces in " " for c in " " – mbomb007 – 2015-05-17T21:57:01.633

0

Jelly, 67 bytes

ØDṙ1ṭØQ;Øq;"“{}|“:"“<>?“-=`“[]\“;'“,./“~!@#$%^&*()_+“ ”
¢œiⱮ+2¦€œị¢

Try it online!

A dyadic link taking the string as its left argument and the number of places to shift as its right argument.

Nick Kennedy

Posted 2015-05-17T09:38:12.090

Reputation: 11 829

0

Python 2, 194 bytes

f=lambda s,n:n and f(''.join(B[B.find(c)+1]for c in s),n-1)or s
A='qwertyuiop%sqasdfghjkl%sazxcvbnm%sz'
B='`1234567890-=`~!@#$%^&*()_+~'+A%('[]\\',";'",',./')+(A%('{}|',':"','<>?')).upper()+'  '

Try it online!

Chas Brown

Posted 2015-05-17T09:38:12.090

Reputation: 8 959

0

Python 3, 271 255 bytes

Baseline, almost ungolfed, used to create the shifted words in the question.

x=input().split()
n=int(x[-1])
x=' '.join(x[:-1])
l=['`1234567890-=','qwertyuiop[]\\',"asdfghjkl;'",'zxcvbnm,./', '~!@#$%^&*()_+','QWERTYUIOP{}|','ASDFGHJKL:"','ZXCVBNM<>?',' ']
y=''
for i in x:
 for q in l:
  if i in q:y+=q[(q.index(i)+n)%len(q)]
print(y)

Explanation:

x=input().split()    # Get input
n=int(x[-1])         # Get N from input
x=' '.join(x[:-1])   # Get the words from input
                     # Create list of letters

l=['`1234567890-=', 'qwertyuiop[]\\',
   "asdfghjkl;'",   'zxcvbnm,./',
   '~!@#$%^&*()_+', 'QWERTYUIOP{}|',
   'ASDFGHJKL:"',   'ZXCVBNM<>?',
   ' ']

y=''                 # Blank string
for i in x:          # Loop through letters in input
    for q in l:      # Loop through items in list
        if i in q:   # Is letter of input in item of list?
            y+=q[                          # Append letter to y
                 (q.index(i)+n)            # locate the letter in item, and add N
                               %len(q)]    # % is modulus, loop to beginning if big
print(y)             # Print out the offset word.

Tim

Posted 2015-05-17T09:38:12.090

Reputation: 2 789

I think you should delete this. Let other people work out their own strategies... – mbomb007 – 2015-05-17T21:58:46.287

@mbomb007 it's not very golfed, and I used it to create them... I think it's fair enough to post it, personally. – Tim – 2015-05-18T07:19:07.413

0

JavaScript (ES6), 200 216

Using template strings, the newlines are significant and counted.

Note about replace: the two snippets string.split('x').map(w=>...) and string.replace(/[^x]+/g,w=>...) are equally valid ways to execute a function for each part in a string, using a separator. Using a newline as a separator is handy as the replace regexp becomes /.+/g, because the dot match any non-newline. And using templated strings the newlines have no extra cost.

f=(t,d)=>[for(c of t)`~!@#$%^&*()_+
1234567890-=
QWERTYUIOP{}|
qwertyuiop[]\\
ASDFGHJKL:"
asdfghjkl;'
ZXCVBNM<>?
zxcvbnm,./`.replace(/.+/g,r=>(p=r.indexOf(c))<0?0:q=r[(p+d)%r.length],q=c)&&q].join('')

// less golfed
x=(t,d)=>
  [for(c of t)
    '~!@#$%^&*()_+ 1234567890-= QWERTYUIOP{}| qwertyuiop[]\\ ASDFGHJKL:" asdfghjkl;\' ZXCVBNM<>? zxcvbnm,./'
    .split(' ')
    .map(r=>(p=r.indexOf(c))<0?0:q=r[(p+d)%r.length],q=c)&&q
  ].join('')
  
// TEST

out=x=>O.innerHTML+=x+'\n'

;[['Hello World',7,],['My name is Tim',3],['I Wi5h I h4d b3773r C@d3ing ski{{s', 3]]
.forEach(p=>out(p+' -> '+f(p[0],p[1])))
<pre id=O></pre>

edc65

Posted 2015-05-17T09:38:12.090

Reputation: 31 086

0

CJam, 107 bytes

lS/)~\S*\",./ ;'  <>? :\"  _+~!@#$%^&*() -=`"A,s(++S/"zxcvbnm
asdfghjkl
[]\qwertyuiop"N/_32ff^+.+_@fm>s\ser

Try it online in the CJam interpreter.

How it works

lS/)   e# Read one line from STDIN, split at spaces and pop the last chunk.
~\S*\  e# Evaluate the popped chunk and join the remaining ones back together.
",./ ;'  <>? :\"  _+~!@#$%^&*() -=`"
       e# Push that string.
A,s(++ e# Concatenate it with "1234567890".
S/     e# Split at spaces.
"zxcvbnm asdfghjkl []\qwertyuiop"
       e# Push that string.
S/     e# Split at spaces. (`N/' would split at linefeeds.)
_32ff^ e# XOR each character of a copy with 32.
+      e# Concatenate the copies.
.+     e# Perform vectorized concatenation. This pushes the following array:
          [ ",./zxcvbnm" ";'asdfghjkl" "[]\qwertyuiop" "<>?ZXCVBNM"
           ":\"ASDFGHJKL" "{}|QWERTYUIOP" "_+~!@#$%^&*()" "-=`1234567890" ]
_@fm>  e# Rotate each chunk by the number of character specified in the input.
s\s    e# Flatten this array and the original.
er     e# Perform transliteration.

Dennis

Posted 2015-05-17T09:38:12.090

Reputation: 196 637