โหมโรงตรวจสอบไวยากรณ์


10

โหมโรงเป็นภาษาการเขียนโปรแกรมลึกลับซึ่งมีข้อ จำกัด น้อยมาก แต่ผิดปกติในสิ่งที่ถือว่าเป็นโปรแกรมที่ถูกต้อง บล็อกใด ๆ ของข้อความ ASCII ที่พิมพ์ได้ ("บล็อก" หมายความว่าบรรทัดของ ASCII ที่พิมพ์ได้จะถูกคั่นด้วยบรรทัดใหม่ - 0x0A) ถูกต้องหากว่า:

  • ทุกคน (แนวตั้ง) คอลัมน์ของข้อความที่มีอย่างหนึ่งมากที่สุดของและ()
  • ละเว้นตำแหน่งแนวตั้งของพวกเขา(และ)มีความสมดุลนั่นคือแต่ละ(คู่จะถูกจับคู่กับหนึ่ง)ไปทางขวาของมันและในทางกลับกัน

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

คุณต้องไม่สมมติว่าอินพุตเป็นรูปสี่เหลี่ยม

นี่คือรหัสกอล์ฟดังนั้นการส่งที่สั้นที่สุด (เป็นไบต์) ชนะ

ตัวอย่าง

ต่อไปนี้เป็นโปรแกรมโหมโรงที่ถูกต้อง (อันที่จริงมันเป็นโปรแกรมนำเสนอจริง ):

?1-(v  #1)-             
1   0v ^(#    0)(1+0)#)!
    (#)  ^#1-(0 #       
1(#  1) v #  - 1+)
    vv (##^v^+
? v-(0 # ^   #)
?
  1+              1-!

และนี่คืออินพุตจำนวนหนึ่งซึ่งไม่ถูกต้องทั้งหมด :

#(#(##)##)##(
)##(##(##)#)#
#(#)
)###
#(##
(##)
(##)
(#)#
(##)
(###
#(#)
(##)
#(#)
###)
#()#
()##
#(#)##
###
###(#)

โหมโรงมีความคิดเห็นที่สามารถปิดกั้น paren ปิด?
Alex A.

@ เลขที่กฎกติกาข้างต้นเป็นจริงทั้งหมดมีการตัดสินใจว่าโปรแกรมถูกต้องหรือไม่
Martin Ender

เจ๋งขอบคุณที่ชี้แจง แค่อยากให้แน่ใจ
Alex A.

กฎข้อที่ 1 - "ทุกคอลัมน์ของข้อความมีอย่างน้อยหนึ่งใน (และ)"; ตัวอย่างที่ 1 บรรทัดที่ 2: "1 0v ^ (# 0) (1 + 0) #)!" -> ผมเห็น 3 )และ (2 มันควรจะไม่เพียง 1 ต่อบรรทัด?
Ismael Miguel

1
@IsmaelMiguel "คอลัมน์"มักจะเข้าใจเพื่ออ้างถึงเส้นแนวตั้ง (โดยเฉพาะในบริบทของกริด) ฉันชี้แจงมันต่อไปแม้ว่า
Martin Ender

คำตอบ:


3

CJam, 57 56 ไบต์

qN/z_{_"()"--W<},,\s:Q,{)Q/({_')/,\'(/,-}:T~\sT0e>+z+}/!

นานเกินไปสามารถเล่นกอล์ฟได้มาก คำอธิบายที่จะเพิ่มเมื่อฉันกอล์ฟมัน

คำอธิบายสั้น ๆ

มีการตรวจสอบสองครั้งในรหัส:

  • ตัวกรองแรกตรวจสอบว่าแต่ละคอลัมน์เป็นวงเล็บ 1 ตัวมากที่สุด ผลลัพธ์สุดท้ายของตัวกรองคือจำนวนคอลัมน์ที่มีวงเล็บมากกว่า 1 ตัว
  • ที่สองเราแปลงอินพุตเป็นรูปแบบหลักของคอลัมน์จากนั้นแยกแต่ละดัชนีออกเป็นสองส่วน
    • ในแต่ละส่วนเหล่านี้ ( Number of "(" - Number of ")") ควรได้รับการชมเชย ดังนั้นเมื่อคุณเพิ่มมันควรจะส่งผลให้ 0 ส่วนใด ๆ ที่ล้มเหลวในคุณสมบัตินี้ทำให้อินพุตทั้งหมดมีวงเล็บที่ไม่ตรงกัน
    • ฉันต้องแน่ใจด้วยว่า "(" อยู่ทางซ้ายของ ")" ซึ่งหมายความว่าค่าของNumber of "(" - Number of ")"ไม่สามารถลบสำหรับบล็อกด้านขวา

ลองออนไลน์ได้ที่นี่


6

Python 2, 128 119 105 ไบต์

def F(p):
 v=n=1
 for r in map(None,*p.split("\n")):A,B=map(r.count,"()");n+=B-A;v*=n<2>A+B
 return n*v>0

คุณรู้หรือไม่ว่าคุณสามารถแมปไม่มีใน Python 2 ได้

คำอธิบาย

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

ยกเว้นการทำแผนที่None:

>>> print map(None,*[[1,2,3],[4],[5,6]])
[(1, 4, 5), (2, None, 6), (3, None, None)]

น่าเสียดายที่โชคดีสำหรับวัตถุประสงค์ที่ไม่ใช่กอล์ฟทั้งหมดนี้ใช้งานได้ใน Python 2 เท่านั้น

สำหรับnและv:

  • n1 - <number of unmatched '(' remaining>ทำหน้าที่เหมือนสแต็คนับ สำหรับทุก ๆ ที่(เราเห็นว่าเราลบ 1 และสำหรับทุก ๆ ที่)เราเห็นเราเพิ่ม 1 ดังนั้นถ้าn >= 2ณ จุดใดก็ตามเราเห็นจำนวนมากเกินไป)และโปรแกรมไม่ถูกต้อง หากnยังไม่เสร็จในวันที่ 1 แสดงว่าเรามี(เหลืออย่างน้อยหนึ่งที่ไม่ตรงกัน
  • vตรวจสอบความถูกต้องและเริ่มต้นที่ 1 หากโปรแกรมไม่ถูกต้อง ( n >= 2หรือA+B >= 2) จากนั้นvกลายเป็น 0 เพื่อทำเครื่องหมายการไม่ใช้งาน

n = 1, v = 1ดังนั้นหากโปรแกรมที่ถูกต้องแล้วในตอนท้ายเราจะต้องมี หากโปรแกรมไม่ถูกต้องแล้วโดยท้ายที่สุดเราจะต้องมีหรือv = 0 ดังนั้นความถูกต้องสามารถแสดงได้ชัดถ้อยชัดคำเป็นv = 1, n <= 0n*v>0

(ขอบคุณ @feersum สำหรับคำแนะนำที่ดีมากมายซึ่งนำออกไป 14 ไบต์!)

ก่อนหน้าการส่งที่อ่านง่ายขึ้น:

def F(p):
 p=map(None,*p.split("\n"));v=n=0
 for r in p:R=r.count;A=R("(");B=R(")");n+=A-B;v|=A+B>1or n<0
 return n<1>v

นั่นเป็นการใช้อย่างบ้าคลั่งของmap...
xnor

1
119 -> 106def F(p): v=n=3 for r in map(None,*p.split("\n")):A,B=map(R.count,"()");n+=A-B;v*=n>2>A+B return n*v==9
feersum

@feersum ขอบคุณ! ผมได้พยายามที่จะเปลี่ยนorเข้าสู่การผูกมัดเปรียบเทียบ แต่ผมไม่คิดว่าการเปลี่ยนแปลงเข้าสู่|= *=เอาออกไบต์อีกแม้ว่าโดยการทำสิ่งที่ยิ่งมากขึ้นไปข้างหลัง :)
SP3000

2

J, 64 ไบต์

อินพุตเป็นสตริงที่มีบรรทัดใหม่ต่อท้าย เอาต์พุตคือ 0 หรือ 1

(0=(1<|s)s+[:(|@{:+(0>])s)[:+/\]s=.+/@:)@(1 _1 0{~[:'()'&i.];.2)

ตัวอย่างการใช้งาน

   ]in=.'#(#)##',LF,'###',LF,'###(#)',LF
#(#)##
###
###(#)

   ((0=(1<|s)s+[:(|@{:+(0>])s)[:+/\]s=.+/@:)@(1 _1 0{~[:'()'&i.];.2)) in
0

วิธีการดังต่อไปนี้

  • ตัดอินพุตที่บรรทัดใหม่และใส่ลงในเมทริกซ์ ];.2
  • แผนที่(/ )/ anything elseเป็น1/ -1/0 1 _1 0{~[:'()'&i.]
  • กำหนดs=.+/@:คำวิเศษณ์ที่เพิ่มเข้าไปในคำกริยาผลรวมของอาร์เรย์คำกริยาเอาท์พุท
  • เพิ่มค่าในคอลัมน์ ]s

    • ตรวจสอบ()ยอดเงินคงเหลือในทุกส่วนนำหน้า [:(0>])s)[:+/\]
    • ตรวจสอบ()ยอดเงินคงเหลือในรายการทั้งหมด (เช่นในคำนำหน้าสุดท้าย) |@{:@]
  • เพิ่ม abs (ค่า) ในคอลัมน์และตรวจสอบทุกองค์ประกอบเพื่อหาค่าสูงสุด 1 (1<|s)s

  • เนื่องจากการตรวจสอบก่อนหน้านี้ทั้งหมดให้ผลบวกเมื่อล้มเหลวเราจึงทำการเพิ่มและเปรียบเทียบกับ 0 เพื่อรับความถูกต้องของอินพุต 0=]


2

J, 56 ไบต์

3 :'*/0<: ::0:(+/\*:b),-.|b=.+/+.^:_1]0|:''()''=/];.2 y'

นั่นคือฟังก์ชั่นนิรนามที่ยอมรับสตริงที่มีบรรทัดใหม่ต่อท้ายและส่งคืน 0 หรือ 1 การอ่านจากขวาไปซ้าย:

  • ];.2 yในการส่ง J อื่น ๆ ตัดสตริงyที่เกิดขึ้นทั้งหมดของอักขระตัวสุดท้าย (ซึ่งเป็นสาเหตุที่อินพุตต้องการขึ้นบรรทัดใหม่) และสร้างเมทริกซ์รูปสี่เหลี่ยมผืนผ้าที่มีแถวเป็นชิ้นส่วนเบาะด้วยช่องว่างหากจำเป็น

  • '()'=/เปรียบเทียบอักขระทุกตัวในเมทริกซ์(นั้นก่อนแล้วจึง)คืนค่ารายการเมทริกซ์ 0-1 สองรายการ

  • +.^:_1]0|:เปลี่ยนรายการของเมทริกซ์สองตัวนั้นให้เป็นเมทริกซ์เดียวของจำนวนเชิงซ้อน จนถึงตอนนี้โปรแกรมจะเปลี่ยนทุกสิ่ง(ในอินพุตให้เป็น 1, )กลายเป็น i, และอักขระอื่น ๆ ทั้งหมดเป็น 0

  • b=.+/bกำหนดผลรวมของแถวของเมทริกซ์ที่ซับซ้อนในการที่

  • -.|bทำให้รายการของ 1 | z | สำหรับทุก Z bใน เงื่อนไขที่ทุกคอลัมน์มีวงเล็บในวงเล็บมากที่สุดจะแปลเป็นตัวเลขทั้งหมดเหล่านี้ 1- | z | เป็น nonnegative

  • +/\*:bbเป็นเวกเตอร์ของการทำงานผลรวมของสี่เหลี่ยมของตัวเลขใน หากทุกคอลัมน์มีวงเล็บไม่เกินหนึ่งตัวสี่เหลี่ยมของตัวเลขbจะเป็น 0, 1 หรือ -1 ,เชื่อมเวกเตอร์นี้กับเวกเตอร์ของ 1- บน | Z | 's

  • ตอนนี้สิ่งที่เราต้องทำคือการทดสอบว่ารายการของเวกเตอร์ที่ต่อกันของเราvนั้นเป็นตัวเลขที่ไม่ใช่เชิงลบนี่คือเกือบ*/0<:vยกเว้นว่าจะทำให้เกิดข้อผิดพลาดหากบางรายการของvไม่จริงดังนั้นเราจึงแทนที่<:ด้วย<: ::0:0 เพียงในกรณีที่มีข้อผิดพลาด .


แนวคิดที่ยอดเยี่ยมพร้อมตัวเลขที่ซับซ้อน แต่คุณต้องตรวจสอบด้วยว่า0={:+/\*:bเพราะเช่น(นั้นไม่ถูกต้อง
randomra

โอ้คุณพูดถูก @ randomra ฉันลืม!
โอมา

1
0=(-|)vสั้นลง 2 ไบต์เพื่อตรวจสอบ reals ที่ไม่เป็นลบ (มาเอาชนะ CJam!: P)
สุ่ม

1
โอ้และinvแทนที่จะ^:_1 บันทึกอีกหนึ่งไบต์
randomra

1
กลับไปที่ 56 3 :'*/0=({:,]-|)(-.@|,+/\@:*:)+/+.inv]0|:''()''=/];.2 y'(มีการตรวจสอบยอดเงิน):
randomra
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.