ฉันจะเลื่อนแยกชิ้นส่วนปริศนาออกได้หรือไม่


38

เขียนโปรแกรมหรือฟังก์ชั่นที่ใช้เวลาในตารางสี่เหลี่ยมของข้อความที่มือถือของทุกคนเป็นอย่างใดอย่างหนึ่งหรือA เซลล์Bทั้งหมดAจะสร้างรูปร่างที่เชื่อมต่ออย่างง่ายๆนั่นคือเซลล์เหล่านั้นทั้งหมดจะเชื่อมต่อแบบ orthogonally โดยไม่มีรู ในทำนองเดียวกันBเซลล์ทั้งหมดจะสร้างรูปทรงอื่นที่เชื่อมต่อกัน ตารางจะมีอย่างน้อยหนึ่งAและอย่างน้อยหนึ่งBเสมอ

ลองนึกภาพกริดนั้นจริง ๆ แล้วเป็นพลาสติกสองชิ้นที่มีรูปทรงบล็อกสองชิ้นแสดงโดยAและBบางส่วน หากวางราบบนโต๊ะทั้งสองชิ้นจะแยกออกจากกันในขณะที่วางทั้งสองไว้บนโต๊ะอย่างสมบูรณ์ได้หรือไม่

พิมพ์หรือส่งกลับtruthyค่าถ้าทั้งสองAและBรูปร่างอาจจะแยกออกจากกันเช่นนี้โดยเพียงแค่ดึงพวกเขาออกจากกัน ถ้าไม่พิมพ์หรือกลับfalsyค่า

ตัวอย่างเช่นการป้อนข้อมูล

AAA
ABB
AAA

เป็นจริงเพราะBBส่วนสามารถเลื่อนไปทางขวาแยกออกจากA's:

AAA
A    BB
AAA

อย่างไรก็ตามการป้อนข้อมูล

AAAA
ABBA
ABAA

เป็นเท็จเพราะไม่มีวิธีการเลื่อนAและBแยกส่วนโดยไม่ทับซ้อนกัน

รหัสที่สั้นที่สุดในหน่วยไบต์ชนะ หากต้องการคุณอาจจะใช้สอง Distict พิมพ์ ASCIIตัวละครในสถานที่และAB

ตัวอย่างความจริง (คั่นด้วยบรรทัดว่าง)

BBB
BAA
BBB

BA

A
B

AB
AB

AAA
BBB

AAAAB
ABBBB

ABBA
ABBA
AAAA

AAAAAABBBBBBBBB
AABBBBBBBBBBBBB
AAAAAAAAAABBBBB
AABBBBBBBBBBBBB
AAAAAAAAAAAAAAB

AAAAAAAAAAAA
ABABABABABAB
BBBBBBBBBBBB

BAAAAABB
BBAAABBB
BBBABBBB
BBBABBBB
BBBABBBB
BBBBBBBB
BBBBBBBB

AAA
BAA
AAA

ตัวอย่างที่เป็นเท็จ

BBBB
BAAB
BABB

BBBB
BAAB
AABB

BBBBBBB
BBBBBAB
AAAAAAB
BBBBBBB

BAAA
BABA
BBBA
AABA
AAAA

AAAAAAA
ABBBBBA
AAAAABA
BBBBBBA

BAAAAABB
BBAAABBB
BBBABBBB
BBBABBBB
BBBAABBB
BBBBBBBB
BBBBBBBB

AAA
ABA
BBA
ABA
AAA

คำตอบ:


9

หอยทาก, 14

o(t\B+~)+!(t\B

หากตัวต่อสามารถเลื่อนออกได้มันจะพิมพ์พื้นที่ของอินพุต มิฉะนั้นจะพิมพ์ 0

มันค่อนข้างช้าสำหรับตัวอย่างที่มีขนาดใหญ่เนื่องจากมันต้องใช้เวลาในการคำนวณปัจจัยในพื้นที่ของกริด

         ,, the program will print the number of starting cells matching this pattern
o        ,, pick a cardinal direction
(
    t    ,, teleport to any cell on the grid
    \B+  ,, match "B" 1 or more times, moving in the direction set by 'o'.
         ,, when a cell is matched, it gets slimed and can't be matched again.
    ~    ,, match an out-of-bounds cell
)+       ,, do parenthesized instructions 1 or more times
!(       ,, the following must not match:
    t\B  ,, teleport to some cell and match 'B'

4
"มันเป็นบิตช้า .." ไม่แน่ใจว่าสิ่งที่คุณคาดหวังจากภาษาที่เรียกว่าหอยทาก ...
Bassdrop Cumberwubwubwub

4
@Bas ตอนนี้ไม่มีเหตุผลที่จะถูเกลือในบาดแผล
Trasiva

21

CJam, 33 32 20 19 17 ไบต์

รุ่นที่ปรับปรุงใหม่พร้อมการรองรับอย่างมากจาก @ Sp3000 และ @ MartinBüttner:

qN/_z]{:e`z,3<}/|

ลองออนไลน์

การมีส่วนร่วม

  • @ Sp3000 แนะนำการลดความซับซ้อนที่สำคัญให้กับอัลกอริทึมดั้งเดิมของฉัน
  • @ MartinBüttnerใช้ทักษะการตีกอล์ฟที่บ้าคลั่งของเขากับวิธีการแก้ไขซึ่งเกือบจะส่งผลให้รหัสสั้นกว่าที่ฉันคิดไว้แม้หลังจากพิจารณาถึงความเรียบง่าย

อัลกอริทึมและการพิสูจน์

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

ฉันจะใช้คำว่า "ยืด" สำหรับลำดับสูงสุดของตัวอักษรเดียวกัน ตัวอย่างเช่นแถวต่อไปนี้มี 1, 2 และ 3 ทอดยาวตามลำดับ:

AAAAAAAA
BBBAAAAA
AABBBAAA

ฉันจะใช้คำว่า "interlocked" เป็นแถว / ตัวต่อที่ไม่สามารถเลื่อนออกจากกันได้

สังเกตที่สำคัญคือปริศนาสามารถเลื่อนออกจากกันและถ้าหากทุกคนมีแถวที่มากที่สุด 2 เหยียด หรือกลับก็จะประสานและถ้าหากมีแถวใด ๆ ที่มีมากกว่า 2 เหยียด

ต่อไปนี้อาจไม่ถือว่าเป็นข้อพิสูจน์ทางคณิตศาสตร์ที่เข้มงวด แต่ฉันเชื่อว่ามันเป็นคำอธิบายที่น่าเชื่อถือว่าทำไมต้องเป็นเช่นนี้

มันง่ายที่จะเห็นว่าตัวต่อถูกเชื่อมต่อกันถ้ามันมีแถวมากกว่า 2 แนว ดูแถวที่มี 3 เหยียด:

BBBAAB

เห็นได้ชัดว่ามันป้องกันปริศนาจากการเลื่อนแยกเนื่องจากการAยืดถูกล็อกระหว่างการBเหยียด ซึ่งหมายความว่าแถวนั้นเชื่อมต่อกันซึ่งจะทำให้ตัวต่อทั้งหมดประสานกัน

ทิศทางตรงกันข้ามของการพิสูจน์นั้นค่อนข้างชัดเจน เราจำเป็นต้องแสดงให้เห็นว่าไม่มีปริศนาเชื่อมต่อกันที่ทุกแถวมีเพียง 1 หรือ 2 แถวเท่านั้น เริ่มต้นด้วยการสังเกตสองสามข้อ:

  • แถวที่มีการยืดเพียง 1 อันไม่ได้ช่วยไขปริศนาที่เชื่อมต่อกันเนื่องจากสามารถเลื่อนไปในทิศทางใดก็ได้โดยไม่เกิดการชน
  • หากแถวทั้งหมดที่มี 2 เหยียดมีคำสั่งเหมือนกันAและBปริศนาจะไม่เชื่อมประสานกันอย่างชัดเจน ในกรณีนี้Aเซลล์ทั้งหมดจะอยู่ด้านซ้ายของBเซลล์ทั้งหมดหรือในทางกลับกันและไม่มีการชนกันเมื่อเลื่อนทั้งสองชิ้นออกจากกัน

กรณีที่ยุ่งยากเท่านั้นจะเป็นปริศนาที่เรามีแถวที่มีลำดับที่แตกต่างกัน 2 อัน ฉันจะแสดงให้เห็นว่าปริศนาดังกล่าวไม่มีอยู่ภายใต้ข้อกำหนดที่กำหนด หากต้องการแสดงสิ่งนี้ให้ดูที่ตัวต่อบางส่วนที่มีการกำหนดค่านี้ซึ่ง.เป็นสัญลักษณ์แทน:

.......
AAABBBB
.......
BBAAAAA
.......

ตอนนี้สเปคบอกว่าทั้งสองAและBเซลล์มีการเชื่อมต่อในปริศนาที่ถูกต้องทั้งหมด ในการทำให้Aเซลล์เชื่อมต่อในปริศนาบางส่วนด้านบนเรามีสองตัวเลือก:

  1. เราวนรอบหนึ่งในBตัวอย่าง:

    ..AAAAAA
    AAABBBBA
    .......A
    BBAAAAAA
    ........
    

    ในการทำเช่นนี้เราหลีกเลี่ยงไม่ได้ที่จะขยายหนึ่งในแถวให้มี 3 แนวดังนั้นเราจะไม่ไขปริศนาที่ถูกต้องที่ทุกแถวมีแนวยืดได้ไม่เกิน 2 แถว

  2. เราเชื่อมต่อพวกเขาบนเส้นทางตรง:

    .......
    AAABBBB
    ..A....
    BBAAAAA
    .......
    

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

เมื่อต้องการนับการยืดการใช้งานใช้ตัวดำเนินการ CJam RLE

คำอธิบายของรหัส

qN/     Get input and split at newlines.
_z      Make a transposed copy.
]       Wrap the original and transposed puzzle in an array so that we can
        loop over the two.
{       Start of loop over original and transposed puzzle.
  :e`     Apply RLE to all rows.
  z,      Transpose the matrix with the RLE rows, and take the element count of the
          result. Or in other words, take the column count. This will be the length
          of the longest row after RLE.
  3<      Check the length for less than 3.
}/      End of loop over original and transposed puzzle.
|       Or the results of the two.

9

JavaScript (ES6), 108 107 98 91 82 ไบต์

a=>!(T=[],R=/AB+A|BA+B/).test([...a].map((c,i)=>T[i%-~a.search`
`]+=c))|!R.test(a)

การสาธิตสด ทดสอบใน Firefox รับอินพุตเป็นสตริงที่คั่นด้วยบรรทัดใหม่

การแก้ไข:

  • บันทึก 1 ไบต์โดยเปลี่ยน\nเป็นบรรทัดใหม่ตามตัวอักษร
  • บันทึก 9 ไบต์โดยทำการทดสอบ RegExp โดยตรงกับสตริงหลายบรรทัดแทนที่จะแปลงเป็นอาร์เรย์
  • กำจัดอีก 9 ไบต์โดยใช้ความเข้าใจของอาเรย์เพื่อแยกสตริงย้าย! เข้าสู่gฟังก์ชั่นและเรียก RegExp findโดยตรงบนอาร์เรย์แทนการใช้
  • ดำเนินการลำดับ arthmetic ต่อโดยบันทึกอีก 9 ไบต์ ทำโมดูลัสกับดัชนีแทนการแบ่งอาร์เรย์ด้วยการขึ้นบรรทัดใหม่ก่อนทำการแปลง

มันทำงานอย่างไร

รุ่นก่อนหน้า:

a=>(T=[],a.split`
`.map(s=>s.split``.map((c,i)=>T[i]+=c)),!T.find(g=s=>/AB+A|BA+B/.test(s)))|!g(a)
  1. รับอินพุตaและแบ่งตามบรรทัดใหม่เป็นอาร์เรย์ของสตริง
  2. ย้ายและเก็บไว้ในa Tใช้mapย้ำกว่าองค์ประกอบของแต่ละaแยกสตริงเป็นอาร์เรย์ตัวอักษรและใช้mapอีกครั้งเพื่อผนวกiตัวอักษร TH ในสายไปยังiสาย TH Tของ เนื่องจากองค์ประกอบแต่ละส่วนของTไม่ได้กำหนดค่าเริ่มต้นจึงจะมีลักษณะคล้าย"undefinedAAABBA"กัน แต่สิ่งนี้จะไม่สำคัญ
  3. สร้างฟังก์ชั่นการทดสอบนิพจน์ทั่วไปตามที่ตรงกับรูปแบบg /AB+A|BA+B/หากตรงกับชิ้นส่วนจะถูกล็อคในทิศทางที่กำหนดเพราะมีชุดของBแซนวิชระหว่างสองคนขึ้นไปAหรือในทางกลับกัน
  4. ใช้ฟังก์ชั่นการทดสอบgเพื่อทดสอบองค์ประกอบทั้งหมดของบล็อกaและ transpose ของการแข่งขันโดยใช้T findหากทั้งคู่ตรงกันดังนั้นชิ้นส่วนจะถูกล็อคในทั้งสองทิศทางดังนั้นส่งออกค่าเท็จหรือเป็นจริง

5

Javascript (ES6), 118

slidey=
// code
a=>!a.match(R=/AB+A|BA+B/)||!(a=a.split`
`.map(b=>b.split``))[0].map((_,c)=>a.map(d=>d[c])).some(e=>e.join``.match(R))

// IO
var S =document.getElementById('S');
S.onkeyup = _=> document.getElementById('P').innerText = slidey(S.value);

document.getElementById('P').innerText = slidey(S.value);
<textarea id='S'>BAAAAABB
BBAAABBB
BBBABBBB
BBBABBBB
BBBABBBB
BBBBBBBB
BBBBBBBB</textarea>
<p id='P'></p>

คำอธิบาย:

a=> !/* check string horizontally */ || !/* check string vertically by transposing it and
                                            running the same horizontal check */

a=> !a.match(R=/AB+A|BA+B/) || !/* ... */
// check for lines containing something like BAAAAAB or ABBBBBBBA
// this is the only way something can get blocked horizontally
// eg AAAAAAA
//    AAABAAA <<< note the B in the middle of As here
//    AAABBBB <<< blocked from being pulled out horizontally
//    AAAAAAA

a=> /* ... */ ||!( a = a.split('\n').map(b=> b.split('')) ) // split a into 2D array
    [0].map((_,c)=>a.map(d=>d[c])) // transpose it
    .some(e=>e.join``.match(R)) // run the check again using `some` to go line by line
                                // which is shorter than .join().match() outside

a=> !/* returns null if no horizontal obstacles and an array if there are */
    || !/* same thing */
// negate both to cast to a boolean (false if obstacles, true if not)
// an input can only be unslidable if both directions are blocked
// so (no obstacles vertically? || no obstacles horizontally?) gives the answer

หนู! เอาชนะฉันให้ได้
intrepidcoder

5

JavaScript (ES6) 72 74

แก้ไข 2 ไบต์ที่บันทึกไว้ขอบคุณ @NotthatCharles

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

ดังนั้นฉันจะตรวจสอบเพียงขั้นตอนเดียวในแต่ละทิศทาง

อักขระที่ใช้: 1 และ 0
2 ไบต์เพื่อใช้อักขระที่พิมพ์ได้ 2 ตัวเช่น A และ B

ทดสอบการเรียกใช้ตัวอย่างข้อมูลด้านล่างในเบราว์เซอร์ที่สอดคล้องกับ EcmaScript 6 (รองรับผู้ดำเนินการแพร่กระจาย - IE Firefox)

f=s=>[w=~s.search`
`,-w,-1,1].some(o=>![...s].some((x,p)=>x+s[p+o]==10))

// 4 bytes more- for any symbol, not just 1 and 0 (for instance A and B):
g=s=>[w=~s.search`
`,-w,-1,1].some(o=>![...s].some((x,p)=>x+s[p+o]=='AB'))

//TEST
console.log=x=>O.innerHTML+=x+'\n'

testOk = [
 '111\n100\n111',
 '10',
 '0\n1',
 '01\n01',
 '000\n111',
 '00001\n01111',
 '0110\n0110\n0000',
 '000000111111111\n001111111111111\n000000000011111\n001111111111111\n000000000000001',
 '000000000000\n010101010101\n111111111111',
 '10000011\n11000111\n11101111\n11101111\n11101111\n11111111\n11111111',
 '000\n100\n000'
]

testKo = [
 '1111\n1001\n1011',
 '1111\n1001\n0011',
 '1111111\n1111101\n0000001\n1111111',
 '1000\n1010\n1110\n0010\n0000',
 '0000000\n0111110\n0000010\n1111110',
 '10000011\n11000111\n11101111\n11101111\n11100111\n11111111\n11111111',
 '000\n010\n110\n010\n000'
]

console.log('Expecting true')
testOk.forEach(t=>console.log(t+'\n'+f(t)+'\n'))
console.log('Expecting false')
testKo.forEach(t=>console.log(t+'\n'+f(t)+'\n'))
<pre id=O></pre>


นั่นเป็นเพียงอัจฉริยะ แพ้อีกครั้งโดยมือโปร :-)
ETHproductions

s[p+o]=='0'ดูเหมือนจะยาวไปหน่อย มันสามารถถูกแทนที่ด้วย1-s[p+o]หรืออย่างน้อยs[p+o]==0?
ETHproductions

@ ETHproductions ใช่มันยาวมันคุ้มค่ากับการคิดมากกว่า มันจะต้องให้เท็จสำหรับ '\ n' (เส้นขอบแนวตั้ง, แปลงเป็น 0) และสำหรับไม่ได้กำหนด (ขอบบนและล่าง, แปลงเป็น NaN)
edc65

=='A'<'B'จะถูกแทนที่ด้วย เหมือนกัน=='B'
ไม่ใช่ว่า Charles

คุณทำx+s[p+o]=='AB'ไม่ได้เหรอ?
ไม่ใช่ว่า Charles

3

Mathematica 100 69 ไบต์

ด้วยขนาดใหญ่ 31 ไบต์ที่บันทึกไว้ต้องขอบคุณ @Martin Buttner

g=Max[Length/@Split/@#]<3&;g[c=Characters@StringSplit@#]||g@Thread@c&

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

{a,a,b,b,b} มีจดหมายจำนวน 2 ฉบับ

{a,a,b,a,a} มี 3 ตัวอักษรวิ่ง

{a,a,b,a,a,a,b,b,b,b,b,b,b,b} มีตัวอักษร 4 วิ่ง


2

Dyalog APL ขนาด 22 ไบต์

(∨/{∧/2>+/2≠/⍵}¨)⊂∘⍉,⊂

ลองที่นี่ นี่คือฟังก์ชั่นที่ใช้ในอาร์เรย์ของตัวละครแบบ 2D และส่งกลับ1สำหรับอินสแตนซ์เลื่อนและ0สำหรับคนที่ไม่เลื่อน อัลกอริทึมนั้นคล้ายกับคำตอบอื่น ๆ ส่วนใหญ่: ตรวจสอบเมทริกซ์และไขว้ที่ไม่มีแถวมีมากกว่าหนึ่งคู่ที่อยู่ติดกันของตัวอักษรที่แตกต่างกัน สำหรับอินพุตเมทริกซ์ 4x3

AAAA
ABBB
AAAB

สามารถเรียกใช้ฟังก์ชันเป็น

f ← (∨/{∧/2>+/2≠/⍵}¨)⊂∘⍉,⊂
f 4 3 ⍴ 'AAAAABBBAAAB'

1ซึ่งผลในการ

คำอธิบาย

⊂∘⍉,⊂   The matrix and its transpose.
{...}¨   For each of them:
  2≠/⍵   On each row, replace each adjacent pair with 1 if they differ, with 0 otherwise
  2>+/    Take the sum on each row and check that it's less than 2
  ∧/     AND over all rows
∨/      OR over the resulting two values

1

JavaScript (ES6), 94 ไบต์

x=>!(y=/AB+A|BA+B/).test(x)|(z=[],x.split`
`.map(b=>b.split``.map((c,i)=>z[i]+=c)),!y.test(z))

วิธีสำรองขนาดเดียวกัน:

x=>(t=s=>!/AB+A|BA+B/.test(s),z=[],x.split`
`.map(b=>b.split``.map((c,i)=>z[i]+=c)),t(x)|t(z))

สิ่งนี้จะส่งกลับ1สำหรับอินพุตที่เป็นความจริงและ0เป็นเท็จ ฉันเริ่มทำงานก่อนที่จะมีคำตอบอื่น ๆ ตอนแรกฉันก็ลองใช้ความเข้าใจในอาร์เรย์ของ ES7 แต่มันจบลงด้วยความยาวกว่า 10 chars กว่าวิธีนี้

ลองดูสิ:

a=x=>!(y=/AB+A|BA+B/).test(x)|(z=[],x.split`
`.map(b=>b.split``.map((c,i)=>z[i]+=c)),!y.test(z))

P.onclick=_=>Q.innerHTML='Result: '+a(O.value)
<textarea id=O cols="20" rows="8">AAAAAABBBBBBBBB
AABBBBBBBBBBBBB
AAAAAAAAAABBBBB
AABBBBBBBBBBBBB
AAAAAAAAAAAAAAB</textarea>
<button id=P>Test</button>
<p id=Q>Result: </p>

ยินดีต้อนรับข้อเสนอแนะ!


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