Clarence is a data entry clerk who works at an internet service provider. His job is to manually enter the IP addresses of all of the ISP's customers into the database. He does this using a keypad which has the following layout:


The distance between the centre of horizontally or vertically adjacent keys is exactly one centimetre. For instance, the distance between the centres of 3 and 9 would be two centimetres. The distance between the centres of 3 and 5 would be √2cm. The Pythagoras theorem is sufficient to calculate the distance between any two keys.

Clarence, as you might expect from one who works in an ISP, uses a very slow and inefficient system of typing. He uses a single finger and searches for the key, and then moves his finger to the key, then presses it, and repeats for all of the digits in the number. You might know of this style as the "eagle search system" since the finger searches above the keyboard for the correct key before plunging down for the keypress, like an eagle plunging down for a kill.

For example, here is how Clarence would type out the number 7851:

  1. He starts his finger at 7 and pushes the key.
  2. He moves his finger to the right 1cm to 8 and pushes the key.
  3. He moves his finger upwards 1cm to 5 and pushes the key.
  4. He moves his finger diagonally upwards and left √2cm to 1 and pushes the key.

Therefore the total distance that Clarence moved his finger to type in 7851 is 1 + 1 + √2 which is about 3.41cm.

Your task is to write a program that calculates the distance Clarence must move his finger to type in arbitrary IP addresses.

Input Description

Input is a string that will be in the form


where each () is an integer in the range 0 - 999. This represents the IP address that Clarence must type in. An example input might be:

I would also like to point out that inputs such as or 999.999.999.999 are still valid inputs, despite the fact that they are invalid IP addresses. So you don't need to include any IP address verification code in your program.

Output Description

Output the distance that Clarence must move his finger in order to type in the specified IP address. Round answers to two decimal places where needed, and use the cm unit in your output. The output for the example input is 27.38cm (1 + √8 + √5 + 2 + 1 + √5 + 3 + 1 + √5 + √13 + 3 + 1 + √5).

  • 30
    \$\begingroup\$ Man, ISPs have weird keyboards... \$\endgroup\$
    – Dennis
    Commented May 25, 2015 at 2:15
  • 3
    \$\begingroup\$ @dacapoaria - 'eagle search' is also known as 'hunt and peck' or 'search and destroy' for the more heavy-handed typists. \$\endgroup\$
    – user31556
    Commented May 25, 2015 at 9:51
  • 2
    \$\begingroup\$ @MathiasFoster Search and Destroy typing gives me an interesting mental image. Thanks for telling me these different terms. \$\endgroup\$
    – absinthe
    Commented May 25, 2015 at 10:45
  • 12
    \$\begingroup\$ @ArtofCode Clarence works at an ISP, and sometimes the ISP sends him the invalid data to type into the database. Clarence types the data in anyway. That's the canonical reason anyway. The actual reason is because I overlooked that when writing the spec. \$\endgroup\$
    – absinthe
    Commented May 25, 2015 at 11:59
  • 3
    \$\begingroup\$ Considering only the valid range (0-255) IP Addresses, which should be the optimum arrangement of the keyboard to type all that addresses in the shortest path? \$\endgroup\$ Commented May 25, 2015 at 17:18

8 Answers 8


CJam, 46 44 43 38 37 34 bytes


Thanks to @user23013 for suggesting mh, which made it possible to save 5 bytes.

Try it online in the CJam interpreter.

How it works

r     e# Read a token from STDIN.
A,    e# Push [0 1 2 3 4 5 6 7 8 9].
s     e# Stringify: [0 1 2 3 4 5 6 7 8 9] -> "0123456789"
d     e# Cast to Double: "0123456789" -> 123456789.0
`     e# Inspect: 123456789.0 -> "123456789.0"
f#    e# Push the index of each character from the input in "123456789.0".
3fmd  e# Push the quotient and residue of each index divided by 3.
2/    e# Split the resulting array into pairs.
2ew   e# Convert the array of pairs in the array of all overlapping pairs of pair.
::.-  e# Reduce each pair using vectorized difference: [[a b][c d]] -> [a-b c-d]
::mh  e# Reduce each reduced pair to its 2-norm distance: [a b] -> sqrt(aa + bb)
:+    e# Sum all distances.
2mO   e# Round to two decimal places.
"cm"  e# Push "cm".
  • 2
    \$\begingroup\$ {3fmd~@-@@-mh}%. \$\endgroup\$
    – jimmy23013
    Commented May 25, 2015 at 3:57
  • \$\begingroup\$ @user23013: Thanks. I had no idea mh even existed. \$\endgroup\$
    – Dennis
    Commented May 25, 2015 at 4:16

Pyth, 38 35 34 bytes

+.Rs.aM-M.:m.jF.Dx`ciUTT1b3z2 2"cm


Indexing into the string of a float idea thanks to @Dennis.

Explanation, on the phony input 15.0:

  • First, we take the input. It is implicitly stored in z. '15.0'
  • We map this list as follows: m.jF.Dx`ciUTT1k3z.

    • UT: We generate the list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].
    • iUTT: Next, we treat this list as a base 10 number giving us 123456789.
    • ciUTT1: Next, we convert this number to a float by floating point dividing it by 1, giving 123456789.0.
    • `: Convert to a string. '123456789.0'
    • x k: Take the index of the input character in that string. [0, 4, 9, 10].
    • .D 3: .D is the divmod function, outputing its first input divided and modulo'd by the second input. The second input is 3, here. This gives the physical location of the character on the numpad. [(0, 0), (1, 1), (3, 0), (3, 1)].
    • .jF: .j is the complex number constructor. F applies it to the tuple. [0j, (1+1j), (3+0j), (3+1j)].
  • .: 2: Now, we take the 2 entry substrings of this list so we can find the pairwise distances. [[0j, (1+1j)], [(1+1j), (3+0j)], [(3+0j), (3+1j)]].
  • -M: Takes the difference of the two complex numbers. [(-1-1j), (-2+1j), -1j].
  • .aM: Takes the absolute value of the result. This is the distance between the keypad locations. [1.4142135623730951, 2.23606797749979, 1.0]
  • s: Sum the distances. 4.650281539872885.
  • .R 2: Round to 2 decimal places. 4.65.
  • + "cm: Add 'cm' to the end and print. 4.65cm.

PHP - 108 Bytes


Input is taken from stdin. The -.987654321 sent to the strpos function evaluates to '-0.987654321' in a string context.

Sample usage:

$ echo | php isp.php

C, 192 177 159 bytes

Updated version, now complete program using command line argument. At the same time, improved to still be shorter than previous version:

#define G c=*a[1]++,c=c>48?c-49:c/2-14,u=c%3,v=c/3
float r;c,u,v,p,q;main(int n,char**a){for(G;*a[1];)p=u,q=v,G,p-=u,q-=v,r+=sqrt(p*p+q*q);printf("%.2fcm",r);}


#include <stdio.h>
#include <math.h>

float r;
int c, u, v, p, q;

int main(int n, char** a) {
    c = *a[1]++;
    c = c > 48 ? c - 49 : c / 2 - 14;
    u = c % 3;
    v = c / 3;
    for ( ; *a[1]; ) {
        p = u;
        q = v;
        c = *a[1]++;
        c = c > 48 ? c - 49 : c / 2 - 14;
        u = c % 3;
        v = c / 3;
        p -= u;
        q -= v;
        r += sqrt(p * p + q * q);


    return 0;

The golfed version uses a preprocessor #define to shorten some of the repeated code in the full version.

  • 2
    \$\begingroup\$ 1. Your golfed version is missing a semicolon at the end. 2. Your golfed version is producing incorrect results, since you increment s before checking that *s is non-zero. 3. The OP said program in his post. I'm not sure if a function is accepted. 4. With GCC, you don't need the include. 5. sqrt is shorter than sqrtf. 6. pow(u-p,2) is shorter than (u-p)*(u-p). 7. I'm not sure, but I think storing both coordinates in a single string and setting u=x[c]/3 and v=x[c]%3 should be shorter. \$\endgroup\$
    – Dennis
    Commented May 25, 2015 at 4:59
  • \$\begingroup\$ Fixed the correctness problem. Turns out that I kept compiling an earlier version while doing fine tuning. Sorry about that. 1, 2. Fixed. I was actually surprised that I could leave them away. The broken testing would explain it... 3. Based on what I saw on wiki/meta, it sounded like taking the input as function arguments is an allowed option if the input is not explicitly specified. I'll change it if my interpretation is incorrect. 4. I always thought that only functions that return int could be used undeclared. But indeed, clang also accepts it with a warning, so I got rid of it. \$\endgroup\$ Commented May 25, 2015 at 5:38
  • \$\begingroup\$ The wiki states that functions are allowed by the default, yes, but the OP wrote your task is to write a program... You don't need the brackets you introduced if you write the loop as p=u,q=v,G,r+=.... \$\endgroup\$
    – Dennis
    Commented May 25, 2015 at 5:52
  • \$\begingroup\$ I asked the OP for clarification on the input requirements. On the code, I rolled it back to a slightly older version before I optimized it into incorrectness. I'll take another shot at tuning it tomorrow, but I didn't want to leave a broken version standing for too long. Thanks for the pointers. \$\endgroup\$ Commented May 25, 2015 at 6:01
  • \$\begingroup\$ @Dennis Ok, updated version should be better in every way. Now a complete program, and still shorter thanks to some optimizations. Thanks again for letting me know about the problems with the initial version. \$\endgroup\$ Commented May 25, 2015 at 22:19

JavaScript (ES6), 132

I/O via popup. Run the snippet to test (Firefox only)

[for(a of prompt(d=''))[p,q,d]=[x=(a=a<'0'?9:-a?a-1:10)%3,y=a/3|0,d!==''?d+Math.sqrt((p-=x)*p+(q-=y)*q):0]],alert(d.toFixed(2)+'cm')


Python 3, 108 bytes

L=[x//3*1j+x%3for x in map("123456789.0".find,input())]
print("%.2fcm"%sum(abs(a-b)for a,b in zip(L,L[1:])))

Admittedly not very well golfed, but at least it ties with PHP.


Ruby 135 139

gets.chars.each_cons(2).map{|a|i,j=a.map{|e|'123456789.0'.index e}
print s.round(2),'cm'

Test it online: http://ideone.com/2CIQa5


Python 199 171 166

There's a shorter Python code (108) for this by SP3000:


import sys
for i in sys.argv[1]:
 if i!=".":c=divmod(int(i)-1,3)
 if i<1:c=3,1
 if p:r+=((p[1]-c[1])**2+(p[0]-c[0])**2)**0.5

Sample usage:

$ python isp.py

Run online: http://codepad.org/h9CWCBNO

Commented code

import sys

# p - last position as (y,x) tuple - initialized with 0, because "if 0" -> equals to "False"
p = 0
# r - result of adding all distances - ini with 0, because not moved any distances on start
r = 0

# Loop over chars
for char in sys.argv[1]:
   # c - current position of typist as (y,x) tuple

   # Always set c to position of "." key 
   c = 3,0 # lazy for c=(3,0)

   # Check if char is not the "." key
   if char !=".":

      # Get position of char on keypad

      if char<1:

   # If this is the first char, 
   # then STORE_OPERATION has not been executed, 
   # so p is still p=0 from original initialization 
   # calling "if 0" evaluates to False,
   # so we jump this code block, for the first char
   if p:                           
      # calculate delta of x, y from current and last position, 
      # then add both deltas squared (**2),
      # then get square root of it (**0.5 = **1/2)
      # add to r (+=)
      r+=( (p[1]-c[1])**2 + (p[0]-c[0])**2 )**0.5

   # STORE_OPERATION - Store current position as last position
   p = c

# .2f returns r with 2 trailing digits
  • 1
    \$\begingroup\$ You can save some bytes by defining if clauses on one line, like if i<1:c=3,1 \$\endgroup\$
    – Zgarb
    Commented May 27, 2015 at 13:08
  • 1
    \$\begingroup\$ You can add syntax highlighting by putting this comment at the top of your post: <!-- language: lang-python --> \$\endgroup\$ Commented May 27, 2015 at 13:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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