[language-agnostic] 코드 골프 : Four is magic

퍼즐

고등학교 때 들었던 작은 수수께끼는 이런 식으로 진행되었습니다.

  • 질문자는 나에게 번호를 물어볼 것입니다.
  • 숫자를 듣고 질문자는 결국 숫자 4에 도달 할 때까지 (예를 들어 10은 3 이라고 말할 수 있음) 반복적으로 변형을 수행합니다 ( 4로 끝나는 시점 은 마술입니다 ).
  • 어떤 숫자라도 결국 4 개로 변환 될 수있는 것 같습니다.

목표는 변형 함수를 알아 내고이 퍼즐을 스스로 확실하게 감독 할 수 있도록하는 것이 었습니다.

해결책

모든 단계에서 변환 기능은

  • 문제의 번호를 가지고
  • 하이픈이나 공백 또는 “and”를 무시하고 영어 단어 표현의 문자 수를 계산합니다 (예 : “ten”에는 3 개의 문자가 있고, “thirty-four”에는 10 개의 문자가 있습니다. “1 백 사십 삼”) 20 글자 포함).
  • 그 수의 문자를 반환하십시오.

내가 테스트 해 본 모든 숫자에 대해, 이것은 4로 수렴됩니다. “four”도 그 안에 4 개의 문자가 있기 때문에 여기에 무한 루프가 있습니다. 대신 시퀀스를 끝내는 것은 관례 상 마법 이라고합니다 .

도전

당신의 도전은 사용자로부터 숫자를 읽을 코드 조각을 만들고 “four is magic”에 도달 할 때까지 반복적으로 적용되는 변환 함수를 보여주는 줄을 인쇄하는 것입니다.

구체적으로 특별히:

  1. 솔루션은 그 자체로 완전한 프로그램이어야합니다. 그것들은 단순히 숫자를 취하는 함수가 될 수 없습니다.
  2. 입력은 표준 입력에서 읽어야합니다. ( “echo”에서 파이핑하거나 입력 리디렉션을 사용하는 것은 stdin에서도 오기 때문에 괜찮습니다)
  3. 입력은 숫자 형식이어야합니다.
  4. 변환 함수를 적용 할 때마다 한 줄을 인쇄해야합니다. a is b.여기서 a와 b는 변환에서 숫자의 숫자 형식입니다.
  5. 마침표 (마침표)가 필요합니다!
  6. 마지막 줄은 당연히 4 is magic..
  7. 코드는 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.

우승자는 또한 정확한 소스 코드 문자 수에 의한 가장 짧은 제출 입니다.

보너스

변환 함수의 각 응용 프로그램과 함께 숫자에 대한 영어 이름을 인쇄하는 코드 버전을 작성할 수도 있습니다. 원래 입력은 여전히 ​​숫자이지만 출력 행에는 숫자의 단어 형식이 있어야합니다.

(코드로 도형을 그리는 데 두 배의 보너스)

(편집) 일부 설명 :

  1. 해당하는 모든 경우에 단어가 양쪽에 나타나기를 원합니다. 예 : Nine is four. Four is magic.
  2. 하지만 대소 문자는 신경 쓰지 않습니다. 그리고 토큰이라는 단어를 분리하는 방법은 신경 쓰지 않습니다. 비록 분리되어야하지만 : ninety-nine괜찮아, ninety nine괜찮아, ninetynine괜찮지 않습니다.

도전과 관련하여 보너스 경쟁을위한 별도의 범주로 간주하고 있으므로,이 경우 코드가 숫자 버전보다 길다는 것에 대해 걱정하지 마십시오.

각 버전에 대해 하나의 솔루션을 자유롭게 제출하십시오.



답변

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."


답변

Perl, 약 147 자

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


답변

Common Lisp 157 Chars

새롭고 더 적합한 버전, 이제 표준 입력 형식을 읽고 공백과 하이픈을 무시합니다.

(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.


답변

Python 2.x, 144 150 154 166 문자

이것은 숫자를 10과 1로 분리하고 합산합니다. 의사 – 삼원 연산자의 바람직하지 못한 특성 경우 반환 0 여기 학대이다.a and b or ccb

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."


답변

C-숫자 단어 포함

445 431 427 421 399 386 371 359 * 356 개 354 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's 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"*/);
}

시작 부분의 인코딩 된 문자열 정보

숫자의 이름은 매우 간단한 체계를 사용하여 압축됩니다. 자주 사용되는 부분 문자열은 이름 배열의 한 문자 인덱스로 대체됩니다. 추가 이름 항목의 “조회 테이블”이 첫 번째 세트에서 전체적으로 사용되지 않는 부분 문자열의 끝에 추가됩니다. 조회는 재귀 적입니다. 항목은 다른 항목을 참조 할 수 있습니다.

예를 들어 11의 압축 된 이름은 elM. 이 print()함수는 문자 el(숫자 ‘1’이 아닌 소문자 ‘L’)을 그대로 출력하지만를 찾아서 M29 번째 항목의 인덱스 (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 컴파일러에서 올바르게 컴파일되는 완전히 합법적 인 C 프로그램입니다 (경고가 있음에도 불구하고). stdio 함수에 대한 프로토 타입이 부족하면 컴파일러는 이들이를 반환하는 cdecl 함수라고 가정하고 int전달할 인수를 알고 있다고 신뢰합니다. 어쨌든이 프로그램에서 반환 값은 무시되고, 그것들은 모두 cdecl ( “C”호출 규칙) 함수이며, 우리는 실제로 어떤 인자를 전달할지 알고 있습니다.

산출

예상대로 출력됩니다.

0
0은 4입니다.
4는 마법입니다.
1
하나는 셋입니다.
3은 5입니다.
5는 4입니다.
4는 마법입니다.
4
4는 마법입니다.
20
20은 6입니다.
6은 3입니다.
3은 5입니다.
5는 4입니다.
4는 마법입니다.
21
21은 9입니다.
9는 4입니다.
4는 마법입니다.

* 이전 버전은 사양의 두 부분에서 표시를 놓쳤습니다. 0을 처리하지 않았고 stdin 대신 명령 줄에 입력을 받았습니다. 0으로 추가 된 문자를 처리하지만 명령 줄 인수 대신 stdin을 사용하고 몇 가지 다른 최적화를 사용하면 동일한 수의 문자가 저장되어 세척이 발생했습니다.

“is”의 양면에 숫자 단어를 인쇄해야 함을 명확히하기 위해 요구 사항이 변경되었습니다. 이 새 버전은 해당 요구 사항을 충족하고 필요한 추가 크기를 설명하기 위해 몇 가지 더 많은 최적화를 구현합니다.


답변

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.


답변

T-SQL, 413451 499

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 p=@x,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.