เคล็ดลับสำหรับการเล่นกอล์ฟใน C ++


48

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


4
หลายเคล็ดลับสำหรับการเล่นกอล์ฟใน Cนอกจากนี้ยังมีผลบังคับใช้กับ C ++ ดังนั้นโปรดคิดว่าผู้อ่านมีความคุ้นเคยกับคำถามที่; โพสต์ที่นี่เฉพาะในกรณีที่คุณมีบางอย่างที่ไม่ได้เป็นเคล็ดลับการเล่นกอล์ฟ C ที่ถูกต้อง
Toby Speight

@TobySpeight อาจเป็นเพราะพวกเขามี URL เดียวกันนอกเหนือจากรหัสคำถาม
NoOne อยู่ที่นี่

C และ C ++ แม้ว่าจะไม่ใช่ประเภท 'golfing' นั้นถูกและง่าย (หากพิจารณาเป็นเซตย่อยที่เหมาะสมของ C ++)
RosLuP

คำตอบ:


24

ผู้ประกอบการที่มีเงื่อนไข ternary ?:มักจะสามารถใช้เป็นขาตั้งในที่เรียบง่ายif- elseงบที่เงินออมมาก

เป็นค่าพิเศษที่สามารถใช้เพื่อเลือกค่า lvalues ​​แบบอื่นได้

#include <iostream>
#include <cstdlib>
int main(int c, char**v){
  int o=0,e=0,u;
  while(--c) ((u=atoi(v[c]))%2?o:e)+=u;
  std::cout << "Sum of odds " << o <<std::endl
            << "Sum of evens " << e <<std::endl;
}

ยังไม่ได้เรียกใช้รหัส แต่ฉันไม่คิดว่ามันจะทำงานในแบบที่คุณพูด ((u = atoi (v [c]))% 2? o: e) + = u ไม่ได้ทำอะไรนอกจากการเพิ่มค่า u ลงในนิพจน์ทางด้านซ้ายซึ่งได้รับค่า o หรือ e แต่ตัวแปร o และ e ยังคงไม่เปลี่ยนแปลงดังนั้นพวกเขาจะเป็น 0 ตรวจสอบรหัสเพื่อดูสิ่งที่เกิดขึ้น คุณควรใช้ที่อยู่เพื่อให้มันทำงาน
Bogdan Alexandru

4
@BogdanAlexandru เอ้อ ... ทำได้แล้ว มันใช้งานได้จริง มูลค่าของการแสดงออกในวงเล็บคือการอ้างอิงถึงหนึ่งหรืออื่น ๆ ของและe oโปรดทราบว่านี่คือสิ่งที่แตกต่างจากวิธีการทำงานของผู้ประกอบการนี้ในคที่เคล็ดลับนี้ไม่ทำงานเพราะมันไม่สามารถ lvalue
dmckee

แทนที่std::endlด้วย'\n'ที่บันทึก 5 ตัวอักษร
Mukul Kumar

3
@MukulKumar ดีใช่ แต่สำหรับจุดประสงค์ในการสาธิตเคล็ดลับนี้ฉันได้ทิ้งทุกอย่างไว้ยกเว้นการยกเลิกการเล่นกอล์ฟแบบไม่มีเงื่อนไขเพื่อความชัดเจน
dmckee

22

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

int main()
{
  int a=0;
  // ...
}

คุณสามารถเขียน

int a;
int main()
{
  // ...
}

+1 แต่การปฏิบัติที่ไม่ดีอย่างแน่นอน
mondlos

@mondlos: การเล่นกอล์ฟโดยทั่วไปหมายถึงการปฏิบัติที่ไม่ดี
celtschk

15

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

int n='  ';

ค่าเป็นการนำไปปฏิบัติโดยเฉพาะ โดยปกติค่าของการ'ab'เป็นหรือ256*'a'+'b' 'a'+256*'b'คุณสามารถระบุอักขระได้สูงสุด 4 ตัวระหว่างเครื่องหมายคำพูด


3
GCC? คุณหมายถึงg ++ ?
Nathan Osman

6
@George Edison: GCC ย่อมาจากGNU Compiler Collectionซึ่งครอบคลุมส่วนหน้าทั้งหมดรวมถึง C, C ++, Go และอื่น ๆ
Joey Adams

@ โจอี้: ฉันรู้ แต่มันก็เป็นชื่อของ GNU C Compiler
Nathan Osman

25
@George: คอมไพเลอร์ GNU C เรียกว่า gcc ไม่ใช่ GCC
fredoverflow

อาจจำได้ว่าฉันสามารถลืม

12

สิ่งที่ฉันพบว่ามีประโยชน์:

การใช้ประโยชน์จากความจริงที่ว่าค่าที่ไม่เป็นศูนย์ประเมินเป็นtrueนิพจน์บูลีนและx&&yประเมินว่าx*yเมื่อจัดการกับบูลีน

(x!=0 && y!=0)

ประเมินให้

(x*y)

คุณเพียงแค่ต้องระวังกระแสเกินตามที่ระบุไว้ด้านล่าง


2
ในทางเทคนิคx!=0 && y!=0แล้ว แต่เมื่อใช้การคูณคุณต้องระวังด้วยการล้น เมื่อใช้ 32 บิตจำนวนเต็มx y = = 65536 (และอีกหลายชุดอื่น ๆ ของผู้มีอำนาจของทั้งสอง) นอกจากนี้ยังจะให้ผลผลิตx * Y = 0
Martin Ender

ถูกต้องเลย. ฉันใช้มันเป็นขอบเขตอาร์เรย์สองมิติตรวจสอบที่นี่: codegolf.stackexchange.com/a/37571/31477ที่ไม่สำคัญ ฉันจะแก้ไขคะแนนเหล่านั้นใน
Baldrickk

1
อย่างไรก็ตามโปรดทราบว่า&&มีพฤติกรรมการลัดวงจรที่*ขาด ตัวอย่างเช่นคุณไม่สามารถแทนที่ด้วยi++!=0&&j++!=0 i++*j++
celtschk

@celtschk ใช่จุดดี แต่ถ้าคุณทำพีชคณิตบูลีนอย่างหมดจดมันก็ใช้ได้
Baldrickk

11

ใช้ประเภทต่อไปนี้:

u64, s64, u32, s32 (or int)

สำหรับคำ / ประเภทซ้ำ ๆ ให้ใช้#defines:

#define a while

มันคุ้มค่าถ้าคุณใช้whileมากในการแต่งหน้า 10 ตัวอักษรพิเศษ ( ประมาณ 4 )


1
ประเภท u64, s64, u32 และ s32 ไม่ได้เป็นส่วนหนึ่งของ C ++ พวกเขาอาจเป็นส่วนเสริมที่ไม่ได้มาตรฐานของคอมไพเลอร์ของคุณ (ฉันไม่เคยเห็นมาก่อน)
celtschk

5
เคล็ดลับสองข้อนี้ควรอยู่ในคำตอบที่แยกกันสองคำเพื่อให้สามารถลงคะแนนทีละรายการได้
trichoplax


10

เมื่อเป็นไปได้ให้เปลี่ยน&&และ||ไปที่&และ|ตามลำดับ

เมื่อใช้ง่าย ๆ ถ้าข้อความ:

if(<condition>)<stuff>;

สามารถเปลี่ยนเป็น:

<condition>?<stuff>:<any single letter variable>;

ซึ่งบันทึกอักขระ



8

การใช้เครื่องหมายคอมม่าแทนวงเล็บปีกกาเปิดและปิดสามารถบันทึกอักขระได้ไม่กี่ตัวถ้าคุณมีสถานการณ์ที่ประโยคของคุณมีข้อความสั่งมากกว่าหนึ่งข้อความ:

if(c){x=1;cout<<"Hi";y=2;}else{x=2;cout<<"Bye";y=3;}

เมื่อเทียบกับ

if(c)x=1,cout<<"Hi",y=2;else x=2,cout<<"Bye",y=3;###

บันทึกอักขระสองตัวไว้บน IF ธรรมดาหรือทั้งหมดสามตัวสำหรับ IF / ELSE

ในฐานะที่เป็นจุดแยกระหว่าง C และ C ++ ผลลัพธ์ของนิพจน์คอมม่าใน C ++ โดยรวมอาจถูกใช้เป็น lvalue ... FWIW


7

เนื่องจากองค์ประกอบอาร์เรย์จะถูกเก็บไว้โดยตรงหลังจากอยู่ในหน่วยความจำแทนที่จะเป็นดังนี้:

for(int x = 0; x < 25; x++) {
    for(int y = 0; y < 25; y++)
        array[x][y] = whatever;
}

คุณสามารถทำสิ่งนี้:

int* pointer = array;
for(int i = 0; i < 25*25; i++, pointer++)
    *pointer = whatever;

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


อย่าลืมว่าคุณสามารถตัดช่องว่างทั้งหมดออกไปได้! (เคล็ดลับที่แตกต่างกัน แต่ควรพูดถึง)
stokastic

@stokastic ตัวอย่างไม่ได้หมายถึงกอล์ฟเพียงเพื่อแสดงให้เห็นถึงวิธีการใช้เทคนิค
Stuntddude

6
ทำไมไม่for(int* i=array; i<array+25*25; i++)? จากนั้นคุณจะต้องติดตามตัวแปรเดียวเท่านั้น
ลูคัส

6

ค่อนข้างชัดเจน แต่คุณใช้ไลบรารีมาตรฐานจำนวนมากusing namespace std;อาจบันทึกอักขระไม่กี่ตัว


5
หากคุณใช้ชื่อเพียงชื่อเดียว แต่using std::name;อาจจะค่อนข้างสั้นกว่า
celtschk

10
การทำเช่นนี้จะช่วยประหยัดอักขระหากคุณใช้std::ห้าครั้งขึ้นไป
nyuszika7h

6

มันจะมีประโยชน์ที่จำได้ว่าเป็นเช่นเดียวกับa[i]*(a+i)

แทนที่a[0]ด้วย*aเพื่อการประหยัดอักขระสองตัว นอกจากนี้a[i][0]จะเทียบเท่ากับ*a[i]และหดตัวลงไปa[0][i] i[*a]ดังนั้นหากคุณเข้ารหัส0ดัชนีในอาเรย์ของคุณอย่างหนักอาจเป็นวิธีที่ดีกว่า


5

แทนการเขียนอำนาจใหญ่ของ 10 ใช้สัญกรณ์อิเล็กทรอนิกส์ ตัวอย่างเช่นมีความยาวมากกว่าa=1000000000 a=1e9นี้สามารถขยายไปยังหมายเลขอื่น ๆ เช่นดีกว่าa=1e9+24a=1000000024


1
โปรดทราบว่าสิ่งนี้ไม่เทียบเท่ากันต้องแปลงเป็นประเภทจำนวนเต็มก่อนใช้ ยกตัวอย่างเช่น1e9/xไม่ได้เป็นเช่นเดียวกับหรือ1000000000/x int(1e9)/x
user202729

5

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

#include <iostream>

int foo()
{
    std::cout << "Foo\n";
}

int main()
{
    1?foo():0;  // if (true) foo()
    0?:foo();   // if (!false) foo()
}

ตรวจสอบที่นี่


5
ดูเหมือนว่าจะเป็นส่วนขยาย GNU และไม่อยู่ในมาตรฐาน C ++ https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Conditionals.html#Conditionals
ceilingcat

? R foo (): 0; // ถ้า (r) foo () นี่ใช้ได้ ;;;;; แต่สำหรับ r นี้: foo (); ฉันไม่รู้
RosLuP

5

ส่วนหัวที่สั้นกว่า

นี่เป็นเฉพาะ GCC มันอาจขยายไปถึงคอมไพเลอร์อื่น ๆ

ส่วนหัวที่คอมไพล์แล้ว

ใน G ++ bits/stdc++.hส่วนหัวที่ประกอบไว้ล่วงหน้าประกอบด้วยส่วนหัวอื่น ๆ ทั้งหมด หากคุณต้องการimport2 แบบที่แตกต่างกันคุณสามารถใช้มันได้

ส่วนหัวที่สั้นกว่า

นี่คือส่วนหัวทั้งหมดที่ระบุไว้ในhttp://en.cppreference.com/w/cpp/header :

เรียงตามลำดับความยาวที่เพิ่มขึ้น

บางส่วนยาวกว่าbits/stdc++.hและบางส่วนต้องการการสนับสนุน C ++ 17 TIO G ++ บางคนไม่รองรับบางคน (ด้วยเหตุผลที่ฉันไม่รู้) กรองพวกเขาที่เรามี:

มันอาจเกิดขึ้นได้ว่าบางคนสามารถถูกแทนที่ด้วยคนที่สั้นกว่า เพียงแค่ค้นหาแบบไบนารี่ไม่ว่าจะเป็นสิ่งที่คุณต้องการจะถูกแทนที่ โดยเฉพาะอย่างยิ่ง:

cstdio -> ios        (-3 bytes)
algorithm -> regex   (-4 bytes)
vector -> queue      (-1 byte)
string -> map        (-3 bytes)
bitset -> regex      (-1 byte)
numeric -> random    (-1 byte)

4

#importแทนที่จะ#includeให้คุณเพิ่มหนึ่งไบต์

นอกจากนี้อักขระเว้นวรรคระหว่าง#importและส่วนหัวไม่จำเป็นต้อง:

#include <map>
// vs
#import<map>

และถ้าคุณต้องการบางอย่างจากstdlibส่วนหัวคุณสามารถนำเข้าส่วนหัวใด ๆ กับคอนเทนเนอร์ STL (ดีกว่าsetหรือmap ) cstdlibแทน


3

การดำเนินการทางคณิตศาสตร์ใน Booleans:

แม้ว่า

a*=b>0?.5:-.5

ดีกว่า

if(b>0)a*=.5;else a*=-.5;

มันไม่ดีเท่า

a*=(b>0)-.5

นอกจากนี้ยังใช้ #define กับทุกสิ่งที่ใช้บ่อย มันมักจะสั้นกว่าการใช้ฟังก์ชั่นเนื่องจากชื่อประเภทไม่จำเป็น

รวมสิ่งต่าง ๆ ให้มากที่สุด:

a+=a--;

เป็นเช่นเดียวกับ

a=2*a-1;

ในขณะที่ตัวอย่างของคุณถูกต้องระวังการเรียกใช้พฤติกรรมที่ไม่ได้กำหนดเมื่อใช้xเป็น lvalue และx++rvalue พฤติกรรมที่ไม่ได้กำหนดและจุดลำดับ
ceilingcat

ใช่เป็นไปได้ + = a--; มีพฤติกรรมที่ไม่ได้กำหนด
RosLuP

3

ใช้ lambdas ทั่วไปเป็นแม่แบบราคาถูก

สำหรับประเภทอื่นที่ไม่ใช่การintใช้มันเป็นอาร์กิวเมนต์ของฟังก์ชันอาจมีราคาแพง อย่างไรก็ตามมีการแนะนำแลมบ์ดาทั่วไป (ใน C ++ 14?) และอนุญาตให้แลมบ์ดาใด ๆ เป็นเทมเพลตซึ่งการใช้autoประเภทอาร์กิวเมนต์สามารถบันทึกเป็นไบต์ได้ เปรียบเทียบ:

double f(double x, double y)
[](auto x, auto y)

แลมบ์ดาทั่วไปยังสะดวกมากสำหรับการยอมรับตัววนซ้ำ - อาจเป็นวิธีที่ดีที่สุดในการยอมรับอินพุตอาเรย์ใน C ++ คือ[](auto a, auto z)ที่ ๆaและzถูกส่งผ่านเป็นbegin()และend()ของอาร์เรย์ / vector / list / etc


2

ในความพยายามครั้งแรกของฉันที่การตีกอล์ฟสำหรับงาน "ลบหมายเลขถัดไป"ฉันได้เริ่มต้นจากฟังก์ชั่น (58 ไบต์)

int f(int N, int P){int F;for(F=N;P;F-=++N,P--);return F;}

ปลอดภัยแล้ว 5 ไบต์ด้วยการเปลี่ยนเป็นแลมบ์ดาและย้ายการเริ่มต้นออกจากfor(53)

[](int N,int P){int F=N;for(;P;F-=++N,P--);return F;}

และในที่สุดหลังจากเปลี่ยนจากforเป็นwhileฉันได้ 51 ไบต์:

[](int N,int P){int F=N;while(P--)F-=++N;return F;}

รหัสการทดสอบที่ไม่ถูกจับตาดูมีลักษณะดังนี้:

#include <iostream>
int main(void)
{
    int N, P;
    std::cin >> N >> P;
    auto f = [](int N,int P)
    {
        int F = N;
        while (P--)
            F -= ++N;
        return F;
    };
    std::cout << f(N, P) << std::endl;
    return 0;
}

UPDATE:

จริงๆแล้วforสามารถเข้าถึงความยาวเท่ากับwhile:

[](int N,int P){int F=N;for(;P--;F-=++N);return F;}

2

ฉันไปงานปาร์ตี้สาย ...

หากคุณต้องการเปลี่ยนนิพจน์เป็น -1 และ 1 แทน 0 และ 1 แทนที่จะเป็น:

int x;
if (a * 10 > 5)
    x = 1;
else
    x = -1;

ทำเช่นนี้:

int x = (a * 10 > 5) * 2 - 1;

มันสามารถบันทึกบางไบต์ขึ้นอยู่กับการใช้งาน


แทนที่จะint x=(a*10>5)*2-1;ทำคุณทำไม่int x=a*10>5?1:-1;ได้ซึ่งจะสั้นกว่า 1 ไบต์?
girobuz

2

หากคุณต้องการสลับสองจำนวนเต็ม a และ b

a^=b^=a^=b;

สามารถใช้งานได้ประหยัด 5 ตัวอักษรกว่าวิธีมาตรฐาน

a+=b;
b=a-b;
a-=b;

1
เกี่ยวกับวิธีมาตรฐาน ,tที่ ints ที่สร้างขึ้นก่อนหน้านี้และจากนั้นt=a;a=b;b=t;จะสั้นกว่า 3 ไบต์ไปa+=b;b=a-b;a-=b;แล้ว แต่ถึงกระนั้นคุณa^=b^=a^=b;ก็สั้นกว่านั้นดังนั้น +1 จากฉัน ผมไม่ทราบว่า C ++ แต่มันใช้งานได้จริง ในฐานะที่เป็น Java รหัสนักกอล์ฟที่ฉันเศร้าก็ดูเหมือนจะไม่ทำงานที่นั่น :(
Kevin Cruijssen

1
@KevinCruijssen ใช่ฉันควรจะพูดถึง C ++ ฉันไม่รู้ java มาก แต่a^=b;b^=a;a^=b;ทำงานได้ดีใน java
joker007

1
ไม่จำเป็นต้องพูดถึง C ++ อย่างชัดเจน เคล็ดลับทั้งหมดนี้สำหรับ C ++ :) ในฐานะนักพัฒนา Java ฉันแค่อยากรู้ว่าสิ่งที่คล้ายกันสามารถทำได้ใน Java แต่ดูเหมือนจะไม่ a^=b;b^=a;a^=b;ทำงานแน่นอน แต่มีความยาวเกิน+,t t=a;a=b;b=t;ขออภัยที่กล่าวถึง Java เนื่องจากเป็นหัวข้อที่นี่ แต่เคล็ดลับที่ดีสำหรับนักเขียนโค้ด C ++!
Kevin Cruijssen

2

ใช้ GCC ในตัวแทนการนำเข้า

หากคุณใช้คอมไพเลอร์ GCC บางครั้งอาจช่วยให้ใช้ฟังก์ชั่นในตัวเช่น__builtin_putsหรือ__builtin_clzหรือตัวอย่างเช่น,

44 ไบต์:

int main(){__builtin_puts("Hello, world!");}`

50 ไบต์:

#import<cstdio>
int main(){puts("Hello, world!");}

1

หากคุณกำลังทำ C ++ 11 หรือใหม่กว่า (ซึ่งควรเป็นกรณีนี้เสมอ) ใช้autoสำหรับประเภทที่ซับซ้อนถ้าเป็นไปได้

ตัวอย่าง: 54 ไบต์แทน 66

#include<vector>
std::vector<int> f(std::vector<int> l){return l;}
#include<vector>
auto f(std::vector<int> l){return l;}

นอกจากนี้เนื่องจากประสิทธิภาพไม่สำคัญสำหรับความท้าทายบางอย่าง a std::listอาจทำงานได้น้อยกว่าไม่กี่ไบต์:

#include<list>
auto f(std::list<int> l){return l;}

1

ฟังก์ชั่นในการ<algorithm>มักจะต้องผ่านa.begin(),a.end()ซึ่งเป็นนานจริงๆแทนคุณสามารถใช้&a[0],&*end(a)เพื่อประหยัด 3 ไบต์ถ้าaเป็นหรือvectorstring

sort(a.begin(),a.end());
sort(begin(a),end(a));
sort(&a[0],&*end(a));

0

อย่าใช้การใช้งานstring("") ""มันช่วยประหยัด 8 ไบต์


มันไม่เทียบเท่ากันแน่ ยกตัวอย่างเช่น"" + 'a'เป็นchar* + charซึ่งเป็นตัวชี้นอกจากนี้ในขณะที่std::string("") + 'a'เป็นstd::string + char- สตริง string()จะทำงาน.
user202729
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.