Виявити вікна мистецтва ASCII, виконані з символів M і S


28

Вікно - це квадрат ASCII-мистецтва з непарною стороною не менше 3, з одинарною облямівкою по краю, а також вертикальними та горизонтальними штрихами посередині:

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

MS Window - це вікно, де рамка складається лише з символів Mта S. Ваше завдання - написати програму (або функцію), яка займає рядок і виводить триєдине значення, якщо вхід є дійсним вікном MS, і значення фальси, якщо його немає.

Технічні умови

  • Ви можете взяти вхід як рядок, розділений новим рядком, або масив рядків, що представляють кожен рядок.
  • Межа вікна MS може містити поєднання символів M і S, але внутрішня сторінка завжди буде складатися з пробілів.
  • Ви можете визначити лише вікна з останніми рядками або лише вікна без зворотних рядків, але не обидва.

Випробування

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

Фальсі:

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
Це чудовий поворот мистецтва ASCII, проблема вирішення виявлення певної структури.
xnor

4
@xnor Мені здається, що ми могли б хотіти іншого тегу для зворотного мистецтва ASCII, як це.
Esolanging Fruit

2
Хоча це не стосується мистецтва ascii, відповідність шаблонів може стати хорошим вибором для нового тегу
Destructible Lemon

Чи можете ви додати тестовий чи два випадки, коли рядок не утворює прямокутний масив?
Грег Мартін

1
@Mast, ви цілком праві! Можливо, виклик потребує уточнення
Кріс М

Відповіді:


1

Пайк, 34 31 байт

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

Спробуйте тут!

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 байт

Завдяки Zgarb за збереження 1 байта.

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

Спробуйте в Інтернеті!

Я не впевнений, чи існує простіший спосіб застосувати співвідношення квадратних сторін окремих компонентів вікна, ніж використання рекурсивного нетерміналу, але це, здається, працює досить добре.

Пояснення

Найкраще читати програму знизу вгору.

W=[MS

Це просто визначає нетермінал (який можна думати як підпрограму, що відповідає прямокутнику), Wщо відповідає або Mабо, і S(неявно ]в кінці рядка).

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

Це визначає нетермінальний, Bякий відповідає приблизно чверті виводу, тобто одна панель вікон з лівою та верхньою межею. Щось на зразок цього:

MSM
S  
M  

Для того, щоб ця панель вікон була квадратною, ми визначаємо Bрекурсивно. Це або символ вікна W, або він B/W\ * W/\ /*додає один шар праворуч і знизу. Щоб побачити, як це робиться, давайте видалимо трохи синтаксичного цукру:

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

Це те саме, тому що горизонтальне конкатенацію можна записати або, ABабо A B, але остання має нижчий пріоритет, ніж вертикальна конкатенація, /тоді як для першої має вищу. Так B/W[ ]*само і Bз символом вікна та рядом пробілів внизу. А потім горизонтально додаємо, W/[ ]/*який є символом вікна зі стовпцем пробілів.

Нарешті, ми збираємо ці нетермінали в остаточну форму вікна:

BB/BB/W+ W/+

Це чотири віконні панелі, Bза якими слідує ряд символів вікна та стовпець символів вікна. Зауважимо, що ми не робимо явного твердження, що чотири віконні панелі однакового розміру, але якщо вони не є, неможливо об'єднати їх у прямокутник.

Нарешті, e`на початку - це просто конфігурація, яка наказує Grime перевірити, чи може весь вхід відповідати цьому шаблону (і він друкує 0або 1відповідно).


5

JavaScript (ES6), 115 113 байт

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

Приймає введення як масив масивів символів (додайте 5 байт для масиву рядків) і повертає 1або 0. Після перевірки, що висота непарна, кожен рядок перевіряється, щоб масив був квадратним, і кожен символ перевіряється як один із символів, які ми очікуємо в цій конкретній позиції. Редагувати: збережено 2 байти завдяки @PatrickRoberts.


Ви можете змінити, (...).includes(c)щоб ~(...).search(c)зберегти 1 байт
Патрік Робертс

1
Насправді, навіть краще, ви можете змінити його, щоб (...?/ /:/[MS]/).test(c)зберегти 2 байти замість всього 1.
Патрік Робертс

@PatrickRoberts Симпатичний, спасибі!
Ніл

5

Perl, 124 123 119 95 93 84

Наведений нижче скрипт Perl читає один кандидат MS MS зі стандартного вводу. Потім він закінчується з нульовим статусом виходу, якщо кандидатом є вікно MS та з ненульовим статусом виходу, якщо його немає.

Він працює, генеруючи два регулярних вирази, по одному для верхнього, середнього та нижнього рядка та по одному для кожного іншого рядка та перевіряючи вхід проти них.

Дякую, @Dada. І знову.

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

Я не впевнений, що давати результат, оскільки статус виходу дозволено (однак у мене немає часу шукати відповідний мета-пост). Незалежно від цього, ви можете зберегти кілька байтів:@a=<>;$s=$"x(($.-3)/2);$m="[MS]";map{$a[$_]!~($_%($./2)?"$m$s$m$s$m":"$m${m}{$.}")&&die}0..--$.
Дада,

@Dada: Дякую! Це вражаюче поліпшення: 24 символи. (У вашому коді був бродячий "$ m", тож він навіть коротший, ніж це виглядало спочатку.) Я не був впевнений, чи дозволено повідомлення про результат із кодом виходу, але я взяв "написати програму ( або функція) "як дозволяє бути гнучким у тому, як результат повертається в цьому конкретному випадку; Вихідні коди - це практично повернені значення середовища * nix. :-)
nwk

Зробіть це 26 символів.
nwk

1
Насправді я декрементую $.в кінці, щоб уникнути використання двічі $.-1(тим більше, що вперше це було ($.-1)/2так, що потрібні були додаткові дужки), так що $mв $m${m}{$.}не помилка. Крім того, я щойно зрозумів, але регулярні вирази повинні бути оточені ^...$(тому зайві символи в кінці або на початку роблять їх невдалими) або коротше: використовувати neзамість !~.
Дада

Не забувайте, явно ви не можете використовувати neзамість цього !~(я не повинен писати повідомлення, коли я прокинувся всього 15 хвилин!). Тож вам доведеться використовувати ^...$в обох регулярних виразах.
Дада

2

Математика, 166 байт

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

Без імені функція приймає список списків символів в якості вхідних даних і повернення Trueабо False. Ось менш гофрована версія:

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

Перший рядок визначає функцію t, яка відокремлює список довжини dна дві частини, перша з яких - перша, середина та остання записи списку, а друга - всі інші. Другий рядок перевіряє, чи вхід є квадратним масивом в першу чергу. Четвертий рядок використовує tдвічі, один раз на самому вході та один раз на всіх * рядків у вході, щоб відокремити символи, які повинні бути "M"або "S"від символів, які повинні бути пробілами; то п'ятий та сьомий рядки перевіряють, чи справді вони є такими, якими вони повинні бути.


2

JavaScript (ES6), 108 106 байт

Вхід: масив рядків / вихід: 0або1

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)

Тестові справи


2

JavaScript (ES6), 140 138 141 140 байт

Я знаю, що це не виграшний байт (хоча завдяки Патріку Робертсу за -3, і я зрозумів, що він кинув помилкові позитиви для 1 замість M / S: +3), але я це зробив трохи по-іншому, я новачок у цьому, і це було весело ...

Приймає масив рядків, по одному для кожного рядка, і повертає true або false. Новий рядок додано для наочності (не включається до складу байтів).

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

Замість того, щоб перевіряти вхід на узагальнену схему, я будую вікно 'M' однакового розміру, замінюю S на M на вході та порівнюю два.

Безумовно

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

Тестові справи

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
Для подальшого ознайомлення, якщо функція не є рекурсивною, f=не потрібно включати в число байтів, тому це фактично подання 138 байт.
Патрік Робертс

Ви можете замінити z=-1+s/2|0з , z=(s-3)/2щоб зберегти 1 байт
Патрік Робертс

Крім того, можна замінити e.replace(/S/g,'M')==...з , e.split`S`.join`M`==...щоб зберегти інші байти
Патрік Робертс

Спасибі! z=-1+s/2|0чи є повернути додатне ціле число для s == 1 і навіть s, тобто функція повертає false, без того, як Array () збиває його. Інакше необхідна логіка зробила це довше. Чудова порада про розділення / приєднання, спасибі
Кріс М

Хороший улов, я не розглядав s=1справу, оскільки мій недійсний регулярний вираз просто мовчки виходить з ладу.
Патрік Робертс

1

JavaScript (ES6), 109 107 106 105 99 байт

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

Редагувати : О, Арнольд врятував мені 6 байт, змінивши s.split`\n`.lengthна s.search`\n`! Спасибі!

Це займає одну багаторядкову рядок і будує RegExpвалідацію на основі базису, використовуючи довжину вхідного рядка. Повертається trueабо false. Передбачає дійсне вікно має НЕ символ кінця рядка.

Демо

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


Гарний підхід! Чи можете ви використовувати r=s.search('\n')замість split / length?
Арнольд

@Arnauld дивовижна пропозиція, дякую!
Патрік Робертс

Круглі дужки s=>!s.split`S`.join`M`.search([...])можна видалити, не викликаючи синтаксичних помилок.
Ісмаїл Мігель

@IsmaelMiguel правильний, але потім рядок передається як шаблон, який скасовує неявнеRegExp
Патрік Робертс

Це відстійно ... Я насправді цього не очікував ...
Ісмаель Мігель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.