20
\$\begingroup\$

A "triplet bracket" (that I made up for this challenge) is one of the following:

(...+...)
[...:...]
{...|...}
<...-...>

A balanced triplet bracket string (BTBS for short) is either an empty string, two BTBSes concatenated, or one of the above triplet brackets with each ... replaced with a BTBS.

Your task is to write a program or function that checks whether a string that consists of only (+)[:]{|}<-> is balanced. Shortest code wins.

Examples

Your program should return truthy for the following strings:

(+)(+)(+)
[[[:]:]:(+(+))]{<->|<(+)->[:]}(+)
<<<<<<<<<<<<->->->->->->->->->->->->
{|(+[:<-{|(+[:<->])}>])}
[[[:]:[:]]:[[:]:[:]]]
{[:](+)|<->{|}}[(+)<->:{|}(+)]

Your program should return falsy for the following strings:

:[
<|>
(+(+)
[:][:](+[[:]):]
{|{|{|(+{|{|{|}}}}}+)}[:]{|}
{{||}}
<<->-<->-<->>
[(+):((+)+)+(+(+))]
<<<<<->->->->->->
\$\endgroup\$
2
  • \$\begingroup\$ Is (|) valid. I don't think so, but I'm not sure \$\endgroup\$ Commented Oct 22, 2016 at 12:37
  • \$\begingroup\$ @RomanGräf No, as <|> in the falsy examples. \$\endgroup\$
    – jimmy23013
    Commented Oct 23, 2016 at 7:14

9 Answers 9

14
\$\begingroup\$

JavaScript (ES6), 77 58 57 56 bytes

f=s=>s==(s=s.replace(/\(\+\)|\[:]|{\|}|<->/,''))?!s:f(s)

Test cases

f=s=>s==(s=s.replace(/\(\+\)|\[:]|{\|}|<->/,''))?!s:f(s)

console.log("Testing truthy values");
console.log(f("(+)(+)(+)"));
console.log(f("[[[:]:]:(+(+))]{<->|<(+)->[:]}(+)"));
console.log(f("<<<<<<<<<<<<->->->->->->->->->->->->"));
console.log(f("{|(+[:<-{|(+[:<->])}>])}"));
console.log(f("[[[:]:[:]]:[[:]:[:]]]"));
console.log(f("{[:](+)|<->{|}}[(+)<->:{|}(+)]"));

console.log("Testing falsy values");
console.log(f(":["));
console.log(f("<|>"));
console.log(f("(+(+)"));
console.log(f("[:][:](+[[:]):]"));
console.log(f("{|{|{|(+{|{|{|}}}}}+)}[:]{|}"));
console.log(f("{{||}}"));
console.log(f("<<->-<->-<->>"));
console.log(f("[(+):((+)+)+(+(+))]"));
console.log(f("<<<<<->->->->->->"));

\$\endgroup\$
6
  • 2
    \$\begingroup\$ The same idea in Retina is 26 bytes (the first line just makes it a test suite): retina.tryitonline.net/… \$\endgroup\$ Commented Oct 22, 2016 at 11:17
  • 1
    \$\begingroup\$ And 39 with perl : perl -lpe 's/<->|\(\+\)|{\|}|\[:]//&&redo;$_=!$_'. \$\endgroup\$
    – Dada
    Commented Oct 22, 2016 at 11:33
  • \$\begingroup\$ @Dada That will consider 0 a BTBS. Use this 38 instead: perl -pe 's/<->|\(\+\)|{\|}|\[:]//&&redo;$_=/^$/' \$\endgroup\$
    – Ton Hospel
    Commented Oct 22, 2016 at 11:45
  • \$\begingroup\$ @TonHospel Didn't thought of that, indeed.. thanks for pointing it out! (feel free to post it if you want by the way, or at least don't hold back because of me) \$\endgroup\$
    – Dada
    Commented Oct 22, 2016 at 11:48
  • \$\begingroup\$ That S/s mix was slightly confusing, perhaps f=s=>s==(s=s.replace(...))?!s:f(s)? \$\endgroup\$
    – Neil
    Commented Oct 23, 2016 at 10:25
5
\$\begingroup\$

sed, 28 27 bytes

:
s#(+)\|\[:]\|{|}\|<->##
t

sed doesn't have a concept of truthy/falsy, so I'm considering an empty string truthy and a non-empty string falsy. This checks out if we consider the conditional /^$/.

Thanks to @Neil for golfing off 1 byte!

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ For once, BRE is actually an advantage. \$\endgroup\$
    – Dennis
    Commented Oct 22, 2016 at 15:23
  • \$\begingroup\$ Do you need the \] or does ] suffice? \$\endgroup\$
    – Neil
    Commented Oct 23, 2016 at 10:26
4
\$\begingroup\$

Python, 77 bytes

lambda s:eval("s"+".replace('%s','')"*4%('(+)','[:]','{|}','<->')*len(s))==''

Uses Arnauld's replacement idea. Generates and evaluates a long string like

s.replace('(+)','').replace('[:]','').replace('{|}','').replace('<->','').replace('(+)','').replace('[:]','').replace('{|}','').replace('<->','')

to cycle between replacing all the bracket types. Then, checks if the result is the empty string.

\$\endgroup\$
3
\$\begingroup\$

Mathematica, 55 bytes

StringDelete["(+)"|"[:]"|"{|}"|"<->"]~FixedPoint~#==""&

Anonymous function. Takes a string as input and returns True or False as output. Uses the standard method for doing this.

\$\endgroup\$
2
\$\begingroup\$

Grime, 39 bytes

e`\(_\+_\)|\[_\:_\]|\{_\|_\}|\<_\-_\>v*

Try it online! Sadly, the TIO version runs out of memory on most of the test cases.

Explanation

Nothing too fancy here. _ is shorthand for the entire pattern, and v* is the same as *, but with lower precedence.

e`                                       Match entire input against this pattern:
  \(_\+_\)                               '(', match of _, '+', match of _, ')'
          |                              or
           \[_\:_\]|\{_\|_\}|\<_\-_\>    same for the other bracket types
                                     v*  repeated 0-∞ times
\$\endgroup\$
2
\$\begingroup\$

J, 48 bytes

a:=([:delstring&.>/'(+)';'[:]';'{|}';'<->';])^:_

Similar to the others, this is also based on Arnauld's method.

Usage

   f =: a:=([:delstring&.>/'(+)';'[:]';'{|}';'<->';])^:_
   f '(+)(+)(+)'
1
   f '[[[:]:]:(+(+))]{<->|<(+)->[:]}(+)'
1
   f '<<<<<<<<<<<<->->->->->->->->->->->->'
1
   f '<|>'
0
   f '[:][:](+[[:]):]'
0
   f '{|{|{|(+{|{|{|}}}}}+)}[:]{|}'
0

Explanation

a:=([:delstring&.>/'(+)';'[:]';'{|}';'<->';])^:_  Input: string S
   (                                        )^:_  Repeat until convergence
                                         ]          Get S
                 '(+)';'[:]';'{|}';'<->';           Append to ['(+)', '[:]', '{|}', '<->']
    [:delstring&.>/                                 Reduce right-to-left by deleting
                                                    occurrences of each string on the
                                                    left from the right
                                                    Return the final string as the new S
a:=                                               Test if the final value of S is empty
\$\endgroup\$
1
\$\begingroup\$

Japt, 25 bytes

!Ue"%(%+%)|%[:]|\{%|}|<->

Test it online!

e on strings is a recursive-replace function. The second parameter defaults to the empty string, which means this recursively removes matches of the Japt regex "%(%+%)|%[:]|\{%|}|<->" (in regular terms, /\(\+\)|\[:]|{\|}|<->/). This returns an empty string for balanced triplet strings and a non-empty string for non-balanced, so the correct return value is the logical NOT of this.

\$\endgroup\$
1
\$\begingroup\$

Pip, 26 bytes

L#aaR:"(+)[:]{|}<->"<>3x!a

Try it online!

Loops len(a) times, replacing all occurrences of empty triplet brackets ("(+)[:]{|}<->"<>3, where <> is the "group" operator, => ["(+)"; "[:]"; "{|}"; "<->"]) with empty string (x). This many iterations is overkill, but it will always be more than enough to completely reduce all properly formed triplet brackets to nothing. After the loop completes, outputs !a: 0 if a is truthy (still has some characters), 1 if a is falsey (empty).

\$\endgroup\$
0
\$\begingroup\$

Scala, 96 bytes

def&(s:String):Any={val t=s.replaceAll(raw"\(\+\)|\[:]|\{\|}|<->","")
if(t==s)t.size<1 else&(t)}

This is basically the same idea as the other answers, but with some scala boilerplate.

without stealing ideas from others (188 bytes):

import scala.util.parsing.combinator._
val a = new RegexParsers{def r:Parser[_]="("~r~"+"~r~")"|"["~r~":"~r~"]"|"{"~r~"|"~r~"}"|"<"~r~"-"~r~">"|""
def!(s:String)= !parseAll(r,s).isEmpty}!_
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.