하나의 간단한 GOTO로 프로그램 구축


25

XKCD GOTO 만화

당신의 임무는 정확히 하나의 GOTO를 사용하여 가능한 한 가장 큰 프로그램을 만드는 것입니다. 점수는 코드가 GOTO없이 재구성 될 때 장소 를 변경 하거나 새로 도입 된 (설명을 제거해도 점수에 추가되지 않는) 코드의 문장 수로 계산됩니다 (다른 사람들은 더 많은 것을 제시함으로써 구조 조정에 도전 할 수 있음) 우아한 하나). 이것이 코드 볼링이므로 최고 점수가 이깁니다.

참고 :이 도전을 시도하여 벨로시 랩터 공격에 대한 책임을 주장하지 않습니다.


2
하나의 고토는 문제가 보인다. 내가 생각할 수있는 모든 C 코드는 단일 goto를 사용하여 구조적 구조를 사용하도록 간단하게 변경할 수 있습니다. 그러나 여러 고
— 토스

@Pubby의 주장은 현재 두 가지 솔루션에 반대되는 것으로 보입니다. 두 가지 모두 교체 goto가 switch가능해 보입니다.
— ugoren

@Pubby 실행 가능한 솔루션을 만들려면 몇 개의 goto가 필요합니까? 현재 언급 된 문제가 불가능한 경우 다른 문제를 만들 수 있습니다.
— Joe Z.

링크가있는 한 만화를 포함시킬 수 있다고 생각합니다.
— luser droog

답변:


11

C 피즈 버즈

이 솔루션은 인터럽트 및 레이블 변수에 대한 아이디어를 바탕으로 실행됩니다 (gcc 만 해당, 죄송합니다). 이 프로그램은 주기적으로 main을 호출하는 타이머를 설정합니다. 인터럽트 처리기 (main)의 마지막 실행 위치는 우리에게 알려야합니다.

나는 전에 타이머 또는 레이블 변수를 사용한 적이 없으므로 여기에 볼이 많이 있다고 생각합니다.

#include <sys/time.h>
#include <signal.h>
#include <stdio.h>

int main(int argc)
{
    static int run = 1;
    static int* gotoloc = &&init;
    static int num = 0;
    static int limit = 50;

    goto *gotoloc;
init:
    signal(SIGVTALRM, (void (*)(int)) main);
    gotoloc = &&loop;

    struct itimerval it_val;

    it_val.it_value.tv_sec = 0;
    it_val.it_value.tv_usec = 100000;
    it_val.it_interval.tv_sec = 0;
    it_val.it_interval.tv_usec = 100000;
    setitimer(ITIMER_VIRTUAL, &it_val, NULL);

    while(run);

loop:
    num = num + 1;
    run = num < limit;
    gotoloc = &&notfizz + (&&fizz - &&notfizz) * !(num % 3);
    return 1;

fizz:
    printf("fizz");
    gotoloc = &&notbuzz + (&&buzz - &&notbuzz) * !(num % 5);
    return 1;

notfizz:
    gotoloc = &&notfizzbuzz + (&&buzz - &&notfizzbuzz) * !(num % 5);
    return 1;

buzz:
    printf("buzz\n");
    gotoloc = &&loop;
    return 1;

notbuzz:
    printf("\n");
    gotoloc = &&loop;
    return 1;

notfizzbuzz:
    printf("%d\n", num);
    gotoloc = &&loop;
    return 1;
}

run선언해야합니다 volatile. 그렇지 않으면 while(run)"최적화"될 수 있습니다 while(1). 또는 대신을 호출하는 곳으로 이동하십시오 exit.
— ugoren

@ugoren 좋은 지적. 나는 최적화 (O1, O2 및 Os)를 켜고 모든 사람들이 프로그램을 중단했습니다. 불행히도 실행 앞에 '휘발성'을 추가하면 gotoloc과 num이 수정되지 않았습니다. 이러한 종류의 코드를 최적화하기 위해 gcc가 빌드되지 않았을 수 있습니다.
— shiona

volatile int num메인 외부에서 정의 하면됩니다. staticgcc를 사용하면 누가 엉망인지 알 수 있다고 생각합니다.
— ugoren

불행히도 메인 외부에 gotoloc을 만들 수 없거나 외부에서 0으로 설정 한 다음 0의 경우 메인의 시작 부분에서만 재설정해야합니다. 그리고 항소 통계는 사라질 것입니다. 따라서 C를 나쁜 방법으로 사용하고 있다고 말하는 것이 가장 좋습니다 .gcc는 올바르게 최적화하지 않으므로 시도하지 마십시오.
— shiona

5

펄

나는 볼링을 잘하지 않지만 OP에 관심이있을 것 같습니다. 이것은 변수 goto를 사용하는 에라토스테네스의 체입니다. 이것이 '리팩토링 된'것이었을 것입니다. 아마도 처음 몇 줄을 제외하고는 재사용 할 수 있을지 의심됩니다. 체가 끝나면 배열에 남아있는 모든 1s는 @primes소수 값에 해당합니다.

재미를 더하기 위해 ands, ors, ternaries, conditional 또는 모든 종류의 비교 연산자가 사용되지 않습니다.

@primes[2..1e4]=(1)x9999;
$a=2;
Y:
  $b=$a*~-$a;
X:
  $primes[$b+=$a+=$c=$a/100%2+$b/1e4%2]=0;
  goto"$c"^h;
Z:

내가 왜 여기에 이것을 게시하고 있는지에 대해 혼란스러워하는 경우 별도의 질문 (현재 삭제됨)에서 OP는 "이것은 실제로 물어보고 싶은 질문"이라고 말했지만 가능한지 확실하지 않았습니다. .
— primo

내가 게시 한 질문에 대해 혼동이있는 경우 하나가 아닌 GOTO 만 사용하여 코드를 작성하는 것에 대한 질문이었습니다 .
— Joe Z.

1
@JoeZeng 원래 3 개를 가지고 있었지만이 문제에 대한 올바른 해결책이되도록 1 개로 줄였습니다.
— primo

3

기음

매크로 사용으로 "하나의 GOTO"가되지는 않을 것입니다.
그리고 그것은 짧기 때문에 "완전히 재구성 된"것은 그리 많지 않습니다.
그러나 여기 내 시도가 있습니다.

표준 입력에서 숫자를 읽고 모듈러스 3을 인쇄합니다.

int main() {
    char s[100], *p, r=0;
    void *pl[] = { &&a, &&b, &&c, &&d, &&e, &&f, &&g, &&h, &&i, &&j, &&a, &&b, &&x, &&y, &&z }, *p1;
    p = gets(s);
    #define N(n) (pl+n)[!*p*60+*p-48];p++;goto *p1
    a: p1=N(0);
    b: p1=N(1);
    c: p1=N(2);
    d: p1=N(0);
    e: p1=N(1);
    f: p1=N(2);
    g: p1=N(0);
    h: p1=N(1);
    i: p1=N(2);
    j: p1=N(0);
    z: r++;
    y: r++;
    x: printf("%d\n", r);

    return 0;
}

1
예, 그런 매크로를 사용하는 것은 "하나의 GOTO"가 아닙니다. 그러나 그때도 GOTO를 사용하지 않고 프로그램의 재구성을 제공해야합니다. 문장을 제거해도 점수에 추가되지 않습니다.
— Joe Z.

숫자 3을 모듈로 인쇄하면 단지를 사용하여 쉬운 것입니다 printf및 scanf. 귀하의 솔루션의 점수는 대부분 약 2 또는 3입니다.
— Joe Z.

1
페어 포인트. 그래도 왜 그런 식으로 인쇄 하는 것을 프로그래밍 하려는 사람이 있는지 생각할 수 없습니다 n%3. 그것은 GOTO 가 소개 될 때가 아니라 제거 될 때 복잡 해지는 프로그램이어야한다 .
— Joe Z.

2
"왜?" 이 사이트와 관련이 없습니다. 어리석은 일을하는 어리석은 방법들로 가득합니다. 를 제거 goto하면 프로그램이 작동하지 않습니다. 그러나 당신은 무엇을 기대 했습니까? 프로그램은 제거만으로 복잡해질 것입니까?
— ugoren

1
제거 및 후속 구조 조정을 통해 가능합니다. 간단한 예는 goto를 사용하여 여러 개의 중첩 루프에서 벗어날 수 있습니다.
— Joe Z.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.