13
\$\begingroup\$

INPUT: Any string consisting exclusively of lowercase letters via function argument, command line argument, STDIN, or similar.

OUTPUT: Print or return a number that will represent the sum of the distances of the letters according to the following metric:

You take the first and second letter and count the distance between them. The distance is defined by the QWERTY keyboard layout, where every adjacent letter in the same row has distance 1 and every adjacent letter in the same column has distance 2. To measure the distance between letters that aren't adjacent, you take the shortest path between the two.

Examples:

q->w is 1 distance apart
q->e is 2 distance
q->a is 2 distance
q->s is 3 distance (q->a->s or q->w->s)
q->m is 10 distance

Then you take the second and third letter, then the third and fourth, etc., until you reach the end of the input. The output is the sum of all those distances.

Example input and output:

INPUT: qwer
OUTPUT: 3

INPUT: qsx
OUTPUT: 5

INPUT: qmq
OUTPUT: 20

INPUT: tttt
OUTPUT: 0

Here is an image showing which letters are in the same column:

letters in column

This is code golf, so the shortest code in bytes wins!

\$\endgroup\$
  • 1
    \$\begingroup\$ I think q->m is only 8 keys... \$\endgroup\$ – SuperJedi224 Jun 30 '15 at 12:22
  • 2
    \$\begingroup\$ if you go down one row it counts as 2 distance, you dont count the key distance \$\endgroup\$ – Vajura Jun 30 '15 at 12:24
  • \$\begingroup\$ its up there too :) \$\endgroup\$ – Vajura Jun 30 '15 at 12:25
  • \$\begingroup\$ Can we assume that the input string will always be nonempty? \$\endgroup\$ – Alex A. Jun 30 '15 at 14:35
  • \$\begingroup\$ This is quite similar to codegolf.stackexchange.com/questions/50722/…. Except that this uses letters, while the other one used numbers. \$\endgroup\$ – Reto Koradi Jun 30 '15 at 14:46
2
\$\begingroup\$

CJam, 50 bytes

r{i",ÙZ°^ªýx´|"257b27b=A+Ab}%2ew::.-::z2fb:+

Note that the code contains unprintable characters.

Try it online in the CJam interpreter. If the permalink doesn't work, copy the code from this paste.

Background

We start assigning positions 0 to 9 to the letters on the top row, 10 to 18 to the letters on the home row and 20 to 26 to the letters on the bottom row.

The positions of all 26 letters, in alphabetical order, are

[10 24 22 12 2 13 14 15 7 16 17 18 26 25 8 9 0 3 11 4 6 23 1 21 5 20]

This is an array of length 26. Since arrays wrap around in CJam, and the code point of the letter h is 104 = 4 × 26, we rotate the array 7 units to the left, so that each letter's position can be accessed by its code point.

[15 7 16 17 18 26 25 8 9 0 3 11 4 6 23 1 21 5 20 10 24 22 12 2 13 14]

Now we encode this array by considering its elements digits of a base 27 number and convert the resulting integer to base 257.

[6 153 44 8 217 90 176 156 94 24 170 253 147 120 180 124]

By replacing each integers by the corresponding Unicode character, we obtain the string from the source code.

How it works

r              e# Read a whitespace separated token from STDIN.
{              e# For each character:
  i            e#   Push its code point.
  ",ÙZ°^ªýx´|" e#   Push that string.
  257b27b      e#   Convert from base 257 to base 27.
  A+Ab         e#   Add 10 and convert to base 10.
               e#   Examples: 7 -> [1 7], 24 -> [3 4]
}%             e#
2ew            e# Push all overlapping slices of length 2.
::.-           e# Subtract the corresponding components of the pairs in each slice.
::z            e# Apply absolute value to the results.
2fb            e# Convert each to integer (base 2).
               e# Example: [2 5] -> 2 × 2 + 5 = 9
:+             e# Add the distances.
\$\endgroup\$
  • 1
    \$\begingroup\$ man how does that even work \$\endgroup\$ – Vajura Jul 2 '15 at 7:32
  • \$\begingroup\$ @Vajura Dennis usually gets around to adding explanations, if you wait he'll probably add one :) If you want a more vague/basic explanation, usandfriends made a CJam explainer which you can use here. \$\endgroup\$ – Kade Jul 2 '15 at 13:00
  • \$\begingroup\$ @Vajura: I've edited my answer. \$\endgroup\$ – Dennis Jul 2 '15 at 18:37
7
\$\begingroup\$

Python 2, 220 ... 124 119 Bytes

Huge thanks to Sp3000 for saving a lot of bytes.

f='qwertyuiopasdfghjkl zxcvbnm'.find
g=lambda i:sum(abs(f(x)%10-f(y)%10)+2*abs(f(x)/10-f(y)/10)for x,y in zip(i,i[1:]))

Usage:

g("tttt") -> 0

Check it out here.

Slightly ungolfed + explanation:

f='qwertyuiopasdfghjkl zxcvbnm'.find  # Defining keyboard rows and aliasing find
g=lambda i:                           # Defining a function g which takes variable i
    sum(                              # Sum of 
        abs(f(x)%10-f(y)%10)          # horizontal distance, and
        + 2*abs(f(x)/10-f(y)/10)      # vertical distance,
        for x,y in zip(i,i[1:]))      # for each pair in the zipped list

# Example of zipping for those unaware:
# Let i = asksis, therefore i[1:] = sksis, and zip would make
# the list of pairs [(a,s),(s,k),(k,s),(s,i),(i,s)].
\$\endgroup\$
5
\$\begingroup\$

Java, 266 bytes

int c(String q){String[]r={"qwertyuiop","asdfghjkl","zxcvbnm"};int v=0,l=q.length();int[][]p=new int[l][2];for(int i=0;i<l;i++){while(p[i][0]<1)p[i][0]=r[p[i][1]++].indexOf(q.charAt(i))+1;v+=i<1?0:Math.abs(p[i][0]-p[i-1][0])+2*Math.abs(p[i][1]-p[i-1][1]);}return v;}

Ungolfed version:

int c(String q) {
    String[] r = {
        "qwertyuiop",
        "asdfghjkl",
        "zxcvbnm"
    };
    int v = 0, l = q.length(); // v=return value, l = a shorter way to refer to input length
    int[][] p = new int[l][2]; // an array containing two values for each
                               // letter in the input: first its position
                               // within the row, then its row number (both
                               // 1 indexed for golfy reasons)
    for(int i = 0; i<l; i++) { // loops through each letter of the input
        while (p[i][0] < 1) // this loop populates both values of p[i]
            p[i][0] = r[p[i][1]++].indexOf(q.charAt(i))+1;
        v += (i<1) ? 0 : Math.abs(p[i][0]-p[i-1][0])+2*Math.abs(p[i][1]-p[i-1][1]); // adds onto return value
    }
    return v;
}
\$\endgroup\$
  • \$\begingroup\$ You can save a few bytes by using int v=0,l=q.length(),p[][]=new int[l][2]; \$\endgroup\$ – Ypnypn Jul 3 '15 at 18:20
3
\$\begingroup\$

SWI-prolog, 162 bytes

a(A):-a(A,0).
a([A,B|C],T):-Z=`qwertyuiopasdfghjkl0zxcvbnm`,nth0(X,Z,A),nth0(Y,Z,B),R is T+(2*abs(Y//10-X//10)+abs(Y mod 10-X mod 10)),(C=[],print(R);a([B|C],R)).

Example: a(`qmq`) outputs 20 (And true after it but there's nothing I can do about that).

Edit: had to use 3 more bytes. My original program passed the test cases given but was actually incorrect (absolute values were misplaced/missing)

Note: if you want to use it on say Ideone, you have to replace all backquotes ` to double quotes ". Backquotes in my case (which is the current standard in SWI-Prolog) represent codes list for strings, and double-quotes character strings, but this is different in older versions of SWI-Prolog.

\$\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.