ตรวจจับหน้าต่างศิลปะ ASCII ที่ทำจากอักขระ M และ S


28

Window เป็นสี่เหลี่ยมจัตุรัส ASCII-art ที่มีความยาวด้านคี่อย่างน้อย 3 เส้นโดยมีเส้นขอบตัวอักษรหนึ่งเส้นล้อมรอบขอบเช่นเดียวกับลายเส้นแนวตั้งและแนวนอนตรงกลาง:

#######
#  #  #
#  #  #
#######
#  #  #
#  #  #
#######

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

ข้อมูลจำเพาะ

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

กรณีทดสอบ

Truthy:

MMM
MMM
MMM

SMSMS
M M S
SMSMM
S S M
SMSMS

MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM

Falsey:

Hello, World!

MMMM
MSSM
MS M
MMMM

MMSMM
M S.M
sSSSS
M S M
MMSMM

MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM

MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM

MMSSMSSMM
M   M   M
S   S   S
S   S  S
MMSSMSSMM
S   S   S
S   S   S
M   M   M
MMSSMSSMM

3
นี่คือการบิดอย่างยอดเยี่ยมในศิลปะ ASCII ปัญหาการตัดสินใจในการตรวจสอบโครงสร้างบางอย่าง
xnor

4
@xnor ฉันรู้สึกว่าเราอาจต้องการแท็กอื่นสำหรับศิลปะ ASCII แบบย้อนกลับเช่นนี้
แยกผลไม้

2
ในขณะที่ไม่เจาะจงสำหรับศิลปะ ASCII การจับคู่รูปแบบอาจเป็นทางเลือกที่ดีสำหรับแท็กใหม่
Destructible Lemon

คุณสามารถเพิ่มกรณีทดสอบหรือสองกรณีที่สตริงไม่ได้สร้างอาร์เรย์แบบสี่เหลี่ยมได้หรือไม่?
Greg Martin

1
@ เร็ว ๆ นี้คุณพูดถูก! บางทีความท้าทายต้องการความกระจ่าง
Chris M

คำตอบ:




7

Grime , 39 38 ไบต์

ขอบคุณ Zgarb ที่ช่วยประหยัด 1 ไบต์

e`BB/BB/W+ W/+
B=W|B/W\ * W/\ /*
W=[MS

ลองออนไลน์!

ฉันไม่แน่ใจว่าจะมีวิธีที่ง่ายกว่าในการบังคับใช้อัตราส่วนภาพสี่เหลี่ยมจัตุรัสของส่วนประกอบหน้าต่างแต่ละตัวแทนที่จะใช้แบบเรียกซ้ำแบบไม่ระบุชื่อ แต่สิ่งนี้ดูเหมือนว่าจะทำงานได้ค่อนข้างดี

คำอธิบาย

เป็นการดีที่สุดที่จะอ่านโปรแกรมจากล่างขึ้นบน

W=[MS

สิ่งนี้จะนิยาม nonterminal (ซึ่งคุณคิดว่าเป็นรูทีนย่อยที่ตรงกับรูปสี่เหลี่ยมผืนผ้า) Wซึ่งจับคู่กับMหรือS(มีความหมายโดยนัย]ในตอนท้ายของบรรทัด)

B=W|B/W\ * W/\ /*

สิ่งนี้กำหนดว่าไม่ใช่เทอร์มินัลBซึ่งตรงกับประมาณหนึ่งในสี่ของผลลัพธ์เช่นแผงหน้าต่างหนึ่งที่มีเส้นขอบซ้ายและขอบบน บางสิ่งเช่นนี้

MSM
S  
M  

เพื่อให้แน่ใจว่าแผงหน้าต่างนี้เป็นสี่เหลี่ยมจัตุรัสเรากำหนดBแบบเรียกซ้ำ มันอาจเป็นอักขระหน้าต่างWหรือB/W\ * W/\ /*เพิ่มเลเยอร์หนึ่งไปทางขวาและด้านล่าง เพื่อดูว่ามันทำอย่างไรเราจะเอาน้ำตาลซินแทคติคออก:

(B/W[ ]*)(W/[ ]/*)

สิ่งนี้เป็นแบบเดียวกันเนื่องจากการเขียนเรียงต่อกันในแนวนอนสามารถเขียนได้อย่างใดอย่างหนึ่งABหรือA Bแต่แบบหลังมีความสำคัญต่ำกว่าการต่อเรียงแนวตั้ง/ในขณะที่แบบก่อนหน้ามีค่าสูงกว่า ดังนั้นB/W[ ]*จะBมีตัวอักษรหน้าต่างและแถวของช่องว่างด้านล่าง แล้วเราต่อท้ายแนวนอนW/[ ]/*ซึ่งเป็นอักขระหน้าต่างที่มีคอลัมน์ของช่องว่าง

ในที่สุดเรารวบรวมคำที่ไม่เกี่ยวข้องเหล่านี้เป็นรูปร่างหน้าต่างสุดท้าย:

BB/BB/W+ W/+

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

ในที่สุดe`จุดเริ่มต้นก็คือการกำหนดค่าที่บอกให้ Grime ตรวจสอบว่าอินพุตทั้งหมดสามารถจับคู่โดยรูปแบบนี้ (และจะพิมพ์0หรือ1ตามลำดับ)


5

JavaScript (ES6), 115 113 ไบต์

a=>(l=a.length)&a.every((b,i)=>b.length==l&b.every((c,j)=>(i&&l+~i-i&&l+~i&&j&&l+~j-j&&l+~j?/ /:/[MS]/).test(c)))

จะเข้าเป็น array ของอาร์เรย์ของตัวละคร (เพิ่ม 5 ไบต์สำหรับอาร์เรย์ของสตริง) และส่งกลับหรือ1 0หลังจากตรวจสอบว่าความสูงเป็นเลขคี่ทุกแถวจะถูกตรวจสอบเพื่อให้แน่ใจว่าอาร์เรย์เป็นสี่เหลี่ยมจัตุรัสและอักขระทุกตัวได้รับการตรวจสอบว่าเป็นหนึ่งในอักขระที่เราคาดหวังในตำแหน่งนั้น แก้ไข: บันทึก 2 ไบต์ด้วย @PatrickRoberts


คุณสามารถเปลี่ยน(...).includes(c)เป็น~(...).search(c)บันทึก 1 ไบต์
Patrick Roberts

1
ที่จริงดียิ่งขึ้นคุณสามารถเปลี่ยนได้เพื่อ(...?/ /:/[MS]/).test(c)ที่จะบันทึก 2 ไบต์แทนเพียง 1
แพทริคโรเบิร์ต

@PatrickRoberts น่ารักขอบคุณ!
Neil

5

เพิร์ล 124 123 119 95 93 84

สคริปต์ Perl ต่อไปนี้อ่านหนึ่งหน้าต่าง MS ของผู้สมัครจากอินพุตมาตรฐาน จากนั้นจะออกโดยมีสถานะออกเป็นศูนย์หากผู้สมัครเป็น MS Window และมีสถานะออกไม่เป็นศูนย์หากไม่มี

มันทำงานได้โดยการสร้างนิพจน์ทั่วไปสองนิพจน์สำหรับด้านบนกลางและล่างและอีกหนึ่งบรรทัดสำหรับบรรทัดอื่นและตรวจสอบอินพุตกับพวกเขา

ขอบคุณ @Dada และอีกครั้ง.

map{$s=$"x(($.-3)/2);$m="[MS]";($c++%($#a/2)?/^$m$s$m$s$m$/:/^${m}{$.}$/)||die}@a=<>

ฉันไม่แน่ใจว่าจะให้ผลลัพธ์เนื่องจากสถานะการออกได้รับอนุญาต (ฉันไม่มีเวลาที่จะค้นหาเมตาโพสต์ที่เกี่ยวข้อง) ไม่ว่าคุณจะสามารถบันทึกได้กี่ไบต์:@a=<>;$s=$"x(($.-3)/2);$m="[MS]";map{$a[$_]!~($_%($./2)?"$m$s$m$s$m":"$m${m}{$.}")&&die}0..--$.
Dada

@Dada: ขอบคุณ! นั่นเป็นการปรับปรุงที่น่าประทับใจ: 24 ตัวอักษร (มีรหัส "$ m" จรจัดอยู่ในรหัสของคุณดังนั้นจึงสั้นกว่าที่ดูไว้ในตอนแรก) ฉันไม่แน่ใจว่าการรายงานผลด้วยรหัสออกจะได้รับอนุญาตโดยทั่วไป แต่ฉันใช้ "เขียนโปรแกรม ( หรือฟังก์ชั่น) "เพื่อให้ผู้ใช้มีความยืดหยุ่นในการคืนผลลัพธ์ในกรณีนี้โดยเฉพาะ รหัสทางออกเป็นค่าฟังก์ชันส่งคืนของสภาพแวดล้อม * nix :-)
nwk

ทำให้ตัวละครนั้น 26 ตัว
nwk

1
ที่จริงฉันกำลังลดลง$.ในตอนท้ายเพื่อหลีกเลี่ยงการใช้สองครั้ง$.-1(โดยเฉพาะตั้งแต่ครั้งแรกที่($.-1)/2มันจำเป็นต้องใช้วงเล็บพิเศษบางอย่าง) ดังนั้นสิ่งที่$mอยู่ภายใน$m${m}{$.}ไม่ใช่ข้อผิดพลาด นอกจากนี้ผมเพิ่งตระหนักในขณะนี้ แต่ regexs ควรจะล้อมรอบด้วย^...$(ตัวอักษรพิเศษเพื่อที่สิ้นสุดหรือทำให้จุดเริ่มต้นที่พวกเขาล้มเหลว) หรือสั้น: ใช้แทนne !~
Dada

ไม่เป็นไรเห็นได้ชัดว่าคุณไม่สามารถใช้neแทน!~(ฉันไม่ควรเขียนข้อความเมื่อฉันตื่นขึ้นมาเพียง 15 นาที!) ดังนั้นคุณจะต้องใช้^...$ทั้ง regex ฉันกลัว
Dada

2

Mathematica, 166 ไบต์

Union[(l=Length)/@data]=={d=l@#}&&{"M","S"}~(s=SubsetQ)~(u=Union@*Flatten)@{#&@@(p={#,(t=#~TakeDrop~{1,-1,d/2-.5}&)/@#2}&@@t@#),p[[2,All,1]]}&&{" "}~s~u@p[[2,All,2]]&

ฟังก์ชั่นที่ไม่มีชื่อสละรายชื่อของรายการของตัวละครที่เป็น input และกลับหรือTrue Falseนี่คือรุ่นที่ไม่ค่อยตีกอล์ฟ:

(t = TakeDrop[#1, {1, -1, d/2 - 0.5}] &; 
Union[Length /@ data] == {d = Length[#1]}
  &&
(p = ({#1, t /@ #2} &) @@ t[#1];
SubsetQ[{"M", "S"}, Union[Flatten[{p[[1]], p[[2, All, 1]]}]]]
  && 
SubsetQ[{" "}, Union[Flatten[p[[2, All, 2]]]]])) &

บรรทัดแรกกำหนดฟังก์ชั่นtซึ่งแยกรายการความยาวdออกเป็นสองส่วนส่วนแรกคือรายการแรกกลางและสุดท้ายของรายการและส่วนที่สองเป็นส่วนที่เหลือทั้งหมด บรรทัดที่สองตรวจสอบว่าอินพุตเป็นอาร์เรย์สี่เหลี่ยมในตำแหน่งแรกหรือไม่ บรรทัดที่สี่ใช้tสองครั้งในอินพุตหนึ่งตัวและหนึ่งครั้งบน * ทั้งหมดของสตริงในอินพุตเพื่อแยกอักขระที่ควรจะเป็น"M"หรือ"S"จากอักขระที่ควรจะเว้นวรรค จากนั้นบรรทัดที่ห้าและเจ็ดจะตรวจสอบว่าพวกเขาเป็นสิ่งที่ควรจะเป็นจริงหรือไม่


2

JavaScript (ES6), 108 106 ไบต์

อินพุต: อาร์เรย์ของสตริง / เอาต์พุต: 0หรือ1

s=>s.reduce((p,r,y)=>p&&r.length==w&(y==w>>1|++y%w<2?/^[MS]+$/:/^[MS]( *)[MS]\1[MS]$/).test(r),w=s.length)

กรณีทดสอบ


2

JavaScript (ES6), 140 138 141 140 ไบต์

ฉันรู้ว่านี่ไม่ใช่การนับไบต์ที่ชนะ (แม้ว่าต้องขอบคุณ Patrick Roberts ที่ -3 และฉันรู้ว่ามันโยนผลบวกปลอมสำหรับ 1 แทน M / S: +3) แต่ฉันทำมันแตกต่างออกไปเล็กน้อยฉัน ' ใหม่สำหรับสิ่งนี้และมันสนุก ...

ยอมรับอาร์เรย์ของสตริงหนึ่งรายการสำหรับแต่ละบรรทัดและส่งคืนค่าจริงหรือเท็จ เพิ่มบรรทัดใหม่เพื่อความชัดเจน (ไม่รวมอยู่ในจำนวนไบต์)

f=t=>t.every((e,i)=>e.split`S`.join`M`==[...p=[b='M'.repeat(s=t.length),
...Array(z=-1+s/2|0).fill([...'MMM'].join(' '.repeat(z)))],...p,b][i])

แทนที่จะตรวจสอบอินพุตกับรูปแบบทั่วไปฉันสร้างหน้าต่าง 'M' ที่มีขนาดเท่ากันแทนที่ S ด้วย M บนอินพุตและเปรียบเทียบทั้งสอง

Ungolfed

f = t => t.every( // function returns true iff every entry in t
                  // returns true below
  (e, i) => e.split`S`.join`M` // replace all S with M
                                 // to compare to mask
  == [ // construct a window of the same size made of Ms and
       // spaces, compare each row 
      ...p = [ // p = repeated vertical panel (bar above pane)
               // which will be repeated
              b = 'M'.repeat(s = t.length),
                  // b = bar of Ms as long as the input array
              ...Array(z = -1 + s/2|0).fill([...'MMM'].join(' '.repeat(z)))],
              // z = pane size; create enough pane rows with
              // Ms and enough spaces
      ...p, // repeat the panel once more
      b][i] // finish with a bar
)

console.log(f(["111","111","111"]))

console.log(f(["MMMMM","M S M","MSSSM","M S M","MSSSM"]))

กรณีทดสอบ

f=t=>t.every((e,i)=>e.split`S`.join`M`==[...p=[b='M'.repeat(s=t.length),
...Array(z=-1+s/2|0).fill([...'MMM'].join(' '.repeat(z)))],...p,b][i])


truthy=`MMM
MMM
MMM

SMSMS
M M M
SMSMS
M M M
SMSMS

MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM`.split('\n\n')

falsey=`Hello, World!

MMMM
MSSM
MS M
MMMM

MMSMM
M S.M
sSSSS
M S M
MMSMM

MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM

MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM`.split('\n\n')

truthy.forEach(test=>{
  console.log(test,f(test.split('\n')))
})

falsey.forEach(test=>{
  console.log(test,f(test.split('\n')))
})


1
สำหรับการอ้างอิงในอนาคตยกเว้นว่าฟังก์ชั่นจะเรียกซ้ำf=ไม่จำเป็นต้องรวมอยู่ในการนับไบต์ดังนั้นนี่จึงเป็นการส่ง 138 ไบต์
Patrick Roberts

คุณสามารถแทนที่z=-1+s/2|0ด้วยz=(s-3)/2การบันทึก 1 ไบต์
Patrick Roberts

คุณสามารถแทนที่e.replace(/S/g,'M')==...ด้วยe.split`S`.join`M`==...เพื่อบันทึกไบต์อื่นได้
Patrick Roberts

ขอบคุณ! z=-1+s/2|0จะมีการส่งกลับจำนวนเต็มบวกสำหรับ s == 1 และแม้กระทั่ง s คือฟังก์ชั่นกลับเท็จโดยไม่ต้อง Array () ชนมัน มิฉะนั้นตรรกะที่จำเป็นทำให้มันนานขึ้น เคล็ดลับที่ยอดเยี่ยมในการแยก / เข้าร่วมขอบคุณ
Chris M

จับดีฉันไม่ได้พิจารณาs=1กรณีเนื่องจาก regex ที่ไม่ถูกต้องของฉันเพิ่งล้มเหลวในความเงียบ
Patrick Roberts

1

JavaScript (ES6), 109 107 106 105 99 ไบต์

s=>!s.split`S`.join`M`.search(`^((M{${r=s.search`
`}})(
(M( {${w=(r-3)/2}})M\\5M
){${w}}))\\1\\2$`)

แก้ไข : โอ้โห Arnauld ช่วยฉัน 6 ไบต์ด้วยการเปลี่ยนs.split`\n`.lengthเป็นs.search`\n`! ขอบคุณ!

สิ่งนี้ใช้สตริงหลายบรรทัดเดียวและสร้างการRegExpตรวจสอบความถูกต้องโดยใช้ความยาวของสตริงอินพุต ผลตอบแทนหรือtrue falseถือว่าหน้าต่างที่ถูกต้องมี ไม่ได้มีอักขระขึ้นบรรทัดใหม่

การสาธิต

f=s=>!s.split`S`.join`M`.search(`^((M{${r=s.search`
`}})(
(M( {${w=(r-3)/2}})M\\5M
){${w}}))\\1\\2$`);
`MMM
MMM
MMM

SMSMS
M M M
SMSMS
M M M
SMSMS

MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM

Hello, World!

MMMM
MSSM
MS M
MMMM

MMSMM
M S.M
sSSSS
M S M
MMSMM

MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM

MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM`.split`

`.forEach(test=>{console.log(test,f(test));});


วิธีการที่ดี! คุณสามารถใช้r=s.search('\n')แทนsplit / length?
Arnauld

@Arnauld ข้อเสนอแนะที่ยอดเยี่ยมขอบคุณ!
Patrick Roberts

สามารถเปิดวงเล็บในs=>!s.split`S`.join`M`.search([...])โดยไม่ทำให้เกิดข้อผิดพลาดทางไวยากรณ์
Ismael Miguel

@IsmaelMiguel แก้ไข แต่แล้วสตริงได้รับผ่านเป็นแม่แบบซึ่งเลิกนัยRegExp
แพทริคโรเบิร์ต

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