Palavras de fácil digitação

30

Esta competição acabou.

O vencedor é CJam com 22 caracteres, superando a resposta de TwiNight por um caractere. Parabéns Dennis !

Uma menção honrosa vai para Falko , que ficou totalmente doida com as importações gratuitas.

.


Há um tempo atrás, eu queria saber como posso superar os smartphones modernos com o meu Nokia 3310 e, embora algumas respostas sejam realmente boas, ainda não consigo acompanhar! Talvez eu deva adotar uma abordagem diferente e simplesmente não escrever nenhuma palavra que seja difícil de digitar.

Chamaremos um pedaço de texto de fácil digitação se não houver duas letras consecutivas no mesmo botão do teclado do telefone, de acordo com o layout padrão:

Telephone Keyboard


Sua tarefa

Sua tarefa é escrever um programa / função que aceite uma string sde stdin / como parâmetro e retorne um valor verdadeiro, se sfor facilmente digitável, e um valor falso, caso contrário. A entrada consistirá apenas de letras minúsculas e espaços e é garantida que não está vazia!

Pontuação

Este é um codegolf, então a menor contagem de caracteres vence.

Declarações de importação não serão contados para a sua pontuação final, por isso, se você sempre quis para uso std::set_symmetric_difference, liftM4ou itertools.combinationsem seu código, agora é a hora!

-3 se o seu código-fonte for facilmente digitado, assumindo que tudo o que não é uma letra está no botão 0. Afinal, talvez eu queira enviar seu código para alguns amigos!

Casos de teste

Aqui estão alguns casos de teste para verificar se seu código está funcionando como pretendido:

"x" -> True
"aardvark" -> False
"ardvark" -> True
"flonk" -> False

"im codegolfing all day long" -> False
"i indulge in minimizing bytecount" -> True

"havent heard from you in a long time" -> False
"your silence was of undue permanence" -> True

"how are  you" -> False
"how are you" -> True

Feliz golfe!

Flonk
fonte
Dois espaços consecutivos são ruins?
Martin Ender
@ MartinBüttner yes! Provavelmente deve adicionar um caso de teste para isso.
Flonk
9
Eu tenho um dumbphone nokia, se eu pressionar espaço duas vezes, recebo um número 0.
overactor
1
Pergunta relacionada: crie um layout de teclado para telefone que maximize alguma pontuação com base na facilidade de digitação das palavras que ocorrem com mais frequência.
justinpc 11/09/14
1
@ jpcooper como os dois mencionados aqui ? Eu usei o 8pen e gosto muito dele, exceto que o vidro do meu telefone esquenta com o uso (do contato, não da atividade da CPU) e o coeficiente de atrito dificulta o uso de entradas longas. Usando o s-caneta na nota 3 é muito mais fácil :)
Eben

Respostas:

6

CJam, 34 31 27 22 caracteres

1l{'h-_9/-D+3/X\:X^*}/

Experimente online.

Exemplo de execução

$ cjam <(echo "1l{'h-_9/-D+3/X\:X^*}/") <<< 'aardvark'; echo
0
$ cjam <(echo "1l{'h-_9/-D+3/X\:X^*}/") <<< 'ardvark'; echo
66000

Como funciona

1l                         " Push a R := 1 and read a line L from STDIN.                  ";
                           " Initialize X := 1. (implicit)                                ";
  {                  }/    " For each character C of L, do the following:                 ";
    'h-                    "     C -= 'h'                                                 ";
       _9/-D+3/            "     Y := (C - C / 9 + 13) / 3                                ";
               X\  ^*      "     R *= X ^ Y                                               ";
                 :X        "     X := Y                                                   ";
                           " Print R. (implicit)                                          ";

fundo

O núcleo do código consiste em aplicar um mapa F a cada caractere C da sequência de entrada, para que as imagens dos símbolos na mesma tecla sejam correspondentes. Encontrei o mapa adequado observando o seguinte:

O mapa T: C ↦ (C - 'h') + 13 transforma a sequência S: = "abcdefghijklmnopqrstuvxyz" da seguinte maneira:

[-59   6  7  8   9 10 11  12 13 14  15 16 17  18 19 20  21 22 23 24  25 26 27  28 29 30 31]

Para as chaves 0para 6, seria suficiente para dividir T (C) por 3 , mas nós temos que aplicar algum tipo de correção para os personagens s , t , v , y e z .

O mapa D: C ↦ (C - 'h') / 9 transforma a cadeia S na seguinte matriz:

[ -8   0  0  0   0  0  0   0  0  0   0  0  0   0  0  0   0  1  1  1   1  1  1   1  1  1  2]

Isto corrige os quocientes de s , t , v , y e z , sem afectar os outros.

Finalmente, o mapa F: C ↦ (T (C) - D (C)) / 3 transforma a sequência S da seguinte maneira:

[-17   2  2  2   3  3  3   4  4  4   5  5  5   6  6  6   7  7  7  7   8  8  8   9  9  9  9]

Tudo o que resta é comparar os caracteres consecutivos de alguma forma. Para esse propósito, XOR F (C) com a imagem do caractere anterior - para o primeiro, XOR F (C) com 1 (valor padrão da variável X ), que não possui pré-imagem - e multiplicamos todos os resultados.

O produto será Falsas se e apenas se um dos factores é zero, ou seja, se e somente se dois caracteres consecutivos têm a mesma imagem por F .

Dennis
fonte
Eu acho que o byte (não caractere) conta para este é 54
@Optimizer Acho que o wiki da tag code-golf diz bytes
Esta resposta não contém mais caracteres não ASCII.
Dennis
@professorfish A tag wiki é apenas o padrão. Se o desafio especificar caracteres, são caracteres.
Martin Ender
27

Python 2-80, 68, 64, 61, 58, 50, 48, 45, 44 42

Embora esteja ficando um pouco ridículo agora, continuarei usando importações de bibliotecas gratuitas, até a __builtin__biblioteca:

from numpy import diff as D
from pprint import pprint as P
from __builtin__ import all as A
from __builtin__ import raw_input as I
from __builtin__ import bytearray as B

Portanto, apenas a seguinte linha curta conta para o comprimento do código:

P(A(D([(o-o/112-o/59)/3for o in B(I())])))

Créditos à Markuz pelas idéias a respeito input()! Esses desafios de importação gratuita sempre apresentam algumas bibliotecas menos conhecidas. ;)


Alternativa usando apenas a operatorbiblioteca ( 98, 83 79):

from operator import ne as n
K=[(ord(c)-1-(c>'p')-(c>'w'))/3for c in input()]
print all(map(n,K[1:],K[:-1]))

Eu vou parar por aqui Mas você poderia promover golf esta versão usando sys, pprinte outras bibliotecas ...


Alternativa sem bibliotecas (105):

s=input()
n=lambda c:(ord(c)-1-(c>'p')-(c>'w'))/3
print all([n(s[i])!=n(s[i+1])for i in range(len(s)-1)])
Falko
fonte
E, mais uma vez, publicamos independentemente a mesma solução em Ruby e Python. Parece que desta vez você está ganhando. ;) ... Você também não pode salvar 4 bytes, atribuindo ord(c)a uma variável (digamos o) e subtraindo c/112e, em c/119vez dos booleanos?
Martin Ender
@ MartinBüttner: Sim, de vez em quando o Python pode vencer o Ruby. Infelizmente, não posso atribuir variáveis ​​com lambdaexpressões tão facilmente. Com [(o-1-o/112-o/119)/3for o in map(ord,s)]eu termino com 80 bytes novamente.
Falko
Ah entendo. Doente nova melhoria embora! : D
Martin Ender
Muito impressionante. E você ainda pode salvar 3 bytes from sys import argv as susando, em s[1]vez de #input()
Markuz
importação inputde __builtin__bem é, na verdade ainda melhor: D salvando ainda um outro Byte.
Markuz
20

Ruby Regex (most popular flavours), 106 83 bytes

Because regex

^(?!.*(  |[abc]{2}|[def]{2}|[ghi]{2}|[jkl]{2}|[mno]{2}|[p-s]{2}|[tuv]{2}|[w-z]{2}))

I've just cut the middleman (Ruby) and made this a pure-regex solution. Works in a lot of flavours and only finds a match if the string does not contain two consecutive characters on the same button.

Martin Ender
fonte
Can't you put that {2} outside the alternation, saving 22 bytes?
Niet the Dark Absol
1
@NiettheDarkAbsol unfortunately not, because then it can pick different alternatives for the two repetitions.
Martin Ender
Aah, of course. I knew there was a reason XD
Niet the Dark Absol
Kudos for a readable, understandable, golfed solution!
GreenAsJade
12

Bash+coreutils, 49

tr a-z $[36#8g7e9m4ddqd6]7778888|grep -Pq '(.)\1'

Returns an exit code of 1 for TRUE and 0 for FALSE:

$ for s in "x" "aardvark" "ardvark" "flonk" "im codegolfing all day long" "i indulge in minimizing bytecount" "havent heard from you in a long time" "your silence was of undue permanence" "how are  you" "how are you"; do echo "./3310.sh <<< \"$s\" returns $(./3310.sh <<< "$s"; echo $?)"; done
./3310.sh <<< "x" returns 1
./3310.sh <<< "aardvark" returns 0
./3310.sh <<< "ardvark" returns 1
./3310.sh <<< "flonk" returns 0
./3310.sh <<< "im codegolfing all day long" returns 0
./3310.sh <<< "i indulge in minimizing bytecount" returns 1
./3310.sh <<< "havent heard from you in a long time" returns 0
./3310.sh <<< "your silence was of undue permanence" returns 1
./3310.sh <<< "how are  you" returns 0
./3310.sh <<< "how are you" returns 1
$ 
Digital Trauma
fonte
Very nice! This would be 46 characters in Perl: perl -pE'y/a-z/aaadddgggjjjmmmpppptttwwww/;$_=!/(.)\1/' <(echo "x") It prints 1 for true and nothing for false.
hmatt1
@chilemagic Go ahead and post the perl answer :). Don't forget to add one to the score for using the -p command-line parameter (as per code-golf conventions).
Digital Trauma
I thought I could find a way to shorten aaadddgggjjjmmmpppptttwwww but I've given up.
Ben Jackson
2
@BenJackson I figured out a way. We can actually use a string of any distinct characters - 11122233344455566667778888 will do. By base 36 encoding the first 19 digits of this number, we can save 1 char!
Digital Trauma
9

APL(Dyalog), 24 23

~∨/2=/⌊¯13⌈.21-.31×⎕AV⍳⍞

∧/2≠/⌊¯13⌈.21-.31×⎕AV⍳⍞

Explanation

: Takes string input from screen
⎕AV: This is the atomic vector which is bascially a string of all characters APL recognizes, which of course include all lowercase letters (index 18~43) and space (index 5)
: IndexOf function. For many functions in APL that takes one or two scalar arguments, you can feed it an array in place of a scalar - APL will do the looping for you. So returns a numeric array of indices. .21-.31×: Times 0.31 and then subtract from 0.21. This is a little trick that maps letter on the same key (especially PQRS) to the same number (when rounded down to integers), except Z, which get mapped to its own group
¯13⌈: max with -13. This brings Z back to the group with WXY
: Round down to integers
2≠/: Pairwise-. Returns a boolean array for each consecutive pair.
∧/: AND together all entries of the resulting array.

TwiNight
fonte
I was going to post something like this, but you beat me to it. Damn Z key! You can still shave 1 char off by saying ∧/2≠/ (all consecutive pairs are typed on different keys) instead of ~∨/2=/ (no consecutive pair is typed on the same key.) APL FTW!!!
Tobia
Yes tkx. I was thinking "I should be able to shave off 1 char here why can't I do it OMGGGG!!!" But I got to go to class so I just post what I have. And, yes, DAMN Z KEY. Unfortunately I am on my phone so I can't edit it until later
TwiNight
And I made a conscious thought about De Morgan's Laws and still can't figure it out... How dumb
TwiNight
1
Good luck texting this to your friends. ;)
Thane Brimhall
This looks very interesting. Is there any way to try this code without purchasing a Dyalog APL interpreter? The online interpreter I usually use doesn't seem to understand the dialect...
Dennis
7

Perl - 44

This is basically a Perl adaptation of @DigitalTrauma's answer posted with his permission. Shaved off 2 characters thanks to @KyleStrand.

y/b-y/aadddgggjjjmmmpppptttzzz/;$_=!/(.)\1/

43 characters + 1 for -p flag. y/// is the same as tr///. It prints 1 for true and nothing for false. I can post a detailed explanation if requested.

Example run:

perl -pE'y/b-y/aadddgggjjjmmmpppptttzzz/;$_=!/(.)\1/' <(echo "x")

Perl - 81

$s=join"]{2}|[",qw(abc def ghi jkl mno p-s tuv w-z);say/^(?!.*(  |[$s]{2}))/?1:0

+1 for -n flag. It works by using join to create the regex (same one as Martin's), which shaves of a few bytes.

Example run:

perl -nE'$s=join"]{2}|[",qw(abc def ghi jkl mno p-s tuv w-z);say/^(?!.*(  |[$s]{2}))/?1:0' <(echo "your silence was of undue permanence")
hmatt1
fonte
Couldn't you shave off two characters from the Perl solution by letting a and z remain untransliterated? y/b-y/aadddgggjjjmmmpppptttzzz/;$_=!/(.)\1/ Also, this won't handle spaces, will it?
Kyle Strand
...oh, right, two spaces in a row is already two identical characters in a row. My bad.
Kyle Strand
@KyleStrand nice call on letting a and z remain the same. Updated answer!
hmatt1
4

JavaScript - 159 156 bytes

function g(s){p=n=-1;for(i=0;i!=s.length;i++){p=n;n=s.charCodeAt(i);n-=97;if(n>17)n--;if(n>23)n--;if(p==-1)continue;if(~~(p/3)==~~(n/3))return 0;}return 1;}

Returns 1 for truthy and 0 for falsy.

If only I could get rid of the keywords.

Lozzaaa
fonte
At least you can get rid of some whitespaces and if's :) 141 : function g(s){p=n=-1;for(i=0;i<s.length;i++){p=n;n=s.charCodeAt(i)-97;n>17&&n--;n>23&&n--;if(~p)continue;if(~(p/3)==~(n/3))return 0}return 1}
Optimizer
You use lots of interesting things in your answer that I haven't seen before. I usually write in C++ but I thought I'd give JS a shot as it's quicker to test online.
Lozzaaa
I only found this place today and thought I'd give it a shot. My next try will be superior :D
Lozzaaa
You can make your code a character shorter by replacing the != in the for loop by a <.
ProgramFOX
Yes that was in Optimizer's optimisations :) what's the etiquette on using people's suggestions in my answer? Now that there is another JavaScript entry that I can beat by accepting those modifications.
Lozzaaa
4

c, 74 bytes

main(c,d,r){for(;~(c=getchar());r*=d!=c/3,d=c/3)c-=--c/'p'*(c-'k')/7;c=r;}

Returns a non-zero exit status for TRUE and 0 for FALSE:

$ for s in "x" "aardvark" "ardvark" "flonk" "im codegolfing all day long" "i indulge in minimizing bytecount" "havent heard from you in a long time" "your silence was of undue permanence" "how are  you" "how are you"; do echo "./3310 <<< \"$s\" returns $(./3310 <<< "$s"; echo $?)"; done
./3310 <<< "x" returns 40
./3310 <<< "aardvark" returns 0
./3310 <<< "ardvark" returns 216
./3310 <<< "flonk" returns 0
./3310 <<< "im codegolfing all day long" returns 0
./3310 <<< "i indulge in minimizing bytecount" returns 72
./3310 <<< "havent heard from you in a long time" returns 0
./3310 <<< "your silence was of undue permanence" returns 232
./3310 <<< "how are  you" returns 0
./3310 <<< "how are you" returns 8
$ 
Digital Trauma
fonte
You can save 3 bytes by changing your while to for(;c=~getchar();d=c/3), and another byte by changing your first if to a ?: operator.
Allbeert
@Allbeert - Thanks. The parenthesis around c=getchar() are required though because ~ has higher precedence than =. Still, I'll take the other two bytes :)
Digital Trauma
For the last bit, does something like exit(d!=c/3); instead of if(d==c/3)exit(0); work?
@professorfish That would make the exit at that point unconditional, which I don't want
Digital Trauma
You can save one character with r*=d^c/3
Alchymist
3

Ruby 1.8, 89 83 81 78 bytes

p$*[0].chars.map{|c|c=c[0];(c-c/?p-c/?w-1)/3}.each_cons(2).map{|a,b|a!=b}.all?

Here is another submission. To my shame, it beats the regex. :(

This takes the string via command-line argument and prints a boolean.

As for the algorithm, I'm shifting down the letters after p by one and after z by two, and then I check that there are no collisions after integer division by 3.

PS: This is the first time, that using Ruby 1.8 shortened the code (due to the shorter way to get character codes).

Martin Ender
fonte
3

Cobra - 80

def f(s)
    for c in s
        for x in 9,if' adgjmptw'[x]>c,break
        t,f=x,t<>x
    print f
Οurous
fonte
3

JavaScript (ES6) 66 74

F=s=>[...s].every(c=>[...' adgjmptw'].map(x=>s+=c<x,w=s,s=0)|s!=w)

The inner loop find the group for each character. Conceptually is a 'reduce' but 'map' is shorter. The outer loop compare the group of consecutive chars and exits with false if they are equal.

Test In Firefox/Firebug console

;["x","aardvark","ardvark","flonk","im codegolfing all day long",
"i indulge in minimizing bytecount","havent heard from you in a long time",
"your silence was of undue permanence","how are  you","how are you"]
.forEach(x=>console.log(x + ' -> ' + F(x)))

Output

x -> true
aardvark -> false
ardvark -> true
flonk -> false
im codegolfing all day long -> false
i indulge in minimizing bytecount -> true
havent heard from you in a long time -> false
your silence was of undue permanence -> true
how are  you -> false
how are you -> true
edc65
fonte
You can do .some instead of every. Because even if it fails one time, the answer is falsy.
Optimizer
@Optimizer some and every are interchangeble, fiddling with the conditions. But here simply put some instead of every will not work, try it.
edc65
Hmm, you are right. I need to understand your logic first.
Optimizer
Please don't mind if I start using this [...s].every trick in my golfs :)
Optimizer
2

Perl, 83 bytes

$_=<>;chop;map{$_=ord;$_=($_-$_/112-$_/119-1)/3;die 0 if$l==$_;$l=$_}split//;die 1

Making heavy abuse of $_ in Perl.

mcreenan
fonte
1
As you can observe, is allowed to pass command-line parameters to the interpreter, just you have to count the extra parameters. (The bare minimum needed to access the code, -e in Perl, is free.) 71 characters alternative with command-line parameters: perl -nlaF -e 'map{$_=ord;$_=($_-$_/112-$_/119-1)/3;die 0 if$l==$_;$l=$_}@F;die 1'.
manatwork
@manatwork you don't need the -l, but it looks good!
hmatt1
@chilemagic, I just tried to reproduce the original code's equivalent, so I added -l as replacement for chop. But of course, you are right.
manatwork
Thanks @manatwork, I didn't even think to making use of the command line options for Perl.
mcreenan
2

Two tasks are tricky in Python; detecting chains, and assigning the groups. Both can be assisted using numpy, but it is not in the standard library.

Python 2 (only standard library) - 59 chars function

from itertools import imap as M
from __builtin__ import bytearray as A, all as E
from operator import ne as D, not_ as N
from re import S, sub as X, search as F

# 68
#def f(s):
# g=[(n-n/115-n/61)/3for n in A(s)]
# return E(M(D,g,g[1:]))

# 67 with regex via regex
#f=lambda s:N(F(X('(\S)(.)',r'|[\1-\2]{2}','  acdfgijlmopstvwz'),s))

# 59 slightly optimized ordinal classifier and regex sequence detector
f=lambda s:N(F(r'(.)\1',A((n-n/23-n/30)/3for n in A(s)),S))

# 69 using itertools.groupby
#from itertools import groupby as G
#from __builtin__ import sum as S, len as L
#f=lambda s:N(S(L(A(g))-1for _,g in G((n-n/115-n/61)/3for n in A(s))))

Python 2 (only standard library) - 53 chars stdin to exit value

Here I abuse the fact that issubclass(bool,int), so changing all() to any() gets me a valid exit value, shaving off the not() from the return value. The removal of function overhead made the regex versions fall behind in size.

from itertools import groupby as G, imap as M
from __builtin__ import bytearray as A, any as E
from __builtin__ import raw_input as I
from sys import exit as Q
from operator import eq as S

g=[(n-n/23-n/30)/3for n in A(I())]
Q(E(M(S,g,g[1:])))
Yann Vernier
fonte
2

J - 42 char

Function taking string on the right.

*/@(2~:/\(I.4 3 4 1,~5#3){~(u:97+i.26)&i.)

First we map the alphabet (u:97+i.26) into the numbers 0 through 25, all other characters (including spaces) going to 26 (i.). Then we map ({~) the first three elements map to the first key, the next three to the next key, and so on through the keys of the phone pad, making sure to map the space/other punctuation to a separate key at the end. (4 3 4 1,~5#3 is equal to 3 3 3 3 3 4 3 4 1 and I. turns that into a 27-item array where the first three are key 1, etc.) Then we check for pairwise inequality (2~:/\) and AND all the results together (*/).

   */@(2~:/\(I.4 3 4 1,~5#3){~(u:97+i.26)&i.) 'i indulge in minimizing bytecount'
1
   f =: */@(2~:/\(I.4 3 4 1,~5#3){~(u:97+i.26)&i.)
   f 'im codegolfing all day long'
0
   f '*/@(2~:/\(I.4 3 4 1,~5#3){~(u:97+i.26)&i.)'  NB. no -3 bonus :(
0
algorithmshark
fonte
2

Racket, 119

(define(f t)(for*/and([s(map ~a'(abc def ghi jkl mno pqrs tuv wxyz))][i s][j s])(not(regexp-match(format"~a~a"i j)t))))

Ungolfed (combinatoric regexing):

(define(f t)
  (for*/and([s (map ~a '(abc def ghi jkl mno pqrs tuv wxyz))]
            [i s]
            [j s])
    (not (regexp-match (format "~a~a" i j) t))))
Matthew Butterick
fonte
1

JavaScript - 152

Not a winner but I gave it a shot. Beats @Lozzaaa by 4 bytes as of posting time :)

function m(a){c="abc-def-ghi-jkl-mno-pqrstuv-wxyz";j=a.split("");for(z in j)if(j[z]=Math.floor(c.indexOf(j[z])/4),0!=z&&j[z-1]==j[z])return 0;return 1};

Passes all the tests.
Takes advantage of JS's lack of typing to make a multi type array, and it takes advantage of indexOf returning -1 for space support.

Usage:

m("string here")

Assumes lowercase alphabetic characters and spaces only. Returns 1 for true, 0 for false.

Maybe if I knew ES6 I could try the second challenge...

DankMemes
fonte
"if only ... " - Did you see my answer ? :P
Optimizer
Yes I did. I don't know ES6 (yet), sadly. However, this was interesting to make.
DankMemes
Yeah, your solution using an interesting approach.
Optimizer
1

ES6, JavaScript 89 70 characters

I know its not a winner because when coming to handy operations like getting ASCII value of character, JS puts a lot of bloat (.charCodeAt()).

N=s=>[...s].every(c=>l-(l=(c.charCodeAt()-(c>"r")-(c>"y")-1)/3|0),l=1)

Run it in Web Console of latest Firefox.

Usage:

N("testing if this works")

The function returns either true or false.

EDIT: Golfed a lot using the [...x].every trick learned from @edc65 (Thanks!)

I will try to golf it more :)

Optimizer
fonte
0

GML (Game Maker Language), 149

s=argument0p=n=-1for(i=0;i<string_length(s);i++){p=n;n=string_char_at(s,i)-97;x=n>17&&n--;x=n>23&&n--‌​;if(!p)x=1if(!(p/3)=!(n/3))x=0}show_message(x)
Timtech
fonte
0

Python 3 - 152 chars

Not the shortest I could go, but it'll do for now

k=['abc','def','ghi','jkl','mno','pqrs','tuv','wxyz',' ']
x=input()
l=2>1
for i in range(len(x)-1):
 for j in k:
  if x[i+1] in j and x[i] in j:l=1>2
print(l)
Beta Decay
fonte