慢速打字员克拉伦斯


35

介绍

克拉伦斯(Clarence)是一位数据输入业务员,在互联网服务提供商处工作。他的工作是将所有ISP客户的IP地址手动输入数据库。他使用具有以下布局的键盘进行此操作:

123
456
789
.0

水平或垂直相邻按键的中心之间的距离恰好为1厘米。例如,3和的中心之间的距离9将是2厘米。中心之间的距离3,并5会√2cm。毕达哥拉斯定理足以计算任意两个键之间的距离。

正如您可能希望从从事ISP的人那里得到的那样,Clarence使用了非常缓慢且效率低下的键入系统。他用一根手指搜索键,然后将手指移至该键,然后按该键,然后重复输入数字中的所有数字。您可能将这种样式称为“鹰搜寻系统”,因为手指在按下键盘上方之前会搜索正确的键,然后再按下以进行击键,就像一只老鹰落下以进行杀死。

例如,这是Clarence输入数字的方式7851

  1. 他开始用手指按7并按下钥匙。
  2. 他将手指向右移动1厘米,8然后按下键。
  3. 他将手指向上移动1厘米,5然后按下按键。
  4. 他沿对角线向上移动手指,向左移动√2cm 1并按下键。

因此,总距离克拉伦斯移动他的手指在输入7851就是1 + 1 + √2大约是3.41厘米。

您的任务是编写一个程序,该程序计算Clarence必须移动手指才能键入任意IP地址的距离。

输入说明

输入是将采用以下格式的字符串

().().().()

其中每个()都是0- 范围内的整数999。这代表Clarence必须输入的IP地址。示例输入可能是:

219.45.143.143

我还要指出,尽管输入0.42.42.42999.999.999.999仍然是有效的输入,尽管它们是无效的IP地址。因此,您无需在程序中包含任何IP地址验证代码。

输出说明

输出Clarence为了输入指定的IP地址必须移动手指的距离。将答案四舍五入到需要的小数点后两位,然后cm在输出中使用单位。示例输入的输出为27.38cm(1 +√8+√5+ 2 +1 +√5+ 3 +1 +√5+√13+ 3 +1 +√5)。


29
伙计,ISP的键盘很奇怪……
丹尼斯2015年

1
@RetoKoradi我希望有一个程序,是的。可以使用stdin,命令行参数或用户输入函数。
2015年

2
@dacapoaria-对于较笨拙的打字员来说,“猎鹰搜索”也被称为“猎杀啄”或“搜索并消灭”。

12
@ArtofCode Clarence在ISP工作,有时ISP向他发送无效数据以输入数据库。Clarence无论如何都要键入数据。无论如何,这就是规范的原因。实际原因是因为我在编写规范时忽略了这一点。
2015年

3
仅考虑有效范围(0-255)IP地址,这应该是键盘在最短路径上键入所有地址的最佳安排吗?
以色列士气2015年

Answers:


16

CJam,46 44 43 38 37 34字节

rA,sd`f#3fmd2/2ew::.-::mh:+2mO"cm"

感谢@ user23013的建议mh,这使得节省5个字节成为可能。

CJam解释器中在线尝试。

怎么运行的

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
{3fmd~@-@@-mh}%
jimmy23013 2015年

@ user23013:谢谢。我mh什至不知道存在。
丹尼斯

16

Pyth,38 35 34字节

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

示范。

感谢@Dennis,将其编入浮动提示的字符串中。

解释,关于假的输入15.0

  • 首先,我们接受输入。它隐式存储在中z。'15 .0'
  • 我们将此列表映射如下:m.jF.Dx`ciUTT1k3z

    • UT:我们生成列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    • iUTT:接下来,我们将此列表视为以10为基数的数字,给我们123456789
    • ciUTT1:接下来,我们将该数字转换为浮点数,方法是将浮点数除以1,得到123456789.0
    • `:转换为字符串。 '123456789.0'
    • x k:获取该字符串中输入字符的索引。[0, 4, 9, 10]
    • .D 3.D是divmod函数,输出其第一输入除以第二输入并进行模运算。第二个输入是3,在这里。这给出了字符在小键盘上的物理位置。[(0, 0), (1, 1), (3, 0), (3, 1)]
    • .jF.j是复数构造函数。F将其应用于元组。[0j, (1+1j), (3+0j), (3+1j)]
  • .: 2:现在,我们采用此列表的2个条目子字符串,以便我们可以找到成对的距离。[[0j, (1+1j)], [(1+1j), (3+0j)], [(3+0j), (3+1j)]]
  • -M:取两个复数的差。[(-1-1j), (-2+1j), -1j]
  • .aM:获取结果的绝对值。这是键盘位置之间的距离。[1.4142135623730951, 2.23606797749979, 1.0]
  • s:计算距离。4.650281539872885
  • .R 2:舍入到小数点后两位。4.65
  • + "cm:添加'cm'到最后并打印。4.65cm

7

PHP-108字节

<?for(;$v=strpos(-.987654321,fgetc(STDIN));$l=$v)$l&&$t+=hypot($l/3%4-$v/3%4,$l%3-$v%3);printf('%.2fcm',$t);

输入来自标准输入。在-.987654321发送给strpos函数的计算结果为'-0.987654321'字符串中的上下文。


用法示例:

$ echo 219.45.143.143 | php isp.php
27.38cm

5

C,192个 177 159字节

更新版本,现在使用命令行参数完成程序。同时,改进后仍比以前的版本短:

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

    printf("%.2fcm",r);

    return 0;
}

高尔夫版本使用预处理器#define来缩短完整版本中的某些重复代码。


2
1.您打高尔夫球的版本末尾缺少分号。2.您打高尔夫球的版本产生了错误的结果,因为您s在检查*s非零值之前先进行了递增。3. OP在他的帖子中说过该程序。我不确定功能是否被接受。4.使用GCC,您不需要包含。5. sqrt比短sqrtf。6. pow(u-p,2)比短(u-p)*(u-p)。7.我不确定,但是我认为将两个坐标都存储在单个字符串和设置中,u=x[c]/3并且v=x[c]%3应该更短。
丹尼斯

修复了正确性问题。事实证明,在进行微调时,我一直在编译早期版本。对于那个很抱歉。1,2.固定。我真的很惊讶我可以离开他们。破碎的测试将解释这一问题... 3.根据我在Wiki / meta上看到的内容,如果未明确指定输入,则听起来像将输入作为函数参数是允许的选项。如果我的解释不正确,我会更改它。4.我一直以为只有返回的函数才int可以不声明使用。但是确实,clang也接受警告,所以我摆脱了它。
Reto Koradi 2015年

Wiki声明默认情况下允许使用功能,是的,但是OP编写您的任务是编写程序 ...如果将循环编写为,则不需要引入括号p=u,q=v,G,r+=...
丹尼斯

我要求OP澄清输入要求。在代码上,我将其回滚到稍旧的版本,然后将其优化为错误。我明天还会再进行调整,但是我不想让一个坏的版本停留太长时间。感谢您的指导。
Reto Koradi

@Dennis好吧,从各个方面来说,更新版本都应该更好。现在是完整的程序,并且由于进行了一些优化而缩短了程序。再次感谢您让我知道初始版本的问题。
Reto Koradi 2015年

3

JavaScript(ES6),132

通过弹出窗口进行I / O。运行代码片段进行测试(仅适用于Firefox)

[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')


3

Python 3,108个字节

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

公认打高尔夫球不是很好,但是至少可以和PHP联系在一起。



2

Python的199 171 166

SP3000为此提供了一个较短的Python代码(108):

https://codegolf.stackexchange.com/a/50854/41163

import sys
p=r=0
for i in sys.argv[1]:
 c=3,0
 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
 p=c
print"%.2fcm"%r

用法示例:

$ python isp.py 219.45.143.143
27.38cm

在线运行:http//codepad.org/h9CWCBNO

注释代码

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
      c=divmod(int(char)-1,3)

      if char<1:
         c=3,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
print"%.2fcm"%r

1
您可以通过if在一行上定义子句来节省一些字节,例如if i<1:c=3,1
Zgarb

1
您可以通过在文章顶部添加以下注释来突出显示语法:<!-- language: lang-python -->
Martin Ender
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.