Erkennen von ASCII-Kunstfenstern aus M- und S-Zeichen

28

Ein Fenster ist ein ASCII-artiges Quadrat mit einer ungeraden Seitenlänge von mindestens 3, einem einzelnen Zeichenrahmen am Rand sowie vertikalen und horizontalen Strichen in der Mitte:

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

Ein MS-Fenster ist ein Fenster, in dem der Rahmen nur aus den Zeichen Mund besteht S. Ihre Aufgabe ist es, ein Programm (oder eine Funktion) zu schreiben, das eine Zeichenfolge verwendet und einen Wahrheitswert ausgibt, wenn die Eingabe ein gültiges MS Window ist, und einen Falsey-Wert, wenn dies nicht der Fall ist.

Spezifikationen

  • Sie können die Eingabe als durch Zeilenumbrüche getrennte Zeichenfolge oder als ein Array von Zeichenfolgen für jede Zeile verwenden.
  • Der Rand eines MS-Fensters kann eine Mischung aus M- und S-Zeichen enthalten, das Innere besteht jedoch immer aus Leerzeichen.
  • Sie können auswählen, ob nur Fenster mit nachgestellten Zeilen oder nur Fenster ohne nachgestellte Zeilen erkannt werden sollen, jedoch nicht beide.

Testfälle

Wahrheit:

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
quelle
3
Dies ist eine große Wendung in Bezug auf ASCII-Künste, ein Entscheidungsproblem beim Erkennen einer bestimmten Struktur.
Xnor
4
@xnor Ich habe das Gefühl, wir möchten vielleicht ein anderes Tag für umgekehrte ASCII-Grafiken wie dieses.
Esolanging Fruit
2
Obwohl es sich nicht speziell um ASCII-Kunst handelt, ist der Mustervergleich möglicherweise eine gute Wahl für ein neues Tag
Destructible Lemon
Können Sie einen oder zwei Testfälle hinzufügen, bei denen die Zeichenfolge kein rechteckiges Array bildet?
Greg Martin
1
@Mast, du hast ganz recht! Vielleicht muss die Herausforderung geklärt werden
Chris M

Antworten:

1

Pyke, 34 31 Bytes

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

Probieren Sie es hier aus!

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")
Blau
quelle
8

Retina , 68 67 Bytes

Die Anzahl der Bytes setzt die Kodierung nach ISO 8859-1 voraus.

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

Probieren Sie es online!

Martin Ender
quelle
7

Schmutz , 39 38 Bytes

Vielen Dank an Zgarb für das Speichern von 1 Byte.

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

Probieren Sie es online!

Ich bin mir nicht sicher, ob es eine einfachere Möglichkeit gibt, das quadratische Seitenverhältnis der einzelnen Fensterkomponenten zu erzwingen, als ein rekursives Nichtterminal zu verwenden, aber dies scheint recht gut zu funktionieren.

Erläuterung

Lesen Sie das Programm am besten von unten nach oben.

W=[MS

Dies definiert einfach ein Nichtterminal (das Sie sich als eine Unterroutine vorstellen können, die einem Rechteck entspricht), Wdas entweder einem Moder einem entspricht S( ]am Ende der Zeile befindet sich ein Implizit ).

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

Dies definiert ein Nicht-Terminal, Bdas ungefähr einem Viertel der Ausgabe entspricht, dh ein Fensterfeld mit dem linken und oberen Rand. Etwas wie das:

MSM
S  
M  

Um sicherzustellen, dass dieses Fensterfeld quadratisch ist, definieren wir Brekursiv. Es ist entweder ein Fensterzeichen Woder es B/W\ * W/\ /*fügt eine Ebene rechts und unten hinzu. Um zu sehen, wie das funktioniert, entfernen wir etwas syntaktischen Zucker:

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

Dies ist das Gleiche, da die horizontale Verkettung entweder ABoder geschrieben werden A Bkann, die letztere jedoch eine niedrigere Priorität als die vertikale Verkettung hat, /während die erstere eine höhere Priorität hat. So B/W[ ]*ist a Bmit einem Fensterzeichen und einer Reihe von Leerzeichen darunter. Und dann hängen wir horizontal an, W/[ ]/*was ein Fensterzeichen mit einer Spalte von Leerzeichen ist.

Schließlich montieren wir diese Nichtterminale in die endgültige Fensterform:

BB/BB/W+ W/+

Das sind vier Fenster, Bgefolgt von einer Reihe von Fensterzeichen und einer Spalte von Fensterzeichen. Beachten Sie, dass wir nicht explizit behaupten, dass die vier Fenster die gleiche Größe haben, aber wenn dies nicht der Fall ist, ist es unmöglich, sie zu einem Rechteck zusammenzufügen.

Schließlich ist der e`Anfang einfach eine Konfiguration, die Grime anweist, zu überprüfen, ob die gesamte Eingabe mit diesem Muster übereinstimmt (und es druckt 0oder 1dementsprechend).

Martin Ender
quelle
5

JavaScript (ES6), 115 113 Byte

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

Nimmt Eingaben als ein Array von Arrays von Zeichen (füge 5 Bytes für ein Array von Zeichenfolgen hinzu) und gibt 1oder zurück 0. Nachdem überprüft wurde, dass die Höhe ungerade ist, wird jede Zeile überprüft, um sicherzustellen, dass das Array quadratisch ist, und jedes Zeichen wird als eines der Zeichen überprüft, die wir an dieser bestimmten Position erwarten. Bearbeiten: 2 Bytes dank @PatrickRoberts gespeichert.

Neil
quelle
Sie können ändern (...).includes(c), ~(...).search(c)um 1 Byte zu speichern
Patrick Roberts
1
Noch besser ist es, wenn Sie (...?/ /:/[MS]/).test(c)2 statt nur 1 Byte speichern.
Patrick Roberts
@PatrickRoberts Süß, danke!
Neil
5

Perl, 124 123 119 95 93 84

Das folgende Perl-Skript liest ein Kandidaten-MS-Fenster aus der Standardeingabe. Es wird dann mit einem Beendigungsstatus von Null beendet, wenn der Kandidat ein MS-Fenster ist, und mit einem Beendigungsstatus ungleich Null, wenn dies nicht der Fall ist.

Dabei werden zwei reguläre Ausdrücke generiert, einer für die obere, mittlere und untere Zeile und einer für jede zweite Zeile, und die Eingabe wird mit diesen verglichen.

Danke, @Dada. Und wieder.

map{$s=$"x(($.-3)/2);$m="[MS]";($c++%($#a/2)?/^$m$s$m$s$m$/:/^${m}{$.}$/)||die}@a=<>
nwk
quelle
Ich bin mir nicht sicher, ob das Ergebnis angegeben werden kann, da der Exit-Status zulässig ist (ich habe jedoch keine Zeit, nach dem entsprechenden Meta-Post zu suchen). Unabhängig davon können Sie ein paar Bytes speichern:@a=<>;$s=$"x(($.-3)/2);$m="[MS]";map{$a[$_]!~($_%($./2)?"$m$s$m$s$m":"$m${m}{$.}")&&die}0..--$.
Dada
@Dada: Danke! Das ist eine beeindruckende Verbesserung: 24 Zeichen. (In Ihrem Code gab es ein streuendes "$ m", es ist also noch kürzer als es zuerst ausgesehen hat.) Ich war mir nicht sicher, ob das Melden des Ergebnisses mit einem Exit-Code generell erlaubt war, aber ich habe das Programm "Write a Program" gewählt. ( oder Funktion) "so, dass man flexibel sein kann, wie das Ergebnis in diesem speziellen Fall zurückgegeben wird; Exit-Codes sind praktisch die Funktionsrückgabewerte der * nix-Umgebung. :-)
nwk
Machen Sie das 26 Zeichen.
nwk
1
Eigentlich bin ich Erniedrigen $.am Ende zweimal zu vermeiden , mit $.-1(vor allem seit dem ersten Mal war es ($.-1)/2so dass es einige zusätzliche Klammer erforderlich), so dass die $min $m${m}{$.}kein Fehler ist. Außerdem habe ich gerade erst gemerkt, dass Regex- ^...$Zeichen mit (also zusätzliche Zeichen am Ende oder am Anfang scheitern) umgeben sein sollten, oder kürzer: nestatt verwenden !~.
Dada
Vergiss nicht, du kannst natürlich nicht nestattdessen !~schreiben (ich sollte keine Nachrichten schreiben, wenn ich nur 15 Minuten wach bin!). ^...$Ich fürchte, Sie müssen beide Regex verwenden.
Dada
2

Mathematica, 166 Bytes

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]]&

Unbenannte Funktion, die eine Liste von Zeichenlisten als Eingabe und Rückgabe verwendet Trueoder False. Hier ist eine weniger golfige Version:

(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]]]]])) &

Die erste Zeile definiert die Funktion t, die eine Liste mit Längenangaben din zwei Teile unterteilt, wobei der erste der erste, der mittlere und der letzte Eintrag der Liste ist und der zweite der Rest. Die zweite Zeile prüft zunächst, ob die Eingabe ein quadratisches Array ist. In der vierten Zeile werden tzwei Zeichen verwendet , einmal für die Eingabe selbst und einmal für alle Zeichenfolgen in der Eingabe, um die Zeichen, die sein sollen, "M"oder "S"die Zeichen, die Leerzeichen sein sollen , zu trennen . dann überprüfen die fünfte und siebte Zeile, ob sie wirklich das sind, was sie sein sollen.

Greg Martin
quelle
2

JavaScript (ES6), 108 106 Bytes

Eingabe: Array von Strings / Ausgabe: 0oder1

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)

Testfälle

Arnauld
quelle
2

JavaScript (ES6), 140 138 141 140 Bytes

Ich weiß, dass dies keine gewinnende Byteanzahl ist (obwohl Patrick Roberts für -3 zu verdanken war und ich erkannte, dass er 1 anstelle von M / S: +3 falsch positiv war), aber ich habe es auf eine etwas andere Weise getan. ' Ich bin neu in diesem und es hat Spaß gemacht ...

Akzeptiert ein Array von Zeichenfolgen, eine für jede Zeile, und gibt true oder false zurück. Neue Zeile zur Verdeutlichung hinzugefügt (nicht in der Byteanzahl enthalten).

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

Anstatt die Eingabe mit einem verallgemeinerten Muster zu vergleichen, konstruiere ich ein 'M'-Fenster der gleichen Größe, ersetze S durch M bei der Eingabe und vergleiche die beiden.

Ungolfed

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

Testfälle

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
quelle
1
Wenn die Funktion nicht rekursiv ist, f=muss sie für zukünftige Referenzzwecke nicht in die Byteanzahl einbezogen werden. Es handelt sich also tatsächlich um eine 138-Byte-Übermittlung.
Patrick Roberts
Sie können ersetzen z=-1+s/2|0mit z=(s-3)/2zu speichern 1 Byte
Patrick Robert
Sie können auch ersetzen e.replace(/S/g,'M')==...mit e.split`S`.join`M`==...einem anderen Byte speichern
Patrick Robert
Vielen Dank! z=-1+s/2|0Gibt eine positive Ganzzahl für s == 1 und sogar s zurück, dh die Funktion gibt false zurück, ohne dass Array () abstürzt. Ansonsten hat die notwendige Logik es länger gemacht. Toller Tipp für Split / Join, danke
Chris M
Guter Fang, ich habe den s=1Fall nicht in Betracht gezogen , da mein ungültiger regulärer Ausdruck schweigend versagt.
Patrick Roberts
1

JavaScript (ES6), 109 107 106 105 99 Byte

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

Edit : Whoa, Arnauld hat mir 6 Bytes gespart, indem er s.split`\n`.lengthzu geändert hat s.search`\n`! Vielen Dank!

Dies nimmt eine einzelne mehrzeilige Zeichenfolge und erstellt eine RegExpValidierung auf der Grundlage der Länge der Eingabezeichenfolge. Rückgabe trueoder false. Angenommen, ein gültiges Fenster hat keinen nachgestellten Zeilenumbruch.

Demo

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
quelle
Netter Ansatz! Könnten Sie r=s.search('\n')anstelle von verwenden split / length?
Arnauld
@ Arnauld super Vorschlag, danke!
Patrick Roberts
Die Klammern an s=>!s.split`S`.join`M`.search([...])können entfernt werden, ohne Syntaxfehler zu verursachen.
Ismael Miguel
@IsmaelMiguel richtig, aber dann wird die Zeichenfolge als Vorlage übergeben, die das implizite ungültig machtRegExp
Patrick Roberts
Das ist zum Kotzen ... Das habe ich wirklich nicht erwartet ...
Ismael Miguel