Verificador de sintaxe do prelúdio

10

O prelúdio é uma linguagem de programação esotérica, com poucas restrições, mas incomuns, sobre o que constitui um programa válido. Qualquer bloco de texto ASCII imprimível ("bloco" significa que as linhas de ASCII imprimíveis são separadas por novas linhas - 0x0A) é válido desde que:

  • Cada coluna (vertical) de texto contém no máximo um de (e ).
  • Ignorando sua posição vertical, (e )são equilibradas, ou seja, cada uma (é emparelhada com exatamente uma )à direita e vice-versa.

Escreva um programa ou função que, dada uma sequência contendo ASCII imprimível e novas linhas, determine se constitui um programa Prelude válido. Você pode receber informações via STDIN (ou alternativa mais próxima), argumento de linha de comando ou argumento de função. O resultado pode ser retornado ou impresso em STDOUT, usando quaisquer dois valores fixos de verdade / falsidade de sua escolha.

Você não deve assumir que a entrada é retangular.

Isso é código de golfe, então a submissão mais curta (em bytes) vence.

Exemplos

A seguir, são apresentados os programas Prelude válidos (na verdade, são mesmo programas Prelude reais ):

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

E aqui estão algumas entradas, todas inválidas :

#(#(##)##)##(
)##(##(##)#)#
#(#)
)###
#(##
(##)
(##)
(#)#
(##)
(###
#(#)
(##)
#(#)
###)
#()#
()##
#(#)##
###
###(#)
Martin Ender
fonte
O Prelude tem comentários que podem bloquear um parêntese próximo?
Alex A.
@ Alex No. As regras acima são realmente tudo o que há para decidir se um programa é válido ou não.
Martin Ender
Legal, obrigado por esclarecer. Só queria confirmar.
Alex A.
Regra 1 - "Toda coluna de texto contém no máximo um de (e)"; Exemplo 1, linha 2: "1 0v ^ (# 0) (1 + 0) #)!" -> eu vejo 3 )e 2 (. Não deveria ser apenas 1 por linha?
Ismael Miguel
11
@IsmaelMiguel "coluna" é geralmente entendida como se referindo a linhas verticais (especialmente no contexto de grades). Eu esclareci de qualquer maneira, no entanto.
Martin Ender

Respostas:

3

CJam, 57 56 bytes

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

Muito tempo, pode ser jogado muito. Explicação a ser adicionada assim que eu jogar.

Breve explicação

Existem duas verificações no código:

  • O primeiro filtro verifica se cada coluna possui no máximo 1 colchete. A saída final do filtro é o número de colunas com mais de 1 colchetes.
  • Segundo, convertemos a entrada no formato principal da coluna e depois a dividimos em cada índice em duas partes.
    • Em cada uma dessas duas partes, ( Number of "(" - Number of ")") deve estar se elogiando. Portanto, quando você os adiciona, deve resultar em 0. Qualquer parte que falhe nessa propriedade faz com que toda a entrada tenha colchetes não correspondentes.
    • Eu também tenho que ter certeza de que "(" está à esquerda de ")". Isso significa que o valor de Number of "(" - Number of ")"não pode ser negativo para o bloco do lado direito.

Experimente online aqui

Optimizer
fonte
6

Python 2, 128 119 105 bytes

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

Você sabia que pode mapear None no Python 2?

Explicação

Queremos começar pela transposição do Prelude para que as colunas se tornem linhas. Normalmente faríamos isso com isso zip, mas como ziptrunca o menor comprimento de linha e itertools.zip_longesté muito longo para o código-golfe, parece que não há uma maneira curta de fazer o que queremos ...

Exceto pelo mapeamento None:

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

Infelizmente (ou melhor, felizmente para todos os fins que não sejam de golfe), isso só funciona no Python 2.

Quanto ne v:

  • nage como uma pilha, contando 1 - <number of unmatched '(' remaining>. Para cada coisa (que vemos, subtraímos 1 e, para cada coisa )que vemos, adicionamos 1. Portanto, n >= 2a qualquer momento, vimos muitos )seo programa é inválido. Se nnão terminar em 1, temos pelo menos um (restante inigualável .
  • vverifica a validade e começa em 1. Se o programa for inválido ( n >= 2ou A+B >= 2), vserá 0 para marcar a invalidez.

Portanto, se o programa é válido, no final, devemos ter n = 1, v = 1. Se o programa for inválido, no final, devemos ter v = 0ou v = 1, n <= 0. Portanto, a validade pode ser expressa sucintamente como n*v>0.

(Obrigado a @feersum por uma infinidade de boas sugestões que tiraram 14 bytes!)

Envio anterior e mais legível:

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
fonte
Isso é um uso insano de map... #
315
11
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 03/03
@feersum Obrigado! Eu estava tentando mudar o orem comparação encadeamento, mas eu não pensar em mudar |=para *=. Tirou outro byte, porém, fazendo as coisas ainda mais para trás :)
SP3000
2

J, 64 bytes

Entrada é uma sequência com uma nova linha à direita. A saída é 0 ou 1.

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

Exemplo de uso

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

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

O método é o seguinte

  • cortar entrada em novas linhas e colocar em uma matriz ];.2
  • map (/ )/ anything elseem 1/ -1/0 1 _1 0{~[:'()'&i.]
  • definir um s=.+/@:advérbio que adicionado a um verbo soma a saída da matriz de verbos
  • adicionar valores em colunas ]s

    • verifique ()saldo positivo em todos os prefixos [:(0>])s)[:+/\]
    • verifique o ()saldo igual em toda a lista (ou seja, no último prefixo) |@{:@]
  • adicione abs (valores) nas colunas e verifique cada elemento para um valor máximo de 1 (1<|s)s

  • como todas as verificações anteriores tiveram resultados positivos na falha, adicionamos e comparamos com 0 para obter a validade da entrada 0=]

randomra
fonte
2

J, 56 bytes

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

Essa é uma função anônima que aceita uma string com uma nova linha à direita e retorna 0 ou 1. Leitura da direita para a esquerda:

  • ];.2 y, como na outra submissão em J, corta a string yem todas as ocorrências de seu último caractere (é por isso que a entrada precisa de uma nova linha à direita) e cria uma matriz retangular cujas linhas são as peças, preenchidas com espaços, se necessário.

  • '()'=/compara cada caractere naquela matriz primeiro com (e depois )retornando uma lista de duas matrizes 0-1.

  • +.^:_1]0|:transforma essa lista de duas matrizes em uma única matriz de números complexos. Até agora, o programa transforma todos (os dados da entrada em 1, todos os )i e todos os outros caracteres em 0.

  • b=.+/atribui a soma das linhas dessa matriz complexa b.

  • -.|bfaz uma lista de 1- | z | para cada z in b. A condição de que cada coluna contém no máximo um parêntese único se traduz em todos esses números 1- | z | sendo não-negativo.

  • +/\*:bé o vetor de somas em execução dos quadrados dos números em b. Se todas as colunas contiverem no máximo um parêntese, os quadrados dos números bserão todos 0, 1 ou -1. O ,concatena esse vetor com o vetor de 1- | z | 's.

  • Agora, tudo o que precisamos fazer é testar se as entradas do nosso vetor concatenado vsão números reais não negativos, isso é quase */0<:v, exceto que isso causa um erro se algumas entradas de vnão forem reais, então substituímos <:pelo <: ::0:que apenas retorna 0 em caso de erro .

Omar
fonte
Ótimas idéias com números complexos, mas você também precisa verificar se, 0={:+/\*:bpor exemplo, (não é válido.
randomra
Oh, você está certo, @randomra, eu esqueci!
Omar
11
0=(-|)vé 2 bytes mais curto para verificar reais não negativos. (Vamos bater o CJam!: P) #
randomra 26/03
11
Ah, e em invvez de ^:_1 salvar outro byte.
randomra
11
Voltar para 56 (com equilíbrio controlo): 3 :'*/0=({:,]-|)(-.@|,+/\@:*:)+/+.inv]0|:''()''=/];.2 y'.
randomra