Сколько раз я должен нажать на это?

24

Мы все привыкли к старой школьной телефонной клавиатуре, верно? Для справки вот как это выглядит:

Телефонная клавиатура


Если задана строка, состоящая только из строчных букв ASCII и одинарных пробелов , ваша задача состоит в том, чтобы вернуть количество нажатий, которое нужно сделать, чтобы набрать полную строку с телефонной клавиатуры, как показано выше.

Для тех, кто не знаком с этим, вот как это работает:

  • 2Например, на ключе с цифрой также abcзаписана строка . Для того, чтобы набрать a, вы должны нажать эту клавишу один раз, потому что bвы должны нажать дважды, и cвы должны нажать трижды.

  • Для последовательных букв, которые находятся на одной и той же клавише, вы должны подождать 1 секунду, прежде чем нажимать снова. Итак, если вы хотите печатать cb, вы должны нажать 3 раза c, подождать секунду, а затем дважды нажать b, так что еще 5 нажатий.

  • То же самое относится ко всем остальным клавишам, за исключением одного пробела, который требует только одного нажатия. Также обратите внимание, что ключи 7и 9имеют четыре буквы на них. Применяется тот же алгоритм, единственное отличие состоит в количестве букв. Строки, соответствующие каждой клавише, можно найти на изображении выше (но в нижнем регистре) или в следующем списке, который содержит все символы, которые вы можете получить:

    "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz", " "
    

Тестовые случаи

Вход -> Выход (Пояснение)

"" -> 0 (ничего не должно касаться)
«вода» -> 8 («w, a, t» для каждого требуется 1 нажатие (на клавиши 9, 2 и 8), для «e» требуется 2 нажатия (для клавиши 3), для «r» требуется 3 нажатия (для клавиши 7). ), 1 + 1 + 1 + 2 + 3 = 8)
«мыло» -> 9 (4 + 3 + 1 + 1)
"кандела" -> 13 (3 + 1 + 2 + 1 + 2 + 3 + 1)
«код гольф» -> 20 (3 + 3 + 1 + 2 + 1 (для места) + 1 + 3 + 3 + 3)
«Царь горы» -> 33 (2 + 3 + 2 + 1 + 1 + 3 + 3 + 1 + 1 + 2 + 2 + 1 + 2 + 3 + 3 + 3)

Спекуляции

  • Применяются стандартные правила ввода / вывода и стандартные лазейки.

  • Вы можете принимать данные только в родном типе String вашего языка. Вывод может быть целым числом или строковым представлением этого целого числа.

  • Это , выигрывает самый короткий ответ на любом языке .

Мистер Xcoder
источник
2
Я думаю, что это был бы более интересный вопрос, если бы вы делали 1 нажатие в секунду, и вам пришлось ждать 1 секунду и считать секунды вместо нажатий.
Якк
@ Yakk Это было бы слишком сложно
мистер Xcoder
@ Mr.Xcoder А ты уверен? Я видел, как мастера кода делают невозможные вещи в меньшем пространстве, чем твит.
J_F_B_M

Ответы:

11

JavaScript (ES6) 77 66 64 60 байт

(Сохранено несколько байтов благодаря @Johan Karlsson и @Arnauld).

s=>[...s].map(l=>s=~~s+2+'behknquxcfilorvysz'.search(l)/8)|s

Рик Хичкок
источник
(s,t=0)=>[...s].map(l=>t+=(1+'behknquxcfilorvysz'.indexOf(l)/8|0)+1)&&tдля 71 байта
Йохан Карлссон
Спасибо, @JohanKarlsson, я понял то же самое, когда был в душе! Нашел еще одну оптимизацию, чтобы сбрить еще 5 байтов.
Рик Хичкок
6
Я нашел чисто арифметическое решение для 71 байт: f=s=>[...s].map(c=>t+=((c=parseInt(0+c,36))>23?c+3:c&&~-c%3)%7%4+1,t=0)|t.
Нил
1
@ Нил, хотя это не может быть короче, это, конечно, умнее.
Рик Хичкок
1
@Neil Вы должны опубликовать это.
г-н Xcoder
7

05AB1E , 29 26 25 байт

ð¢svA•22ā₂•S£ð«øðδKy.åƶOO

Попробуйте онлайн!

объяснение

ð¢                         # count spaces in input
  sv                       # for each char y in input
    A                      # push the lowercase alphabet
     •22ā₂•S               # push the base-10 digit list [3,3,3,3,3,4,3,4]
            £              # split the alphabet into pieces of these sizes
             ð«            # append a space to each
               ø           # transpose
                ðδK        # deep remove spaces
                   y.å     # check y for membership of each
                      ƶ    # lift each by their index in the list
                       O   # sum the list
                        O  # sum the stack
Emigna
источник
Извините, но для пустого ввода это дает 10. Это хорошо в другом месте
г-н Xcoder
@ Mr.Xcoder: пустая строка не выводит, но все равно не так. Спасибо за уведомление, я исправлю это.
Эминья
2
Это дает 10 на TIO.
Мистер Кскодер
@ Mr.Xcoder: Да, вы должны явно дать пустую строку. Нет ввода не совпадает с пустой строкой. Это немного сбивает с толку, я знаю. Хотя сейчас исправлено :)
Emigna
@ Mr.Xcoder: ввод пустой строки происходит следующим образом
Эмигна
7

Python 2 , 56 байт

Использует тот же алгоритм, что и решение Javascript @ RickHitchcock

lambda x:sum('behknquxcfilorvysz'.find(c)/8+2for c in x)

Попробуйте онлайн!

овс
источник
Интересное решение. Как это работает для пробелов, я не понимаю>. <?
г-н Xcoder
@ Mr.Xcoder для чего-либо не в строке '...'.find(c)возвращается -1. Добавляя 2, мы получаем одно нажатие клавиши.
овс
Я знал, что это вернулось -1, но не осознавал, что у вас есть +2после этого шаблон ... Во всяком случае, самое короткое решение Python на сегодняшний день.
г-н Xcoder
О, я случайно нашел то же самое решение после того, как медленно запустил мою программу, пока не понял, что вы ее опубликовали :( Отличная работа для поиска этого решения :)
Mario Ishac
5

Python 3 , 69 67 65 64 байта

1 байт благодаря мистеру Xcoder.

1 байт благодаря Фелипе Нарди Батиста.

lambda x:sum((ord(i)+~(i>"s"))%3+3*(i in"sz")+(i>" ")for i in x)

Попробуйте онлайн!

Дрянная Монахиня
источник
Сохранить один байт, заменяя i==" "с i<"a", потому что вы получите только буквы и пробелы
г -
4
61 минута ... слишком поздно!
Эрик Outgolfer
5

Дьялог АПЛ, 37 байт

+/⌈9÷⍨'adgjmptw behknqux~cfilorvy~'⍳⍞

Попробуйте онлайн!

Как?

Получить NDEX каждого полукокса входа в строке 'adgjmptw behknqux~cfilorvy~'( sи по zумолчанию будет 28), делим на 9, сгонять и сумму.

Уриэль
источник
Вы можете использовать, 'adgjmptw ' 'behknqux' 'cfilorvy' 'sz'чтобы сохранить некоторые байты
Kritixi Lithos
49 байтов
Утечка Монахиня
@LeakyNun onice
Уриэль
Вы можете
оставить
@ Уриэль, подожди, тебе не нужно считать, f←так что это 47 байт
Leaky Nun
4

JavaScript (ES6), 71 байт

f=
s=>[...s].map(c=>t+=((c=parseInt(0+c,36))>23?c+3:c&&~-c%3)%7%4+1,t=0)|t
<input oninput=o.textContent=f(this.value)><pre id=o>

Смотри без буквенных таблиц! Я не совсем понял формулу @ LeakyNun, поэтому придумал свою.

Нил
источник
Чистая арифметика :)
Mr. Xcoder
Что s=>[...s]делать, почему не простоs=>s.map()...
Эван Кэрролл
1
@EvanCarroll s- это строка, поэтому вы не можете mapнапрямую это сделать. ...sповторяется s, в то время [...s]как итерация преобразуется в массив, эффективно разделяясь sна массив символов.
Нил
4

C, 211 196 байт

Первое представление здесь ... выглядит довольно длинным, и я вижу, что это не эффективный подход, но, по крайней мере, он работает :)

f(char*n){char*k=" abcdefghijklmnopqrstuvwxyz";int t[]={0,3,3,3,3,3,4,3,4};int l=0,s,j,i;while(*n){i=0;while(k[i]){if(k[i]==*n){s=0;for(j=0;s<i-t[j];s+=t[j++]);*n++;l+=(!i?1:i-s);}i++;}}return l;}

Безголовая версия:

int f(char *n){
  char *k=" abcdefghijklmnopqrstuvwxyz";
  int t[]={0,3,3,3,3,3,4,3,4};
  int l=0,s,j,i;
  while(*n){                          // loop through input characters
    i=0;
    while(k[i]){
      if(k[i]==*n){                   // find matching char in k
        s=0;
        for(j=0;s<i-t[j];s+=t[j++]);  // sum up the "key sizes" up to the key found
        *n++;
        l+=(!i?1:i-s);                // key presses are i-s except for space (1)
      }
      i++;
    }
  }
  return l;
}
dbuchmann
источник
*(k+i)может быть k[i].
CalculatorFeline
Вы можете сократить пробел после *(например char*n) и добавить свои декларации в ваш пустой forоператор (вместо того int s=0,j=0;(for(;, чтобы иметь его for(int s=0,k=0;) и вместо i==0использования!i
Tas
Спасибо за эти подсказки. Я не мог поместить его sв цикл for, потому что я использую его позже, но я собрал intобъявления и использовал assignemts там, где они мне были нужны.
dbuchmann
Yay парень C гольфист! В любом случае, некоторые указатели: циклы for строго лучше, чем циклы while практически во всех ситуациях - используйте свободные точки с запятой, особенно в выражении итерации. Используйте запятые вместо точек с запятой в большинстве мест, это позволяет вам избежать использования фигурных скобок в большинстве мест. Есть и другие оптимизации, но они больше зависят от того, какую версию C вы компилируете.
dj0wns
4

Haskell - 74 71 62 байта

Редактировать: удалил 3 байта, используя понимание списка вместо фильтра

Изменить: Сохранить 9 байтов благодаря Сиракузы, Лайкони и Згарб!

f=sum.(>>= \x->1:[1|y<-"bcceffhiikllnooqrrsssuvvxyyzzz",y==x])

использование

λ> f "candela"
13
λ>

Попробуйте онлайн!

Генри
источник
Какова цель дубликатов писем?
г-н Xcoder
@ Mr.Xcoder Он используется для подсчета нажатий, я добавлю объяснение.
Генри
Вы можете сохранить один байт, переписав fв f=length.(=<<)(\x->x:[y|y<-l,y==x]), где (=<<)находится concatMapздесь.
Сиракуза
И еще один с возвращением к filter:f=length.(=<<)(\x->x:filter(==x)l)
Сиракуза
1
Поскольку вы используете lтолько один раз, он может быть встроен.
Лайкони
3

Clojure, 82 76 байт

#(apply +(for[c %](+(count(filter #{c}"bcceffhiikllnooqrrsssuvvxyyzzz"))1)))

О, это проще всего filterи countчем использовать frequencies. Оригинал:

#(apply +(count %)(for[c %](get(frequencies"bcceffhiikllnooqrrsssuvvxyyzzz")c 0)))

Строка кодирует во сколько раз больше, чем один раз, когда вам нужно нажать клавишу для данного символа :)

NikoNyrh
источник
2

Ява, 95 73 байта

a->a.chars().map(b->1+(b<64?0:b+(Math.abs(b-115)<4?4:5))%(3+b/112)).sum()

Спасибо Кевину Круйссену за то, что он сделал функцию лямбда-выражением (где aимеет тип String). 95 байтов стало 73 байта!

Лямбда-выражение суммирует количество нажатий каждого символа, используя map(). map()преобразует каждый символ (ASCII в диапазоне строчного является 97-122) в потоке до соответствующего значения (выглядит как простая пила волна, но , принимая во внимание как 4 цикла напрягает) , используя эту математику: 1+(b<64?0:b+(Math.abs(b-115)<4?4:5))%(3+b/112). Вот график desmos этой модели.

Адам Менденхолл
источник
В списке лазеек написано, что не следует размещать фрагменты кода, даже если кажется, что все это уже сделали. В любом случае, моя полная программа составляет 130 байтов . Вот оно:interface Z{static void main(String a){System.out.print(a.chars().map(b->1+(b<64?0:b+(Math.abs(b-115)<4?4:5))%(3+b/112)).sum());}}
Адам Менденхолл
1
Добро пожаловать в PPCG! Вы действительно правы, что фрагменты запрещены, но по умолчанию это программа или функция . А с Java 8 вы можете использовать лямбды. Так что в этом случае a->{return a.chars().map(b->1+(b<64?0:b+(Math.abs(b-115)<4?4:5))%(3+b/112)).sum();}это разрешено. И так как это единственное возвращаемое утверждение, a->a.chars().map(b->1+(b<64?0:b+(Math.abs(b-115)<4?4:5))%(3+b/112)).sum()( 73 байта ) будет вашим ответом. Кроме того, вот ссылка TryItOnline вашего ответа, которую вы, возможно, захотите добавить в свой ответ. Еще раз: добро пожаловать и хороший ответ. +1 от меня.
Кевин Круйссен
2
Несколько замечаний по поводу лямбд. Вам не нужно считать f=ни ведущую точку с запятой ;. И вам также не нужно добавлять тип параметра, если вы упоминаете, что это за тип (поэтому вместо того, (String a)->чтобы использовать a->и указать, что входные данные aесть Stringв вашем ответе). О, и « Советы по игре в гольф на Java» и « Советы по игре в гольф на <все языки>» могут быть интересными, если вы еще этого не сделали.
Кевин Круйссен
1

Mathematica, 83 байта

c=Characters;Tr[Tr@Mod[c@"bc1def1ghi1jkl1mno1pqrstuv1wxyz "~Position~#,4]+1&/@c@#]&
J42161217
источник
Кажется общепринятым, что в ответах Mathematica разрешено использовать списки символов для строковых переменных, таких как входные данные для этой функции. (Также есть aпропущенные в начале "bc1..."?)
Грег Мартин
это код golf.this дает правильный результат без "Tr" делает работу
J42161217
1

QBIC , 94 байта

[_l;||_SA,a,1|p=p-(instr(@sz`,B)>0)-(instr(@cfilorvy`+C,B)>0)-(instr(@behknqux`+C+D,B)>0)+1}?p

объяснение

[    |      FOR a = 1 TO
 _l |         the length of
   ;            the input string (A$)
_SA,a,1|    Take the a'th char of A$ and assign it to B$
p=p         p is our tap-counter, and in each iteration it gets increased by the code below
            which consist of this pattern:
                instr(@xyz`,B)>0    where 
                - instr tests if arg 2 is in arg 1 (it either returns 0 or X where X is the index of a2 in a1)
                - @...` defines the letters we want to test as arg1
                - B is the current letter to count the taps for
            Each of these blocks adds 1 tap to the counter, and each block has the letters of its level
            (4-taps, 3-taps or 2-taps) and the level 'above' it.
    -(instr(@sz`,B)>0)              <-- letters that require 4 taps
    -(instr(@cfilorvy`+C,B)>0)      <-- 3 or 4 taps
    -(instr(@behknqux`+C+D,B)>0)    <-- 2, 3,or 4 taps
    +1                              <-- and always a 1-tap
}           NEXT
?p          PRINT the number of taps
steenbergh
источник
1

удар ,69 68 байт

bc<<<`fold -1|tr "\n "adgjmptwbehknquxcfilorvysz +[1*9][2*8][3*8]44`

Попробуйте онлайн!

Складывает по одному символу в строке, транслитерирует каждую новую строку, +каждый пробел 1и каждую букву с соответствующим количеством нажатий. БК делает сумму.

marcosm
источник
на вашей машине вам может понадобитьсяbc <(fold -1|tr "\n "adgjmptwbehknquxcfilorvysz +[1*9][2*8][3*8]44;echo 0)
marcosm
1

C 92 88 байтов

c,n;f(char*s){n=0;while(c=*s++)n+=(c=='s')+3*(c>'y')+1+(c+1+(c<'s'))%3-(c<33);return n;}
луч
источник
Вы можете использовать, s=nчтобы заменить return n, и объединить s++;с c=*s. Это может быть на 9 байт короче.
Кейу Ган
@KeyuGan s=nне будет работать, так sкак это местный. И *s=nне будет работать, так как есть только CHAR_BITбиты *s, которых было бы недостаточно для некоторых сообщений. Но ты прав насчет s++. Спасибо.
Рэй
1

APL (Dyalog) , 36 байт

{+/(3×⍵∊'sz'),1+31+⍵⍳⍨819⌶⎕A~'SZ'}

Попробуйте онлайн!

Находят моды-3 индексов в алфавите без S и Z . Поскольку пробел, S и Z не найдены, они имеют «индекс» 25 (на один больше, чем индекс max), что хорошо для пробела. Тогда нам просто нужно добавить 3 для каждого S или Z .

{ Функция анонимная , где аргумент представлен :

⎕A~'SZ' в верхнем регистре lphabet, за исключением S и Z

819⌶ в нижнем регистре

⍵⍳⍨ в ɩ ndices аргумента в том , что

¯1+ добавить отрицательный

3| мод-3

1+ добавить один (это преобразует все 0-моды в 3)

(), Prepend:

  ⍵∊'sz' Boolean, где аргумент является либо s, либо z

   умножить на 3

+/ сумма

Адам
источник
1

C (gcc) , 7577 байтов

n,b;f(char*a){for(n=0;b=*a++;)n+=b<'s'?--b%3+(b>31):""[b-'s'];a=n;}

Непечатная строка ""представляет собой таблицу 04 01 02 03 01 02 03 04.

Попробуйте онлайн!

Кейу Ган
источник
@ceilingcat спасибо!
Кейу Ган
1

Пип , 100 90 байт

a:qb:["abc""def""ghi""jkl""mno""pqrs""tuv""wxyz"s]Fc,#a{Fd,#b{e:((bd)@?(ac))e<4?i+:e+1x}}i

Проверьте каждый символ ввода на совпадение в каждом элементе b. Индекс этого совпадения плюс 1 добавляется к итогу.

Попробуйте онлайн!

Кеннет Тейлор
источник