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


16

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

โปรดระบุในเคล็ดลับของคุณหากมีความเฉพาะเจาะจงกับการใช้งานโปรล็อก (เช่น SWI-Prolog ในตัวเฉพาะ)

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


1
prologแท็กจะไม่ได้ผลครับ นอกจากว่าเราจะมีความท้าทายล่ามล่ามเราไม่ต้องการ
แมว

คำตอบ:


11

ใช้โอเปอเรเตอร์สำหรับชื่อภาคแสดง

เป็นไปได้ที่จะให้ตัวดำเนินการเพรดิเคตเป็นชื่อตราบใดที่โอเปอเรเตอร์เป็นหนึ่งในโอเปอเรเตอร์ที่กำหนดไว้ล่วงหน้า (อยู่ที่นี่ ) และยังไม่ได้กำหนดเป็นเพรดิเคต สิ่งนี้ช่วยประหยัดทั้งสองไบต์เมื่อกำหนดและเรียกใช้เพรดิเคตเนื่องจากเพรดิเคตตัวดำเนินการไม่จำเป็นต้องเขียนในname(arg1,arg2,etc..)รูปแบบปกติและสามารถเรียกได้ว่าใครจะคาดหวังกับตัวดำเนินการ

สำหรับการโต้แย้งหนึ่งและสองเพรดิเคตพวกเขาสามารถให้ชื่อของผู้ประกอบการเอกและไบนารีตามลำดับ สำหรับเพรดิเคต arity ที่สูงขึ้นเรายังสามารถหลีกเลี่ยงวงเล็บโดยใช้การจับคู่รูปแบบ ตัวอย่างเช่นถ้าเรามีมูลฐานA+B+C:-..., เปิดฉากจะใช้ของผู้ประกอบการมีความสำคัญและเชื่อมโยงกันกฎที่จะเปลี่ยนมันเป็นซึ่งเป็นคำกริยาผู้ประกอบการที่อาร์กิวเมนต์แรกเป็นรูปแบบการจับคู่กับ(A+B)+C:-... A+BหรือA-B+C*D:-...ซึ่งจะกลายเป็น(A-B)+(C*D)ดังนั้นอาร์กิวเมนต์แรกของมันคือรูปแบบการจับคู่กับและครั้งที่สองของมันคือรูปแบบการจับคู่กับA-BC*D

ตัวอย่าง

_+_+_.
A-B+C*D:-between(A,B,C),C+D.
\X:-X>1,X<10.
X+Y:-length(Y,X),member(X,Y).



5+[10,5,3,2,5],a+b+c,0-20+X*[2,4,6,5,40],\9.

ผลลัพธ์จะเป็น X = 5.

ลองออนไลน์!

ควันหลง

เนื่องจากDCGsเป็นน้ำตาลซินแทคติคสำหรับเพรดิเคตพวกเขาก็สามารถให้ชื่อได้เช่นกัน สิ่งนี้ทำงานได้อย่างที่คาดไว้เมื่อเรียกพวกเขาเป็น DCG ทั้งจาก DCG หรือใช้ภาคphraseแสดงหรืออื่น ๆ ที่ออกแบบมาเพื่อทำงานกับ DCG เมื่อเรียกพวกเขาเป็นวงเล็บภาคแสดงจะต้อง (เช่นA+B-->...ต้องเรียกว่าชอบ+(A,B,...)) เนื่องจากภาค DCG ใช้สองข้อโต้แย้งเพิ่มเติมสำหรับรายการที่แตกต่างของพวกเขา สำหรับโอเปอเรเตอร์ชื่อ DCGs ที่มีมากกว่าสองข้อโต้แย้งโดยใช้การจับคู่รูปแบบของตัวดำเนินการนั้นเป็นสิ่งสำคัญเพื่อให้แน่ใจว่าเมื่อเรียกมันว่าเพรดิเคตว่าตัวดำเนินการที่จับคู่รูปแบบนั้นถูกต้อง

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

ตัวอย่าง

/ -->a+b+X,X+d+e.
A+B+C-->[A],[B],[C].


X/[],member(c,X),phrase(f+o+o,Y),+(b+a,r,Z,[]).

ผลผลิตจะได้

X = [a, b, c, c, d, e],
Y = [f, o, o],
Z = [b, a, r].

ลองออนไลน์!

คำเตือน

ด้วยโอเปอเรเตอร์ unary +และ-Prolog จะตีความ+20หรือ-20เป็นตัวเลขแทนการเรียกไปยัง+/1หรือเพ-/1รดิเคต เพรดิเคตที่กำหนดให้เป็นเอกภาพ+หรือ-เป็นชื่อยังสามารถเรียกใช้บนตัวเลขโดยใช้วงเล็บ ( +(20), -(20)) หากหลีกเลี่ยงไบต์พิเศษจากวงเล็บเป็นที่พึงปรารถนาประกอบการเอกภาคอื่น ๆ เช่น\, $ฯลฯ สามารถนำมาใช้เป็นชื่อแทน

การรวมกันของการจับคู่รูปแบบและตัวดำเนินการที่ชื่อว่าเพรดิเคตนั้นไม่สมบูรณ์โดยไม่มีข้อบกพร่อง หากคุณมีเพรดิเคตสองตัวที่มีโอเปอเรเตอร์เดียวกับชื่อและด้วยการจับคู่รูปแบบจะมีความเข้มงวดกว่าอีกแบบหนึ่งโดยทั่วไปแล้วจะมีการเรียกทั่วไปที่ใหญ่กว่าก่อน . ยกตัวอย่างเช่นในตัวอย่างข้างต้นถ้าล้มเหลวเพื่อให้ตรงกับการป้อนข้อมูลของมันแล้วเปิดฉากจะพยายามโทรA-B+C*D X+Yซึ่งจะส่งผลในข้อผิดพลาดเนื่องจากlength/2ต้องให้เป็นจำนวนเต็มซึ่งมันจะไม่เป็นเพราะมันจะอยู่ในรูปแบบY C*Dสิ่งนี้สามารถหลีกเลี่ยงได้ง่ายๆโดยตรวจสอบให้แน่ใจว่าไม่มีเพรดิเคตสองตัวที่มีตัวดำเนินการเหมือนกับชื่อของพวกเขาหรือถ้ามันล้มเหลวจากนั้นใช้การตัดและสั่งซื้ออย่างระมัดระวัง


3
มันน่าพิศวงว่ามันมีประโยชน์สำหรับการเล่นกอล์ฟอย่างไร ฉันเพิ่งลดจำนวนคำตอบจำนวน 16% โดยใช้เคล็ดลับนี้เพียงอย่างเดียว!
DLosc

7

พยายามทำให้ทุกกรณีเป็นไปได้ในกฎเดียว

วิธีที่ชัดเจนในการเขียนโปรแกรมใน Prolog คือการประกาศกฎหลาย ๆ กฎสำหรับภาคแสดงเดียวกัน ตัวอย่างเช่นเพรดิเคตเพื่อย้อนกลับรายการที่มีตัวสะสมจะมีลักษณะดังนี้:

r([],Z,Z).
r([H|T],Z,R):-r(T,[H|Z],R).

ใน Code-golf เราสามารถลบกฎข้อแรกและเพิ่ม a ;ท้ายกฎที่สองเพื่อเขียนรหัสการเรียกซ้ำ:

r([H|T],Z,R):-r(T,[H|Z],R);R=[H|Z].

เรารู้ว่าเงื่อนไขแรกr(T,[H|Z],R)จะล้มเหลวหาก T ว่างเปล่าเช่นถ้าการเรียกซ้ำจำเป็นต้องจบและทำให้เราสามารถเพิ่มการยกเลิกของเราเป็นข้อหรือหลังจากนั้น

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


7

ใช้ตัวดำเนินการทางคณิตศาสตร์เป็นตัวสร้าง tuple และคู่ข้อเสีย

[A,B]หากคุณต้องการที่จะผ่านโครงสร้างเดียวประกอบด้วยสองหรือมากกว่าค่าสิ่งที่เห็นได้ชัดที่สุดที่จะใช้เป็นรายการเช่น ที่จริง verbose แม้ว่า

มีทางเลือกอื่น ค่าโปรล็อกสามารถจัดเก็บโครงสร้างซ้อนกันได้โดยพลการซึ่งไม่ได้รับการประเมิน นี่คือตัวอย่างที่แสดงวิธีการทำงาน:

| ?- member(member(A,B),C).
C = [member(A,B)|_] ? ;
C = [_,member(A,B)|_] ? ;
(etc.)

member(A,B)เป็นเพียง tuple ที่มีชื่อในสถานการณ์นี้และภายนอกmember(ซึ่งเป็นการเรียกใช้ฟังก์ชัน) กำลังปฏิบัติต่อสิ่งนี้

แม้ว่า tuples ที่ตั้งชื่อนั้นมีประโยชน์พอสมควรในการเขียนโปรแกรม Prolog ที่ไม่ได้ตีกอล์ฟ แต่พวกเขาอาจดูเหมือน verbose มากกว่าวิธีการแบบรายการ อย่างไรก็ตามเราสามารถใช้ตัวละครโดยพลการในชื่อของตัวสร้าง tuple (สมมติว่าพวกมันถูกอ้างอิงอย่างเหมาะสม); แทนที่จะเป็นสิ่งที่น่ารักmemberหรือตัวละครเดียวaเราสามารถทำสิ่งนี้:

| ?- A = '-'('/'(1,2), '/'(3,4)).
A = 1/2-3/4

นี่ tuple ก่อสร้างของเรามีและ'-' '/'และน่าสนใจที่จะทราบว่าเครื่องพิมพ์สวย ๆ ทำอะไรกับพวกเขา มันใช้สัญกรณ์มัดสำหรับทูเปิล นี่เป็นคำย่อและแยกวิเคราะห์ในลักษณะเดียวกันกับที่การคำนวณทางคณิตศาสตร์เปรียบเทียบ (นี่ยังอธิบายว่าทำไมเลขคณิตisไม่ใช้=; A = 1+2จะรวมเป็นหนึ่งAเดียวกับtuple '+'(1,2)ดังนั้นจึงจำเป็นต้องใช้ไวยากรณ์แยกต่างหากเพื่อประเมินการแสดงออกทางคณิตศาสตร์ที่ไม่ได้ประเมินค่า) เนื่องจากตัวสร้าง tuple ต้องถูกเรียกอะไรบางอย่างคุณอาจใช้อักขระที่มี terse ไวยากรณ์ (และเป็นโบนัส-และ/เป็นตัวเลือกที่พบบ่อยที่สุดในโค้ดที่ไม่ใช่ golfed เช่นกันเมื่อพวกเขาต้องการตัวสร้าง tuple แบบเร่งด่วนแทนที่จะเป็นสิ่งที่มีความหมายในแบบเดียวกับที่iมักใช้เป็นตัวแปรวนดังนั้นพวกเขาจึงมีเหตุผลพอที่จะใช้ใน อินพุทและเอาท์พุทถ้าคุณต้องการทูเปิลที่นั่นด้วยเหตุผลบางอย่าง)

'-'และ'/'เป็นตัวเลือกที่ดีสำหรับผู้สร้างสิ่งอันดับเพราะพวกเขามีความประพฤติดีและมีประโยชน์นำไปสู่การอนุญาตให้คุณเขียนตัวอักษร tuple อย่างกว้างขวาง อย่างไรก็ตามโปรดทราบว่าคุณไม่จำเป็นต้องกังวลเกี่ยวกับการมาก่อนเมื่อค่ากลางถูกสร้างขึ้นภายในโปรแกรม อารัมภบททำให้สิ่งอันดับทูเปิลที่เก็บไว้เป็นต้นไม้แทนที่จะเป็นซอร์สโค้ดและเครื่องพิมพ์ที่สวยสามารถเอาท์พุทได้อย่างไม่น่าสงสัย:

| ?- A = '-'('-'(1,2), '-'(3,4)).
A = 1-2-(3-4)

เนื่องจากไวยากรณ์ของ tuple นั้นสั้นมาก ( f(A,B)ไม่สั้นกว่าf(A-B)) คุณสามารถแทนที่อาร์กิวเมนต์ของเพรดิเคตหลาย ๆ อันด้วย tuples โดยไม่มีค่าใช้จ่ายซึ่งหมายความว่าหากเพรดิเคตต้องการผ่านอาร์กิวเมนต์สองตัวหรือมากกว่าไปยังเพรดิเคตอื่น tuple และเพิ่งส่งผ่าน tuple (แม้ว่าสิ่งนี้จะต้องเปลี่ยนการเรียกไปยังเพรดิเคตทั้งหมดนอกเหนือจากเพรดิเคตเองเพื่อใช้การผสมผสานที่เหมาะสมของตัวสร้าง tuple และเครื่องหมายจุลภาค)

ข้อดีอีกอย่างของไวยากรณ์นี้คือถ้าคุณต้องการใช้ลิสต์ภายใน (แทนที่จะทำงานร่วมกับเพรดิเคตมาตรฐาน); รายการนั้นเป็นเพียงชุดของเซลล์ที่ซ้อนกันและเซลล์ข้อเสียเป็นเพียงสิ่งอันดับเดียวกับตัวสร้าง'.'ตามที่เห็นได้ที่นี่:

| ?- Q = '.'('.'(A,B),'.'(C,D)).
Q = [[A|B],C|D]

หากรหัสของคุณใช้ในรายการ "ด้วยตนเอง" ก็สามารถทำให้ความรู้สึกมากที่จะใช้คอนสตรัค tuple '.'ขนาดใหญ่น้อยกว่า ตัวเลือกทั่วไปสำหรับฉันคือการแสดงเซลล์ข้อเสียเป็น'/'(Tail,Head)(เพราะเป็นเรื่องเกี่ยวกับการอ่านมากที่สุดที่คุณจะได้รับในการแก้ปัญหาการส่งออกโดยไม่ต้องเสียตัวอักษร) โปรดทราบว่าคุณอาจต้องการความ[]เท่าเทียมของคุณเองเช่นกัน คุณสามารถใช้[]แต่มีความยาวสองไบต์และมีอะตอมจำนวนหนึ่งไบต์ (ตัวอักษรตัวพิมพ์เล็กทั้งหมด) ที่คุณสามารถใช้แทนได้

ตัวอย่างเช่นรายการต่อไปนี้:

[1,2,3]

สามารถแปลงเป็นการแสดงด้วยตนเองในจำนวนอักขระเช่นนี้:

x/3/2/1

ในขณะที่ความได้เปรียบที่[H|T]ตรงกับรูปแบบสไตล์ในขณะนี้สามารถเขียนได้มากขึ้นเป็นกะทัดรัดT/Hและทดสอบกับรายการที่ว่างเปล่าเป็นเพียงมากกว่าอีกต่อไปx [](ของหลักสูตรนี้มาพร้อมกับข้อเสียที่เห็นได้ชัดว่าmember, appendและอื่น ๆ จะไม่ทำงานในการแสดงนี้.)


+1! ไม่จำเป็นต้องราคาเดียวเมื่อใช้เป็นและ- /นี่เป็นอะตอมปกติที่สมบูรณ์แบบแล้ว
เสื่อ

และไม่จำเป็นต้องมีเครื่องหมายอัญประกาศเดี่ยวรอบตัว.หากอักขระต่อไปนี้ไม่ใช่แบบ%หรือเค้าโครง
เท็จ

6

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

ใช้ B-Prolog หรือ GNU Prolog ที่มีข้อ จำกัด ดังกล่าวอยู่ในกรอบโดยไม่จำเป็นต้องโหลดไลบรารีใด ๆ


2
นี่เป็นสิ่งที่ฉันเกลียด SWI-Prolog เสมอเมื่อทำสิ่งท้าทายที่นี่ การใช้ CLPFD จะทำให้บางอย่างสะอาดและสั้นลง แต่คุณต้องเพิ่มโค้ดพิเศษจำนวนมากเพื่อให้มันทำงานได้ ฉันคิดว่าฉันเคยใช้มันในคำตอบนี้เท่านั้น
ลดขนาด

3
ฉันเกลียดที่มากเกินไปและการตรวจสอบเวลาที่ในที่สุดก็จะมาถึงเมื่อlibrary(clpfd)จะสามารถใช้ได้เป็นโหลดไว้หรืออย่างน้อยautoloadedห้องสมุดยังอยู่ใน SWI-เปิดฉาก อาจใช้เวลาสองสามปีก่อนที่การคำนวณทางคณิตศาสตร์จะเป็นที่เข้าใจและชื่นชมจากผู้ใช้ทุกคนซึ่งได้สะสมประสบการณ์มานานหลายทศวรรษด้วยคุณลักษณะที่ล้าสมัยและล้าสมัย ยิ่งคุณใช้และสนับสนุน CLP (FD) มากเท่าไหร่เราก็จะได้รับเร็วขึ้นตามค่าเริ่มต้น จนแล้วคุณก็สามารถใส่:- use_module(library(clpfd)).ในของ~/.swiplrcรัฐเพียงและที่คุณกำลังใช้ที่ "แตกต่าง" ของ SWI-เปิดฉาก
เสื่อ

5

ไวยากรณ์ที่สั้นลงสำหรับรายการของรายการและวิธีการประกาศแผนที่

คุณสามารถบันทึกไบต์ในรายการของรายการ หากคุณมีรายการ[[1,2],[3,4]]คุณสามารถประกาศเป็นจริงได้[1:2,3:4]ซึ่งจะบันทึก 4 วงเล็บ = 4 ไบต์ โปรดทราบว่าคุณสามารถใช้อย่างอื่นที่ไม่ใช่:(ตัวอย่างเช่น^)

1:2ไม่จริงรายการในกรณีที่ (ในขณะที่[1,2]เป็น) :(1,2)ก็มีตัวแทนอยู่ภายในเป็น ดังนั้นคุณไม่สามารถใช้เพรดิเคตที่ทำงานกับรายการในรายการย่อยที่ใช้โคลอน

เคล็ดลับนี้ใช้เพื่อประกาศแผนที่เป็นหลักเช่นรายการของคีย์ที่มีค่าติดอยู่ ตัวอย่างเช่นหากคุณต้องการประกาศแผนที่Mที่มีตัวสะกดของตัวเลขทั้งภาษาอังกฤษและภาษาฝรั่งเศสคุณสามารถทำสิ่งนี้:

M=[0:'Zero':'Zéro',1:'One':'Un',2:'Two':'Deux', ... ]

member/2จากนั้นคุณสามารถเช่นดึงองค์ประกอบของแผนที่ที่มีในตัวคำกริยาเช่น ตัวอย่างเช่นหากคุณต้องการให้ตัวเลขและคำภาษาอังกฤษตรงกับ'Quatre'ในMคุณสามารถทำได้:

member(Digit:Name:'Quatre',M).

1
คุณสามารถพูดคุยเรื่องนี้ ตัวอย่างเช่นคุณสามารถ wirte [[1,2],[3,4]]เป็น1*2+3*4ซึ่งเป็น+(*(1,2),*(3,4))และยังใช้เพียงหนึ่งไบต์ที่คุณจะต้องสองสำหรับการเปิดและปิดวงเล็บ
เสื่อ

รายการคำพูดสองครั้งจะสั้นกว่า: "abc"แทน[a,b,c]
เท็จ

5

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

- ซ้ำ writeln (HI) 0 = 1

3
พันธกรณีThe Art of Prologอ้างอิง: " ในการเขียนโปรแกรม Prolog (ในทางตรงกันข้ามบางทีเพื่อชีวิตโดยทั่วไป) เป้าหมายของเราคือล้มเหลวโดยเร็วที่สุด " สนุกจริง: คุณยังสามารถใช้\+!เป็น 3 ไบต์วิธีแปลกที่จะล้มเหลวซึ่งไม่จริงทริกเกอร์ตัด!(ดูนี้สำหรับเหตุผล ) ฉันไม่คิดว่าเป็นไปได้ที่จะล้มเหลวในเวลาน้อยกว่า 3 ไบต์
ลดขนาด

ฉันยังคิดเกี่ยวกับคำพูดนั้นเมื่อฉันเขียนสิ่งนี้ ;-)
mat

2
เราต้องการทั้งสองเวอร์ชันจริง ๆ ติด\+!กาวไปทางซ้ายไปยังอักขระกราฟิกอื่น ๆ ในขณะที่ติด0=1กาวทางซ้ายสำหรับชื่อ
เท็จ

5

ใช้เพรดิเคตอีกครั้งด้วยโหมดการโทรที่แตกต่างกัน

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.