Kann ich das Puzzle auseinander schieben?


38

Schreiben Sie ein Programm oder eine Funktion, die ein rechteckiges Textraster enthält, in dem jede Zelle entweder eine Aoder eine ist B. Alle die AZellen eine Form einfach zusammenhängende Form, dh sie werden alle orthogonal werden verbunden ohne Löcher (diagonal benachbarten Buchstaben zählen nicht als angeschlossen). Ebenso bilden alle BZellen eine andere einfach verbundene Form. Das Gitter enthält immer mindestens eins Aund mindestens eins B.

Stellen Sie sich vor, das Gitter besteht aus zwei quaderförmigen Teilen aus dünnem Kunststoff, die durch die Abschnitte Aund dargestellt werden B. Wenn es flach auf einen Tisch gelegt würde, könnten die beiden Teile auseinander geschoben werden, während beide vollständig flach auf dem Tisch bleiben?

Drucken oder einen Rück truthy Wert , wenn die beiden Aund BFormen wie diese getrennt werden konnten , indem sie einfach auseinanderziehen. Wenn nicht, drucken Sie einen falschen Wert oder geben Sie ihn zurück .

Zum Beispiel die Eingabe

AAA
ABB
AAA

ist wahr, weil der BBAbschnitt nach rechts verschoben werden kann, indem er von den folgenden getrennt wird A:

AAA
A    BB
AAA

Allerdings ist die Eingabe

AAAA
ABBA
ABAA

ist falsch, weil es keine Möglichkeit gibt, die Aund BTeile auseinander zu schieben, ohne dass sie sich überlappen.

Der kürzeste Code in Bytes gewinnt. Falls gewünscht, können Sie anstelle von und zwei beliebige druckbare ASCII- Zeichen verwenden .AB

Wahrheitsbeispiele (durch Leerzeilen getrennt)

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

Falsche Beispiele

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

Antworten:


9

Schnecken, 14

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

Wenn das Puzzle auseinander geschoben werden kann, wird der Bereich der Eingabe gedruckt. Andernfalls wird 0 ausgegeben.

Bei den größeren Beispielen ist es etwas langsam, da es im Bereich des Gitters Zeitfaktoriell erfordert.

         ,, 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
"Es ist ein bisschen langsam ..." . Nicht sicher, was Sie von einer Sprache namens Schnecken erwartet ...
Bassdrop Cumberwubwubwub

4
@Bas Nun, jetzt kein Grund, Salz in die Wunden zu reiben.
Trasiva

21

CJam, 33 32 20 19 17 Bytes

Überarbeitete Version, mit massiver Unterstützung von @ Sp3000 und @ MartinBüttner:

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

Probieren Sie es online aus

Beiträge

  • @ Sp3000 schlug eine kritische Vereinfachung meines ursprünglichen Algorithmus vor.
  • @ MartinBüttner hat seine verrückten Golffähigkeiten auf die überarbeitete Herangehensweise angewendet, was mit ziemlicher Sicherheit zu einem kürzeren Code führte, als ich es mir trotz Vereinfachung ausgedacht hätte.

Algorithmus und Beweis

Im Folgenden werden die Kriterien für das horizontale Auseinandergleiten des Puzzles erläutert. Der vertikale Fall kann durch Betrachten von Spalten anstelle von Zeilen oder durch Transponieren der Zeichenmatrix und erneutes Betrachten der Zeilen bestimmt werden.

Ich werde den Begriff "Strecken" für eine maximale Folge der gleichen Buchstaben verwenden. Beispielsweise haben die folgenden Zeilen 1, 2 und 3 Abschnitte:

AAAAAAAA
BBBAAAAA
AABBBAAA

Ich werde den Begriff "Interlocked" auch für eine Reihe / ein Puzzle verwenden, die / das nicht auseinander rutschen kann.

Die Schlüsselbeobachtung ist, dass das Puzzle nur dann auseinander rutschen kann, wenn alle Reihen höchstens 2 Strecken haben . Oder umgekehrt, es ist nur dann verriegelt, wenn es eine Reihe mit mehr als 2 Abschnitten gibt .

Das Folgende könnte nicht als strenger mathematischer Beweis gelten, aber ich glaube, dass es eine überzeugende Erklärung dafür liefert, warum dies der Fall sein muss.

Es ist leicht zu erkennen, dass das Puzzle verriegelt ist, wenn es Reihen mit mehr als 2 Abschnitten enthält. Eine Reihe mit 3 Strecken betrachten:

BBBAAB

es ist klar, dass es verhindert, dass das Puzzle auseinander rutscht, da die AStrecke zwischen den BStrecken gesperrt ist . Dies bedeutet, dass die Reihe ineinander greift, wodurch das gesamte Puzzle ineinander greift.

Die Gegenrichtung des Beweises ist nicht ganz so offensichtlich. Wir müssen zeigen, dass es keine ineinandergreifenden Rätsel gibt, bei denen alle Reihen nur 1 oder 2 Strecken haben. Beginnen wir mit ein paar Beobachtungen:

  • Reihen mit nur 1 Dehnung tragen nicht zum Ineinandergreifen eines Puzzles bei, da sie ohne Kollisionen in beide Richtungen gleiten können.
  • Wenn alle Reihen mit 2 Abschnitten die gleiche Reihenfolge von Aund haben B, ist das Rätsel eindeutig nicht miteinander verzahnt. In diesem Fall Ableiben alle BZellen von allen Zellen übrig oder umgekehrt, und es kommt zu keinen Kollisionen, wenn die beiden Teile auseinander geschoben werden.

Der einzige schwierige Fall wären Rätsel, bei denen wir Reihen mit 2 Abschnitten unterschiedlicher Reihenfolge haben. Ich werde zeigen, dass solche Rätsel unter den angegebenen Spezifikationen nicht existieren . Um dies zu zeigen, schauen wir uns ein Teilpuzzlespiel mit dieser Konfiguration an, in dem .sich Platzhalter befinden:

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

Nun, sagt die Spezifikation , dass sowohl die Aund BZellen sind einfach in allen gültigen Puzzles verbunden. Um die AZellen im obigen Teilrätsel zu verbinden, haben wir zwei Möglichkeiten:

  1. Wir umrunden einen der folgenden Abschnitte B:

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

    Um dies zu tun, erweitern wir unvermeidlich eine der Reihen auf 3 Strecken, so dass wir niemals ein gültiges Rätsel erhalten, bei dem alle Reihen höchstens 2 Strecken haben.

  2. Wir verbinden sie auf direktem Weg:

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

    Die AZellen sind jetzt einfach verbunden und es gibt noch keine Zeilen mit mehr als 2 Abschnitten. Die BZellen müssen jedoch auch einfach verbunden werden. Der direkte Pfad wird jetzt von den verbundenen AZellen blockiert , und die einzige Möglichkeit, die BZellen zu verbinden , besteht darin, eine der Zellabschnitte in einer Schleife zu Adurchlaufen. Dies führt zu Fall 1 zurück, in dem wir dies nicht tun können, ohne Zeilen mit 3 Abschnitten zu erstellen.

Zum Zählen der Strecken verwendet die Implementierung den CJam-RLE-Operator.

Erklärung des Codes

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 Byte

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

Live-Demo . Getestet in Firefox. Übernimmt die Eingabe als durch Zeilenumbrüche getrennte Zeichenfolge.

Bearbeitungen:

  • 1 Byte gespart, indem \nzu einer wörtlichen Newline gewechselt wird.
  • Durch Ausführen des RegExp-Tests direkt in der mehrzeiligen Zeichenfolge wurden 9 Byte gespart, anstatt in ein Array zu konvertieren.
  • Eliminiert weitere 9 Bytes durch Array-Verständnis zum Teilen von Strings, Verschieben! in gFunktion und RegExp direkt auf dem Array aufrufen, anstatt zu verwenden find.
  • Fortsetzung der arthmetischen Sequenz durch Speichern weiterer 9 Bytes. Habe einen Modul auf dem Index, anstatt das Array durch Zeilenumbrüche zu teilen, bevor die Transponierung durchgeführt wurde.

Wie es funktioniert

Vorherige Version:

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. Nehmen Sie die Eingabe aund teilen Sie sie durch Zeilenumbrüche in eine Reihe von Zeichenfolgen auf.
  2. Transponieren Sie aund speichern Sie es in T. Verwenden Sie map, um über jedes Element von zu iterieren a, die Zeichenfolge in ein Zeichenarray aufzuteilen und maperneut, um das ith-Zeichen in der Zeile an die ith-Zeile von anzuhängen T. Da jedes Element von Tnicht initialisiert ist, sieht es am Ende so aus "undefinedAAABBA", aber das spielt keine Rolle.
  3. Erstellen Sie eine RegExp-basierte Testfunktion g, die dem Muster entspricht /AB+A|BA+B/. Wenn es passt, sind die Teile in der angegebenen Richtung verriegelt, weil dann ein Satz von Bs zwischen zwei oder mehr As liegt oder umgekehrt.
  4. Verwenden Sie die gTestfunktion, um alle Elemente des Blocks aund seine Transponierung Tauf eine Übereinstimmung mit zu testen find. Stimmen beide überein, sind die Teile in beide Richtungen verriegelt. Geben Sie daher einen falschen Wert aus, andernfalls einen wahren.

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>

Erläuterung:

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

Ratten! Schlagen Sie mich zu.
intrepidcoder

5

JavaScript (ES6) 72 74

Bearbeiten Sie 2 Bytes, die dank @NotthatCharles gespeichert wurden

Ich habe das intuitive Verständnis, dass ein Teil, wenn es nur einen Bruchteil einer Stufe gleiten kann, kostenlos ist. Die aktuellen Testfälle bestätigen dies.

Also überprüfe ich nur einen Schritt in jede Richtung.

Verwendete Zeichen: 1 und 0
2 Byte mehr, um 2 beliebige druckbare Zeichen wie A und B zu verwenden

Testen Sie das unten stehende Snippet in einem EcmaScript 6-kompatiblen Browser (unterstützt den Spread-Operator - 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>


Nun, das ist einfach genial. Von einem Profi erneut geschlagen. :-)
ETHproductions

s[p+o]=='0'scheint ein bisschen lang zu sein. Könnte es ersetzt werden durch 1-s[p+o]oder zumindest s[p+o]==0?
ETHproductions

@ETHproductions ja, es ist lang, es lohnt sich noch etwas nachzudenken. Es muss false für '\ n' (vertikaler Rand, konvertiert zu 0) und für undefined (oberer und unterer Rand, konvertiert zu NaN) geben
edc65 14.10.15

=='A'kann durch ersetzt werden <'B'. Gleiches gilt für=='B'
Nicht dass Charles

Kannst du es auch nicht einfach tun x+s[p+o]=='AB'?
Nicht dass Charles

3

Mathematica 100 69 Bytes

Dank @Martin Buttner konnten 31 Bytes eingespart werden.

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

Formatiert die Eingabe als Zeichenmatrix. Es macht auch eine Transponierung der Matrix. Wenn entweder die Matrix oder ihre Transponierte nicht mehr als 2 Läufe pro Reihe hat, kann das Rätsel verschoben werden.

{a,a,b,b,b} hat 2 Buchstabenreihen.

{a,a,b,a,a} hat 3 Buchstabenreihen.

{a,a,b,a,a,a,b,b,b,b,b,b,b,b} hat 4 Buchstabenreihen.


2

Dyalog APL, 22 Bytes

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

Probieren Sie es hier aus. Dies ist eine Funktion, die ein 2D-Array von Zeichen aufnimmt und 1für gleitende und 0für nicht gleitende Instanzen zurückgibt . Der Algorithmus ähnelt den meisten anderen Antworten: Prüfen Sie, ob die Matrix und ihre Transponierung mehr als ein benachbartes Paar verschiedener Buchstaben enthält. Für die 4x3 Eingangsmatrix

AAAA
ABBB
AAAB

Die Funktion kann aufgerufen werden als

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

was ergibt 1.

Erläuterung

⊂∘⍉,⊂   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 Byte

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

Alternative Methode gleicher Größe:

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))

Dies kehrt 1für eine wahrheitsgemäße Eingabe und 0für falsch zurück. Ich habe damit begonnen, bevor irgendwelche anderen Antworten veröffentlicht wurden. Ursprünglich habe ich auch versucht, das Array-Verständnis von ES7 zu verwenden, aber das Ergebnis war ungefähr 10 Zeichen länger als diese Methode.

Versuch es:

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>

Vorschläge willkommen!


Die Verwendung von [... b] anstelle von b.split`` spart 3 Bytes, funktioniert jedoch nur in einigen Browsern.
intrepidcoder
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.