Créez un programme avec un simple GOTO

25

La bande dessinée XKCD GOTO

Votre tâche consiste à créer le plus grand programme possible qui utilise exactement un GOTO, sans lequel l'ensemble du programme (ou du moins une énorme partie) doit être complètement restructuré. Le score est compté comme le nombre d'instructions dans votre code qui changent de place ou sont nouvellement introduites (la suppression des instructions n'ajoute pas à votre score) lorsque le code est restructuré sans le GOTO (d'autres sont autorisés à contester votre restructuration en présentant un plus élégant). Comme il s'agit de bowling de code, le meilleur score l'emporte.

Remarque: je ne revendique aucune responsabilité pour les attaques de vélociraptors en tentant ce défi.

Joe Z.
la source
2
Le seul goto semble problématique. Chaque code C auquel je peux penser qui utilise un seul goto peut être trivialement changé pour utiliser des constructions structurées. Plusieurs gotos cependant ...
Pubby
@ L'affirmation de Pubby semble s'opposer aux deux solutions actuelles. Le remplacement gotopar switchsemble possible pour les deux.
ugoren
@Pubby De combien de goto auriez-vous besoin pour créer une solution viable? Si le problème tel qu'énoncé actuellement est impossible, je peux créer un autre problème.
Joe Z.
Je pense que vous êtes autorisé à intégrer le dessin animé, tant qu'il y a un lien aussi.
luser droog
1
Il ne se qualifie pas, mais je l'ai vraiment fait .
luser droog

Réponses:

11

C fizzbuzz

Cette solution tourne autour de l'idée des interruptions et des variables d'étiquette (gcc uniquement, désolé). Le programme met en place une minuterie qui appelle périodiquement main, où nous sommes arrivés à l'endroit où la dernière exécution de notre gestionnaire d'interruption (main) nous a dit que nous devrions.

Je n'ai jamais utilisé de minuteries ou de variables d'étiquette auparavant, donc je pense qu'il y a beaucoup à jouer ici.

#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;
}
shiona
la source
rundoit être déclaré volatile, sinon while(run)peut être "optimisé" pour while(1). Ou à la place, allez à un endroit qui appelle exit.
ugoren
@ugoren Bon point. J'ai activé les optimisations (O1, O2 et Os) et tous ceux qui ont interrompu le programme. Malheureusement, juste l'ajout de «volatile» devant la course, gotoloc et num ne l'ont pas corrigé. Il se peut que gcc ne soit pas conçu pour optimiser ce type de code.
shiona
Définir en volatile int numdehors de main devrait le faire. Avec static, gcc pense qu'il sait qui peut jouer avec.
ugoren
malheureusement, je ne peux pas créer gotoloc en dehors du principal, ou je le pourrais, mais je devrais le mettre à zéro à l'extérieur et puis ne réinitialiser au début de principal que si c'est zéro. Et les statistiques d'appel à s'estomper. Donc je pense qu'il est préférable de dire que j'utilise mal le C, gcc à juste titre ne l'optimise pas correctement, alors n'essayez pas.
shiona
5

Perl

Je ne suis pas très bon au bowling, mais je pense que cela peut intéresser l'OP. Il s'agit d'un tamis d'Eratosthène utilisant une variable goto. Si cela devait être «refactorisé», je doute que tout soit réutilisable, à part peut-être les premières lignes. Lorsque le tamis se termine, tous les 1s restants du @primestableau correspondent à des valeurs premières.

Pour plus de plaisir, aucun ands, ors, ternaires, conditionnels ou opérateurs de comparaison de toute nature sont utilisés.

@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:
primo
la source
En cas de confusion quant à la raison pour laquelle je poste ceci ici, dans un question distincte (maintenant supprimée), le PO a déclaré que, "c'était la question qu'il voulait réellement poser", mais n'était pas sûr si c'était possible .
primo
Au cas où il y aurait une confusion quant à la question que j'ai postée, c'était une question sur le code de construction en utilisant uniquement GOTO, plutôt qu'un seul.
Joe Z.
1
@JoeZeng J'en avais à l'origine trois, mais je l'ai réduit à un afin que ce soit également une solution valable à ce problème.
primo
3

C

Mon utilisation des macros n'en fait peut-être pas "un GOTO".
Et c'est assez court, donc "complètement restructuré" n'est pas grand-chose.
Mais voici ma tentative de toute façon.

Lit un nombre à partir de l'entrée standard, l'imprime 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;
}
ugoren
la source
1
Ouais, utiliser des macros comme ça n'est pas "un GOTO". Mais même alors, vous auriez besoin de fournir la restructuration du programme sans utiliser de GOTO. La suppression des déclarations n'ajoute rien à votre score.
Joe Z.
L'impression d'un nombre modulo 3 serait facile en utilisant simplement un printfet scanf. Le score de votre solution serait probablement d'environ 2 ou 3.
Joe Z.
1
Bon point. Je ne peux pas penser pourquoi quelqu'un aurait jamais envie de programmer quelque chose qui imprime n%3de cette façon, cependant. Il doit s'agir d'un programme qui devient compliqué lorsque le GOTO est supprimé , et non lorsqu'il est introduit .
Joe Z.
2
"Pourquoi?" n'est pas pertinent pour ce site - il est plein de façons stupides de faire des choses stupides. Si vous supprimez goto, le programme ne fonctionnera pas. Mais à quoi vous attendiez-vous - que le programme devienne compliqué par la seule suppression?
ugoren
1
Par la suppression et la restructuration ultérieure, oui. Un exemple simple pourrait être l'utilisation de goto pour sortir de plusieurs boucles imbriquées.
Joe Z.