Code Golf: Четыре - это волшебство

Пазл

Маленькая головоломка, которую я слышал, когда я училась в старшей школе, пошла примерно так...

  • Ответчик попросит меня дать ему номер;
  • При прослушивании номера вопроситель неоднократно делал какое-то преобразование (например, он мог бы сказать, что ten - это три), до тех пор, пока он не достигнет числа 4 (после чего он будет финишировать с помощью four is magic).
  • Любое число, по-видимому, трансформируется в четыре, независимо от того, что.

Цель состояла в том, чтобы попытаться выяснить функцию преобразования, а затем быть в состоянии надежно прокторировать эту загадку самостоятельно.

Решение

Функция преобразования на любом этапе была

  • Возьмите номер, о котором идет речь,
  • Подсчитайте количество букв в его английском представлении слов, игнорируя дефис или пробелы или "и" (например, "десять" имеет в нем 3 буквы, "тридцать четыре" имеет в нем 10 букв ", сто сорок -three" имеет в нем 20 букв).
  • Вернуть это количество букв.

Для всех чисел, которые мне когда-либо приходилось испытывать, это сходится к 4. Так как "четыре" также имеет четыре буквы в нем, здесь будет бесконечный цикл; вместо этого он просто называется magic по соглашению для завершения последовательности.

Задача

Ваша задача - создать фрагмент кода, который будет считывать номер от пользователя, а затем печатать строки, показывающие, что функция преобразования повторно применяется до тех пор, пока не будет достигнута "четыре магии".

В частности:

  • Решения должны быть полными программами сами по себе. Они не могут быть просто функциями, которые принимают во входном числе числовой коэффициент.
  • Вход должен считываться со стандартного ввода. (Трубопровод из "эха" или с использованием перенаправления ввода отлично, так как это также происходит от stdin)
  • Вход должен быть в числовой форме.
  • Для каждого применения функции преобразования должна быть напечатана строка: a is b., где a и b - числовые формы чисел в преобразовании.
  • Требуется полная остановка (периоды)!
  • Последняя строка, естественно, должна сказать: 4 is magic..
  • Код должен выдавать правильный вывод для всех чисел от от 0 до 99.

Примеры:

> 4
4 is magic.

> 12
12 is 6.
6 is 3.
3 is 5.
5 is 4.
4 is magic.

> 42
42 is 8.
8 is 5.
5 is 4.
4 is magic.

> 0
0 is 4.
4 is magic.

> 99
99 is 10.
10 is 3.
3 is 5.
5 is 4.
4 is magic.

Победителем является кратчайшая подача по количеству символов исходного кода, которая также является правильной.

BONUS

Вы также можете попытаться написать версию кода, который печатает АНГЛИЙСКИЕ ИМЯ для чисел с каждым применением функции преобразования. Первоначальный ввод по-прежнему является числовым, но выходные строки должны иметь форму слова номера.

(двойной бонус для рисования фигур с кодом)

(EDIT) Некоторые пояснения:

  • Я хочу, чтобы слово отображалось с обеих сторон во всех применимых случаях, например. Nine is four. Four is magic.
  • Я не забочусь о капитализации. И мне все равно, как вы разделяете токены, хотя они должны быть разделены: ninety-nine в порядке, ninety nine в порядке, ninetynine не в порядке.

Я рассматриваю это отдельную категорию для бонусного конкурса в отношении проблемы, поэтому, если вы пойдете на это, не беспокойтесь о том, что ваш код длиннее числовой версии.

Не забудьте отправить одно решение для каждой версии.

Ответ 1

GolfScript - 101 96 93 92 91 90 94 86 байт

90 → 94: Исправлен вывод для кратных 10.
94 → 86: реорганизованный код. Использование базы 100 для удаления непечатаемых символов.
86 → 85: более короткое преобразование в строку.

{n+~."+#,#6$DWOXB79Bd")base`1/10/~{~2${~1$+}%(;+~}%++=" is "\".
"1$4$4-}do;;;"magic."

Ответ 2

Perl, около 147 char

Непосредственно на основе решения Platinum Azure:

               chop
              ($_.=
              <>);@
             u="433
            5443554
           366  887
          798   866
         555    766
        "=~     /\d
       /gx      ;#4
      sub       r{4
     -$_        ?$_
    <20         ?$u
   [$_          ]:(
  $'?           $u[
 $']            :0)
+$u[18+$&]:magic}print"
$_ is ",$_=r(),'.'while
                /\d
                /x;
                444

Ответ 3

Общий Lisp 157 символов

Новая более подходящая версия, теперь читающая форма стандартного ввода и игнорирование пробелов и дефис:

(labels((g (x)(if(= x 4)(princ"4 is magic.")(let((n(length(remove-if(lambda(x)(find x" -"))(format nil"~r"x)))))(format t"~a is ~a.~%"x n)(g n)))))(g(read)))

В удобочитаемой форме:

 (labels ((g (x)
           (if (= x 4)
            (princ "4 is magic.")
            (let ((n (length (remove-if (lambda(x) (find x " -"))
                                        (format nil "~r" x)))))
               (format t"~a is ~a.~%" x n)
               (g n)))))
    (g (read)))

И некоторые тестовые прогоны:

>24
24 is 10.
10 is 3.
3 is 5.
5 is 4.
4 is magic.

>23152436
23152436 is 64.
64 is 9.
9 is 4.
4 is magic.

И бонусная версия, на 165 символов:

 (labels((g(x)(if(= x 4)(princ"four is magic.")(let*((f(format nil"~r"x))(n(length(remove-if(lambda(x)(find x" -"))f))))(format t"~a is ~r.~%"f n)(g n)))))(g(read)))

Предоставление

>24
twenty-four is ten.
ten is three.
three is five.
five is four.
four is magic.

>234235
two hundred thirty-four thousand two hundred thirty-five is forty-eight.
forty-eight is ten.
ten is three.
three is five.
five is four.
four is magic.

Ответ 4

Python 2.x, 144 150 154 166 chars

Это отделяет число до десятков и единиц и суммирует их. Нежелательное свойство псевдотернарного оператора a and b or c, возвращаемое c, если b здесь 0, здесь злоупотребляют.

n=input()
x=0x4d2d0f47815890bd2
while n-4:p=n<20and x/10**n%10or 44378/4**(n/10-2)%4+x/10**(n%10)%10+4;print n,"is %d."%p;n=p
print"4 is magic."

Предыдущая наивная версия (150 символов). Просто кодируйте все длины как целое число.

n=input()
while n-4:p=3+int('1yrof7i9b1lsi207bozyzg2m7sclycst0zsczde5oks6zt8pedmnup5omwfx56b29',36)/10**n%10;print n,"is %d."%p;n=p
print"4 is magic."

Ответ 5

C - с числовыми словами

445 431 427 421 399 386 371 359 * 356 354 & dagger; 348 347 символов

Что это. Я не думаю, что смогу сделать это короче.

Все символы новой строки предназначены для чтения и могут быть удалены:

i;P(x){char*p=",one,two,three,four,five,six,sM,eight,nine,tL,elM,twelve,NP,4P,
fifP,6P,7P,8O,9P,twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,en,evL,thir,eL,tO,ty, is ,.\n,
4RmagicS,zero,";while(x--)if(*++p-44&&!x++)*p>95|*p<48?putchar(*p),++i:P(*p-48);
}main(c){for(scanf("%d",&c);c+(i=-4);P(34),P(c=i),P(35))P(c?c>19?P(c/10+18),
(c%=10)&&putchar(45):0,c:37);P(36);}

Ниже, это несколько неожиданно, но все еще довольно трудно читать. См. Ниже для более читаемой версии.

i;
P(x){
    char*p=",one,two,three,four,five,six,sM,eight,nine,tL,elM,twelve,NP,4P,fifP,6P,7P,8O,9P,twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,en,evL,thir,eL,tO,ty, is ,.\n,4RmagicS,zero,";
    while(x--)
        if(*++p-44&&!x++)
            *p>95|*p<48?putchar(*p),++i:P(*p-48);
}
main(c){
    for(scanf("%d",&c);c+(i=-4);P(34),P(c=i),P(35))
        P(c?
            c>19?
                P(c/10+18),
                (c%=10)&&
                    putchar(45)
            :0,
            c
        :37);
    P(36);
}

Развернуть и прокомментировать:

int count; /* type int is assumed in the minified version */

void print(int index){ /* the minified version assumes a return type of int, but it ignored */
    /* see explanation of this string after code */
    char *word =
        /* 1 - 9 */
        ",one,two,three,four,five,six,sM,eight,nine,"
        /* 10 - 19 */
        "tL,elM,twelve,NP,4P,fifP,6P,7P,8O,9P,"
        /* 20 - 90, by tens */
        "twLQ,NQ,forQ,fifQ,6Q,7Q,8y,9Q,"
        /* lookup table */
        "en,evL,thir,eL,tO,ty, is ,.\n,4RmagicS,zero,";

    while(index >= 0){
        if(*word == ',')
            index--;
        else if(index == 0) /* we found the right word */
            if(*word >= '0' && *word < 'a') /* a compression marker */
                print(*word - '0'/*convert to a number*/);
            else{
                putchar(*word); /* write the letter to the output */
                ++count;
            }
        ++word;
    }
}
int main(int argc, char **argv){ /* see note about this after code */
    scanf("%d", &argc); /* parse user input to an integer */

    while(argc != 4){
        count = 0;
        if(argc == 0)
            print(37/*index of "zero"*/);
        else{
            if(argc > 19){
                print(argc / 10/*high digit*/ + 20/*offset of "twenty"*/ - 2/*20 / 10*/);
                argc %= 10; /* get low digit */

                if(argc != 0) /* we need a hyphen before the low digit */
                    putchar('-');
            }
            print(argc/* if 0, then nothing is printed or counted */);
        }
        argc = count;
        print(34/*" is "*/);
        print(argc); /* print count as word */
        print(35/*".\n"*/);
    }
    print(36/*"four is magic.\n"*/);
}

О закодированной строке в начале

Имена номеров сжимаются с использованием очень простой схемы. Часто используемые подстроки заменяются односимвольными индексами в массив имен. В конец добавляется "таблица поиска" дополнительных имен имен для подстрок, не используемых полностью в первом наборе. Lookups являются рекурсивными: записи могут ссылаться на другие записи.

Например, сжатое имя для 11 равно elM. Функция print() выводит символы e и l (нижний регистр "L", а не номер "1" ) дословно, но затем он находит M, поэтому он называет себя индексом 29-го запись (ASCII 'M' - ASCII '0') в таблицу поиска. Эта строка evL, поэтому она выводит e и v, а затем снова вызывает себя с индексом 28-й записи в таблице поиска, которая является en и выводится дословно. Это полезно, потому что en также используется в eL для een (используется после eight в eighteen), который используется в tO для teen (используется для любого другого имени -teen).

Эта схема приводит к довольно существенному сжатию имен номеров, но требует только небольшого количества кода для распаковки.

Запятые в начале и в конце строковой учетной записи для упрощенного способа нахождения подстрок в этой строке. Добавление двух символов позволяет сэкономить больше символов позже.

О злоупотреблении main()

argv игнорируется (и поэтому не объявляется в сжатой версии), значение argc игнорируется, но хранилище повторно используется для хранения текущего номера. Это просто избавляет меня от необходимости объявлять дополнительную переменную.

Об отсутствии #include

Некоторые будут жаловаться на то, что опускание #include <stdio.h> обманывает. Это совсем не так. Данная полностью законная программа на языке C, которая будет правильно компилироваться на любом компиляторе, который я знаю (хотя и с предупреждениями). Не имея протойпов для функций stdio, компилятор предположит, что они являются функциями cdecl, возвращающими int, и будут доверять тому, что вы знаете, какие аргументы должны пройти. В любом случае возвращаемые значения игнорируются в этой программе, и все они являются функциями cdecl ( "C" ), и мы действительно знаем, какие аргументы должны пройти.

Выход

Вывод выполняется так, как ожидалось:

0
zero is four.
four is magic.
1
one is three.
three is five.
five is four.
four is magic.
4
four is magic.
20
twenty is six.
six is three.
three is five.
five is four.
four is magic.
21
twenty-one is nine.
nine is four.
four is magic.

* Предыдущая версия пропустила отметку на двух частях спецификации: она не обрабатывала нуль, и вместо ввода stdin она вводилась в командной строке. Обработка нулей добавленных символов, но использование stdin вместо командной строки args, а также пара других оптимизаций сохранили одинаковое количество символов, что привело к стиранию.

& dagger; Требования были изменены, чтобы было ясно, что числовое слово должно быть напечатано с обеих сторон "is". Эта новая версия удовлетворяет этому требованию и реализует еще пару оптимизаций (более) для учета необходимого размера.

Ответ 6

J, 107 112 символы

'4 is magic.',~}:('.',~":@{.,' is ',":@{:)"1]2&{.\.
(]{&(#.100 4$,#:3 u:ucp'䌵䐵吶梇禈榛ꪛ멩鮪鮺墊馊꥘誙誩墊馊ꥺ겻곋榛ꪛ멩鮪鮺'))^:a:

(только для чтения только для чтения)

Использование и вывод:

    '4 is magic.',~}:('.',~":@{.,' is ',":@{:)"1]2&{.\.(]{&(#.100 4$,#:3 u:ucp'䌵䐵吶梇禈榛ꪛ멩鮪鮺墊馊꥘誙誩墊馊ꥺ겻곋榛ꪛ멩鮪鮺'))^:a:12
12 is 6.    
6 is 3.     
3 is 5.     
5 is 4.     
4 is magic. 

Ответ 7

T-SQL, 413 451 499 chars

CREATE FUNCTION d(@N int) RETURNS int AS BEGIN
Declare @l char(50), @s char(50)
Select @l='0066555766',@s='03354435543668877987'
if @N<20 return 0+substring(@s,@N+1,1) return 0+substring(@l,(@N/10)+1,1) + 0+(substring(@s,@N%10+1,1))END
GO
CREATE proc M(@x int) as BEGIN
WITH r(p,n)AS(SELECT [email protected],n=dbo.d(@x) UNION ALL SELECT p=n,n=dbo.d(n) FROM r where n<>4)Select p,'is',n,'.' from r print '4 is magic.'END

(Не то, чтобы я серьезно предлагал вам сделать это... действительно, я просто хотел написать CTE)

Для использования:

M 95

Возвращает

p                n
----------- ---- -----------
95          is   10.
10          is   3.
3           is   5.
5           is   4.
4 is magic.

Ответ 8

Java (с шаблоном), 308 290 286 282 280 символов

class A{public static void main(String[]a){int i=4,j=0;for(;;)System.out.printf("%d is %s.%n",i=i==4?new java.util.Scanner(System.in).nextInt():j,i!=4?j="43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:".charAt(i)-48:"magic");}}

Я уверен, что Groovy избавится от большей части этого.

Объяснение и форматирование (все комментарии, новые строки и ведущие/конечные пробелы удалены в счетчике):

Разумно прямо, но

//boilerplate
class A{
   public static void main(String[]a){
      //i is current/left number, j right/next number.  i=4 signals to start
      //by reading input
      int i=4,j=0;
      for(;;)
         //print in the form "<left> is <right>."
         System.out.printf(
            "%d is %s.%n",
            i=i==4?
               //<left>: if i is 4 <left> will be a new starting number
               new java.util.Scanner(System.in).nextInt():
               //otherwise it the next val
               j,
            i!=4?
               //use string to map number to its length (:;< come after 9 in ASCII)
               //48 is value of '0'.  store in j for next iteration
               j="43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:".charAt(i)-48:
               //i==4 is special case for right; print "magic"
               "magic");
   }
}

Изменить: больше не использовать hex, это меньше нажатий клавиш

Ответ 9

Windows PowerShell: 152 153 184 байты

на основе предыдущего решения, с большим влиянием других решений

$o="03354435543668877988"
for($input|sv b;($a=$b)-4){if(!($b=$o[$a])){$b=$o[$a%10]-48+"66555766"[($a-$a%10)/10-2]}$b-=48-4*!$a
"$a is $b."}'4 is magic.'

Ответ 10

C, 158 символов

main(n,c){char*d="03354435543668877988";for(scanf("%d",&n);n-4;n=c)printf("%d is %d.\n",n,c=n?n<19?d[n]-48:d[n%10]-"_,**+++)**"[n/10]:4);puts("4 is magic.");}

(первоначально на основе кода Влада Питона, заимствован трюк от решения Си ++ Смита Сидгедаса, чтобы выжать еще несколько символов)

расширенная версия:

main(n, c) {
    char *d = "03354435543668877988";
    for (scanf("%d",&n); n-4; n = c)
        printf("%d is %d.\n", n, c = n ? n<19 ? d[n]-48 : d[n%10] - "_,**+++)**"[n/10]  : 4);
    puts("4 is magic.");
}

Ответ 11

Perl: 148 символов

(Perl: 233 181 212 206 200 199 198 185 179 149 148 символов)

  • Перемещено хеши исключений в массив единиц. Это привело к тому, что я смог вырезать много символов: -)
  • mobrule указал на неприятную ошибку. Быстрое исправление добавляет 31 символ, ouch!
  • Рефакторинг для нулевого частного случая, мягкий гольф также сделан.
  • Прямой доступ к списку для одноразового использования, а не для хранения в массиве? Ад да!
  • ТАК БОЛЬШОЙ РЕАКТОРИНГ для ОДНОГО кровавого характера. Это, действительно, жизнь гольфиста.: - (
  • Упс, простое исправление пробелов. 198.
  • Реализован некоторый избыточный код.
  • Последнее ключевое слово возврата в r не нужно, сбрил еще немного.
  • Массивный рефакторинг в комментариях; к сожалению, я мог получить его только до 149, потому что мне пришлось исправить ошибку, которая присутствовала как в моем предыдущем коде, так и в версиях комментаторов.
  • Попытка "волшебного" слова ".".

Пусть этот шар катится с скромной попыткой в ​​Perl.

@u=split'','4335443554366887798866555766';$_=<>;chop;print"$_ is ".($_=$_==4?0:$_<20?$u[$_]:($u[$_/10+18]+($_%10&&$u[$_%10]))or magic).".
"while$_

подсказки:

Слишком много!

Ответ 12

С#: 210 символов.

сплющенные:

using C=System.Console;class B{static void Main(){int
x=0,y=int.Parse(C.ReadLine());while(x!=4)C.Write((x=y)+" is {0}.\n",x==4?"magic":""+(y=x==0?4:"03354435543668877988"[x<20?x:x%10]+"0066555766"[x/10]-96));}}

Expanded:

using C=System.Console;
class B
{
    static void Main()
    {
        int x=0,y=int.Parse(C.ReadLine());
        while(x!=4)
            C.Write((x=y)+" is {0}.\n",
                x==4?
                     "magic":
                     ""+(y= x==0?
                                4:
                                "03354435543668877988"[x<20?x:x%10]+
                                "0066555766"[x/10]-96)
                   );
    }
}

Трюки этого подхода используют:

  • Создайте таблицу поиска для длин имен номеров на основе цифр, отображаемых в номере.
  • Использовать поиск массива символов в строке и char арифметику вместо числового массива.
  • Использовать псевдонимы имен классов с короткими Console. до C.
  • Используйте условный (тройной) оператор (?:) вместо if/else.
  • Используйте \n с Write escape-кодом вместо WriteLine
  • Используйте тот факт, что С# имеет определенный порядок оценки, позволяющий назначать внутри функции Write вызов функции
  • Используйте выражения присваивания для устранения дополнительных операторов и, тем самым, дополнительных брекетов

Ответ 13

Python, 129 133 137 148 chars

Как разминка, вот моя первая версия (улучшает пару символов над предыдущим лучшим Python).

PS. После нескольких редакций теперь около двадцати char короче:

n=input()
while n-4:p=(922148248>>n/10*3&7)+(632179416>>n%10*3&7)+(737280>>n&1)+4*(n<1);print n,'is %d.'%p;n=p
print'4 is magic.'

Ответ 14

JavaScript 1.8 (SpiderMonkey) - 153 Chars

l='4335443554366887798866555766'.split('')
for(b=readline();(a=+b)-4;print(a,'is '+b+'.'))b=a<20?l[a]:+l[18+a/10|0]+(a%10&&+l[a%10])
print('4 is magic.')

Использование: echo 42 | js golf.js

Вывод:

42 is 8.
8 is 5.
5 is 4.
4 is magic.

С бонусом - 364 символа

l='zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty thirty fourty fifty sixty seventy eighty ninety'.split(' ')
z=function(a)a<20?l[a]:l[18+a/10|0]+(a%10?' '+l[a%10]:'')
for(b=+readline();(a=b)-4;print(z(a),'is '+z(b)+'.'))b=z(a).replace(' ','').length
print('four is magic.')

Вывод:

ninety nine is ten.
ten is three.
three is five.
five is four.
four is magic.

Ответ 15

Версия С++ Stdio, сокращенная: 196 символов

#include <cstdio>
#define P;printf(
char*o="43354435543668877988";main(int p){scanf("%d",&p)P"%d",p);while(p!=4){p=p<20?o[p]-48:"0366555966"[p/10]-96+o[p%10]P" is %d.\n%d",p,p);}P" is magic.\n");}

Версия С++ Iostreams, сокращенная: 195 символов

#include <iostream>
#define O;std::cout<<
char*o="43354435543668877988";main(int p){std::cin>>p;O p;while(p!=4){p=p<20?o[p]-48:"0366555966"[p/10]-96+o[p%10]O" is "<<p<<".\n"<<p;}O" is magic.\n";}

Оригинал, не ограничен: 344 символа

#include <cstdio>

int ones[] = { 4, 3, 3, 5, 4, 4, 3, 5, 5, 4, 3, 6, 6, 8, 8, 7, 7, 9, 8, 8 };
int tens[] = { 0, 3, 6, 6, 5, 5, 5, 9, 6, 6 };

int n(int n) {
    return n<20 ? ones[n] : tens[n/10] + ones[n%10];
}

int main(int p) {
    scanf("%d", &p);
    while(p!=4) {
        int q = n(p);
        printf("%i is %i\n", p, q);
        p = q;
    }
    printf("%i is magic\n", p);
}

Ответ 16

Haskell, 224 270 символы

o="43354435543668877988"
x!i=read[x!!i]
n x|x<20=o!x|0<1="0066555766"!div x 10+o!mod x 10
f x=zipWith(\a b->a++" is "++b++".")l(tail l)where l=map show(takeWhile(/=4)$iterate n x)++["4","magic"]
main=readLn>>=mapM putStrLn.f

И немного более читаемый -

ones = [4,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,8,8]
tens = [0,0,6,6,5,5,5,7,6,6]

n x = if x < 20 then ones !! x else (tens !! div x 10) + (ones !! mod x 10)

f x = zipWith (\a b -> a ++ " is " ++ b ++ ".") l (tail l)
    where l = map show (takeWhile (/=4) (iterate n x)) ++ ["4", "magic"]

main = readLn >>= mapM putStrLn . f

Ответ 17

С# 314 286 283 274 289 273 252 символа.

сплющенные:

252 

Normal:

using C = System.Console;
class P
{
    static void Main()
    {
        var x = "4335443554366877798866555766";
        int m, o, v = int.Parse(C.ReadLine());
        do {
            C.Write("{0} is {1}.\n", o = v, v == 4 ? (object)"magic" : v = v < 20 ? x[v] - 48 : x[17 + v / 10] - 96 + ((m = v % 10) > 0 ? x[m] : 48));
        } while (o != 4);
        C.ReadLine();
    }
}

Редактировать Dykam: Проделали довольно осторожные вставки и изменения:

  • Изменено значение l.ToString() в листинге object для string "magic".
  • Создал временную переменную o, поэтому я мог перемещать break вне цикла for, то есть в результате do-while.
  • Настроить назначение o, а также назначение v, продолжить вложение вычисления l в аргументы функции в целом, устранив необходимость в l. Также добавлено назначение m.
  • Удалено пространство в int[] x, int[]x тоже является законным.
  • Попробовал преобразовать массив в строковое преобразование, но using System.Linq было слишком большим, чтобы сделать это улучшением.

Изменить 2 Dykam Изменен массив int в массив/строка char, добавлены правильные арифметики, чтобы исправить это.

Ответ 18

Delphi: 329 символов

Версия одной строки:

program P;{$APPTYPE CONSOLE}uses SysUtils;const S=65;A='EDDFEEDFFEDGGIIHHJII';B='DGGFFFJGG';function Z(X:Byte):Byte;begin if X<20 then Z:=Ord(A[X+1])-S else Z:=(Ord(B[X DIV 10])-S)+Z(X MOD 10)end;var X,Y:Byte;begin Write('> ');ReadLn(X);repeat Y:=Z(X);WriteLn(Format('%d is %d.',[X,Y]));X:=Y;until X=4;WriteLn('4 is magic.');end.

Форматированный:

program P;

{$APPTYPE CONSOLE}

uses
  SysUtils;

const
  S = 65;
  A = 'EDDFEEDFFEDGGIIHHJII';
  B = 'DGGFFFJGG';

function Z(X:Byte):Byte;
begin
  if X<20
  then Z := Ord(A[X+1])-S
  else Z := (Ord(B[X DIV 10])-S) + Z(X MOD 10);
end;

var
  X,Y: Byte;

begin
  Write('> ');
  ReadLn(X);

  repeat
    Y:=Z(X);
    WriteLn(Format('%d is %d.' , [X,Y]));
    X:=Y;
  until X=4;

  WriteLn('4 is magic.');
end.

Вероятно, место для еще более сжатия...:-P

Ответ 19

C - без числовых слов

180 175 * 172 167 символов

Все символы новой строки предназначены для чтения и могут быть удалены:

i;V(x){return"\3#,#6$:WOXB79B"[x/2]/(x%2?1:10)%10;}main(c){for(scanf("%d",&c);
c-4;)i=c,printf("%d is %d.\n",i,c=c?c>19?V(c/10+19)+V(c%10):V(c):4);puts(
"4 is magic.");}

Немного unminified:

i;
V(x){return"\3#,#6$:WOXB79B"[x/2]/(x%2?1:10)%10;}
main(c){
    for(scanf("%d",&c);c-4;)
        i=c,
        printf("%d is %d.\n",i,c=c?c>19?V(c/10+19)+V(c%10):V(c):4);
    puts("4 is magic.");
}

* Предыдущая версия пропустила отметку на двух частях спецификации: она не обрабатывала нуль, и вместо ввода stdin она вводилась в командной строке. Обработка нулевых добавленных символов, но использование stdin вместо командной строки args сохраняется еще больше, что приводит к чистой экономии.

Ответ 20

Lua, 176 символов

o={[0]=4,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,8,8}t={3,6,6,5,5,5,7,6,6}n=0+io.read()while n~=4 do a=o[n]or o[n%10]+t[(n-n%10)/10]print(n.." is "..a..".")n=a end print"4 is magic."

или

  o={[0]=4,3,3,5,4,4
  ,3,5,5,4,3,6,6,8,8
  ,7,7,9,8,8}t={3,6,
   6,5,5,5,7,6,6}n=
   0+io.read()while
   n ~= 4 do a= o[n
   ]or o[n%10]+t[(n
   -n%10)/10]print(
n.." is "..a.."." )n=a
end print"4 is magic."

Ответ 21

perl, 123 122 символа

Просто понял, что нет требования выводить на STDOUT, поэтому вместо этого выведите на STDERR и сбив другой символ.

@u='0335443554366887798866555766'=~/./g;$_+=<>;warn"$_ is ",$_=$_-4?$_<20?$u[$_]||4:$u[chop]+$u[$_+18]:magic,".\n"until/g/

И, версия, которая возвращает пронумерованные номера:

279 278 276 280 символов

@p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);@n=("",One,Two,Three,Four,Five,@p[3..6],Ten,Eleven,Twelve,map$_.teen,@p);s/u//[email protected]=map$_.ty,Twen,@p;$n[8].=t;sub n{$n=shift;$n?$n<20?$n[$n]:"$m[$n/10-2] $n[$n%10]":Zero}$p+=<>;warnt$m=n($p)," is ",$_=$p-4?n$p=()=$m=~/\w/g:magic,".\n"until/c/

В то время как это соответствует спецификации, оно не на 100% хорошо отформатировано. Он возвращает дополнительное пространство после чисел, заканчивающихся на ноль. Спектр говорит:

"Мне все равно, как вы разделяете токены, хотя они должны быть разделены"

Тем не менее. Более правильная версия на

282 281 279 283 символа

@p=(Thir,Four,Fif,Six,Seven,Eigh,Nine);@n=("\x8",One,Two,Three,Four,Five,@p[3..6],Ten,Eleven,Twelve,map$_.teen,@p);s/u//[email protected]=map$_.ty,Twen,@p;$n[8].=t;sub n{$n=shift;$n?$n<20?$n[$n]:"$m[$n/10-2]-$n[$n%10]":Zero}$p+=<>;warn$m=n($p)," is ",$_=$p-4?n$p=()=$m=~/\w/g:magic,".\n"until/c/

Ответ 22

Python:

#!/usr/bin/env python

# Number of letters in each part, we don't count spaces
Decades = ( 0, 3, 6, 6, 6, 5, 5, 7, 6, 6, 0 )
Smalls  = ( 0, 3, 3, 5, 4, 4, 3, 5, 5, 4 )
Teens  =  ( 6, 6, 8, 8, 7, 7, 9, 8, 8 )

def Count(n):
    if n > 10 and n < 20: return Teens[n-11]
    return   Smalls[n % 10 ] + Decades [ n / 10 ]

N = input()

while N-4:
    Cnt = Count(N)
    print "%d is %d" % ( N, Cnt)
    N = Cnt

print "4 is magic"

Ответ 23

Ruby, 164 символа

n=gets.to_i;s="03354435543668877987";if n==0;puts"0 is 4.";else;puts"#{n} is #{n=(n<20)?s[n]-48:"0066555766"[n/10]-48+s[n%10]-48}." until n==4;end;puts"4 is magic."

декодируется:

n = gets.to_i
s = "03354435543668877987"
if n == 0
  puts "0 is 4."
else
  puts "#{n} is #{n = (n < 20) ? s[n] - 48 : "0066555766"[n / 10] - 48 + s[n % 10] - 48}." until n == 4
end

puts "4 is magic."

Ответ 24

С++, 171 символ (#include опущен)

void main(){char x,y,*a="03354435543668877988";scanf("%d",&x);for(;x-4;x=y)y=x?x<19?a[x]-48:"_466555766"[x/10]+a[x%10]-96:4,printf("%d is %d.\n",x,y);puts("4 is magic.");}

Ответ 25

Lua 185 190 199

добавлены периоды, добавлен io.read, удален() при последней печати

 n=io.read();while(n~=4)do m=('43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:'):sub(n+1):byte()-48;print(n,' is ',m,'.')n=m;end print'4 is magic.'

с разрывами строк

 n=io.read()
 while (n~=4) do
    m=('43354435543668877988699;::9;;:699;::9;;:588:998::9588:998::9588:998::97::<;;:<<;699;::9;;:699;::9;;:'):sub(n+1):byte()-48;
    print(n,' is ',m,'.')
    n=m;
 end 
 print'4 is magic.'

Ответ 26

Код PhP

function get_num_name($num){  
    switch($num){  
        case 1:return 'one';  
    case 2:return 'two';  
    case 3:return 'three';  
    case 4:return 'four';  
    case 5:return 'five';  
    case 6:return 'six';  
    case 7:return 'seven';  
    case 8:return 'eight';  
    case 9:return 'nine';  
    }  
}  

function num_to_words($number, $real_name, $decimal_digit, $decimal_name){  
    $res = '';  
    $real = 0;  
    $decimal = 0;  

    if($number == 0)  
        return 'Zero'.(($real_name == '')?'':' '.$real_name);  
    if($number >= 0){  
        $real = floor($number);  
        $decimal = number_format($number - $real, $decimal_digit, '.', ',');  
    }else{  
        $real = ceil($number) * (-1);  
        $number = abs($number);  
        $decimal = number_format($number - $real, $decimal_digit, '.', ',');  
    }  
    $decimal = substr($decimal, strpos($decimal, '.') +1);  

    $unit_name[1] = 'thousand';  
    $unit_name[2] = 'million';  
    $unit_name[3] = 'billion';  
    $unit_name[4] = 'trillion';  

    $packet = array();    

    $number = strrev($real);  
    $packet = str_split($number,3);  

    for($i=0;$i<count($packet);$i++){  
        $tmp = strrev($packet[$i]);  
        $unit = $unit_name[$i];  
        if((int)$tmp == 0)  
            continue;  
        $tmp_res = '';  
        if(strlen($tmp) >= 2){  
            $tmp_proc = substr($tmp,-2);  
            switch($tmp_proc){  
                case '10':  
                    $tmp_res = 'ten';  
                    break;  
                case '11':  
                    $tmp_res = 'eleven';  
                    break;  
                case '12':  
                    $tmp_res = 'twelve';  
                    break;  
                case '13':  
                    $tmp_res = 'thirteen';  
                    break;  
                case '15':  
                    $tmp_res = 'fifteen';  
                    break;  
                case '20':  
                    $tmp_res = 'twenty';  
                    break;  
                case '30':  
                    $tmp_res = 'thirty';  
                    break;  
                case '40':  
                    $tmp_res = 'forty';  
                    break;  
                case '50':  
                    $tmp_res = 'fifty';  
                    break;  
                case '70':  
                    $tmp_res = 'seventy';  
                    break;  
                case '80':  
                    $tmp_res = 'eighty';  
                    break;  
                default:  
                    $tmp_begin = substr($tmp_proc,0,1);  
                    $tmp_end = substr($tmp_proc,1,1);  

                    if($tmp_begin == '1')  
                        $tmp_res = get_num_name($tmp_end).'teen';  
                    elseif($tmp_begin == '0')  
                        $tmp_res = get_num_name($tmp_end);  
                    elseif($tmp_end == '0')  
                        $tmp_res = get_num_name($tmp_begin).'ty';  
                    else{  
                        if($tmp_begin == '2')  
                            $tmp_res = 'twenty';  
                        elseif($tmp_begin == '3')  
                            $tmp_res = 'thirty';  
                        elseif($tmp_begin == '4')  
                            $tmp_res = 'forty';  
                        elseif($tmp_begin == '5')  
                            $tmp_res = 'fifty';  
                        elseif($tmp_begin == '6')  
                            $tmp_res = 'sixty';  
                        elseif($tmp_begin == '7')  
                            $tmp_res = 'seventy';  
                        elseif($tmp_begin == '8')  
                            $tmp_res = 'eighty';  
                        elseif($tmp_begin == '9')  
                            $tmp_res = 'ninety';  

                        $tmp_res = $tmp_res.' '.get_num_name($tmp_end);  
                    }  
                    break;  
            }  

            if(strlen($tmp) == 3){  
                $tmp_begin = substr($tmp,0,1);  

                $space = '';  
                if(substr($tmp_res,0,1) != ' ' && $tmp_res != '')  
                    $space = ' ';  

                if($tmp_begin != 0){  
                    if($tmp_begin != '0'){  
                        if($tmp_res != '')  
                            $tmp_res = 'and'.$space.$tmp_res;  
                    }  
                    $tmp_res = get_num_name($tmp_begin).' hundred'.$space.$tmp_res;  
                }  
            }  
        }else  
            $tmp_res = get_num_name($tmp);  
        $space = '';  
        if(substr($res,0,1) != ' ' && $res != '')  
            $space = ' ';  
        $res = $tmp_res.' '.$unit.$space.$res;  
    }  

    $space = '';  
    if(substr($res,-1) != ' ' && $res != '')  
        $space = ' ';  

    if($res)  
        $res .= $space.$real_name.(($real > 1 && $real_name != '')?'s':'');  

    if($decimal > 0)  
        $res .= ' '.num_to_words($decimal, '', 0, '').' '.$decimal_name.(($decimal > 1 && $decimal_name != '')?'s':'');  
    return ucfirst($res);  
}  

////////////тестирование////////////////

 $str2num = 12;
    while($str2num!=4){
        $str = num_to_words($str2num, '', 0, '');  
        $str2num = strlen($str)-1;
        echo $str . '=' . $str2num .'<br/>';
        if ($str2num == 4)
            echo 'four is magic';
    }

//////Результаты/////////

Twelve =6
Six =3
Three =5
Five =4
four is magic

Ответ 27

Perl - 130 символов


5.12.1 (130 символов) 121 123 132 136 140

#        1         2         3         4         5         6         7         8         9        100        11        12        13       14    
#23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123

@u='4335443554366887798866555766'=~/./g;$_=pop;say"$_ is ",$_=$_-4?$_<20?$u[$_]:$u[$_/10+18]+(($_%=10)&&$u[$_]):magic,"."until/\D/


5.10.1 (134 символа) 125 127 136 140 144

#        1         2         3         4         5         6         7         8         9        100        11        12        13       14    
#23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234

@u='4335443554366887798866555766'=~/./g;$_=pop;print"$_ is ",$_=$_-4?$_<20?$u[$_]:$u[$_/10+18]+(($_%=10)&&$u[$_]):magic,".\n"until/\D/


История изменений:

20100714:2223 - обратное изменение в обращении mobrule, но ($_%10&&$u[$_%10])(($_%=10)&&$u[$_]), который является одним и тем же числом символов, но я сделал это, если кто-то может увидеть способ его улучшить.

20100714:0041 - split//,'...''...'=~/./g
20100714:0025 - ($_%10&&$u[$_%10])$u[$_%10]
20100713:2340 - while$_until/\D/ + удалены ненужные круглые скобки
20100713:xxxx - $=<>;chop;$_=pop; - любезно предоставлено mobrule


Примечание: Я устал улучшать ответы других в комментариях, так что теперь я жадный и могу просто добавить свои изменения здесь:) Это отрывок от Platinum Azure ответ - частично отчасти Hobbs, mobrule и Platinum Azure.

Ответ 28

Бесстыдный Perl с числовыми словами (329 символов)

Адаптировано довольно прямо из кода P Daddy C с некоторыми настройками до p(), чтобы заставить его делать то же самое, используя примитивы Perl вместо C, и главным образом перезаписанный mainloop. См. Его объяснение. Новые строки являются необязательными.

@t=(qw(zero one two three four five six sM eight nine
tL elM twelve NP 4P fifP 6P 7P 8O 9P twLQ NQ forQ fifQ
6Q 7Q 8y 9Q en evL thir eL tO ty 4SmagicT)," is ",".\n");
sub p{local$_=$t[pop];1while s/[0-Z]/$t[-48+ord$&]/e;
print;length}$_=<>;chop;while($_-4){
$_=($_>19?(p($_/10+18),$_&&print("-"),$_%=10)[0]:0)+p$_;
p 35;p$_;p 36}p 34

Боковое примечание: слишком плохо, что perl print просто возвращает true/false; если он вернет счет, он спасет мне 7 ударов.

Ответ 29

Ruby, 141 chars:

n=gets.to_i;m="4335443554366887798866555766";loop{s=n;n=n>20?m[18+n/10]+m[n%10]-96: m[n]-48;puts"#{s} is #{n==s ? 'magic': n}.";n==s &&break}

Ответ 30

while(true)
{
    string a;
    ReadLine(a)
    WriteLine(4);

}