Crea un programma con un semplice GOTO


25

Il fumetto XKCD GOTO

Il tuo compito è quello di costruire il più grande programma possibile che usi esattamente un GOTO, senza il quale l'intero programma (o almeno una parte enorme di esso) deve essere completamente ristrutturato. Il punteggio viene conteggiato come il numero di affermazioni nel tuo codice che cambiano posto o vengono introdotte di recente (la rimozione delle istruzioni non si aggiunge al tuo punteggio) quando il codice viene ristrutturato senza GOTO (ad altri è consentito contestare la tua ristrutturazione presentando un elegante). Poiché si tratta di bowling di codici, il punteggio più alto vince.

Nota: non rivendico alcuna responsabilità per gli attacchi del velociraptor tentando questa sfida.


2
L' unica goto sembra problematica. Ogni codice C che mi viene in mente che utilizza un singolo goto può essere banalmente modificato per usare costrutti strutturati. Goto multiple comunque ...
Pubblico il

L'affermazione di @ Pubby sembra opporsi alle attuali due soluzioni. La sostituzione gotocon switchsembra possibile per entrambi.
ugoren,

@Pubby Di quanti goto avresti bisogno per creare una soluzione praticabile? Se il problema come attualmente dichiarato è impossibile, posso creare un problema alternativo.
Joe Z.

Penso che ti sia permesso di incorporare il cartone, purché ci sia anche un link.
Luser droog

1
Non si qualifica, ma l' ho fatto davvero .
Luser droog

Risposte:


11

C fizzbuzz

Questa soluzione gira attorno all'idea di interrupt e variabili di etichetta (solo gcc, scusate). Il programma imposta un timer che chiama periodicamente main, dove andiamo a qualunque punto l'ultima esecuzione del nostro gestore di interrupt (main) ci ha detto che dovremmo.

Non ho mai usato timer o variabili di etichetta prima, quindi penso che ci sia molto da lanciare qui.

#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;
}

rundovrebbe essere dichiarato volatile, altrimenti while(run)può essere "ottimizzato" per while(1). O invece, vai da qualche parte che chiama exit.
ugoren,

@ugoren Ottimo punto. Ho attivato le ottimizzazioni (O1, O2 e Os) e tutti quelli hanno rotto il programma. Sfortunatamente, semplicemente aggiungendo "volatile" prima della corsa, gotoloc e num non lo hanno risolto. Potrebbe essere gcc non è costruito per ottimizzare questo tipo di codice.
shiona,

Definire volatile int numal di fuori di main dovrebbe farlo. Con static, gcc pensa di sapere chi può rovinarlo.
ugoren,

sfortunatamente non posso creare gotoloc al di fuori del main, o potrei, ma dovrei impostarlo a zero all'esterno e quindi resettare solo all'inizio del main se è zero. E le statistiche sull'appello svaniscono. Quindi penso che sia meglio dire che sto usando C in modo negativo, gcc giustamente non lo ottimizza correttamente, quindi non provare.
shiona,

5

Perl

Non sono molto bravo a giocare a bowling, ma sospetto che questo possa interessare il PO. Questo è un setaccio di Eratostene usando un goto variabile. Se questo fosse "refactored", dubito che una parte sarebbe riutilizzabile, a parte forse le prime righe. Al termine del setaccio, tutte le rimanenti 1s @primesnell'array corrispondono ai valori primi.

Per ulteriore divertimento, vengono utilizzati no ands, ors, ternaries, condizionals o operatori di confronto di qualsiasi tipo.

@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:

Nel caso in cui ci sia confusione sul motivo per cui sto pubblicando questo qui, in una domanda separata (ora eliminata), l'OP ha dichiarato che "questa era la domanda che in realtà voleva porre", ma non era sicuro che fosse possibile .
primo

Nel caso in cui ci sia confusione su quale domanda ho postato, si trattava di costruire codice usando solo GOTO, anziché solo uno.
Joe Z.

1
@JoeZeng ne avevo originariamente tre, ma l'ho ridotto a uno in modo che fosse una soluzione valida anche a questo problema.
primo

3

C

Il mio uso delle macro forse non lo rende "un GOTO".
Ed è piuttosto breve, quindi "completamente ristrutturato" non è molto.
Ma ecco comunque il mio tentativo.

Legge un numero dallo standard input, lo stampa modulu 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
Sì, usare macro come quella non è "un GOTO". Ma anche allora, dovresti fornire la ristrutturazione del programma senza usare un GOTO. La rimozione di dichiarazioni non si aggiunge al tuo punteggio.
Joe Z.

Stampare un numero modulo 3 sarebbe facile semplicemente usando un printfe scanf. Il punteggio della tua soluzione sarebbe molto probabilmente di circa 2 o 3.
Joe Z.

1
Punto valido. Non riesco a pensare a perché qualcuno avrebbe mai voglia di programmare qualcosa che le stampe n%3in quel modo, però. Dovrebbe essere un programma che diventa contorto quando viene rimosso GOTO , non quando viene introdotto .
Joe Z.

2
"Perché?" è irrilevante per questo sito - è pieno di modi stupidi per fare cose stupide. Se rimuovi goto, il programma non funzionerà. Ma cosa ti aspettavi che il programma sarebbe stato contorto dalla sola rimozione?
ugoren,

1
Con la rimozione e la successiva ristrutturazione, sì. Un semplice esempio potrebbe essere l'uso di goto per interrompere più loop nidificati.
Joe Z.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.