สร้างโปรแกรมด้วย GOTO ง่ายๆ


25

การ์ตูน XKCD GOTO

งานของคุณคือการสร้างโปรแกรมที่ใหญ่ที่สุดที่คุณสามารถใช้ GOTO หนึ่งตัวโดยไม่ต้องใช้โปรแกรมทั้งหมด (หรืออย่างน้อยก็ชิ้นใหญ่) คะแนนจะถูกนับเป็นจำนวนของข้อความในรหัสของคุณที่เปลี่ยนสถานที่หรือมีการนำมาใช้ใหม่ (การลบข้อความไม่ได้เพิ่มคะแนนของคุณ) เมื่อรหัสนั้นได้รับการปรับโครงสร้างใหม่โดยไม่ต้องมี GOTO (คนอื่น ๆ สง่างามหนึ่ง) เช่นนี้เป็นโบว์ลิ่งรหัสคะแนนสูงสุดชนะ

หมายเหตุ: ฉันไม่ได้เรียกร้องความรับผิดใด ๆ สำหรับการโจมตีศาสนโดยพยายามท้าทายนี้


2
การข้ามไปครั้งเดียวดูเหมือนว่ามีปัญหา รหัส C ทุกอันที่ฉันนึกได้ว่าใช้ goto เพียงอันเดียวสามารถเปลี่ยนแปลงได้เล็กน้อยเพื่อใช้โครงสร้างที่มีโครงสร้าง อย่างไรก็ตามมีหลาย gotos ...
Pubby

@ การเรียกร้องของ Pubby ดูเหมือนว่าจะยึดมั่นกับโซลูชั่นทั้งสองในปัจจุบัน การแทนที่gotoด้วยswitchอาจเป็นไปได้สำหรับทั้งคู่
ugoren

@Pubby คุณต้องมีวิธีแก้ปัญหาจำนวนกี่ goto เพื่อให้สามารถทำงานได้ หากปัญหาตามที่ระบุไว้ไม่สามารถทำได้ฉันสามารถสร้างปัญหาอื่นได้
Joe Z.

ฉันคิดว่าคุณได้รับอนุญาตให้ฝังการ์ตูนตราบใดที่มีลิงก์ด้วย
luser droog

1
มันไม่ได้มีคุณสมบัติ แต่ฉันไม่ได้จริงๆ
luser droog

คำตอบ:


11

C fizzbuzz

วิธีการแก้ปัญหานี้ทำงานรอบความคิดของการขัดจังหวะและตัวแปรฉลาก (gcc เท่านั้นขออภัย) โปรแกรมตั้งค่าตัวจับเวลาซึ่งเรียก 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 นอกหลักหรือทำได้ แต่ฉันจะต้องตั้งค่าให้เป็นศูนย์นอกแล้วตั้งค่าใหม่เฉพาะในจุดเริ่มต้นของหลักถ้ามันเป็นศูนย์ และสถิติการอุทธรณ์จะจางหายไป ดังนั้นฉันคิดว่าเป็นการดีที่สุดที่จะบอกว่าฉันใช้งาน C ในทางที่ไม่ดี gcc ไม่ถูกต้องเหมาะสมอย่างถูกต้องดังนั้นอย่าพยายาม
shiona

5

Perl

ฉันเล่นโบว์ลิ่งไม่ค่อยเก่ง แต่ฉันคิดว่านี่น่าจะเป็นที่สนใจของ OP นี่คือตะแกรงของ Eratosthenes โดยใช้ตัวแปร goto หากสิ่งนี้เป็น 'refactored' ฉันสงสัยว่ามันจะสามารถใช้ซ้ำได้นอกเหนือจากสองสามบรรทัดแรก เมื่อตะแกรงสิ้นสุดลง1s ทั้งหมดที่เหลืออยู่ใน@primesอาร์เรย์จะสอดคล้องกับค่าเฉพาะ

เพื่อเพิ่มความสนุกไม่ใช้ ands, ors, ternaries, conditionals หรือตัวดำเนินการเปรียบเทียบใด ๆ

@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 ระบุว่า "นี่เป็นคำถามที่เขาต้องการถามจริง ๆ " แต่ไม่แน่ใจว่ามันเป็นไปได้ .
โม่

ในกรณีที่มีความสับสนเกี่ยวกับคำถามที่ฉันโพสต์มันเป็นคำถามเกี่ยวกับการสร้างรหัสโดยใช้GOTO เพียงอย่างเดียวมากกว่าหนึ่ง
Joe Z.

1
@ JoeZeng ฉันมีสามตัวแรก แต่ฉันลดให้เหลือเพียงอันเดียวเพื่อแก้ปัญหานี้ให้ถูกต้องเช่นกัน
primo

3

C

การใช้งานมาโครของฉันอาจไม่ทำให้เป็น "หนึ่ง GOTO"
และมันค่อนข้างสั้นดังนั้น "การปรับโครงสร้างอย่างสมบูรณ์" จึงไม่มากนัก
แต่นี่คือความพยายามของฉัน

อ่านตัวเลขจากอินพุตมาตรฐานพิมพ์มัน 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
ใช่การใช้มาโครอย่างนั้นไม่ใช่ "one 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.