Wykryj okna ASCII-art wykonane ze znaków M i S.

28

Okno to kwadrat ASCII-art o nieparzystej długości co najmniej 3, z pojedynczą obwódką wokół krawędzi oraz pionowymi i poziomymi pociągnięciami na środku:

#######
#  #  #
#  #  #
#######
#  #  #
#  #  #
#######

Okno MS to okno, w którym ramka składa się tylko z znaków Mi S. Twoim zadaniem jest napisanie programu (lub funkcji), który pobierze ciąg znaków i wyświetli prawdziwą wartość, jeśli dane wejściowe są poprawnym MS Window, i wartością falsey, jeśli nie jest.

Dane techniczne

  • Możesz wziąć dane wejściowe jako ciąg oddzielony znakiem nowej linii lub tablicę ciągów reprezentujących każdą linię.
  • Obramowanie okna MS może zawierać mieszankę znaków M i S, ale wnętrze zawsze będzie składać się ze spacji.
  • Możesz wybrać wykrywanie tylko okien z końcowymi znakami nowej linii lub tylko okien bez końcowych znaków nowej linii, ale nie obu.

Przypadki testowe

Prawda:

MMM
MMM
MMM

SMSMS
M M S
SMSMM
S S M
SMSMS

MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM

Falsey:

Hello, World!

MMMM
MSSM
MS M
MMMM

MMSMM
M S.M
sSSSS
M S M
MMSMM

MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM

MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM

MMSSMSSMM
M   M   M
S   S   S
S   S  S
MMSSMSSMM
S   S   S
S   S   S
M   M   M
MMSSMSSMM
Esolanging Fruit
źródło
3
To wielki zwrot w sztuce ASCII, problem decyzyjny w celu wykrycia określonej struktury.
xnor
4
@ xnor Wydaje mi się, że moglibyśmy chcieć innego tagu dla odwróconej grafiki ASCII w ten sposób.
Esolanging Fruit
2
chociaż nie jest specyficzne dla sztuki ascii, dopasowanie wzoru może być dobrym wyborem dla nowego tagu
Destructible Lemon
Czy możesz dodać przypadek testowy lub dwa, w których łańcuch nie tworzy prostokątnej tablicy?
Greg Martin
1
@Mast, masz całkowitą rację! Być może wyzwanie wymaga wyjaśnienia
Chris M

Odpowiedzi:

1

Pyke, 34 31 bajtów

lei}t\Mcn+it*i\M*+s.XM"QJ\S\M:q

Wypróbuj tutaj!

lei                              -         i = len(input)//2
   }t                            -        (^ * 2) - 1
     \Mc                         -       "M".center(^)
        n+                       -      ^ + "\n"
          it*                    -     ^ * (i-1)
                 +               -    ^ + V
             i\M*                -     "M"*i
                  s              -   palindromise(^)
                   .XM"          -  surround(^, "M")
                               q - ^ == V
                       QJ        -   "\n".join(input)
                         \S\M:   -  ^.replace("S", "M")
niebieski
źródło
8

Siatkówka , 68 67 bajtów

Liczba bajtów zakłada kodowanie ISO 8859-1.

S
M
^(M((M)*M)\2)((?<-9>¶M((?<9-3> )*(?(3)!)M|\5)\5)*(?(9)!)¶\1)\4$

Wypróbuj online!

Martin Ender
źródło
7

Grime , 39 38 bajtów

Dzięki Zgarbowi za uratowanie 1 bajtu.

e`BB/BB/W+ W/+
B=W|B/W\ * W/\ /*
W=[MS

Wypróbuj online!

Nie jestem pewien, czy istnieje prostszy sposób narzucenia kwadratowego współczynnika kształtu poszczególnych komponentów okna niż użycie rekurencyjnego nieterminala, ale wydaje się, że działa to całkiem dobrze.

Wyjaśnienie

Najlepiej przeczytać program od podstaw.

W=[MS

Definiuje to po prostu nieterminal (który można traktować jako podprogram pasujący do prostokąta), Wktóry pasuje albo do Malbo S(jest ukryty ]na końcu linii).

B=W|B/W\ * W/\ /*

Definiuje to terminal, Bktóry pasuje do około jednej czwartej wyniku, tj. Jeden panel okna z lewą i górną ramką. Coś takiego:

MSM
S  
M  

Aby upewnić się, że ten panel okna jest kwadratowy, definiujemy Brekurencyjnie. To albo znak okna W, albo ten, B/W\ * W/\ /*który dodaje jedną warstwę po prawej i na dole. Aby zobaczyć, jak to robi, usuńmy cukier syntaktyczny:

(B/W[ ]*)(W/[ ]/*)

To jest to samo, ponieważ konkatenację poziomą można zapisać albo, ABalbo A Bta druga ma niższy priorytet niż konkatenacja pionowa, /podczas gdy dla pierwszej ma wyższą. Podobnie B/W[ ]*jest Bze znakiem okna i rzędem spacji poniżej. A następnie dołączamy poziomo, W/[ ]/*który jest znakiem okna z kolumną spacji.

Na koniec montujemy te nieterminale w końcowym kształcie okna:

BB/BB/W+ W/+

To cztery panele okien, Bpo których następuje rząd znaków okna i kolumna znaków okna. Zauważ, że nie twierdzimy wprost, że cztery panele okien mają ten sam rozmiar, ale jeśli nie są, niemożliwe jest połączenie ich w prostokąt.

Wreszcie, e`na początku jest po prostu konfiguracja, która każe Grime'owi sprawdzić, czy cały sygnał wejściowy może być dopasowany do tego wzorca (i drukuje 0lub 1odpowiednio).

Martin Ender
źródło
5

JavaScript (ES6), 115 113 bajtów

a=>(l=a.length)&a.every((b,i)=>b.length==l&b.every((c,j)=>(i&&l+~i-i&&l+~i&&j&&l+~j-j&&l+~j?/ /:/[MS]/).test(c)))

Pobiera dane wejściowe jako tablicę tablic znaków (dodaj 5 bajtów dla tablicy ciągów znaków) i zwraca 1lub 0. Po sprawdzeniu, że wysokość jest nieparzysta, każdy wiersz jest sprawdzany, aby upewnić się, że tablica jest kwadratowa, i każdy znak jest weryfikowany jako jeden z znaków, których oczekujemy na tej konkretnej pozycji. Edycja: Zapisano 2 bajty dzięki @PatrickRoberts.

Neil
źródło
Możesz zmienić, (...).includes(c)aby ~(...).search(c)zapisać 1 bajt
Patrick Roberts
1
W rzeczywistości jeszcze lepiej możesz to zmienić, aby (...?/ /:/[MS]/).test(c)zapisać 2 bajty zamiast tylko 1.
Patrick Roberts
@PatrickRoberts Śliczne, dzięki!
Neil
5

Perl, 124 123 119 95 93 84

Poniższy skrypt Perla czyta jednego kandydata MS Window ze standardowego wejścia. Następnie kończy pracę z zerowym statusem wyjścia, jeśli kandydat jest oknem MS i z niezerowym statusem wyjścia, jeśli nie jest.

Działa poprzez generowanie dwóch wyrażeń regularnych, jednego dla górnej, środkowej i dolnej linii oraz jednego dla każdej innej linii i sprawdzanie danych wejściowych względem nich.

Dzięki, @Dada. I jeszcze raz.

map{$s=$"x(($.-3)/2);$m="[MS]";($c++%($#a/2)?/^$m$s$m$s$m$/:/^${m}{$.}$/)||die}@a=<>
nwk
źródło
Nie jestem pewien, czy daje to wynik, ponieważ status wyjścia jest dozwolony (chociaż nie mam czasu szukać odpowiedniego meta posta). Niezależnie od tego możesz zaoszczędzić kilka bajtów:@a=<>;$s=$"x(($.-3)/2);$m="[MS]";map{$a[$_]!~($_%($./2)?"$m$s$m$s$m":"$m${m}{$.}")&&die}0..--$.
Dada
@Dada: Dzięki! To imponująca poprawa: 24 znaki. (W twoim kodzie było zbłąkane „$ m”, więc jest nawet krótsze, niż się początkowo wydawało). Nie byłem pewien, czy raportowanie wyniku za pomocą kodu wyjścia jest ogólnie dozwolone, ale wziąłem „napisanie programu ( lub funkcja) ”jako pozwalający na elastyczność w sposobie zwracania wyniku w tym konkretnym przypadku; kody wyjścia są praktycznie funkcją zwracającą wartości środowiska * nix. :-)
nwk
Zrób 26 znaków.
nwk
1
Faktycznie, ja zmniejszanie $.na koniec, aby uniknąć stosując dwukrotnie $.-1(zwłaszcza, że pierwszy raz było ($.-1)/2tak potrzebne dodatkowe nawias), więc $mw $m${m}{$.}nie jest błędem. Poza tym właśnie sobie uświadomiłem, ale wyrażenia regularne powinny być otoczone ^...$(tak, że dodatkowe znaki na końcu lub na początku powodują, że się nie udają), lub krócej: użyj nezamiast !~.
Dada,
Nieważne, oczywiście nie możesz używać nezamiast tego !~(nie powinienem pisać wiadomości, gdy nie śpię przez zaledwie 15 minut!). ^...$Obawiam się, że będziesz musiał użyć obu wyrażeń regularnych.
Dada
2

Mathematica, 166 bajtów

Union[(l=Length)/@data]=={d=l@#}&&{"M","S"}~(s=SubsetQ)~(u=Union@*Flatten)@{#&@@(p={#,(t=#~TakeDrop~{1,-1,d/2-.5}&)/@#2}&@@t@#),p[[2,All,1]]}&&{" "}~s~u@p[[2,All,2]]&

Nienazwana funkcja przyjmująca listę znaków jako dane wejściowe i zwracające Truelub False. Oto mniej golfowa wersja:

(t = TakeDrop[#1, {1, -1, d/2 - 0.5}] &; 
Union[Length /@ data] == {d = Length[#1]}
  &&
(p = ({#1, t /@ #2} &) @@ t[#1];
SubsetQ[{"M", "S"}, Union[Flatten[{p[[1]], p[[2, All, 1]]}]]]
  && 
SubsetQ[{" "}, Union[Flatten[p[[2, All, 2]]]]])) &

Pierwszy wiersz definiuje funkcję t, która dzieli listę długości dna dwie części, z których pierwsza to pierwsza, środkowa i ostatnia pozycja listy, a druga to cała reszta. Drugi wiersz sprawdza, czy dane wejściowe są kwadratową tablicą. Czwarta linia używat dwa razy, raz na samym wejściu i raz na wszystkich * ciągach na wejściu, aby oddzielić znaki, które powinny być "M"lub "S"od znaków, które powinny być spacjami; następnie piąta i siódma linia sprawdzają, czy naprawdę są tym, czym powinny być.

Greg Martin
źródło
2

JavaScript (ES6), 108 106 bajtów

Dane wejściowe: tablica ciągów / Dane wyjściowe: 0lub1

s=>s.reduce((p,r,y)=>p&&r.length==w&(y==w>>1|++y%w<2?/^[MS]+$/:/^[MS]( *)[MS]\1[MS]$/).test(r),w=s.length)

Przypadki testowe

Arnauld
źródło
2

JavaScript (ES6), 140 138 141 140 bajtów

Wiem, że to nie jest zwycięska liczba bajtów (chociaż dzięki Patrickowi Robertsowi za -3 i zdałem sobie sprawę, że rzuciło fałszywe trafienia na 1 zamiast M / S: +3), ale zrobiłem to nieco inaczej, jestem nowy i było fajnie ...

Akceptuje tablicę ciągów, po jednej dla każdej linii i zwraca wartość true lub false. Dodano nową linię dla zachowania przejrzystości (nieuwzględnione w liczbie bajtów).

f=t=>t.every((e,i)=>e.split`S`.join`M`==[...p=[b='M'.repeat(s=t.length),
...Array(z=-1+s/2|0).fill([...'MMM'].join(' '.repeat(z)))],...p,b][i])

Zamiast sprawdzać dane wejściowe względem uogólnionego wzorca, buduję okno „M” o tym samym rozmiarze, zastępuję S literą M na wejściu i porównuję oba.

Nie golfił

f = t => t.every( // function returns true iff every entry in t
                  // returns true below
  (e, i) => e.split`S`.join`M` // replace all S with M
                                 // to compare to mask
  == [ // construct a window of the same size made of Ms and
       // spaces, compare each row 
      ...p = [ // p = repeated vertical panel (bar above pane)
               // which will be repeated
              b = 'M'.repeat(s = t.length),
                  // b = bar of Ms as long as the input array
              ...Array(z = -1 + s/2|0).fill([...'MMM'].join(' '.repeat(z)))],
              // z = pane size; create enough pane rows with
              // Ms and enough spaces
      ...p, // repeat the panel once more
      b][i] // finish with a bar
)

console.log(f(["111","111","111"]))

console.log(f(["MMMMM","M S M","MSSSM","M S M","MSSSM"]))

Przypadki testowe

f=t=>t.every((e,i)=>e.split`S`.join`M`==[...p=[b='M'.repeat(s=t.length),
...Array(z=-1+s/2|0).fill([...'MMM'].join(' '.repeat(z)))],...p,b][i])


truthy=`MMM
MMM
MMM

SMSMS
M M M
SMSMS
M M M
SMSMS

MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM`.split('\n\n')

falsey=`Hello, World!

MMMM
MSSM
MS M
MMMM

MMSMM
M S.M
sSSSS
M S M
MMSMM

MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM

MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM`.split('\n\n')

truthy.forEach(test=>{
  console.log(test,f(test.split('\n')))
})

falsey.forEach(test=>{
  console.log(test,f(test.split('\n')))
})

Chris M.
źródło
1
Do przyszłego wykorzystania, chyba że funkcja jest rekurencyjna, f=nie musi być uwzględniana w liczbie bajtów, więc w rzeczywistości jest to przesłanie 138 bajtów.
Patrick Roberts,
Można wymienić z=-1+s/2|0ze z=(s-3)/2aby zapisać 1 bajt
Patrick Roberts
Można również wymienić e.replace(/S/g,'M')==...się e.split`S`.join`M`==...zapisać kolejny bajt
Patrick Roberts
Dzięki! z=-1+s/2|0jest tam, aby zwrócić dodatnią liczbę całkowitą dla s == 1, a nawet s, tzn. funkcja zwraca wartość false bez awarii Array (). W przeciwnym razie niezbędna logika wydłużyła go. Świetna wskazówka dotycząca podziału / dołączenia, dzięki
Chris M
Dobry haczyk, nie rozważyłem s=1przypadku, ponieważ moje nieprawidłowe wyrażenie regularne po prostu cicho kończy się niepowodzeniem.
Patrick Roberts,
1

JavaScript (ES6), 109 107 106 105 99 bajtów

s=>!s.split`S`.join`M`.search(`^((M{${r=s.search`
`}})(
(M( {${w=(r-3)/2}})M\\5M
){${w}}))\\1\\2$`)

Edycja : Whoa, Arnauld oszczędził mi 6 bajtów, zmieniając s.split`\n`.lengthnas.search`\n` ! Dzięki!

Pobiera to pojedynczy ciąg wielowierszowy i konstruuje RegExpsprawdzanie poprawności na podstawie długości ciągu wejściowego. Zwraca truelub false. Zakłada prawidłowe okno ma nie ma końcowego znaku nowej linii.

Próbny

f=s=>!s.split`S`.join`M`.search(`^((M{${r=s.search`
`}})(
(M( {${w=(r-3)/2}})M\\5M
){${w}}))\\1\\2$`);
`MMM
MMM
MMM

SMSMS
M M M
SMSMS
M M M
SMSMS

MMMMMMM
M  S  M
M  S  M
MSSSSSM
M  S  M
M  S  M
MMMMMMM

Hello, World!

MMMM
MSSM
MS M
MMMM

MMSMM
M S.M
sSSSS
M S M
MMSMM

MMMMMMM
M  M  M
MMMMMMM
M  M  M
MMMMMMM

MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM
M M M M
MMMMMMM`.split`

`.forEach(test=>{console.log(test,f(test));});

Patrick Roberts
źródło
Niezłe podejście! Czy możesz użyć r=s.search('\n')zamiast split / length?
Arnauld
@Arnauld niesamowite sugestie, dzięki!
Patrick Roberts,
Włączone nawiasy s=>!s.split`S`.join`M`.search([...])można usunąć bez powodowania błędów składniowych.
Ismael Miguel
@ IsmaelMiguel jest poprawny, ale potem ciąg zostaje przekazany jako szablon, co unieważnia domniemaneRegExp
Patrick Roberts
To do bani ... Naprawdę nie spodziewałem się, że ...
Ismael Miguel