Detecção de retângulo

21

Escreva um programa ou função que utilize uma sequência de linhas múltiplas de 0's 1' e 's. Nenhum outro caractere estará na string e a string sempre será retangular (todas as linhas terão o mesmo número de caracteres), com dimensões tão pequenas quanto 1 × 1, mas, caso contrário, os 0's 1' e 's podem ser organizados arbitrariamente.

Você pode assumir que a string possui uma nova linha à direita opcional e, se desejar, pode usar dois caracteres ASCII imprimíveis distintos no lugar de 0e 1.

Imprima ou retorne um valor verdadeiro se todas as regiões conectadas ao caminho de 0's 1' e 's na cadeia de caracteres forem retângulos sólidos , caso contrário, produz um valor falso .

Um caminho conectado à região de 0significa que, de qualquer um 0na região, todos os outros 0podem ser alcançados movendo-se para cima, para baixo, esquerda e direita para os outros 0(e não se movendo na diagonal, não se movendo para nenhum 1, e não se movendo fora dos limites de cordas). A mesma idéia se aplica ao 1caminho de regiões conectadas.

Um retângulo sólido de 0's significa que toda a área do retângulo é preenchida com 0' e 1' não '. A mesma idéia se aplica a 1retângulos sólidos.

O código mais curto em bytes vence. O desempatador é a resposta anterior.

(Observe que a corda não se enrola com as condições de contorno toroidais .)

Exemplos

1) Esta sequência de entrada possui 3 regiões conectadas ao caminho (2 para 0e 1 para 1). Apenas a 00região inferior direita é um retângulo sólido, portanto a saída seria falsa.

0011
0111
0100

2) Esta sequência de entrada possui 4 regiões conectadas ao caminho (2 para ambos 0e 1). Todos eles são retângulos sólidos, portanto a saída seria verdadeira.

0011
0011
1100

3) Esta entrada possui 2 regiões conectadas ao caminho, mas apenas uma delas é um retângulo sólido, portanto a saída seria falsa.

00000000
01111110
00000000

4) Esta entrada possui apenas 1 região conectada ao caminho e é trivialmente um retângulo sólido, portanto a saída é verdadeira.

11111111
11111111
11111111

Casos de teste

Um Tlogo abaixo da string de entrada Fsignifica verdade , significa falsidade.

0
T

1
T

00
T

01
T

10
T

11
T

0000000
T

1111111
T

011100100100101100110100100100101010100011100101
T

00
11
T

01
10
T

01
11
F

00
01
F

11
11
T

110
100
F

111
000
T

111
101
111
F

101
010
101
T

1101
0010
1101
0010
T

1101
0010
1111
0010
F

0011
0111
0100
F

0011
0011
1100
T

00000000
01111110
00000000
F

11111111
11111111
11111111
T

0000001111
0000001111
T

0000001111
0000011111
F

0000001111
1000001111
F

1000001111
1000001111
T

1110100110101010110100010111011101000101111
1010100100101010100100010101010101100101000
1110100110010010110101010111010101010101011
1010100100101010010101010110010101001101001
1010110110101010110111110101011101000101111
F
Passatempos de Calvin
fonte

Respostas:

5

Geléia , 7 bytes

ṣ⁷µ=ḢZE

Isso usa o mesmo algoritmo da resposta Ruby do @ LevelRiverSt . O algoritmo real se encaixa nos últimos 4 bytes; os 3 primeiros bytes são necessários para analisar o formato de entrada.

Experimente online!

Como funciona

ṣ⁷µ=ḢZE  Main link. Argument: t (string)

ṣ⁷       Split t at linefeeds..
  µ      Begin a new, monadic link. Argument: A (list of strings)
    Ḣ    Pop the first string of A.
   =     Compare all other strings in A with the first.
         = compares characters, so this yields a list of Booleans for each string.
         For a truthy input, all pairs of lines now have been transformed in lists
         of only 1's or only 0's. That means all columns must be equal.
     Z   Zip; transpose rows with columns.
      E  Check if all rows (former columns) are equal to each other.
Dennis
fonte
16

Geléia , 11 10 bytes

ṣ⁷^2\⁺€FS¬

Agradeço imensamente ao @Dennis por jogar este até a metade do seu tamanho original (através de recursos não documentados).

Experimente online ! Observe que as aspas triplas são para uma sequência multilinha.

Explicação

O algoritmo básico é: return true se cada sub-grade 2x2 tiver um número par de 1s (ou, equivalentemente, 0s).

Está claro por que um número ímpar de 1s não funciona, pois teríamos um dos seguintes:

10  01  00  00  01  10  11  11
00  00  01  10  11  11  10  01

Observe que as 4 primeiras são rotações da mesma coisa e o mesmo vale para as 4. últimas. O ângulo reflexo não pode fazer parte de um retângulo, portanto, por que seria inválido.

Em outras palavras, todas as subgrades 2x2 devem ser uma das seguintes:

00  00  11  01  10  01  10  11
00  11  00  01  10  10  01  11

que, se olharmos para os limites, podem ser imaginadas como as seguintes "peças do quebra-cabeça":

 ___    ___    ___    ___
|   |  | | |  |   |  | | |
|   |  | | |  |---|  |-|-|
|___|  |_|_|  |___|  |_|_|

E tente formar um não-retângulo com essas peças do quebra-cabeça :) (enquanto as extremidades coincidem)

A implementação real é assim:

ṣ⁷               Split input by newlines to give rows
  ^2\            Taking overlapping sets of 2 rows at a time: accumulate rows by XOR
                 Note that strings cast to integers automatically for bitwise operators
     ⁺€          Repeat the previous link (⁺), on each (€) element in the resulting array
       F         Flatten the array
        S        Sum (effectively reducing by OR)
         ¬       Logical negation of the result

Por exemplo, para a entrada

100
010
000
101

temos:

  ṣ⁷: ["100", "010", "000", "101"]
 ^2\: [[1, 1, 0], [0, 1, 0], [1, 0, 1]]    (e.g. first entry is "100" ^ "010")
^2\€: [[0, 1], [1, 1], [1, 1]]             (e.g. the first entry is [1^1, 1^0] - this
                                            gives the counts of 1s in each subgrid, mod 2)
   F: [0, 1, 1, 1, 1, 1]
   S: 5                                    (this gives the number of invalid 2x2 subgrids,
                                            which is indeed all but the top left)
   ¬: 0
Sp3000
fonte
11
Você pode documentar os recursos que usou? Se as pessoas fizerem isso, a documentação acontecerá!
CalculatorFeline
Você precisa achatar?
CalculatorFeline
@CatsAreFluffy Se você não achatar, Jelly tenta somar uma lista de vetores e você terá um vector como resultado
SP3000
Apenas soma e soma, é melhor!
CalculatorFeline
4
"Recursos não documentados" - aha! Então é assim que Dennis supera todos! : D
AdmBorkBork
12

Ruby, 76

->s{j=!r=1
s.lines{|t|i=t.to_i(2)
j&&r&&=(j^i)%t.tr(?0,?1).to_i(2)<1
j=i}
r}

Em qualquer grade composta inteiramente de retângulos, cada linha deve ser idêntica à linha anterior ou ter todos os bits invertidos de 0 a 1 e vice-versa.

Isso é fácil de provar. Pegue um pedaço de papel e desenhe linhas arbitrárias verticais e horizontais até o fim. Agora pinte os retângulos usando apenas 2 cores. Você terminará com um tabuleiro de damas distorcido, onde todas as cores mudam em cada linha.

Deseja desenhar retângulos com linhas apenas parcialmente abertas? tente excluir um segmento de qualquer uma das suas linhas. Agora você precisará de mais de 2 cores para colorir seu design, porque você terá pontos em que 3 retângulos se encontram (2 cantos e uma aresta). Esses designs são, portanto, irrelevantes para esta pergunta.

Estou surpreso que as respostas até agora não tenham notado isso.

Eu acho que esse algoritmo deve ser muito menor em alguma outra linguagem.

Ungolfed in program program

f=->s{
  j=!r=1                              #r = truthy, j=falsy
  s.lines{|t|                         #for each line
    i=t.to_i(2)                       #i = value of current line, converted to a number in base 2 (binary)
    j&&                               #if j is truthy (i.e this is not the first line)
      r&&=(j^i)%t.tr(?0,?1).to_i(2)<1 #XOR i with the previous line. Take the result modulo (current line with all 0 replaced by 1)
                                      #if the result of the XOR was all 0 or all 1, the modulo == zero (<1). Otherwise, it will be a positive number.   
j=i}                                  #j = value of current line (always truthy in ruby, even if zero)
r}                                    #return 1 or true if all the modulo calculations were zero, else false.



#text to print after test case to check answer is as desired
T='T

'
F='F

'

#test cases
puts f['0'],T

puts f['1'],T

puts f['00
'],T

puts f['01'],T

puts f['10'],T

puts f['11
'],T

puts f['0000000'],T

puts f['1111111'],T

puts f['011100100100101100110100100100101010100011100101'],T

puts f['00
11'],T

puts f['01
10'],T


puts f['01
11'],F

puts f['00
01'],F

puts f['11
11
'],T

puts f['110
100'],F

puts f['111
000'],T

puts f['111
101
111'],F

puts f['101
010
101
'],T

puts f['1101
0010
1101
0010'],T

puts f['1101
0010
1111
0010'],F

puts f['0011
0111
0100
'],F

puts f['0011
0011
1100'],T

puts f['00000000
01111110
00000000'],F

puts f['11111111
11111111
11111111'],T

puts f['0000001111
0000001111'],T

puts f['0000001111
0000011111'],F

puts f['0000001111
1000001111'],F

puts f['1000001111
1000001111'],T

puts f['1110100110101010110100010111011101000101111
1010100100101010100100010101010101100101000
1110100110010010110101010111010101010101011
1010100100101010010101010110010101001101001
1010110110101010110111110101011101000101111'],F
Level River St
fonte
Aposto que usando s.scan(/^?.*\n/)ajudaria a salvar bytes.
Não é Charles Charles
3

Caracóis , 20 bytes

!{to{\0w`3\1|\1w`3\0

Imprime a área da grade se não houver um quadrado 2x2 com 3 zeros e um ou 3 unidades e um zero, ou 0se esse quadrado 2x2 existir.

feersum
fonte
3

MATL , 12 bytes

Ybc2thYCs2\~

O mesmo algoritmo da ótima resposta do @ sp3000 .

Para permitir a entrada de várias linhas, o MATL precisa que a matriz de caracteres de linha (string) seja explicitamente criada usando o caractere 10para nova linha. Portanto, a entrada dos quatro exemplos é (observe que []é concatenação, portanto, cada um deles é uma matriz de linhas de caracteres):

['0011' 10 '0111' 10 '0100']
['0011' 10 '0011' 10 '1100']
['00000000' 10 '01111110' 10 '00000000']
['11111111' 10 '11111111' 10 '11111111']

e os três últimos casos de teste são

['0000001111' 10 '1000001111']
['1000001111' 10 '1000001111']
['1110100110101010110100010111011101000101111' 10 '1010100100101010100100010101010101100101000' 10 '1110100110010010110101010111010101010101011' 10 '1010100100101010010101010110010101001101001' 10 '1010110110101010110111110101011101000101111']

A saída de verdade é uma matriz que contém apenas um.

Experimente online!

Explicação

Este usa o fato de que a paridade de caracteres '0'e '1'é a mesma que a de números 0e 1, portanto, não há necessidade de converter de char para o dígito que representa,

Yb     % split implicit input by whitespace. Gives a cell array
c      % concatenate cell contents into 2D char array
2th    % push array [2 2]
YC     % get 2×2 sliding blocks and arrange as columns
s      % sum of each column
2\     % modulo 2 of each sum
~      % negate. Implicit display
Luis Mendo
fonte
A entrada precisa ser uma cadeia de caracteres
Calvin's Hobbies
@HelkaHomba O MATL não permite entrada de seqüência de linhas múltiplas ... A entrada teria que ser uma matriz de linhas do formulário ['first line' 10 'second llne'], onde 10é ASCII para nova linha. Isso é aceitável?
Luis Mendo
@HelkaHomba Eu usei isso na resposta atualizada. Como alternativa, o espaço pode ser usado em vez da nova linha? O primeiro exemplo seria string'0011 0111 0100'
Luis Mendo
@LuisMendo Eu aprecio o pensamento, mas eu acho que a resposta de Ruby pode realmente ser Golfier em geral aqui :)
SP3000
@ Sp3000 Oh, eu não tinha visto aquele. Muito esperto também
Luis Mendo
2

JavaScript (ES6), 69 bytes

s=>!s.split`
`.some((t,i,u)=>[...t].some((v,j)=>v^t[0]^u[0][j]^s[0]))

Acredito que o critério do retângulo de conexão do caminho é equivalente a exigir que, dados os quatro pontos que formam os cantos de um retângulo arbitrário, exista um número par de 1s. Observe que a paridade do retângulo (0, b), (x, y) é igual a (0, b), (a, y) ^(a, b), (x, y), portanto, só tenho que verificar aqueles retângulos cujo canto superior esquerdo está em (0, 0). Também pelas leis de De Morgan, !.some()é o mesmo .every(!)que me poupa alguns bytes.

Edit: Percebo que a solução Jelly verifica a paridade dos cantos de todos os retângulos 2 × 2, que podem ser equivalentes.

Neil
fonte
quase 7 vezes, mas +1
edc65 05/04
2

JavaScript (ES6), 79

O mesmo algoritmo da resposta Jelly do @ Sp3000 (e feliz por não ter que provar que funciona). Apenas 8 vezes mais

s=>[...s].every((x,i)=>[++i,i+=s.search`
`,i+1].some(p=>!(x^=p=s[p],p>`
`))|!x) 

Menos golfe

s=>[...s].every((x,i)=> // repeat check for every sub square
     [++i,                  // array of position for next char in row
      i+=s.search`\n`, i+1] // and 2 chars at same column in next row
       .some(p=> // for each position 
          !( 
            x^=s[p],  // xor current value with value at position p
            s[p]>`\n` // true if value at position p is valid
           ) // the condition is negated
       ) // if any value scanned is not valid, .some return true
         // else, we must consider the check for current square
       | !x // x can be 0 or 1, to be valid must be 0
   ) 

Suíte de teste

f=s=>[...s].every((x,i)=>[++i,i+=s.search`
`,i+1].some(p=>!(x^=p=s[p],p>`
`))|!x) 

testData=`
0
T

1
T

00
T

01
T

10
T

11
T

0000000
T

1111111
T

011100100100101100110100100100101010100011100101
T

00
11
T

01
10
T

01
11
F

00
01
F

11
11
T

110
100
F

111
000
T

111
101
111
F

101
010
101
T

1101
0010
1101
0010
T

1101
0010
1111
0010
F

0011
0111
0100
F

0011
0011
1100
T

00000000
01111110
00000000
F

11111111
11111111
11111111
T

0000001111
0000001111
T

0000001111
0000011111
F

0000001111
1000001111
F

1000001111
1000001111
T

1110100110101010110100010111011101000101111
1010100100101010100100010101010101100101000
1110100110010010110101010111010101010101011
1010100100101010010101010110010101001101001
1010110110101010110111110101011101000101111
F`

console.log=x=>O.textContent+=x+'\n'

testData.split('\n\n').forEach(t=>{
  var k=t.slice(-1)=='T',
      r=f(t.slice(0,-1))
  console.log(t+' '+r+ (k==r?' OK\n':' KO\n'))
})  
<pre id=O></pre>

edc65
fonte
11
Agora 8 vezes mais!
5116 Neil
1

Grime v0.1, 31 bytes

E=\0+|\1+
N=.+&E!
e`(E/N|N/E)#!

Imprime 1para correspondência e 0sem correspondência. Experimente online!

Explicação

Grime é minha linguagem de correspondência de padrões 2D. Eu o modifiquei hoje, mas apenas para alterar o caractere de um elemento de sintaxe (em `vez de ,), para que não afete minha pontuação.

Estou usando uma abordagem semelhante à do Sp3000 : uma entrada é falsa se contiver um retângulo 2 × N cuja linha contenha ambos 0e 1, e a outra linha não.

E=             Define a nonterminal E, which matches
  \0+|           a horizontal run of one or more 0s, OR
      \1+        a horizontal run of one or more 1s.
N=             Define a nonterminal N, which matches
  .+             a horizontal run of one or more characters,
    &E!          which is NOT matched by E (so contains both 0 and 1).
e`             Match entire input to this pattern:
            !    not
           #     contains
  (E/N|N/E)      E on top of N, or N on top of E
Zgarb
fonte
1

JavaScript (ES6), 64 bytes

s=>(a=s.split`
`).every(l=>l==a[0]|l==a[0].replace(/./g,n=>n^1))

Com base na observação de @ LevelRiverSt de que cada linha deve ser igual ou oposta à primeira.

user81655
fonte