Rileva finestre in formato ASCII fatte di caratteri M e S.


28

Una finestra è un quadrato di arte ASCII con una lunghezza del lato dispari di almeno 3, con un bordo a singolo carattere attorno al bordo e tratti verticali e orizzontali nel mezzo:

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

Una finestra MS è una finestra in cui il bordo è composto solo da caratteri Me S. Il tuo compito è scrivere un programma (o una funzione) che accetta una stringa e genera un valore di verità se l'input è una MS Window valida e un valore di falsa se non lo è.

specificazioni

  • È possibile prendere l'input come una stringa separata da una nuova riga o una matrice di stringhe che rappresentano ciascuna riga.
  • Il bordo di una finestra MS può contenere un mix di caratteri M e S, ma l'interno sarà sempre composto da spazi.
  • Puoi scegliere di rilevare solo le finestre con nuove righe finali o solo le finestre senza nuove righe, ma non entrambe.

Casi test

Truthy:

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

3
Questa è una grande svolta nelle arti ASCII, un problema decisionale per rilevare una certa struttura.
xnor

4
@xnor Sento che potremmo volere un tag diverso per l'arte ASCII inversa come questa.
Esolanging Fruit

2
sebbene non specifico per l'arte ASCII, la corrispondenza dei motivi potrebbe essere una buona scelta per un nuovo tag
Destructible Lemon

Puoi aggiungere uno o due casi di test in cui la stringa non forma un array rettangolare?
Greg Martin,

1
@Mast, hai ragione! Forse la sfida deve essere chiarita
Chris M,

Risposte:


1

Pyke, 34 31 byte

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

Provalo qui!

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


7

Grime , 39 38 byte

Grazie a Zgarb per aver salvato 1 byte.

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

Provalo online!

Non sono sicuro che esista un modo più semplice per applicare le proporzioni quadrate dei singoli componenti della finestra rispetto all'utilizzo di un non terminale ricorsivo, ma questo sembra funzionare abbastanza bene.

Spiegazione

È meglio leggere il programma dal basso verso l'alto.

W=[MS

Questo semplicemente definisce un non terminale (che puoi pensare come una subroutine che corrisponde a un rettangolo) Wche corrisponde a uno Mo uno S(c'è un implicito ]alla fine della linea).

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

Ciò definisce un non terminale Bche corrisponde a circa un quarto dell'output, ovvero un pannello della finestra con il bordo sinistro e superiore. Qualcosa come questo:

MSM
S  
M  

Per garantire che questo pannello della finestra sia quadrato, definiamo in Bmodo ricorsivo. O è un personaggio di finestra W, oppure è quello B/W\ * W/\ /*che aggiunge un livello a destra e in basso. Per vedere come fa, rimuoviamo un po 'di zucchero sintattico:

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

Questo è lo stesso, perché la concatenazione orizzontale può essere scritta o ABoppure A B, ma quest'ultima ha una precedenza inferiore rispetto alla concatenazione verticale, /mentre per la prima ha maggiore. Quindi B/W[ ]*è un Bcon un carattere finestra e una riga di spazi sottostanti. E poi aggiungiamo orizzontalmente W/[ ]/*quale è un personaggio di finestra con una colonna di spazi.

Infine, assembliamo questi non terminali nella forma finale della finestra:

BB/BB/W+ W/+

Sono quattro pannelli di finestre Bseguiti da una riga di caratteri di finestra e una colonna di caratteri di finestra. Si noti che non affermiamo esplicitamente che i quattro pannelli delle finestre abbiano le stesse dimensioni, ma in caso contrario è impossibile concatenarli in rettangolo.

Infine e`all'inizio è semplicemente una configurazione che dice a Grime di verificare che l'intero input possa essere abbinato a questo modello (e che stampa 0o di 1conseguenza).


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

Prende l'input come una matrice di matrici di caratteri (aggiunge 5 byte per una matrice di stringhe) e restituisce 1o 0. Dopo aver verificato che l'altezza è dispari, ogni riga viene controllata per garantire che l'array sia quadrato e ogni carattere viene verificato come uno dei caratteri che ci aspettiamo in quella particolare posizione. Modifica: salvato 2 byte grazie a @PatrickRoberts.


È possibile modificare (...).includes(c)per ~(...).search(c)salvare 1 byte
Patrick Roberts

1
In realtà, ancora meglio, puoi cambiarlo in (...?/ /:/[MS]/).test(c)per salvare 2 byte anziché solo 1.
Patrick Roberts,

@PatrickRoberts Carino, grazie!
Neil,

5

Perl, 124 123 119 95 93 84

Il seguente script Perl legge un MS Window candidato dall'input standard. Quindi esce con uno stato di uscita pari a zero se il candidato è un MS Window e con uno stato di uscita diverso da zero se non lo è.

Funziona generando due espressioni regolari, una per la riga superiore, centrale e inferiore e una per ogni altra riga e controllando l'input rispetto a esse.

Grazie @Dada. E di nuovo.

map{$s=$"x(($.-3)/2);$m="[MS]";($c++%($#a/2)?/^$m$s$m$s$m$/:/^${m}{$.}$/)||die}@a=<>

Non sono sicuro di dare il risultato in quanto lo stato di uscita è consentito (non ho tempo di cercare il relativo meta post). Indipendentemente da ciò, è possibile salvare alcuni byte:@a=<>;$s=$"x(($.-3)/2);$m="[MS]";map{$a[$_]!~($_%($./2)?"$m$s$m$s$m":"$m${m}{$.}")&&die}0..--$.
Dada

@Dada: grazie! È un miglioramento impressionante: 24 personaggi. (C'era un "$ m" smarrito nel tuo codice, quindi è ancora più breve di quanto non sembrasse all'inizio.) Non ero sicuro che riportare il risultato con un codice di uscita fosse consentito in generale, ma ho preso il "scrivere un programma ( o funzione) "come consentire a uno di essere flessibile con come viene restituito il risultato in questo caso particolare; i codici di uscita sono praticamente i valori di ritorno della funzione dell'ambiente * nix. :-)
nwk

Crea quei 26 personaggi.
nwk,

1
In realtà, $.alla fine sto diminuendo per evitare di usarlo due volte $.-1(soprattutto dalla prima volta, ($.-1)/2quindi ha avuto bisogno di qualche parentesi extra), quindi $min $m${m}{$.}non è un errore. Inoltre, mi sono appena reso conto ora, ma i regex dovrebbero essere circondati da ^...$(quindi un carattere extra alla fine o all'inizio li fa fallire), o più breve: usare neinvece di !~.
Dada,

Non importa, ovviamente non puoi usare neinvece di !~(non dovrei scrivere messaggi quando sono sveglio da soli 15 minuti!). Quindi dovrai usare ^...$entrambi i regex, temo.
Dada,

2

Mathematica, 166 byte

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

Funzione senza nome che prende un elenco di elenchi di caratteri come input e di ritorno Trueo False. Ecco una versione meno golfy:

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

La prima riga definisce la funzione t, che separa un elenco di lunghezza din due parti, la prima delle quali è la prima, la metà e l'ultima voce dell'elenco e la seconda è il resto. La seconda riga controlla innanzitutto se l'input è un array quadrato. La quarta riga utilizza tdue volte, una volta sull'input stesso e una su tutte * le stringhe nell'input, per separare i caratteri che si suppone siano "M"o "S"dai caratteri che si suppone siano spazi; quindi la quinta e la settima riga controllano se sono realmente ciò che dovrebbero essere.


2

JavaScript (ES6), 108 106 byte

Input: matrice di stringhe / Output: 0o1

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)

Casi test


2

JavaScript (ES6), 140 138 141 140 byte

So che questo non è un conteggio di byte vincente (anche se grazie a Patrick Roberts per -3, e mi sono reso conto che ha lanciato falsi positivi per 1 anziché M / S: +3), ma l'ho fatto in un modo leggermente diverso, io ' Sono nuovo di questo, ed è stato divertente ...

Accetta una matrice di stringhe, una per ogni riga e restituisce vero o falso. Newline aggiunto per chiarezza (non incluso nel conteggio dei byte).

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

Invece di controllare l'input rispetto a un modello generalizzato, costruisco una finestra 'M' della stessa dimensione, sostituisco S con M sull'input e confronto i due.

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

Casi test

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


1
Per riferimento futuro, a meno che la funzione non sia ricorsiva, f=non deve essere inclusa nel conteggio dei byte, quindi in realtà si tratta di un invio di 138 byte.
Patrick Roberts,

È possibile sostituire z=-1+s/2|0con z=(s-3)/2per salvare 1 byte
Patrick Roberts

Puoi anche sostituire e.replace(/S/g,'M')==...con e.split`S`.join`M`==...per salvare un altro byte
Patrick Roberts il

Grazie! z=-1+s/2|0è lì per restituire un numero intero positivo per s == 1 e anche s, ovvero la funzione restituisce false senza che Array () lo blocchi. Altrimenti la logica necessaria lo allungava. Ottimo consiglio su split / join, grazie
Chris M

Buona cattura, non ho considerato il s=1caso, dal momento che la mia regex non valida fallisce silenziosamente.
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$`)

Modifica : Whoa, Arnauld mi ha salvato 6 byte cambiando s.split`\n`.lengthin s.search`\n`! Grazie!

Questo prende una singola stringa multilinea e costruisce una RegExpconvalida basata sulla lunghezza usando la lunghezza della stringa di input. Restituisce trueo false. Assume una finestra valida ha non ha un fine riga.

dimostrazione

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


Bel approccio! Potresti usare al r=s.search('\n')posto di split / length?
Arnauld

@Arnauld fantastico suggerimento, grazie!
Patrick Roberts,

Le parentesi s=>!s.split`S`.join`M`.search([...])possono essere rimosse, senza causare errori di sintassi.
Ismael Miguel,

@IsmaelMiguel corretto, ma poi la stringa viene passata come modello, il che invalida l'implicitoRegExp
Patrick Roberts

Che schifo ... Non me lo aspettavo davvero ...
Ismael Miguel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.