The very weird word counter

13

1

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!

Vajura

Posted 2015-06-30T12:19:33.637

Reputation: 447

1I think q->m is only 8 keys... – SuperJedi224 – 2015-06-30T12:22:44.703

2if you go down one row it counts as 2 distance, you dont count the key distance – Vajura – 2015-06-30T12:24:08.463

its up there too :) – Vajura – 2015-06-30T12:25:42.943

Can we assume that the input string will always be nonempty? – Alex A. – 2015-06-30T14:35:58.830

This is quite similar to http://codegolf.stackexchange.com/questions/50722/clarence-the-slow-typist. Except that this uses letters, while the other one used numbers.

– Reto Koradi – 2015-06-30T14:46:49.860

Can we assume that there will be at least two letters? – Dennis – 2015-06-30T16:31:38.190

Yea lets say there will always be atleast 2 letters – Vajura – 2015-07-02T05:19:12.540

Answers

2

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.

Dennis

Posted 2015-06-30T12:19:33.637

Reputation: 196 637

1man how does that even work – Vajura – 2015-07-02T07:32:42.190

@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.

– Kade – 2015-07-02T13:00:18.223

@Vajura: I've edited my answer. – Dennis – 2015-07-02T18:37:02.107

7

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)].

Kade

Posted 2015-06-30T12:19:33.637

Reputation: 7 463

5

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;
}

vijrox

Posted 2015-06-30T12:19:33.637

Reputation: 471

You can save a few bytes by using int v=0,l=q.length(),p[][]=new int[l][2]; – Ypnypn – 2015-07-03T18:20:11.463

3

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.

Fatalize

Posted 2015-06-30T12:19:33.637

Reputation: 32 976