Contar pulsos de discagem rotativa em um número de telefone (incluindo letras)

34

No dia dos seus avós, a discagem de um número de telefone era feita com um seletor rotativo como este:

Para discar cada dígito, coloque o dedo no orifício correspondente, puxe-o até a parada do dedo e solte-o. Um mecanismo fará com que o mostrador volte à sua posição de repouso, e o telefone desconectará e reconectará um circuito um número especificado de vezes, fazendo cliques audíveis.

A discagem do dígito N requer N desses "pulsos", exceto N = 0, que é dez pulsos.

Os telefones rotários têm a propriedade de que dígitos grandes (8, 9, 0) demoram mais para discar do que dígitos pequenos (1, 2, 3). Essa foi uma consideração importante na elaboração de mapas antigos de códigos de área, e por que a cidade de Nova York, com sua densidade populacional (e linha telefônica) pesada, obteve 212 (apenas 5 pulsos), enquanto que 907 (26 pulsos) foram para o Alasca, pouco habitada. Obviamente, tudo isso se tornou irrelevante quando a discagem por tom se tornou popular.

O desafio

Escreva, no menor número de bytes possível, um programa ou função que tenha como entrada uma sequência (ou sequência de caracteres) contendo um número de telefone e emita seu número de pulsos de discagem rotativa. Estes devem ser contados da seguinte forma:

Dígitos

  • Os dígitos 1 a 9 contam como esse número de pulsos.
  • O dígito 0 conta como 10 pulsos.

Cartas

Observe que os dígitos de 2 a 9 no mostrador têm letras do alfabeto latino associadas a eles. Originalmente, eles eram destinados a trocas nomeadas , mas foram reapropriados para palavras de telefone e para sistemas de entrada de mensagens de texto.

Você deve ter letras nos seus números de telefone, usando a atribuição E.161 de letras para dígitos:

  • A, B, C = 2
  • D, E, F = 3
  • G, H, I = 4
  • J, K, L = 5
  • M, N, O = 6
  • P, Q, R, S = 7
  • T, U, V = 8
  • W, X, Y, Z = 9

Você pode assumir que a entrada já foi dobrada em maiúsculas e minúsculas.

Outros personagens

Você deve permitir o uso arbitrário dos caracteres ()+-./e do espaço como separadores de formatação. Você pode optar por permitir qualquer caractere não alfanumérico para esse fim, se for mais fácil de implementar.

Esses caracteres não contribuem para a contagem de pulsos.

Código de exemplo

Uma tabela e função de pesquisa sem golf no Python:

PULSES = {
    '1': 1,
    '2': 2, 'A': 2, 'B': 2, 'C': 2,
    '3': 3, 'D': 3, 'E': 3, 'F': 3,
    '4': 4, 'G': 4, 'H': 4, 'I': 4,
    '5': 5, 'J': 5, 'K': 5, 'L': 5,
    '6': 6, 'M': 6, 'N': 6, 'O': 6,
    '7': 7, 'P': 7, 'Q': 7, 'R': 7, 'S': 7,
    '8': 8, 'T': 8, 'U': 8, 'V': 8,
    '9': 9, 'W': 9, 'X': 9, 'Y': 9, 'Z': 9,
    '0': 10
}

def pulse_count(phone_num):
    return sum(PULSES.get(digit, 0) for digit in phone_num)

Exemplo de entrada e saída

  • 911 → 11
  • 867-5309 → 48
  • 713 555 0123 → 42
  • +1 (212) PE6-5000 → 57
  • 1-800-FLOWERS → 69
  • PUZZLES → 48
dan04
fonte
Suponho que a pontuação e os espaços arbitrários em ASCII sejam restritos aos normalmente usados ​​para números de telefone ( +- ()*#.), assim como as letras são restritas a maiúsculas. Corrija-me se eu estiver errado.
Adám
1
@ Adám: restringi os sinais de pontuação exigidos a apenas alguns separadores comuns. Ele não inclui deliberadamente *e #, que possuem significados especiais em telefones com tom de toque e não podem ser discados em rotativos.
dan04
1
Podemos usar todas as letras minúsculas em vez de todas as letras maiúsculas? Podemos pegar uma matriz de caracteres em vez de uma string?
Grimmy
1
Eu sou um viajante do tempo! Eu sou um viajante do tempo! Eu sou um viajante do tempo! Desde que eu definitivamente usei telefones como este quando eu era criança, claramente EU SOU MEU PRÓPRIO AVÔ !!!!!!! O que é realmente muito nojento quando penso nisso. Bleah !!!
Bob Jarvis - Restabelecer Monica
3
Eu sou o avô. Eu usei telefones assim nos anos 50. E quando me mudei para uma cidade em um local rural, descobri que a companhia telefônica não oferecia serviço de tom. Isso foi em 1985! Sem brincadeiras! Minha avó tinha um telefone na sala com gancho e manivela. Você tirou o fone do gancho e girou a manivela para obter um operador de quadro de distribuição. Ela teve que substituí-lo quando a discagem direta à distância foi configurada.
Walter Mitty

Respostas:

25

05AB1E , 19 18 17 15 bytes

AÁ0ªā6+žq÷9š‡þO

Experimente online!

Esta é a primeira resposta para usar π. Por que usar π, você pode perguntar? Bem, as letras estão associadas a 22233344455566677778889999, em ordem. Observe como a maioria dos dígitos se repete 3 vezes, mas 7 se repete 4 vezes. Você poderia dizer que cada dígito se repete (3 + 1/7) vezes, em média. Gostaria de saber se existe algum número que é aproximadamente 3 + 1/7 e leva menos bytes que 22/7…

Isso fornece apenas 4 7s, não 4 9s, portanto ainda precisamos lidar com Z como um caso especial.

A               # alphabet (abcdefghijklmnopqrstuvwxyz)
 Á              # rotate right (zabcdefghijklmnopqrstuvwxy)
  0ª            # append 0 (zabcdefghijklmnopqrstuvwxy0)

ā6+             # range [7..33]
   žq÷          # divide by π (22233344455566677778889991010)
      9š        # prepend 9 (922233344455566677778889991010)

‡               # transliterate the implicit input with the two lists above
                # this replaces z → 9, a → 2, … y → 9, 0 → 10
 þ              # remove all non-digits
  O             # sum
Grimmy
fonte
Por que letras minúsculas em vez de maiúsculas?
dan04
1
@ dan04 porque 05AB1E tem um built-in para enviar "abcdefghijklmnopqrstuvwxyz", mas não para "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Eu poderia converter o alfabeto em maiúsculas em vez de converter a entrada em minúscula, mas é o mesmo bytecount.
Grimmy
1
Editei a pergunta para tornar desnecessários seus dois primeiros comandos.
dan04
3
@Jonah Comecei com a idéia de dividir um intervalo por uma constante para obter a sequência desejada, e, ao mesmo tempo, procurando a melhor maneira de expressar "um pouco mais que 3" em 05AB1E, lembrei-me de que o pi era um elemento interno.
Grimmy
2
+1 para uso de pi
Draconis
9

C # (compilador interativo do Visual C #) , 51 bytes

n=>n.Sum(x=>x>64?(x-59-x/83-x/90)/3:x>47?1-~x%~9:0)

Guardado 1 byte graças a @recursive

Economizou 10 bytes graças à observação de @ ExpiredData que só () +-/.estará na entrada

Experimente online!

n =>                     // Function taking input as string
  n.Sum(x =>             // Map each value 'x' through the following
    x>64 ?               //   If 'x' is an uppercase letter
      (x-59-x/83-x/90)/3 //     Take each char's ASCII value subtracted by 59, and subtract
                         //     one if the char is 'S' and one if the char is 'Z'
    : x>47 ?             //   Else if the char is a digit
      1-~x%~9            //   Take 1 - (-x - 1) % -10 (Maps 0 to 10, and 1-9 to themselves
    : 0                  //   Else, 0
  )                      // And sum it all up, then return it
Modalidade de ignorância
fonte
4
-10é ~9, o que deve funcionar em contexto.
recursivo
@recursive Isso é inteligente, obrigado
Modalidade de Ignorância
1
x <91 check é redundante, pois a entrada consiste apenas em () + -. / a tecla de espaço e os números todos <64, portanto, podemos determinar se o caractere está em maiúscula simplesmente verificando x> 64 (so -5 bytes)
Dados expirados
O mesmo vale para a verificação x <58, pois nada no intervalo 58-64 estará na entrada
Data de
51 bytes
Dados expirados
5

APL (Dyalog Unicode) , SBCS de 27 bytes

Função de prefixo tácito anônimo.

+/'@ADGJMPTW'∘⍸+11|(1⌽⎕D)∘⍳

Experimente online!

()∘⍳ Encontre o ndex * de cada caractere na seguinte string:
  * elementos que não foram encontrados, obtenha o índice 1 + o índice máximo, ou seja, 11
⎕D  os dígitos:"0123456789"

1⌽ gire ciclicamente um passo para a esquerda; "1234567890"

11| o restante da divisão, quando dividido por 11 *
  *, fornece 0 para todos os que não sejam dígitos
... + adicione isso ao seguinte:

'@ADGJMPTW'∘⍸ o ter nterval ɩ ndex * para cada caractere
  * Portanto, [−∞, "@") fornece 0, ["@", "A") fornece 1, ["A", "D") fornece 2, etc.
+/  soma que

Adão
fonte
5

Python 2 , 74 bytes

lambda s:sum([(n-59-n/83-n/90)/3,1-~n%~9][n<58]for n in map(ord,s)if n>47)

Experimente online!

Faz alguma aritmética no valor ASCII para cada caractere. A primeira opção verifica letras e a segunda opção verifica números. O esclarecimento de que todos os caracteres de pontuação permitidos na entrada são aqueles com valores ASCII menores que 48 permitem-me simplificar a lógica, mas agora um novo método pode ser melhor.

Python 2 , 84 bytes

lambda s:sum(1+'1xxxx2ABCx3DEFx4GHIx5JKLx6MNOx7PQRS8TUVx9WXYZ0'.find(c)/5for c in s)

Experimente online!

Usa uma string de pesquisa codificada, com cada bloco de 5 caracteres correspondente aos caracteres, fornecendo cada valor começando com 1. Os espaços em branco são preenchidos x, o que não pode estar na entrada que está em maiúscula. Felizmente, os caracteres que não aparecem na cadeia produzem -1o .findque fornece uma soma de zero.

xnor
fonte
5

JavaScript (Node.js) , ... 76 69 bytes

s=>s.replace(/\w/g,q=>w+=1/q?+q||10:parseInt(q,35)*.32-1|0||9,w=0)&&w

Experimente online!

-7 obrigado @Arnauld!

Explicação

 q |     1/q     |  +q  | parseInt(q,35)*.32 | parseInt(q,35)*.32-1|0 | Output
---+-------------+------+--------------------+------------------------+--------
 0 | Infinity(T) | 0(F) |         N/A        |           N/A          |   10
 1 |  1.0000(T)  | 1(T) |         N/A        |           N/A          |    1
 2 |  0.5000(T)  | 2(T) |         N/A        |           N/A          |    2
 3 |  0.3333(T)  | 3(T) |         N/A        |           N/A          |    3
 4 |  0.2500(T)  | 4(T) |         N/A        |           N/A          |    4
 5 |  0.2000(T)  | 5(T) |         N/A        |           N/A          |    5
 6 |  0.1666(T)  | 6(T) |         N/A        |           N/A          |    6
 7 |  0.1428(T)  | 7(T) |         N/A        |           N/A          |    7
 8 |  0.1250(T)  | 8(T) |         N/A        |           N/A          |    8
 9 |  0.1111(T)  | 9(T) |         N/A        |           N/A          |    9
 A |    NaN(F)   |  N/A |        3.20        |          2(T)          |    2
 B |    NaN(F)   |  N/A |        3.52        |          2(T)          |    2
 C |    NaN(F)   |  N/A |        3.84        |          2(T)          |    2
 D |    NaN(F)   |  N/A |        4.16        |          3(T)          |    3
 E |    NaN(F)   |  N/A |        4.48        |          3(T)          |    3
 F |    NaN(F)   |  N/A |        4.80        |          3(T)          |    3
 G |    NaN(F)   |  N/A |        5.12        |          4(T)          |    4
 H |    NaN(F)   |  N/A |        5.44        |          4(T)          |    4
 I |    NaN(F)   |  N/A |        5.76        |          4(T)          |    4
 J |    NaN(F)   |  N/A |        6.08        |          5(T)          |    5
 K |    NaN(F)   |  N/A |        6.40        |          5(T)          |    5
 L |    NaN(F)   |  N/A |        6.72        |          5(T)          |    5
 M |    NaN(F)   |  N/A |        7.04        |          6(T)          |    6
 N |    NaN(F)   |  N/A |        7.36        |          6(T)          |    6
 O |    NaN(F)   |  N/A |        7.68        |          6(T)          |    6
 P |    NaN(F)   |  N/A |        8.00        |          7(T)          |    7
 Q |    NaN(F)   |  N/A |        8.32        |          7(T)          |    7
 R |    NaN(F)   |  N/A |        8.64        |          7(T)          |    7
 S |    NaN(F)   |  N/A |        8.96        |          7(T)          |    7
 T |    NaN(F)   |  N/A |        9.28        |          8(T)          |    8
 U |    NaN(F)   |  N/A |        9.60        |          8(T)          |    8
 V |    NaN(F)   |  N/A |        9.92        |          8(T)          |    8
 W |    NaN(F)   |  N/A |       10.24        |          9(T)          |    9
 X |    NaN(F)   |  N/A |       10.56        |          9(T)          |    9
 Y |    NaN(F)   |  N/A |       10.88        |          9(T)          |    9
 Z |    NaN(F)   |  N/A |         NaN        |          0(F)          |    9

Todos [space]().+-/não são capturados por /\w/g, portanto, eles não afetarão o total.

Shieru Asakoto
fonte
5

Perl 5 -p , 52 51 bytes

@Grimy recebe crédito por -1

y/A-Z/22233344455566677778889/;map$\+=$_||10,/./g}{

Experimente online!

Xcali
fonte
/\d/gdeve ser /./g-1 (sim, ele ainda lida com pontuação corretamente).
Grimmy
4

Retina 0.8.2 , 34 bytes

T`WTPMJGDA`Rd
}T`L`2L
0
55
\d
$*
1

Experimente online! O link inclui casos de teste. Explicação:

T`WTPMJGDA`Rd

Converta as letras WTPMJGDAnos dígitos 9..0.

}T`L`2L

Embaralhe todas as letras restantes em 1 e repita até que todas as letras tenham sido convertidas em dígitos.

0
55

Substitua 0por, 55pois eles recebem o mesmo número de pulsos para discar.

\d
$*
1

Pegue a soma digital.

Neil
fonte
3

K4 , 44 bytes

Solução:

+/(1+(1+&(5#3),4 3 4),!10)(.Q.A,1_.Q.n,"0")?

Exemplos:

q)k)+/(1+(1+&(5#3),4 3 4),!10)(.Q.A,1_.Q.n,"0")?"911"
11
q)k)+/(1+(1+&(5#3),4 3 4),!10)(.Q.A,1_.Q.n,"0")?"867-5309"
48
q)k)+/(1+(1+&(5#3),4 3 4),!10)(.Q.A,1_.Q.n,"0")?"+1 (212) PE6-5000"
57
q)k)+/(1+(1+&(5#3),4 3 4),!10)(.Q.A,1_.Q.n,"0")?"1-800-FLOWERS"
69

Explicação:

Abordagem ingênua, provavelmente bastante jogável. Índice de pesquisa de caracteres, pontuação de pesquisa, soma.

+/(1+(1+&(5#3),4 3 4),!10)(.Q.A,1_.Q.n,"0")? / the solution
                                           ? / lookup
                          (               )  / do this together
                                       "0"   / string "0"
                                      ,      / join with
                                  .Q.n       / string "0123456789"
                                1_           / drop first
                               ,             / join with
                           .Q.A              / "A..Z"
  (                      )                   / do this together
                      !10                    / range 0..9
                     ,                       / join with
     (              )                        / do this together
               4 3 4                         / list (4;3;4)
              ,                              / join with
         (5#3)                               / list (3;3;3;3;3)
        &                                    / where, creates list 0 0 0 1 1 1 2 2 etc
      1+                                     / add 1
   1+                                        / add 1
+/                                           / sum up
rua
fonte
3

Perl 6 , 53 bytes

{sum +<<m:g/\d/X||10}o{S:g[<:L>]=$/.ord*.313-28+|0+9}

Experimente online!

Multiplica o código ASCII com 0,313 em vez de 1/3 e usa OR bit a bit que arredonda para zero para obter o viés correto .

Nwellnhof
fonte
3

C (gcc) , 94 89 86 80 bytes

Obrigado a roofcat, nwellnhof e Rogem pelas sugestões.

c;f(char*s){c=*s-48;s=*s?(c<10U?c?c:10:c-17<26U?(c-11-c/35-c/42)/3:0)+f(s+1):0;}

Experimente online!

ErikF
fonte
80 bytes usando recursão em vez de um loop.
Sugerir em c<43Uvez dec-17<26U
ceilingcat 25/07
2

Bash , 256 bytes

Você pode substituir as (( … ))construções letpor uma contagem de bytes idêntica. Pode haver um bom algoritmo para reduzir as instruções de caso, mas não o encontrou até o momento. Com um pouco de retrabalho, você também pode torná-lo uma função (mas não com o mesmo ou menos bytes, a menos que você possa descontar o function fname { … }topo e a cauda).

read p;while ((${#p}>0));do case ${p:0:1} in ([1-9]) ((d+=${p:0:1}));; ([0]) ((d+=10));; ([ABC) ((d+=2));; ([P-S]) ((d+=7));; ([W-Z]) ((d+=9));;([DEF]) ((d+=3));; ([GHI]) ((d+=4));; ([JKL]) ((d+=5));; ([MNO]) ((d+=6));; (?) d=$d; esac;p=${p#?};done;echo $d

Experimente online!

Uma solução melhor usando a técnica de caractere de mapa faz uso da trferramenta:

[Bash com tr], 173 bytes

read p;p=$(echo $p|tr A-Z 22233344455566677778889999);while ((${#p}>0));do case ${p:0:1} in ([1-9]) ((d+=${p:0:1}));; ([0]) ((d+=10));; (?) d=$d; esac;p=${p#?}; done;echo $d

Experimente online!

PJF
fonte
Um algoritmo que eu perdi, é claro, é fazer alguma substituição / tradução de string no AZ. Isso seria bom. Vou alterar o acima para se adequar.
PJF
while((${#p}))funciona, economizando três bytes. c=${p:0:1};case c in ([0-9]) ((d+=c?c:10));;salva outro 16. Com tr -dc 0-9adicionado ao pipeline tr, você não precisa de uma declaração de caso e a adição pode ser dobrada na whilecondição com &&.
Oh meu Deus
Obrigado OMG. Eu não costumo usar tarefas ternárias, então perdi isso. O uso interessante do complemento de exclusão também (mas isso pressupõe que minha solução ignora qualquer outro caractere). Eu consegui baixá-lo para 133 bytes como em: read p;p=$(echo $p|tr A-Z 22233344455566677778889999|tr -dc [0-9]);while ((${#p}));do c=${p:0:1}&&((d+=c?c:10));p=${p#?};done;echo $d
PJF
1
118: p=$(head -1|tr A-Z 22233344455566677778889|tr -dc 0-9);while((${#p}));do((d+=(c=${p:0:1})?c:10));p=${p#?};done;echo $d.. os três últimos 9s não são necessários porque tr reutilizará o último caractere de substituição se o segundo argumento for muito curto.
Oh meu Deus
1
O primeiro exemplo pode ser reduzido de 256 para 236 removendo alguns espaços desnecessários. read p;while((${#p}>0));do case ${p:0:1} in ([1-9])((d+=${p:0:1}));;([0])((d+=10));;([ABC)((d+=2));;([P-S])((d+=7));;([W-Z])((d+=9));;([DEF])((d+=3));;([GHI])((d+=4));;([JKL])((d+=5));;([MNO])((d+=6));;(?)d=$d;esac;p=${p#?};done;echo $d
steve
2

PowerShell , 109 102 87 bytes

$(switch -r($args|% t*y){\d{$_}[A-Y]{("{0}"-f(.313*$_-18))[0]}[Z]{9}0{10}})-join'+'|iex

Experimente online!

EDIT: Usada a idéia do @ mazzy para um comutador regex com alguma formatação de string para converter char -> int -> string e pegar apenas o primeiro 'dígito'

Original:

[char[]]"$args"|%{$a+=(48,(('22233344455566677778889999')[$_-65],(58,$_)[$_-ne48])[$_-lt64])[$_-gt47]-=48};$a

Eu esperava obter <100 bytes, então continuarei olhando para ver se há mais alguma coisa que eu possa fazer. Provavelmente existe uma maneira de remover a sequência numérica

Desculpe se isso é confuso, pois aninhei matrizes com instruções de indexação booleana, mas -

Explicação:

[char[]]"$args"|%{lê a entrada convertida como uma seqüência de caracteres e a explode em uma matriz char e inicia um loop for-each, verificando ()[$_-gt47]se alguma ()+-./foi inserida (todas possuem valores de caracteres ascii <48)
Nota: O PowerShell aceita $truee $falsecomo 1e 0respectivamente para índices de matriz

Então obtemos 48os símbolos ou:
('22233344455566677778889999'[$_-65],(58,$_)[$_-ne48])[$_-lt64]

As [$_-lt64]verificações de um número ou uma letra (todas assumidas em maiúsculas aqui). Se for uma letra, '22233344455566677778889999'[$_-65]altere para 0-25 para indexar na matriz e gerar o valor do pulso (como um caractere). Se o caractere for um número, veremos: (58,$_)[$_-ne48]verificando 0e emitindo 58ou apenas o caractere numérico.

Em torno de tudo $a+= ... -=48inicializa uma variável numérica $ a at 0e adiciona a saída. A saída é o valor ascii char de um número, portanto subtraia 48.

Nota: se a entrada era um símbolo, obtemos $a+=48-48, efetivamente ignorando-a. Se fosse 0, conseguimos $a+=58-48obter nossos +10

Por fim, ;$aapenas gera nosso post de valor final para cada loop

Sinusoid
fonte
você pode economizar alguns bytes Experimente online!
mazzy 12/06
Ah, sim, eu tinha alguns parênteses extras e os =que sobraram dos meus métodos anteriores de resolver isso, obrigado pela captura! Porém, eu não vi o t*yantes, você poderia explicar por que isso funciona para explodir a string em uma matriz de caracteres?
Sinusoid
para obter '<100 bytes': Experimente online! :)
mazzy
boa ideia com -fe [0].
mazzy
2

PowerShell , 95 85 79 bytes

inspirado pela resposta de nwellnhof .

inspirado pela resposta[0] de Sinusoid .

$(switch -r($args|% t*y){\d{$_}0{10}[A-Y]{"$(.313*$_-18)"[0]}Z{9}})-join'+'|iex

Experimente online!

Versão desenrolada:

$(
    switch -r($args|% toCharArray){
        \d    {$_}
        0     {10}
        [A-Y] {"$(.313*$_-18)"[0]}
        Z     {9}
    }
)-join '+'|Invoke-Expression
key .313*$_-18 "$(...)"[0]
--- ---------- -----------
  A      2.345 2
  B      2.658 2
  C      2.971 2
  D      3.284 3
  E      3.597 3
  F      3.910 3
  G      4.223 4
  H      4.536 4
  I      4.849 4
  J      5.162 5
  K      5.475 5
  L      5.788 5
  M      6.101 6
  N      6.414 6
  O      6.727 6
  P      7.040 7
  Q      7.353 7
  R      7.666 7
  S      7.979 7
  T      8.292 8
  U      8.605 8
  V      8.918 8
  W      9.231 9
  X      9.544 9
  Y      9.857 9
confuso
fonte
1
Esforço em equipe! : D
Sinusoid
1

Kotlin , 113 bytes

{s:String->var t=0
for(c in s){val v=c-'0'
t+=when(v){0->10
in 1..9->v
in 17..42->(v-11-v/35-v/42)/3
else->0}}
t}

Experimente online!

JohnWells
fonte
0

Python 3 , 134 123 bytes

f=lambda n:sum(map(int,n.translate(n.maketrans('ADGJMPTWBEHKNQUXCFILORVYSZ','23456789'*3+'79','()+-./ '))))+10*n.count('0')

Experimente online!

-11 bytes graças a @ dan04

Artemis apoia Monica
fonte
1
Reorganizando as letras para 'ADGJMPTWBEHKNQUXCFILNRVYSZ', você pode reduzir a sequência de números para '23456789'*3+'79'.
dan04 14/06