Wykrywanie prostokąta

21

Napisz program lub funkcję, która pobiera wieloliniowy ciąg 0„s 1” i „s”. Żadne inne znaki nie będą w ciągu, a ciąg będzie zawsze prostokątny (wszystkie linie będą miały tę samą liczbę znaków), o wymiarach tak małych jak 1 × 1, ale w przeciwnym razie 0„i 1” mogą być ustawione dowolnie.

Możesz założyć, że ciąg ma opcjonalny końcowy znak nowej linii, a jeśli chcesz, możesz użyć dwóch różnych drukowalnych znaków ASCII zamiast 0i 1.

Drukuj lub zwróci wartość truthy jeśli wszystko z drogi połączone regiony zarówno 0's i 1jest w struny są stałe prostokąty , wyjście inny Wartość falsy .

Ścieżka połączony obszar od 0„s oznacza, że z jednego 0regionu, wszyscy inni 0” s może być osiągnięty tylko przez przesunięcie w górę, w dół, w lewo iw prawo, aby inny 0„s (a nie w ruchu po przekątnej, nie porusza się każdy 1, a nie wychodząc poza granice łańcucha). Ten sam pomysł dotyczy 1regionów połączonych ze ścieżką.

Stałe prostokąt o 0„s oznacza cały obszar prostokąta jest wypełniona 0” S i nie 1jest. Ten sam pomysł dotyczy 1stałych prostokątów.

Najkrótszy kod w bajtach wygrywa. Tiebreaker to wcześniejsza odpowiedź.

(Należy zauważyć, że łańcuch nie zawija się w toroidalnych warunkach brzegowych .)

Przykłady

1) Ten ciąg wejściowy ma 3 regiony połączone ścieżką (2 dla 0i 1 dla 1). Tylko prawy dolny 00obszar jest jednak stałym prostokątem, więc wynik byłby fałszywy.

0011
0111
0100

2) Ten ciąg wejściowy ma 4 regiony połączone ścieżką (2 dla obu 0i 1). Wszystkie są solidnymi prostokątami, więc wynik byłby prawdziwy.

0011
0011
1100

3) To wejście ma 2 obszary połączone ścieżką, ale tylko jeden z nich jest stałym prostokątem, więc wynik byłby fałszywy.

00000000
01111110
00000000

4) To wejście ma tylko 1 region połączony ze ścieżką i jest trywialnie prostym prostokątem, więc dane wyjściowe są zgodne z prawdą.

11111111
11111111
11111111

Przypadki testowe

TTuż poniżej truthy środki ciąg wejściowy, Fśrodki falsy.

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
Hobby Calvina
źródło

Odpowiedzi:

5

Galaretka , 7 bajtów

ṣ⁷µ=ḢZE

Używa tego samego algorytmu, co odpowiedź Ruby @ LevelRiverSt . Rzeczywisty algorytm mieści się w ostatnich 4 bajtach; pierwsze 3 bajty są wymagane do analizy formatu wejściowego.

Wypróbuj online!

Jak to działa

ṣ⁷µ=Ḣ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
źródło
16

Galaretka , 11 10 bajtów

ṣ⁷^2\⁺€FS¬

Ogromne podziękowania dla @Dennis za grę w golfa do połowy jego oryginalnego rozmiaru (dzięki nieudokumentowanym funkcjom).

Wypróbuj online ! Zauważ, że potrójne cudzysłowy dotyczą ciągu wielowierszowego.

Wyjaśnienie

Podstawowym algorytmem jest: zwracaj wartość prawda tam, gdzie każda podsiatka 2x2 ma parzystą liczbę 1 (lub równoważnie 0).

Jest jasne, dlaczego nieparzysta liczba 1 nie może działać, ponieważ mielibyśmy jedną z następujących czynności:

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

Zauważ, że pierwsze 4 są obrotami tego samego, i to samo dla ostatnich 4. Kąt odruchu nie może być częścią prostokąta, dlatego jest on nieprawidłowy.

Innymi słowy, wszystkie podsiatki 2x2 muszą być jednym z następujących:

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

które, jeśli spojrzymy na granice, można sobie wyobrazić jako następujące „elementy układanki”:

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

I spróbuj utworzyć nieprostokąt z tymi puzzlami :) (jednocześnie dopasowując końce)

Rzeczywiste wdrożenie jest zatem:

ṣ⁷               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

Na przykład dla danych wejściowych

100
010
000
101

mamy:

  ṣ⁷: ["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
źródło
1
Czy możesz udokumentować używane funkcje? Jeśli ludzie to zrobią, powstanie dokumentacja!
CalculatorFeline,
Potrzebujesz spłaszczyć?
CalculatorFeline,
@CatsAreFluffy Jeśli się nie spłaszczysz, Jelly spróbuje zsumować listę wektorów i otrzymasz wektor
Sp3000,
Tylko suma i suma - to lepiej!
CalculatorFeline,
4
„Nieudokumentowane funkcje” - aha! W ten sposób Dennis przeraził wszystkich! : 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}

Na każdej siatce złożonej w całości z prostokątów każda linia musi być identyczna z linią przed lub musi mieć wszystkie bity odwrócone od 0 do 1 i odwrotnie.

Łatwo to udowodnić. Weź kawałek papieru i narysuj na nim dowolne pionowe i poziome linie. Teraz pokoloruj prostokąty używając tylko 2 kolorów. Skończysz ze zniekształconą szachownicą, w której wszystkie kolory odwracają się w każdej linii.

Chcesz narysować prostokąty z liniami tylko częściowo w poprzek? spróbuj usunąć fragment dowolnej linii. Będziesz potrzebował więcej niż 2 kolorów, aby pokolorować swój projekt, ponieważ będziesz miał punkty, w których spotykają się 3 prostokąty (2 rogi i krawędź). Takie projekty nie mają zatem znaczenia dla tego pytania.

Jestem zaskoczony, że jak dotąd odpowiedzi tego nie zauważyłem.

Myślę, że ten algorytm powinien być znacznie krótszy w innym języku.

Niegolfowany w programie testowym

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
źródło
Założę się, s.scan(/^?.*\n/)że użycie pomogłoby zaoszczędzić bajty.
Nie to, że Charles
3

Ślimaki , 20 bajtów

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

Drukuje obszar siatki, jeśli nie ma kwadratu 2x2 z 3 zerami i jednym lub 3 zerami i zero, lub 0jeśli taki kwadrat 2x2 istnieje.

feersum
źródło
3

MATL , 12 bajtów

Ybc2thYCs2\~

Ten sam algorytm jak świetna odpowiedź @ sp3000 .

Aby umożliwić wprowadzanie danych wielowierszowych, MATL wymaga jawnej budowy tablicy znaków (łańcucha) przy użyciu znaku 10nowej linii. Tak więc danymi wejściowymi czterech przykładów są (zauważ, że []jest to konkatenacja, więc każdy z nich to tablica wierszy znaków):

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

a ostatnie trzy przypadki testowe to

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

Prawdziwe dane wyjściowe to tablica zawierająca tylko jedynki.

Wypróbuj online!

Wyjaśnienie

Wykorzystuje to fakt, że parzystość znaków '0'i '1'jest taka sama jak liczb, 0a 1więc nie trzeba konwertować z znaku na cyfrę, którą reprezentuje,

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
źródło
Dane wejściowe muszą być ciągiem
hobby Calvina
@HelkaHomba MATL nie zezwala na wprowadzanie ciągów wielowierszowych ... Dane wejściowe musiałyby być tablicą wierszy o postaci ['first line' 10 'second llne'], gdzie 10jest ASCII dla nowego wiersza. Czy to jest dopuszczalne?
Luis Mendo,
@HelkaHomba Użyłem tego w zaktualizowanej odpowiedzi. Alternatywnie, czy zamiast znaku nowej linii można użyć spacji? Pierwszym przykładem może być struna'0011 0111 0100'
Luis Mendo
@LuisMendo Doceniam tę myśl, ale myślę, że odpowiedź Ruby może być bardziej golfistą tutaj :)
Sp3000
@ Sp3000 Och, nie widziałem tego. Również bardzo sprytny
Luis Mendo,
2

JavaScript (ES6), 69 bajtów

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

Uważam, że kryterium prostokąta połączenia ścieżki jest równoważne wymaganiu, aby biorąc pod uwagę dowolne cztery punkty tworzące rogi dowolnego prostokąta, że ​​istnieje parzysta liczba 1s. Zauważ, że parzystość prostokąta (0, b), (x, y) jest taka sama jak (0, b), (a, y) ^(a, b), (x, y), więc muszę tylko sprawdzić prostokąty, których lewy górny róg ma wartość (0, 0). Również według praw De Morgana !.some()jest to samo, .every(!)co oszczędza mi kilka bajtów.

Edycja: Zauważam, że rozwiązanie Galaretka sprawdza parzystość narożników wszystkich prostokątów 2 × 2, które można wykazać jako równoważne.

Neil
źródło
prawie 7 razy, ale +1
edc65
2

JavaScript (ES6), 79

Ten sam algorytm odpowiedzi Jelly z @ Sp3000 (i szczęśliwy, że nie muszę udowadniać, że działa). Tylko 8 razy dłużej

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

Mniej golfa

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
   ) 

Zestaw testowy

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
źródło
1
Teraz 8 razy dłużej!
Neil,
1

Grime v0.1, 31 bajtów

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

Drukuje 1dla dopasowania i 0bez dopasowania. Wypróbuj online!

Wyjaśnienie

Grime to mój język dopasowywania wzorów 2D. Zmodyfikowałem go dzisiaj, ale tylko po to, aby zmienić charakter elementu składniowego ( `zamiast ,), więc nie wpływa to na mój wynik.

Używam podobnego podejścia do Sp3000 : dane wejściowe są fałszowane, jeśli zawierają prostokąt 2 × N, którego jeden rząd zawiera oba 0i 1, a drugi nie.

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
źródło
1

JavaScript (ES6), 64 bajty

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

Na podstawie obserwacji @ LevelRiverSt, że każda linia musi być taka sama lub przeciwna do pierwszej.

użytkownik 81655
źródło