Puis-je glisser en dehors du puzzle?


38

Ecrivez un programme ou une fonction qui prend une grille de texte rectangulaire dans laquelle chaque cellule est un Aou B. Toutes les Acellules formeront une forme simplement connectée , c'est-à-dire qu'elles seront toutes orthogonalement connectées sans trous (les lettres voisines en diagonale ne comptent pas comme connectées). De même, toutes les Bcellules formeront une autre forme simplement connectée. La grille contiendra toujours au moins un Aet au moins un B.

Imaginez que la grille est en réalité constituée de deux morceaux de plastique mince en forme de bloc, représentés par les parties Aet B. S'il était placé à plat sur une table, les deux pièces pourraient-elles être écartées tout en les maintenant complètement à plat sur la table?

Imprimer ou renvoyer une valeur de vérité si les deux AetB formes formes peuvent être séparées comme ceci en les séparant simplement. Sinon, imprimez ou renvoyez une valeur de fausseté .

Par exemple, l'entrée

AAA
ABB
AAA

est vrai parce que la BBsection peut être glissée vers la droite, en la séparant de celle de A:

AAA
A    BB
AAA

Cependant, l'entrée

AAAA
ABBA
ABAA

est faux car il n’ya aucun moyen de faire glisser les parties Aet Bsans les faire se chevaucher.

Le code le plus court en octets gagne. Si vous le souhaitez, vous pouvez utiliser deux caractères ASCII imprimables à la place de Aet B.

Exemples de vérité (séparés par des lignes vides)

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

Exemples de fausseté

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

Réponses:


9

Escargots, 14

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

Si le puzzle peut être séparé, il affiche la zone de saisie. Sinon, il affiche 0.

C'est un peu lent pour les grands exemples, car cela prend du temps dans le secteur de la grille.

         ,, 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
"C'est un peu lent ..." . Vous ne savez pas ce que vous
attendiez

4
@Bas Maintenant maintenant, aucune raison de frotter le sel dans les plaies.
Trasiva

21

CJam, 33 32 20 19 17 octets

Version révisée, avec le support massif de @ Sp3000 et @ MartinBüttner:

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

Essayez-le en ligne

Contributions

  • @ Sp3000 a suggéré une simplification critique de mon algorithme d'origine.
  • @ MartinBüttner a appliqué ses compétences de golfeur fou à l'approche révisée, ce qui a certainement abouti à un code plus court que celui que j'aurais proposé même après avoir envisagé la simplification.

Algorithme et Preuve

Ce qui suit explique les critères pour le puzzle se séparant horizontalement. Le cas vertical peut être déterminé en regardant les colonnes au lieu de lignes, ou en transposant la matrice de caractères et en regardant à nouveau les lignes.

Je vais utiliser le terme "stretch" pour une séquence maximale des mêmes lettres. Par exemple, les lignes suivantes ont respectivement 1, 2 et 3 tronçons:

AAAAAAAA
BBBAAAAA
AABBBAAA

Je vais aussi utiliser le terme "imbriqué" pour une ligne / puzzle qui ne peut pas se séparer.

L'observation clé est que le puzzle peut se séparer si et seulement si toutes les lignes ont au plus 2 étendues . Ou inversé, il est imbriqué si et seulement s'il y a une ligne avec plus de 2 tronçons .

Ce qui suit n’est peut-être pas considéré comme une preuve mathématique stricte, mais j’estime que cela fournit une explication convaincante de la nécessité de cela.

Il est facile de voir que le puzzle est imbriqué s’il a des rangées de plus de 2 tronçons. En regardant une rangée avec 3 étendues:

BBBAAB

il est clair que cela empêche le puzzle de se séparer car l' Aétirement est bloqué entre les Bétirements. Cela signifie que la ligne est imbriquée, ce qui rend le puzzle entier imbriqué.

Le sens opposé de la preuve n’est pas aussi évident. Nous devons montrer qu’il n’existe pas de casse-tête entremêlés dans lesquels toutes les lignes ne comportent qu’un ou deux tronçons. À partir de quelques observations:

  • Les rangées avec un seul étirement ne contribuent pas à l'enchevêtrement des puzzles, car elles peuvent glisser dans les deux sens sans collision.
  • Si toutes les lignes avec 2 étendues ont le même ordre de Aet B, le puzzle n'est clairement pas emboîté. Dans ce cas, toutes les Acellules sont laissées de toutes les Bcellules, ou inversement, et il n'y a pas de collision lors du glissement des deux pièces.

Le seul cas délicat serait des énigmes où nous avons des rangées avec 2 tronçons d’ordre différent. Je vais montrer que de tels casse - tête n'existent pas dans les spécifications données. Pour montrer cela, regardons un puzzle partiel qui a cette configuration, où .sont des caractères génériques:

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

Maintenant, la spécification indique que les cellules Aet Bsont simplement connectées dans tous les casse-têtes valides. Pour rendre les Acellules connectées dans le puzzle partiel ci-dessus, nous avons deux options:

  1. Nous passons en boucle sur l’un des tronçons de B, par exemple:

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

    Pour ce faire, nous étendons inévitablement l’une des rangées afin d’avoir 3 étendues. Cela ne nous donnera donc jamais un puzzle valide dans lequel toutes les lignes ont au plus 2 étendues.

  2. Nous les connectons sur un chemin direct:

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

    Les Acellules sont maintenant simplement connectées et il n'y a toujours pas de lignes de plus de 2 étendues. Cependant, les Bcellules doivent également être simplement connectées. Le chemin direct est maintenant bloqué par les Acellules connectées et le seul moyen de connecter les Bcellules consiste à effectuer une boucle autour de l'un des segments de Acellules. Cela nous ramène au cas 1, où nous ne pouvons pas faire cela sans créer des rangées de 3 étendues.

Pour compter les tronçons, l'implémentation utilise l'opérateur CJam RLE.

Explication du code

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 octets

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

Démo en direct . Testé dans Firefox. Prend l'entrée en tant que chaîne délimitée par une ligne.

Modifications:

  • Sauvé 1 octet en changeant \npour un saut de ligne littéral.
  • 9 octets enregistrés en effectuant le test RegExp directement sur la chaîne multiligne au lieu de les convertir en tableau.
  • Éliminé encore 9 octets en utilisant des compréhensions de tableaux pour diviser une chaîne, en mouvement! en gfonction et en appelant RegExp directement sur tableau au lieu d'utiliser find.
  • Continué la séquence arthmétique en sauvegardant 9 octets supplémentaires. Est-ce qu'un module sur l'index au lieu de diviser le tableau par newline avant de prendre la transposition.

Comment ça marche

La version précédente:

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. Prenez l’entrée aet scindez-la par des lignes nouvelles en un tableau de chaînes.
  2. Transposer aet stocker dans T. Utilisez cette mapoption pour parcourir chaque élément de a, diviser la chaîne en un tableau de caractères et utiliser à mapnouveau pour ajouter le ie caractère de la ligne à la ie ligne de T. Étant donné que chaque élément de Tn'est pas initialisé, il ressemblera à quelque chose "undefinedAAABBA", mais cela n'aura pas d'importance.
  3. Créez une fonction de test basée sur RegExp gqui correspond au modèle /AB+A|BA+B/. Si cela correspond, les pièces sont verrouillées dans la direction indiquée, car un ensemble de Bs est alors pris en sandwich entre deux ou plus, Aou inversement.
  4. Utilisez la fonction gde test pour tester tous les éléments du bloc aet sa transposition Tpour une correspondance à l'aide de find. Si les deux correspondent, alors les pièces sont verrouillées dans les deux directions, donc une valeur de fausseté, sinon une valeur de vérité.

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>

Explication:

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

Les rats! Me battre à elle.
Intrepidcoder

5

JavaScript (ES6) 72 74

Éditez 2 octets enregistrés thx @NotthatCharles

J'ai la compréhension intuitive que si un morceau peut glisser seulement une fraction de pas, alors c'est gratuit. Les cas de test actuels le confirment.

Je vérifie donc juste un pas dans chaque direction.

Caractères utilisés: 1 et 0
2 octets en plus pour utiliser 2 caractères imprimables comme A et B

Testez l'exécution de l'extrait de code ci-dessous dans un navigateur compatible EcmaScript 6 (prenant en charge l'opérateur de diffusion - 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>


Eh bien, c'est juste du génie. Battu à nouveau par un pro. :-)
ETHproductions

s[p+o]=='0'semble un peu long. Pourrait-il être remplacé par 1-s[p+o], ou du moins s[p+o]==0?
ETHproductions

@ETHproductions Oui, c'est long, cela vaut la peine de réfléchir davantage. Il doit donner false pour '\ n' (bordure verticale, converti en 0) et pour undefined (bordure supérieure et inférieure, converti en NaN)
edc65

=='A'peut être remplacé par <'B'. Pareil pour=='B'
Pas que Charles

Aussi, tu ne peux pas faire juste x+s[p+o]=='AB'?
Pas que Charles

3

Mathematica 100 69 octets

Avec une sauvegarde massive de 31 octets, grâce à @Martin Buttner,

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

Met en forme l'entrée sous forme de matrice de caractères; il fait également une transposition de la matrice. Si la matrice ou sa transposition ne comporte pas plus de 2 analyses par ligne, le puzzle peut alors glisser.

{a,a,b,b,b} a 2 séries de lettres.

{a,a,b,a,a} a 3 courses de lettres.

{a,a,b,a,a,a,b,b,b,b,b,b,b,b} a 4 séries de lettres.


2

Dyalog APL, 22 octets

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

Essayez ici. C'est une fonction qui prend un tableau 2D de caractères, et retourne 1pour les occurrences glissantes et 0pour les non glissantes. L'algorithme est similaire à la plupart des autres réponses: vérifiez la matrice et sa transposition pour qu'aucune ligne ne contienne plus d'une paire adjacente de lettres différentes. Pour la matrice de saisie 4x3

AAAA
ABBB
AAAB

la fonction peut être appelée en tant que

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

qui se traduit par 1 .

Explication

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

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

Méthode alternative de même taille:

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

This returns 1 for a truthy input and 0 for falsy. I started work on this before any other answers had been posted. I also originally tried using ES7's array comprehensions, but that ended up about 10 chars longer than this method.

Try it out:

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>

Suggestions welcome!


Using [...b] instead of b.split`` saves 3 bytes, but only works in some browsers.
intrepidcoder
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.