24
\$\begingroup\$

The XKCD GOTO comic

Your task is to build the largest program you can that uses exactly one GOTO, without which the entire program (or at least a huge chunk of it) must be completely restructured. The score is counted as the number of statements in your code that change places or are newly introduced (removing statements doesn't add to your score) when the code is restructured without the GOTO (others are allowed to challenge your restructuring by presenting a more elegant one). As this is code bowling, highest score wins.

Note: I do not claim any liability for velociraptor attacks by attempting this challenge.

\$\endgroup\$
7
  • 2
    \$\begingroup\$ The one single goto seems problematic. Every C code I can think of that uses a single goto can be trivially changed to use structured constructs. Multiple gotos however... \$\endgroup\$
    – Pubby
    Feb 26, 2013 at 1:42
  • \$\begingroup\$ @Pubby's claim seems to hold against the current two solutions. Replacing goto with switch seems possible for both. \$\endgroup\$
    – ugoren
    Feb 26, 2013 at 7:44
  • \$\begingroup\$ @Pubby How many goto's would you need to create a workable solution? If the problem as currently stated is impossible, I can create an alternative problem. \$\endgroup\$
    – Joe Z.
    Feb 26, 2013 at 14:30
  • 1
    \$\begingroup\$ It doesn't qualify, but I really did this. \$\endgroup\$ Feb 28, 2013 at 4:10
  • 1
    \$\begingroup\$ Voting to close as it is unclear what is meant by "completely restructured", and as most languages allow any program to be restructured to a single statement, the scoring criterion is also hard to define a quantitative limit for. \$\endgroup\$ Oct 29, 2020 at 16:00

3 Answers 3

11
\$\begingroup\$

C fizzbuzz

This solution runs around the idea of interrupts and label variables (gcc only, sorry). The program sets up a timer which periodically calls main, where we goto whichever place the last execution of our interrupt handler (main) told us we should.

I've never used timers or label variables before, so I think there is much to bowl here.

#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;
}
\$\endgroup\$
4
  • \$\begingroup\$ run should be declared volatile, otherwise while(run) can be "optimized" to while(1). Or instead, just goto somewhere that calls exit. \$\endgroup\$
    – ugoren
    Feb 26, 2013 at 7:41
  • \$\begingroup\$ @ugoren Good point. I turned on optimizations (O1, O2 and Os) and all those broke the program. Unfortunately just adding 'volatile' in front of run, gotoloc and num did not fix it. It might be gcc is not built for optimizing this kind of code. \$\endgroup\$
    – shiona
    Feb 26, 2013 at 7:55
  • \$\begingroup\$ Defining volatile int num outside of main should do it. With static, gcc thinks it knows who can mess with it. \$\endgroup\$
    – ugoren
    Feb 26, 2013 at 12:12
  • \$\begingroup\$ unfortunately I can't create gotoloc outside the main, or I could, but I would have to set it to zero outside and then only reset in in the beginning of main if it's zero. And the appeal stats to fade. So I think it's best to say that I'm using C a bad way, gcc rightfully doesn't optimize it correctly so don't try. \$\endgroup\$
    – shiona
    Feb 26, 2013 at 16:26
5
\$\begingroup\$

Perl

I'm not very good at bowling, but I suspect this may interest the OP. This is a Sieve of Eratosthenes using a variable goto. Were this to be 'refactored', I doubt any of it would be reusable, other than perhaps the first few lines. When the sieve ends, all remaining 1s in the @primes array correspond to prime values.

For added fun, no ands, ors, ternaries, conditionals or comparison operators of any kind are used.

@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:
\$\endgroup\$
3
  • \$\begingroup\$ In case there's any confusion as to why I'm posting this here, in a separate question (now deleted), the OP stated that, "this was the question he actually wanted to ask", but wasn't sure if it was possible. \$\endgroup\$
    – primo
    Mar 15, 2013 at 4:20
  • \$\begingroup\$ In case there's any confusion as to what question I posted, it was a question about building code using only GOTO's, rather than just one. \$\endgroup\$
    – Joe Z.
    Mar 15, 2013 at 12:47
  • 1
    \$\begingroup\$ @JoeZeng I originally had three, but I reduced it to one so that it would be a valid solution to this problem as well. \$\endgroup\$
    – primo
    Mar 15, 2013 at 13:24
3
\$\begingroup\$

C

My usage of macros perhaps doesn't make it "one GOTO".
And it's quite short, so "completely restructured" isn't much.
But here's my attempt anyway.

Reads a number from standard input, prints it 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;
}
\$\endgroup\$
6
  • 1
    \$\begingroup\$ Yeah, using macros like that isn't "one GOTO". But even then, you'd need to provide the restructuring of the program without using a GOTO. Removing statements doesn't add to your score. \$\endgroup\$
    – Joe Z.
    Feb 25, 2013 at 20:58
  • \$\begingroup\$ Printing a number modulo 3 would be easy by just using a printf and scanf. Your solution's score would most likely be about 2 or 3. \$\endgroup\$
    – Joe Z.
    Feb 25, 2013 at 21:02
  • 1
    \$\begingroup\$ Fair point. I can't think of why anybody would ever want to program something that prints n%3 in that way, though. It should be a program that becomes convoluted when the GOTO is removed, not when it is introduced. \$\endgroup\$
    – Joe Z.
    Feb 26, 2013 at 1:26
  • 2
    \$\begingroup\$ "Why?" is irrelevant for this site - it's full of stupid ways to do stupid things. If you remove goto, the program won't work. But what did you expect - that the program would become convoluted by the removal alone? \$\endgroup\$
    – ugoren
    Feb 26, 2013 at 7:33
  • 1
    \$\begingroup\$ By the removal and subsequent restructuring, yes. A simple example might be the use of goto to break out of multiple nested loops. \$\endgroup\$
    – Joe Z.
    Feb 26, 2013 at 19:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.