# Open or Close the Parentheses

Every phone needs a calculator app. Because of the limited screen real estate, the developer of mine has decided to save some buttons. Instead of having two dedicated bracket buttons - one for open ( and one for close ) - there is just a single bracket button (). It looks something like this: When the button is pressed, it places a bracket. Based on the input given so far, it predicts whether the bracket should be open ( or close ).

By trial and error, I have found the button to follow these rules:

• If there are no unmatched brackets, the next bracket will always be open (.
• Else, if the last character is a numeral 0123456789 or close ) bracket, the next bracket will be close ).
• Else, if the last character is an operator +-*/ or open ( bracket, the next bracket will be open (.

## The challenge

Based on the given input and the rules mentioned above, predict whether the button places an open ( or close ) bracket.

## Input

Either a string, an array of characters, or anything equivalent. The input will only contain the following characters*: 0123456789+-*/()

## Output

An open ( or close ) bracket or any two consistent values representing them.

## Test cases

""                  -> "("
"(1+"               -> "("
"(1+(2/3"           -> ")"
"(1+(2/3)"          -> ")"
"(1+(2/3))-8"       -> "("
"(1+(2/3))-8*("     -> "("
"(1+(2/3))-8*((5"   -> ")"
"(1+(2/3))-8*((5)"  -> ")"
"(1+(2/3))-8*((5))" -> "("


## Scoring

This is , so the shortest answer in each language wins.

### Note

* The actual calculator also includes the symbols .%, but you don't need to care about those.

• May we assume the input won't contain wonky brackets, e.g. )(1+2? Nov 18 at 8:31
• @pxeger Yes, you may. You can expect the input to be typed on the calculator, too. Nov 18 at 8:33
• @Arnauld You can assume that it doesn't contain either. Nov 18 at 9:25
• These rules aren't correct. For example, the expression ((5+2)(7+3)+4)*2 will not be handled correctly. Instead, your rules will output ((5+2))7+3(+4)*2 Nov 18 at 14:36
• @DonThousand That is indeed what the calculator does. If you want to force ((5+2)(7+3)+4)*2, then you have to include a multiplication sign after ((5+2). The rules are fine in my opinion. Nov 18 at 15:35

# JavaScript (Node.js v11.6.0), 48 bytes

a=>/k/.test(eval("try{eval(a+')')}catch(e){e}"))


Try it online!

We try to append a character ')' to the end of expression and eval it. Node v11.6.0 (as current version on TIO) may:

• Calculate the expression if the expression is valid
• The calculate result may only contain characters /[0-9INafinty]/
• Report error SyntaxError: Unexpected token ) if the ) should not be there
• Report error SyntaxError: Unexpected end of input if the ) is valid there

So we just need to check if the result contains letter "k".

# C (clang) on Linux, 827966 62 bytes

c;f(*x){for(c=0;*x;++x)*x&22?:*x&1?--c:++c;c*=*--x&16|*x==41;}


Try it online!

Expects a nul-terminated ASCII wide string (4 bytes per character). Returns false (zero) for open bracket and true (nonzero) for close bracket.

• Thank you to @AZTECCO for golfing off 13 bytes!
• And thank you to @jdt for golfing off 4 more bytes. (This required switching to clang; the original answer was for gcc.)
• @AZTECCO You've been busy! And I had no idea C has an Elvis operator now — that's awesome. Nov 20 at 1:07
• @jdt Very cool. I will include Clang separately, if that's ok with you, since I had gcc originally. Nov 20 at 1:07
• Sorry for noticing now but it fails on higly unbalanced brackets, e.g. "(((((((((((((()", use *= instead of &= to fix it Try it online! btw lol Elvis operator Nov 20 at 5:24
• Thanks, I've updated the answer (and merged them). I also swapped the --c and ++c to keep the results nonnegative, for purely aesthetic reasons. Nov 20 at 5:50
• @ChrisBouchard about the elvis operator: according to Wikipedia leaving out the second operand in the ternary operator is supported as a GCC extension since 2001, so GCC-style C is probably the origin of the elvis operator :-) Nov 21 at 4:33

# 05AB1E, 18 16 bytes

„()S¢Ëžh')«Iθå≠~


-2 bytes by outputting 1 for ( and 0 for ).

Explanation:

„()        # Push string "()"
S       # Convert it to a character-list: ["(",")"]
¢      # Count the "(" and ")" in the (implicit) input-string
Ë     # Check whether both are the same
žh         # Push builtin "0123456789"
')«     '# Append a ")"
Iθ    # Push the last character of the input-string
å≠  # Check that it's NOT in the string "0123456789)"
~          # Bitwise-OR to check if at least one is truthy
# (after which this is output implicitly as result)


# Python 2, 48 bytes

lambda L:"0">cmp(*map(L.count,"()"))*L[-1:]!=")"


Try it online!

Based on @wasif's Python 3 answer; shortened using cmp which is not available in Python 3.

True for "("

False for ")"

# Perl 5 -nMv5.10, 23 bytes

say!/[\d)]$/||eval&&!$@


Try it online!

Prints true/1 for ( and false/empty string for ).

And for eight extra bytes we can print ( and ) like this: Try it online 31 bytes. The eval&&!$@ checks if the input expression have balancing parentheses by using the Perl compiler to check if it compiles. # Vyxal, 16 bytes ‛()$vO≈9ʀ\)J?tc∨


Try it Online!

0 for ( and 1 for )

# GNU AWK, 75 bytes

BEGIN{RS=".|"}RT~/$$/{++n}RT~/$$/{--n}END{print n?RT~/[\)0-9]/?")":"(":"("}


Try it online!

BEGIN{RS=".|"}


Starts reading the input one character at a time, which are stored in the RT variable, by the way.

RT~/$$/{++n} RT~/$$/{--n}


If the character is a (, increments n by one. If it is ), decrements n by one.

END{print
n?
RT~/[\)0-9]/?
")"
:"("
:"("
}


If n equals zero, i.e., there are as many ( as ), prints (. If n is different from zero, evaluates the last character (registered in RT). If it is a number or ), prints a ), otherwise, prints (.

• Nice! Changing the non-BEGIN/END clauses to this n+=(RT=="(")-RT==")"{} seems to work and shaves off 2 chars. Nov 21 at 11:20
• @cnamejj That was a nice idea! But I couldn't make it work without parenthesizing that second comparison, like this: n+=(RT=="(")-(RT==")"){}. Try it online! Nov 21 at 12:09

# JavaScript (ES6),  52  51 bytes

Expects an array of characters. Returns 0 for (, or 1 for ).

a=>a.map(c=>q+=-(d=c>-1,C=c==')')|c<')',q=0)|q&&d|C


Try it online!

### Commented

a =>               // a[] = input array of characters
a.map(c =>         // for each character c in a[]:
q +=             //   update q
-(             //   which keeps track of the balance of parentheses
d = c > -1,  //   d = digit flag
C = c == ')' //   C = closing parenthesis flag
)              //   decrement q if C is set
| c < ')',     //   or increment it if c is '('
) |                // end of map()
q &&               // return 1 if q is not 0 (unbalanced parentheses)
d                  // and the last character was either a digit
| C              // or a closing parenthesis


# Zsh, 39 bytes

Exits truthy if a ( should be inserted, falsy if a ) should be inserted.

eval ${(s..)1//[^()]/;}||${(M)1%[0-9)]}


Try it online!

The eval handles the matching (getting rid of non-() characters, and spawning nested subshells with spaces and ;s to prevent ()() or (( )) from erroring).

The ${(M)1%[0-9)]} simply tries to run the last character of the input as a program if it is in 0123456789), failing. || brings the whole logic together. # TI-Basic, 71 bytes Prompt Str1 For(I,1,length(Str1 sub(Str1,I,1→Str2 O+(Ans="(→O C+(Str2=")→C End 0 If O≠C not(inString("+-*/(",sub(Str1,length(Str1),1 Ans  Output is stored in Ans and displayed. Outputs 0 for ( and 1 for ). # Jelly, 15 14 bytes ċⱮØ(Iɓ”)ØD;faƒ  Try it online! -1 because I actually looked at other solutions and remembered ċ exists Returns falsy (empty list) for open or truthy (nonempty list) for close. Took a hell of a lot of permuting to get here from =€Ø(ISaṪe”)ṭØD¤Ɗ.  ØD; Concatenate "0123456789" and ”) a closing parenthesis. f Keep only its elements which are also elements of ɓ aƒ the input reduced LtR by logical AND starting with: ċⱮØ( Count the opening and closing parentheses in the input, I and subtract the opens from the closes.  # Haskell, 64 bytes o i=elem(last i)"+-*/("||let[o,c]=[[1|c<-i,c==p]|p<-"()"]in o==c  Try it online! • I think this works as another 64-byter, in case there's some opportunity to golf more from there Nov 22 at 22:39 # C# (8.0), 7668 64 bytes -3 bytes thanks to ceilingcat -1 byte thanks to Aaroneous Miller bool p(char[]i)=>i.Sum(x=>x<42?x*2-81:0)==0||i[^1]<48&i[^1]!=41;  Try it online! Takes not-null (but it might be empty) array of characters and outputs true for ( and false for ). Ungolfed: bool p(char[] input){ int sum = input.Where(x=>x<42) // take only brackets .Select(x=>x*2-81) // replace '(' with -1 and ')' with 1 .Sum(); // sum them if(sum == 0) // if sum is 0, brackets are balanced return true; // when left condition in || operator is true the right one isn't checked // this is beneficial for us because it prevents from taking last element // of empty array - empty input will always have balanced brackets char lastChar = i[^1]; // takes last character (this notation requires C# 8.0) return // return true (opening bracket) IF: lastChar < 48 // last char is '/','*','-','+','(' or ')' && // AND lastChar != 41;// last char isn't ')' }  • You can remove the space in (char[] i) Nov 26 at 20:10 # K (ngn/k), 30 bytes {(^"(*+-/"?*|x)>~+/-/x=/:"()"}  Try it online! Returns 0 for "(" and 1 for ")". • ~+/-/x=/:"()" determine whether or not the input contains a balanced number of parenthesis, i.e. that the number of "("s minus the number of ")"s is 0 • (^"(*+-/"?*|x) determine if the last character is one that should be followed by a "(" (i.e. one of "+-*/(") or not • (...)>... use > as material nonimplication (i.e. only return a truthy value if the left side is truthy and the right side isn't) # Charcoal, 18 bytes ∨⁼№θ(№θ)№(*+-/§θ±¹  Try it online! Link is to verbose version of code. Outputs - for (, nothing for ). Pretty output can be obtained by prefixing §)( (equivalent to AtIndex(")(", ...). Explanation: Port of @wasif's Python answer.  № Count of ( Literal ( θ In input string ⁼ Is equal to № Count of ) Literal ) θ In input string ∨ Logical Or № Count of §θ±¹ Last character of input string (*+-/ In literal (*+-/ Implicitly print  • @KevinCruijssen Yeah originally I wrote it with the §)( and then forgot which character was at which index... – Neil Nov 18 at 9:51 • @KevinCruijssen Yeah I noticed your comment on wasif's post, I just wanted the two fixes to be separate edits. – Neil Nov 18 at 10:00 # Retina 0.8.2, 39 bytes (?>($$)|(?<-1>$$)|.)*$(?<-1>(?<=[\d)]))


Try it online! Outputs 0 for ( or 1 for ), but link is to test suite that maps the results for you. Explanation:

echo $t | ./calc echo done  and it will output either ( or ) to stdout for each test string. # Vyxal, 23 bytes k(↔k(øo[tkd\(+$ck($i|\(  Try it Online! k(↔ # When you remove all but () from the input k(øo # Then remove that until there is no change [ # Is there nothing left? \( # If so, opening bracket | # Else... t # Is the last character of the input...$c        # Contained in...
kd\(+          # Digits + (?
k($i # Index that into ()  • noob here, what does "index that into )(" mean? specifically unsure what "indexing" means in this context, or how you can "index" something into a string or list Nov 18 at 14:11 • @thejonymyster in this context, "indexing X into Y" essentially means "get the X'th element of Y" Nov 18 at 17:07 • @Jitse Fixed... Nov 18 at 18:39 • This can probably lose 4 or so bytes with decision-problem output defaults. Nov 21 at 10:08 • @UnrelatedString Yeah, but I can't be boothered fixing it. Nov 21 at 18:47 # Pip, 17 bytes $>^pNa&[\d)]$Na  Takes the partial expression as a command-line argument. Outputs 0 for open parenthesis, 1 for close parenthesis. Replit! Here's a test suite with the closest equivalent program in Pip Classic: Try it online! ### Explanation $>^pNa&[\d)]$Na a is command-line arg; p is "()" (implicit) ^p Split p into a list of two parenthesis characters Na Get the count of each parenthesis in the argument$>                 Fold on > (1 if there are more open than close parens, 0 otherwise)
(Because we "can expect the input to be typed on the calculator,"
there will never be more close than open parens)
&            Logical AND
          The following regex:
[\d)]       Either a digit or a close paren
$followed by end-of-string N Count matches in a The argument  Thus: • If the parentheses are balanced, $> gives 0, which short-circuits the AND and returns 0 (open paren)
• Otherwise:
• If the argument ends with a digit or ), return 1 (close paren)
• If it doesn't, return 0 (open paren)

To get ( and ) as output, wrap the whole thing in (p ... ) for +3 bytes.

• Every time I see pip on Code Golf SE, I wonder for a moment how someone used the Python package manager to solve the challenge. Nov 20 at 1:59
• @ChrisBouchard And I always wonder how it's possible that the Peripheral Interchange Program is Turing-complete.
– Neil
Nov 21 at 9:26

# Ruby, 47 43 bytes

->e{!!e[/[\d)]$/]&&e.count(?()>e.count(?))}  Try it online! Outputs True for ), False for (. • Thanks to @Dingus for the insights and 4 Bytes saved To choose ) two conditions must hold: !!e[/[\d)]$/] # match($at the end) the set of characters [numbers, ')']. And double negate it to transform nil(no match) to false else true e.count(?()>e.count(?)) # open brackets can be equal if balanced, else more than closed ones in which case the second condition is met. • e.count(?()^e.count(?))? Nov 18 at 18:41 • @emanresu A I'm not sure it's acceptable, it return false or 0 for ( and n>0 for ) but false and 0 are not the same like in many other languages, I may also use =~ instead of === to check last char , it would return nil or 0 for (. Thanks anyways Nov 18 at 19:55 • @Dingus no worries, many thanks! Indexing into a regex is insane Nov 18 at 23:42 # PHP (8.0), 110 bytes <?php$a=$argv;$b=ord($a[-1]??''); die($b>=47||$b==41&&substr_count($a,'(')>substr_count($a,')')?')':'(');  Try it online! Ungolfed: <?php$a = $argv; // Get the binary value of the first byte of the last character$lastCharAsciiCode = ord($a[-1] ?? ''); // If the last character in the string is either 0-9 (47-57) OR Closing parenthesis (41) if ($lastCharAsciiCode >= 47 || $lastCharAsciiCode == 41) { // If we have more opening parenthesis than closing, return closing. if (substr_count($a,'(') > substr_count($a,')')) { die(')'); } } // Return opening by default die('(');  • You can golf off 2 bytes by removing the newlines after the semicolons. 108 bytes Nov 20 at 1:35 • Two more suggestions: I don't think you need ?? '' since ord(null) == 0; and you could replace two calls to substr_count with one call to count_chars, which returns an array indexed by character code. 95 bytes Nov 20 at 1:46 • To clarify, ord(null) == ord('') == 0. Nov 20 at 1:54 • @ChrisBouchard The null coalesce is to prevent$a[-1] from throwing an exception in the event that $argv is either an empty string or not passed. I'll have a look at your suggestion for count_chars. Thanks! Nov 22 at 17:52 • I believe accessing an undefined array entry should only be a notice, which is nonfatal. It's up to you, of course, but I don't think advisory messages would be held against you as long as the code produces the correct result. Nov 22 at 19:50 # R, 57 bytes function(x)sum((x=="(")-(x==")"))&&grepl("[)0-9]",rev(x))  Try it online! Input is an array of characters; outputs TRUE if next parenthesis is close ()), FALSE otherwise. # Rust, 107 104 bytes |s:&str|(|(n,x)|n==0||x)(s.chars().fold((0,true),|v,c|(v.0+match c{'('=>1,')'=>-1,_=>0},c<'0'&&c!=')')))  Try it online! true for ( and false for ) ## Ungolfed |s: &str| { // Iterate over all chars, folding from left let (paren_counter, ends_with_op_or_open) = s.chars().fold( (0, true), // Initial value for fold |(n,_), character| ( // Increment for opening braces and decrement for closing ones n + match character { '(' => 1, ')' => -1, _ => 0 }, // true for +-*/( but not for 0123456789) character < '0' && character != ')' ) ); // Return true if parentheses are balanced or the string ends // with an operator or open parenthesis, false otherwise paren_counter == 0 || ends_with_op_or_open }  # Javascript, 90 chars s=>s.replace(/.*?([\d)])?$/,(m,c)=>")("[s.replace(/[()]/g,m=>t+=m=='('||-1,t=0),+!(t&&c)])


## Test:

f=s=>s.replace(/.*?([\d)])?\$/,(m,c)=>")("[s.replace(/[()]/g,m=>t+=m=='('||-1,t=0),+!(t&&c)])

console.log(
""                  -> "("
"(1+"               -> "("
"(1+(2/3"           -> ")"
"(1+(2/3)"          -> ")"
"(1+(2/3))-8"       -> "("
"(1+(2/3))-8*("     -> "("
"(1+(2/3))-8*((5"   -> ")"
"(1+(2/3))-8*((5)"  -> ")"
"(1+(2/3))-8*((5))" -> "("
.split
.filter(x=>x).map(x=>x.match(/"(.*)".*"(.)"/)).map(([,x,r])=>f(x)==r).every(x=>x))

# brainfuck, 73 bytes

,[+>-->[+]+[->+[--->]<<<]<[->>+<<]>>>[->>-<<],]<[,>>]->[+>[>]--<<<++<+]>.


Try it online!

Outputs truthy for ) and falsy for (. Note that this will fail if there are 256 unmatched (.

Version which outputs '(' or ')' (not particularly golfed)

Explanation:

,[                                           ,]                               loop until end of input
+>-->[+]+[->+[--->]<<<]                                                       paren depth calculation: (brute forced black magic)
'(' => 1
')' => 255
'0123456789+-*/' => 0
<[->>+<<]                                              accumulate paren depth counter
>>>[->>-<<]                                   preserve a data cell uniquely identifying last character
<[,>>]                         if depth counter is nonzero move to cell identifying last character
->[+>[>]--<<<++<+]>.     character to final output calculation: (brute forced black magic)
'+-*/(' or \0 => 0
'0123456789)' => nonzero


# MATLAB, 65 bytes

@(x)all([sum(x(x<42)*2-81),feval(@(a,b)a(end)~=b,[0,x],'/*-+(')])


Try it online! Anonymous function. Outputs logical 1 for ) and logical 0 for (.
Monstrosity with eval is required to handle empty input. Without that case it reduces to:

@(x)all([sum(x(x<42)*2-81),x(end)~='/*-+('])


which is much easier to comprehend. Ungolfed:

@(x)all([                                    % all of the conditions must be met
sum(x(x<42)*2-81)                   % brackets are unbalanced
,                  % AND
x(end)~='/        % last character isn't / AND
*-+('   % isn't * AND ... (so on)
])


Checking of bracket unbalance works by taking only brackets in input: x(x<42) and then with multiplication and subtraction transforming ( into -1 and ) into 1. Then sum of these is converted to logical during execution of all - 0 stays logical 0 anything else becomes logical 1.

Omitted in ungolfed version eval additionaly puts 0 before whole input so last character will always exist.

# Core Maude, 206 bytes

mod B is pr LIST{Int}. ops b p : Nat ~> Nat . var A : Nat . var X Y Z :[Nat]. eq
b(nil)= 0 . eq b(X A)= 0 ^((~ A & 16)*(A xor 41)+ 0 ^ p(X A)). eq p(nil)=
0 . eq p(A X)= 0 ^(A & 22)* -1 ^(A & 1)+ p(X). endm


The result is obtained by reducing the b function with the input string given as a list of ASCII code points. The output will be 0 for open bracket and 1 for close bracket.

### Example Session

Maude> --- "" -> "("
> red b(nil) .
result Zero: 0
Maude> --- "(1+" -> "("
> red b(40 49 43) .
result Zero: 0
Maude> --- "(1+(2/3" -> ")"
> red b(40 49 43 40 50 47 51) .
result NzNat: 1
Maude> --- "(1+(2/3)" -> ")"
> red b(40 49 43 40 50 47 51 41) .
result NzNat: 1
Maude> --- "(1+(2/3))-8" -> "("
> red b(40 49 43 40 50 47 51 41 41 45 56) .
result Zero: 0
Maude> --- "(1+(2/3))-8*(" -> "("
> red b(40 49 43 40 50 47 51 41 41 45 56 42 40) .
result Zero: 0
Maude> --- "(1+(2/3))-8*((5" -> ")"
> red b(40 49 43 40 50 47 51 41 41 45 56 42 40 40 53) .
result NzNat: 1
Maude> --- "(1+(2/3))-8*((5)" -> ")"
> red b(40 49 43 40 50 47 51 41 41 45 56 42 40 40 53 41) .
result NzNat: 1
Maude> --- "(1+(2/3))-8*((5))" -> "("
> red b(40 49 43 40 50 47 51 41 41 45 56 42 40 40 53 41 41) .
result Zero: 0


### Ungolfed

mod B is
pr LIST{Int} .

ops b p : Nat ~> Nat .

var A : Nat .
var X Y Z : [Nat] .

eq b(nil) = 0 .
eq b(X A) = 0 ^ ((~ A & 16) * (A xor 41) + 0 ^ p(X A)) .

eq p(nil) = 0 .
eq p(A X) = 0 ^ (A & 22) * -1 ^ (A & 1) + p(X) .
endm


I hope it's not too cheesy to accept input as ASCII code points. Maude has a string module, but it's pretty weak and kind of verbose.

# Ly, 50 bytes

is<l>0sp["("=l+f")"=fp-sp]<")"=!f'0Lfp*l!+!!")"f-o


Try it online!

The algorithm for this one is:

• read in the input, store the last character in a separate stack
• run through all the chars, track ( vs ) balance in a saved cell
• test, last="(" and last<"0"
• combine those three tests (paren balance is the 3rd one) to pick output

There's a caveat though. I don't think Ly can handle null character (as opposed to numeric) input. So it doesn't handle the first test case, which is a null string.

Here's the sausage making...

First part, get input and setup for run

i        - read the input onto the stack as codepoints
s       - save the last char in the backup cell
<l>    - switch stacks, load backup cell, switch back to original stack
0sp - set the backup cell to "0", then delete 0 from stack


Count the ( vs ) chars, keeping a summary count of the balance

[               p] - process one char per iteration, until stack is empty
"("=              - compare top of stack to "("
l+            - load balance summary, increments on match
f           - flip the current character to the top
")"=       - compare top of stack to ")"
fp     - flip current char to the top, delete it
-    - decrement balance summary if char was ")"
s   - save balance summary to backup cell


Third, test the last character of the input.

<            - switch to the stack where we stashed the last char
")"=        - compare to ")"
!       - negate result, we want "not equal"
f      - pull the character to the top of the stack
'0L   - test if less than character codepoint for "0"
fp - pull the char to the top, then delete it


Fourth, combine the tests to get an output choice

*            - compute "and" of the last two tests
l!          - load balance summary, negate
+         - compute "or" of that and the previous test combo
!!       - convert anything ">0" to "1" via double negate
")"f   - add ")" to stack, pull tests results to top
-  - subtract to change char to "(" if called for
o - output top of stack as a character


# Python3, 69 bytes

lambda d:[')','('][len(set(map(d.count,'()')))<2 or d[-1] in '+-*/(']

• Welcome to CG&CC! This can be golfed by 10 bytes by removing unnecessary whitespace and applying a few of our other tips for golfing in Python: Try it online! Additionally, since this is a decision-problem, the final step of indexing into ')(' can simply be skipped. Happy golfing! Nov 27 at 21:07