Bangun program dengan satu GOTO sederhana

25

Komik GOTO XKCD

Tugas Anda adalah membangun program terbesar yang dapat Anda gunakan yang menggunakan tepat satu GOTO, yang tanpanya seluruh program (atau setidaknya sebagian besar darinya) harus sepenuhnya direstrukturisasi. Skor dihitung sebagai jumlah pernyataan dalam kode Anda yang mengubah tempat atau baru diperkenalkan (menghapus pernyataan tidak menambah skor Anda) ketika kode direstrukturisasi tanpa GOTO (orang lain diizinkan untuk menantang restrukturisasi Anda dengan menyajikan lebih banyak yang elegan). Karena ini adalah bowling kode, skor tertinggi menang.

Catatan: Saya tidak mengklaim tanggung jawab atas serangan velociraptor dengan mencoba tantangan ini.

Joe Z.
sumber
2
Satu goto tunggal tampaknya bermasalah. Setiap kode C yang saya pikirkan yang menggunakan goto tunggal dapat dengan mudah diubah untuk menggunakan konstruksi terstruktur. Namun
goto
Klaim @ Pubby tampaknya bertentangan dengan dua solusi saat ini. Mengganti gotodengan switchtampaknya mungkin untuk keduanya.
ugoren
@ Patby Berapa banyak goto yang Anda perlukan untuk membuat solusi yang bisa diterapkan? Jika masalah seperti yang dinyatakan saat ini tidak mungkin, saya dapat membuat masalah alternatif.
Joe Z.
Saya pikir Anda boleh menanamkan kartun itu, asalkan ada tautannya juga.
luser droog
1
Itu tidak memenuhi syarat, tetapi saya benar-benar melakukan ini .
luser droog

Jawaban:

11

C fizzbuzz

Solusi ini berjalan di sekitar gagasan interupsi dan label variabel (hanya gcc, maaf). Program ini mengatur timer yang secara berkala memanggil utama, di mana kita pergi ke mana saja yang melakukan eksekusi terakhir dari interrupt handler (utama) kita kepada kita.

Saya belum pernah menggunakan timer atau label variabel sebelumnya, jadi saya pikir ada banyak hal yang perlu diperhatikan di sini.

#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
sumber
runharus dinyatakan volatile, jika tidak while(run)dapat "dioptimalkan" untuk while(1). Atau sebagai gantinya, hanya kebagian tempat yang memanggil exit.
ugoren
@ugoren Poin bagus. Saya menyalakan optimisasi (O1, O2 dan Os) dan semua yang melanggar program. Sayangnya hanya menambahkan 'volatile' di depan run, gotoloc dan num tidak memperbaikinya. Mungkin gcc tidak dibangun untuk mengoptimalkan kode semacam ini.
shiona
Mendefinisikan di volatile int numluar main harus dilakukan. Dengan static, gcc berpikir itu tahu siapa yang bisa mengacaukannya.
ugoren
sayangnya saya tidak dapat membuat gotoloc di luar main, atau saya bisa, tetapi saya harus mengaturnya menjadi nol di luar dan kemudian hanya mengatur ulang di awal main jika itu nol. Dan statistik banding memudar. Jadi saya pikir yang terbaik adalah mengatakan bahwa saya menggunakan C dengan cara yang buruk, gcc memang seharusnya tidak mengoptimalkannya dengan benar jadi jangan coba-coba.
shiona
5

Perl

Saya tidak pandai bowling, tapi saya curiga ini mungkin menarik bagi OP. Ini adalah Saringan Eratosthenes menggunakan goto variabel. Kalau ini 'refactored', saya ragu semua itu akan dapat digunakan kembali, selain mungkin beberapa baris pertama. Ketika saringan berakhir, semua yang tersisa 1dalam @primesarray sesuai dengan nilai-nilai prima.

Untuk tambahan kesenangan, tidak ada ands, ors, ternary, conditional atau operator pembanding apa pun yang digunakan.

@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
sumber
Jika ada kebingungan mengapa saya memposting ini di sini, dalam pertanyaan terpisah (sekarang dihapus), OP menyatakan bahwa, "ini adalah pertanyaan yang sebenarnya ingin dia tanyakan", tetapi tidak yakin apakah itu mungkin .
Primo
Jika ada kebingungan mengenai pertanyaan apa yang saya posting, itu adalah pertanyaan tentang membuat kode hanya menggunakan GOTO, bukan hanya satu.
Joe Z.
1
@ Jozeng Saya awalnya punya tiga, tapi saya menguranginya menjadi satu sehingga itu akan menjadi solusi yang valid untuk masalah ini juga.
primo
3

C

Penggunaan makro saya mungkin tidak menjadikannya "satu GOTO".
Dan itu cukup singkat, jadi "sepenuhnya direstrukturisasi" tidak banyak.
Tapi ini usahaku.

Membaca angka dari input standar, mencetaknya 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
sumber
1
Ya, menggunakan makro seperti itu bukan "satu GOTO". Tetapi meskipun begitu, Anda harus menyediakan restrukturisasi program tanpa menggunakan GOTO. Menghapus pernyataan tidak menambah skor Anda.
Joe Z.
Mencetak nomor modulo 3 akan mudah dengan hanya menggunakan a printfdan scanf. Skor solusi Anda kemungkinan besar sekitar 2 atau 3.
Joe Z.
1
Titik adil. Saya tidak bisa memikirkan mengapa ada orang yang ingin memprogram sesuatu yang dicetak n%3dengan cara itu. Itu harus menjadi program yang berbelit-belit ketika GOTO dihapus , bukan ketika diperkenalkan .
Joe Z.
2
"Mengapa?" tidak relevan untuk situs ini - penuh dengan cara bodoh untuk melakukan hal-hal bodoh. Jika Anda menghapus goto, program tidak akan berfungsi. Tapi apa yang Anda harapkan - bahwa program ini akan menjadi berbelit-belit hanya karena dihapus saja?
ugoren
1
Dengan penghapusan dan restrukturisasi selanjutnya, ya. Contoh sederhana mungkin adalah penggunaan goto untuk keluar dari beberapa loop bersarang.
Joe Z.