Prelude Syntax-Checker
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
Did you know that you can map None in Python 2?
Explanation
We want to start by transposing the Prelude so that columns become rows. Usually we would do this with zip
, but since zip
truncates to the shortest row length and itertools.zip_longest
is far too long for code-golf, it seems like there's no short way to do what we want...
Except for mapping None
:
>>> print map(None,*[[1,2,3],[4],[5,6]])
[(1, 4, 5), (2, None, 6), (3, None, None)]
Unfortunately (or rather, fortunately for all non-golf purposes), this only works in Python 2.
As for n
and v
:
n
acts like a stack, counting1 - <number of unmatched '(' remaining>
. For every(
we see we subtract 1, and for every)
we see we add 1. Hence ifn >= 2
at any point, then we've seen too many)
s and the program is invalid. Ifn
doesn't finish on 1, then we have at least one unmatched(
remaining.v
checks validity, and starts at 1. If the program is ever invalid (n >= 2
orA+B >= 2
), thenv
becomes 0 to mark invalidity.
Hence if the program is valid, then by the end we must have n = 1, v = 1
. If the program is invalid, then by the end we must either have v = 0
, or v = 1, n <= 0
. Therefore validity can be succinctly expressed as n*v>0
.
(Thanks to @feersum for a multitude of good suggestions which took off 14 bytes!)
Previous, more readable submission:
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
CJam, 57 56 bytes
qN/z_{_"()"--W<},,\s:Q,{)Q/({_')/,\'(/,-}:T~\sT0e>+z+}/!
Too long, can be golfed a lot. Explanation to be added once I golf it.
Brief explanation
There are two checks in the code:
- First filter checks that each column as at most 1 bracket. The final output of the filter is the number of columns with more than 1 brackets.
- Second we convert the input into column major format and then split it on each index into two parts.
- In each of these two parts, (
Number of "(" - Number of ")"
) should be complimenting each other. So when you add them up, it should result to 0. Any part that fails this property makes the whole input have non matching brackets. - I also have to make sure that "(" are to the left of ")". This means that the value of
Number of "(" - Number of ")"
cannot be negative for the right side block.
- In each of these two parts, (
Try it online here
J, 64 bytes
Input is a string with a trailing newline. Output is 0 or 1.
(0=(1<|s)s+[:(|@{:+(0>])s)[:+/\]s=.+/@:)@(1 _1 0{~[:'()'&i.];.2)
Example usage
]in=.'#(#)##',LF,'###',LF,'###(#)',LF
#(#)##
###
###(#)
((0=(1<|s)s+[:(|@{:+(0>])s)[:+/\]s=.+/@:)@(1 _1 0{~[:'()'&i.];.2)) in
0
The method is the following
- cut input at newlines and put into a matrix
];.2
- map
(
/)
/anything else
into1
/-1
/0
1 _1 0{~[:'()'&i.]
- define an
s=.+/@:
adverb which added to a verb sums the verbs array output add values in columns
]s
- check positive
()
balance in every prefix[:(0>])s)[:+/\]
- check equal
()
balance in the whole list (i.e. in the last prefix)|@{:@]
- check positive
add abs(values) in columns and check every element for a max value of 1
(1<|s)s
as all the previous checks yielded positive at failure we add them up and compare to 0 to get the validity of the input
0=]