Prelude Syntax-Checker

10

Prelude - это эзотерический язык программирования, который имеет очень мало, но необычных ограничений на то, что составляет действительную программу. Любой блок печатного текста ASCII («блок» означает, что строки печатного ASCII разделены символами новой строки - 0x0A) действительны при условии, что:

  • Каждый (вертикальный) столбец текста содержит не более одного (и ).
  • Не обращая внимания на их вертикальное положение, (и )сбалансированы, то есть каждый (в паре с ровно одним )справа от него, и наоборот.

Напишите программу или функцию, которая, учитывая строку, содержащую печатный ASCII и символы новой строки, определяет, является ли она допустимой программой Prelude. Вы можете получить ввод через STDIN (или ближайшую альтернативу), аргумент командной строки или аргумент функции. Результат может быть возвращен или распечатан в STDOUT, используя любые два фиксированных значения истинности / ложности по вашему выбору.

Вы не должны предполагать, что вход является прямоугольным.

Это код гольф, поэтому выигрывает самое короткое представление (в байтах).

Примеры

Ниже приведены действительные программы Prelude (фактически они даже являются настоящими программами Prelude):

?1-(v  #1)-             
1   0v ^(#    0)(1+0)#)!
    (#)  ^#1-(0 #       
1(#  1) v #  - 1+)
    vv (##^v^+
? v-(0 # ^   #)
?
  1+              1-!

И вот несколько входов, все из которых являются недействительными :

#(#(##)##)##(
)##(##(##)#)#
#(#)
)###
#(##
(##)
(##)
(#)#
(##)
(###
#(#)
(##)
#(#)
###)
#()#
()##
#(#)##
###
###(#)
Мартин Эндер
источник
Есть ли у Prelude комментарии, которые могли бы заблокировать близкого человека?
Алекс А.
@ Алекс Нет. Вышеуказанные правила - это действительно все, что нужно, чтобы решить, является ли программа действительной или нет.
Мартин Эндер
Круто, спасибо за разъяснения. Просто хотел убедиться.
Алекс А.
Правило 1 - «Каждый столбец текста содержит не более одного из (и)»; Пример 1, строка 2: «1 0v ^ (# 0) (1 + 0) #)!» -> Я вижу 3 )и 2 (. Разве это не должно быть только 1 на строку?
Исмаэль Мигель
1
@IsmaelMiguel «столбец» обычно понимается как относящийся к вертикальным линиям (особенно в контексте сеток). Я все-таки разъяснил это.
Мартин Эндер

Ответы:

3

CJam, 57 56 байт

qN/z_{_"()"--W<},,\s:Q,{)Q/({_')/,\'(/,-}:T~\sT0e>+z+}/!

Слишком долго, можно много играть в гольф. Объяснение будет добавлено, как только я пойду в гольф.

Краткое объяснение

В коде есть две проверки:

  • Первый фильтр проверяет, чтобы в каждом столбце было не более 1 скобки. Конечный результат фильтра - это количество столбцов с более чем 1 скобками.
  • Во-вторых, мы конвертируем входные данные в основной формат столбца, а затем разделяем его на каждый индекс на две части.
    • В каждой из этих двух частей ( Number of "(" - Number of ")") должны дополнять друг друга. Поэтому, когда вы добавляете их, это должно привести к 0. Любая часть, которая не имеет этого свойства, заставляет весь ввод иметь несоответствующие скобки.
    • Я также должен убедиться, что "(" слева от ")". Это означает, что значение Number of "(" - Number of ")"не может быть отрицательным для правостороннего блока.

Попробуйте онлайн здесь

оптимизатор
источник
6

Python 2, 128 119 105 байт

def F(p):
 v=n=1
 for r in map(None,*p.split("\n")):A,B=map(r.count,"()");n+=B-A;v*=n<2>A+B
 return n*v>0

Знаете ли вы, что вы можете сопоставить None в Python 2?

объяснение

Мы хотим начать с транспонирования Prelude, чтобы столбцы стали строками. Обычно мы делаем это с помощью zip, но, поскольку zipусекается до самой короткой длины строки и itertools.zip_longestслишком длинны для код-гольфа, кажется, что нет короткого способа сделать то, что мы хотим ...

За исключением картирования None:

>>> print map(None,*[[1,2,3],[4],[5,6]])
[(1, 4, 5), (2, None, 6), (3, None, None)]

К сожалению (или, скорее, к счастью для всех целей, не связанных с гольфом), это работает только в Python 2.

Что касается nи v:

  • nдействует как стек, считая 1 - <number of unmatched '(' remaining>. Для каждого, что (мы видим, мы вычитаем 1, и для каждого, что )мы видим, мы добавляем 1. Следовательно, если n >= 2в какой-то момент мы увидели слишком много )s и программа недействительна. Если nне заканчивается на 1, то у нас есть хотя бы один непревзойденный (остаток.
  • vпроверяет правильность и начинается с 1. Если программа когда-либо является недействительной ( n >= 2или A+B >= 2), то vстановится 0, чтобы отметить недействительность.

Следовательно, если программа действительна, то к концу мы должны иметь n = 1, v = 1. Если программа недействительна, то к концу мы должны либо иметь v = 0, либо v = 1, n <= 0. Поэтому действительность может быть кратко выражена как n*v>0.

(Спасибо @feersum за множество хороших предложений, которые заняли 14 байтов!)

Предыдущее, более читаемое представление:

def F(p):
 p=map(None,*p.split("\n"));v=n=0
 for r in p:R=r.count;A=R("(");B=R(")");n+=A-B;v|=A+B>1or n<0
 return n<1>v
Sp3000
источник
Это безумное использование map...
xnor
1
119 -> 106def F(p): v=n=3 for r in map(None,*p.split("\n")):A,B=map(R.count,"()");n+=A-B;v*=n>2>A+B return n*v==9
feersum
@feersum Спасибо! Я пытался преобразовать orв цепочку сравнения, но я не думал о том, чтобы перейти |=в *=. Тем не менее, снял еще один байт, сделав вещи еще более задом наперед :)
Sp3000
2

J, 64 байта

Ввод - это строка с завершающим переводом строки. Выход 0 или 1.

(0=(1<|s)s+[:(|@{:+(0>])s)[:+/\]s=.+/@:)@(1 _1 0{~[:'()'&i.];.2)

Пример использования

   ]in=.'#(#)##',LF,'###',LF,'###(#)',LF
#(#)##
###
###(#)

   ((0=(1<|s)s+[:(|@{:+(0>])s)[:+/\]s=.+/@:)@(1 _1 0{~[:'()'&i.];.2)) in
0

Метод заключается в следующем

  • вырезать ввод в новых строках и поместить в матрицу ];.2
  • карта (/ )/ anything elseв 1/ -1/0 1 _1 0{~[:'()'&i.]
  • определить s=.+/@:наречие, которое добавляется к глаголу суммы выходных данных массива глаголов
  • добавить значения в столбцах ]s

    • проверьте положительный ()баланс в каждом префиксе [:(0>])s)[:+/\]
    • проверить равный ()баланс во всем списке (т.е. в последнем префиксе) |@{:@]
  • добавьте abs (значения) в столбцы и проверьте для каждого элемента максимальное значение 1 (1<|s)s

  • так как все предыдущие проверки дали положительный результат при неудаче, мы складываем их и сравниваем с 0, чтобы получить достоверность ввода 0=]

randomra
источник
2

J, 56 байт

3 :'*/0<: ::0:(+/\*:b),-.|b=.+/+.^:_1]0|:''()''=/];.2 y'

Это анонимная функция, принимающая строку с завершающим переводом строки и возвращающая 0 или 1. Чтение справа налево:

  • ];.2 yКак и в другом представлении J, вырезает строку yво всех вхождениях своего последнего символа (именно поэтому для ввода требуется завершающий символ новой строки) и создает прямоугольную матрицу, строки которой представляют собой фрагменты, дополненные пробелами при необходимости.

  • '()'=/сначала сравнивает каждый символ в этой матрице, (а затем )возвращает список из двух матриц 0-1.

  • +.^:_1]0|:превращает этот список из двух матриц в одну матрицу комплексных чисел. До сих пор программа превращает каждый (входной элемент в 1, каждый )в i, а каждый другой символ в 0.

  • b=.+/присваивает сумму строк этой сложной матрицы b.

  • -.|bсоставляет список 1- | z | для каждого z в b. Условие, что каждый столбец содержит не более одной круглой скобки, переводится на все эти числа 1- | z | быть неотрицательным.

  • +/\*:bвектор бегущих сумм квадратов чисел в b. Если каждый столбец содержит не более одной круглой скобки, все квадраты чисел в b0, 1 или -1. В ,сцепляет этот вектор с вектором 1- | г | 'с.

  • теперь все, что нам нужно сделать, это проверить, что записи нашего связанного вектора vявляются неотрицательными числами вещественных чисел, это почти так */0<:v, за исключением того, что это вызывает ошибку, если некоторые записи vне являются действительными, поэтому мы заменяем <:на то, <: ::0:что просто возвращает 0 в случае ошибки ,

Омар
источник
Прекрасные идеи с комплексными числами, но вы также должны проверить, если, 0={:+/\*:bнапример (, не действует.
Рандомра
О, ты прав, @randomra, я забыл!
Омар
1
0=(-|)vна 2 байта короче для проверки неотрицательных реалов. (Давайте победим CJam!: P)
randomra
1
Ох, и invвместо того, чтобы ^:_1 сохранить еще один байт.
Рандомра
1
Назад к 56 (с проверкой баланса): 3 :'*/0=({:,]-|)(-.@|,+/\@:*:)+/+.inv]0|:''()''=/];.2 y'.
Рандомра