Posso fare a pezzi il puzzle?


38

Scrivi un programma o una funzione che includa una griglia rettangolare di testo in cui ogni cella è una Ao una a B. Tutte le Acelle formeranno una forma semplicemente connessa , cioè saranno tutte collegate ortogonalmente senza buchi (le lettere adiacenti in diagonale non contano come connesse). Allo stesso modo, tutte le Bcelle formeranno un'altra forma semplicemente connessa. La griglia conterrà sempre almeno uno Ae almeno uno B.

Immagina che la griglia sia in realtà due pezzi di plastica sottile a forma di blocco, rappresentati dalle porzioni Ae B. Se fosse collocato piatto su un tavolo, i due pezzi potrebbero essere fatti scivolare a parte mantenendo entrambi completamente piatti sul tavolo?

Stampa o restituisci un valore veritiero se due Ae Bforme potessero essere separate in questo modo semplicemente separandole. In caso contrario, stampare o restituire un valore errato .

Ad esempio, l'input

AAA
ABB
AAA

è vero perché la BBsezione può essere fatta scorrere verso destra, separandola da quella Adi:

AAA
A    BB
AAA

Tuttavia, l'input

AAAA
ABBA
ABAA

è falso perché non c'è modo di far scorrere le parti Ae Bsenza farle sovrapporre.

Vince il codice più breve in byte. Se lo si desidera, è possibile utilizzare due caratteri ASCII stampabili distinti al posto di Ae B.

Esempi di verità (separati da righe vuote)

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

Esempi falsi

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

Risposte:


9

Lumache, 14

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

Se il puzzle può essere diviso, stampa l'area dell'input. Altrimenti, stampa 0.

È un po 'lento per gli esempi più grandi, poiché richiede tempo fattoriale nell'area della griglia.

         ,, 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
"È un po 'lento .." . Non sono sicuro di cosa ti aspettassi da una lingua chiamata Snails ...
Bassdrop Cumberwubwubwub

4
@Bas Ora, nessun motivo per strofinare il sale nelle ferite.
Trasiva,

21

CJam, 33 32 20 19 17 byte

Versione rivista, con il massiccio supporto di @ Sp3000 e @ MartinBüttner:

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

Provalo online

contributi

  • @ Sp3000 ha suggerito una semplificazione fondamentale per il mio algoritmo originale.
  • @ MartinBüttner ha applicato le sue pazze abilità di golf all'approccio rivisto, che quasi sicuramente ha prodotto un codice più breve di quello che avrei escogitato anche dopo aver considerato la semplificazione.

Algoritmo e prova

Di seguito vengono spiegati i criteri per il puzzle che si separa orizzontalmente. Il caso verticale può essere determinato guardando le colonne anziché le righe, oppure trasponendo la matrice di caratteri e guardando di nuovo le righe.

Userò il termine "tratto" per una sequenza massima delle stesse lettere. Ad esempio, le seguenti righe hanno rispettivamente 1, 2 e 3 allungamenti:

AAAAAAAA
BBBAAAAA
AABBBAAA

Userò anche il termine "interbloccato" per una riga / puzzle che non può separarsi.

L'osservazione chiave è che il puzzle può scivolare via se e solo se tutte le file hanno al massimo 2 tratti . O invertito, è bloccato se e solo se c'è una fila con più di 2 tratti .

Quanto segue potrebbe non qualificarsi come una rigorosa dimostrazione matematica, ma credo che sia una spiegazione convincente del perché questo debba essere il caso.

È facile vedere che il puzzle è interbloccato se ha file di più di 2 tratti. Guardando una fila con 3 tratti:

BBBAAB

è chiaro che impedisce al puzzle di scivolare via perché il Atratto è bloccato tra i Btratti. Ciò significa che la riga è interbloccata, il che a sua volta rende l'intero puzzle bloccato.

La direzione opposta della dimostrazione non è così ovvia. Dobbiamo dimostrare che non ci sono puzzle interbloccati in cui tutte le file hanno solo 1 o 2 allungamenti. A partire da un paio di osservazioni:

  • Le righe con solo 1 tratto non contribuiscono al blocco di un puzzle, poiché possono scorrere in entrambe le direzioni senza collisioni.
  • Se tutte le righe con 2 tratti hanno lo stesso ordine di Ae B, il puzzle non è chiaramente bloccato. In questo caso, tutte le Acelle rimangono a sinistra di tutte le Bcelle, o viceversa, e non vi sono collisioni quando si separano i due pezzi.

L'unico caso complicato sarebbero i puzzle in cui abbiamo file con 2 tratti di ordine diverso. Mostrerò che tali puzzle non esistono nelle specifiche indicate. Per mostrarlo, diamo un'occhiata a un puzzle parziale che ha questa configurazione, dove .sono i caratteri jolly:

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

Ora, la specifica dice che sia il Ae Ble cellule sono semplicemente collegati in tutti i puzzle valide. Per rendere le Acelle collegate nel puzzle parziale sopra, abbiamo due opzioni:

  1. Facciamo un giro attorno ad uno dei tratti di B, ad esempio:

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

    Per fare questo, inevitabilmente estendiamo una delle file per avere 3 allungamenti, quindi questo non ci darà mai un puzzle valido in cui tutte le file hanno al massimo 2 allungamenti.

  2. Li colleghiamo su un percorso diretto:

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

    Le Acelle ora sono semplicemente collegate e non ci sono ancora righe con più di 2 tratti. Tuttavia, anche le Bcelle devono essere semplicemente collegate. Il percorso diretto è ora bloccato dalle Acelle collegate e l'unico modo per connettere le Bcelle è di fare un giro attorno a uno dei tratti di Acelle. Questo porta al caso 1, dove non possiamo farlo senza creare file di 3 tratti.

Per contare i tratti, l'implementazione utilizza l'operatore CJam RLE.

Spiegazione del codice

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)

Demo dal vivo . Testato su Firefox. Accetta l'input come stringa delimitata da nuova riga.

modifiche:

  • Salvato 1 byte passando \na una nuova riga letterale.
  • Salvato 9 byte eseguendo il test RegExp direttamente sulla stringa multilinea invece di convertirla in un array.
  • Eliminati altri 9 byte usando la comprensione dell'array per dividere la stringa, spostandosi! in gfunzione e chiamando RegExp direttamente sull'array invece di utilizzare find.
  • Continua la sequenza artmetica salvando altri 9 byte. Ha fatto un modulo sull'indice invece di dividere l'array per newline prima di prendere la trasposizione.

Come funziona

Versione precedente:

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. Prendi l'input ae dividerlo per newline in una matrice di stringhe.
  2. Traspone ae archivia T. Utilizzare mapper scorrere su ogni elemento di a, dividere la stringa in una matrice di caratteri e utilizzare mapnuovamente per aggiungere il icarattere th nella riga alla iriga th di T. Poiché ogni elemento di Tnon è inizializzato, finirà per assomigliare a qualcosa del genere "undefinedAAABBA", ma questo non importa.
  3. Creare una funzione di test basata su RegExp gche corrisponda al modello /AB+A|BA+B/. Se corrisponde, i pezzi vengono bloccati nella direzione data perché poi ci sono un set di Bs tra due o più As o viceversa.
  4. Utilizzare la funzione gdi test per testare tutti gli elementi del blocco ae la sua trasposizione Tper una corrispondenza utilizzando find. Se entrambi corrispondono, i pezzi sono bloccati in entrambe le direzioni, quindi emetti un valore falso, altrimenti veritiero.

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>

Spiegazione:

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

Ratti! Battimi.
intrepidcoder

5

JavaScript (ES6) 72 74

Modifica 2 byte salvati grazie a @NotthatCharles

Ho la comprensione intuitiva che se un pezzo può scorrere solo una frazione del passo, allora è gratuito. Gli attuali casi di test lo confermano.

Quindi controllo solo un passo in ogni direzione.

Caratteri utilizzati: 1 e 0
2 byte in più per utilizzare 2 caratteri stampabili come A e B.

Prova a eseguire lo snippet di seguito in un browser conforme a EcmaScript 6 (che supporta l'operatore di diffusione - 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>


Bene, questo è solo geniale. Picchiato di nuovo da un professionista. :-)
ETHproductions

s[p+o]=='0'sembra un po 'lungo. Potrebbe essere sostituito con 1-s[p+o], o almeno s[p+o]==0?
ETHproductions

@ETHproductions sì, è lungo, vale la pena pensarci ancora. Deve dare false per '\ n' (bordo verticale, converte in 0) e per indefinito (bordo superiore e inferiore, converte in NaN)
edc65

=='A'può essere sostituito da <'B'. Lo stesso per=='B'
Non che Charles

Inoltre, non puoi semplicemente farlo x+s[p+o]=='AB'?
Non che Charles il

3

Mathematica 100 69 byte

Con un enorme risparmio di 31 byte, grazie a @Martin Buttner,

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

Formatta l'input come una matrice di caratteri; effettua anche una trasposizione della matrice. Se la matrice o la sua trasposizione non hanno più di 2 corse per riga, il puzzle è in grado di scorrere.

{a,a,b,b,b} ha 2 serie di lettere.

{a,a,b,a,a} ha 3 serie di lettere.

{a,a,b,a,a,a,b,b,b,b,b,b,b,b} ha 4 serie di lettere.


2

Dyalog APL, 22 byte

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

Provalo qui. Questa è una funzione che accetta una matrice 2D di caratteri e ritorna 1per istanze scorrevoli e 0per quelle non scorrevoli. L'algoritmo è simile alla maggior parte delle altre risposte: controlla la matrice e la sua trasposizione che nessuna riga contiene più di una coppia adiacente di lettere diverse. Per la matrice di input 4x3

AAAA
ABBB
AAAB

la funzione può essere invocata come

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

che risulta in 1.

Spiegazione

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

Metodo alternativo della stessa dimensione:

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

Questo ritorna 1per un input veritiero e 0per un falso. Ho iniziato a lavorare su questo prima che fossero state pubblicate altre risposte. Inizialmente ho anche provato a utilizzare la comprensione dell'array di ES7, ma alla fine questo metodo è durato circa 10 caratteri.

Provalo:

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>

Suggerimenti benvenuti!


L'uso di [... b] invece di b.split`` consente di risparmiare 3 byte, ma funziona solo in alcuni browser.
intrepidcoder
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.