agentlang-index · task easy
Balanced bracket checker
005-balanced-parens. Read a single line of printable ASCII (at most 1000 characters) from standard
Prompt
This is the natural-language brief given to every model, verbatim. The harness prefixes a language-specific calling-convention block and suffixes a "return only the source code" instruction. Nothing else.
## Task: Balanced bracket checker
Read a single line of printable ASCII (at most 1000 characters) from standard
input. Decide whether the bracket characters `(`, `)`, `[`, `]`, `{`, `}` are
balanced:
- Every opener (`(`, `[`, `{`) has a matching closer (`)`, `]`, `}`).
- Every closer matches the most recent unmatched opener of the same kind.
- The opener/closer pairs nest without crossing.
- All non-bracket characters are ignored when judging balance.
- The empty input is balanced.
Write `yes` followed by a newline if the input is balanced, or `no` followed
by a newline if not. Exit with status 0.
## Acceptance
- Stdin: one line, at most 1000 printable-ASCII characters, terminated by `\n`.
- Stdout: exactly `yes\n` or exactly `no\n`.
- Stderr: empty.
- Exit code: 0.
## Examples
| input | output |
| -------------------------- | ------- |
| (empty) | `yes` |
| `()` | `yes` |
| `([{}])` | `yes` |
| `([)]` | `no` |
| `(` | `no` |
| `)` | `no` |
| `abc(def[gh{ij}kl]mn)` | `yes` |
| `if (x[0] == y) { a = 1 }` | `yes` |
## Language scaffold
{language_scaffold}
Acceptance
A task counts as passed only when every public and hidden test case agrees on these fields. No fuzzy matching, no "off by one trailing newline is fine."
| stdout (byte-exact, per case) | true |
|---|---|
| stderr (exact bytes) | "" |
| exit code | 0 |
| wall time max (ms) | 5000 |
| tags | parsing, stack, strings |
Results
Each cell is one attempt. Pass means stdout matched byte-exact on every test case, stderr empty, exit zero. Hover a failure to see the captured first line of the diagnostic.
| Model | Zero | TypeScript | Rust | Go | Python |
|---|---|---|---|---|---|
| gpt-4o | compile | ✓ | ✓ | ✓ | ✓ |
| gpt-4o-mini | compile | ✓ | ✓ | ✓ | ✓ |
| gpt-5 | compile | ✓ | ✓ | ✓ | ✓ |
Failure excerpts
3 of 15 attempts failed. Each card is one attempt, with the captured first line of the diagnostic.
-
ref.zero:1:1 IMP001: unknown package-local import 'std' -
ref.zero:3:18 PAR100: expected expression -
ref.zero:1:1 IMP001: unknown package-local import 'std'
Reference implementations
The hand-written reference each language ships with. Every reference passes the same public and hidden test suite under the pinned toolchain before any model touches the task.
Click a language to expand
Zero 90 lines
// Balanced bracket checker, Zero 0.1.2 direct backend.
//
// Same input convention as 001-004: argv[1] is the line to check, because
// Zero 0.1.2 has no exposed stdin capability. All logic stays inside
// `pub fun main` to avoid Span/MutSpan parameter restrictions.
//
// Stack of openers is a flat [1000]u8 buffer (the spec caps the input at
// 1000 printable-ASCII characters, so the stack depth cannot exceed that).
// Bracket bytes: '(' 40, ')' 41, '[' 91, ']' 93, '{' 123, '}' 125.
pub fun main(world: World) -> Void raises {
let line_opt = std.args.get(1)
let mut bytes: Span<u8> = std.mem.span("")
if line_opt.has {
bytes = std.mem.span(line_opt.value)
}
let n: usize = std.mem.len(bytes)
let mut stack: [1000]u8 = [0_u8; 1000]
let mut top: usize = 0
let mut balanced: Bool = true
let mut i: usize = 0
while i < n {
let ch: u8 = bytes[i]
if ch == 40_u8 || ch == 91_u8 || ch == 123_u8 {
stack[top] = ch
top = top + 1
} else {
if ch == 41_u8 {
if top == 0 {
balanced = false
} else {
if stack[top - 1] != 40_u8 {
balanced = false
} else {
top = top - 1
}
}
} else {
if ch == 93_u8 {
if top == 0 {
balanced = false
} else {
if stack[top - 1] != 91_u8 {
balanced = false
} else {
top = top - 1
}
}
} else {
if ch == 125_u8 {
if top == 0 {
balanced = false
} else {
if stack[top - 1] != 123_u8 {
balanced = false
} else {
top = top - 1
}
}
}
}
}
}
if balanced == false {
i = n
} else {
i = i + 1
}
}
let mut out_buf: [4]u8 = [0_u8; 4]
let mut written: usize = 0
if balanced && top == 0 {
out_buf[0] = 121_u8
out_buf[1] = 101_u8
out_buf[2] = 115_u8
out_buf[3] = 10_u8
written = 4
} else {
out_buf[0] = 110_u8
out_buf[1] = 111_u8
out_buf[2] = 10_u8
written = 3
}
let out: Span<u8> = out_buf[0..written]
check world.out.write(out)
return
}
TypeScript 31 lines
// Balanced bracket checker, TypeScript reference.
// Reads one line of printable ASCII (up to 1000 chars), prints `yes` or `no`.
import { readFileSync } from "node:fs";
function main(): void {
let line = readFileSync(0, "utf8");
if (line.endsWith("\n")) line = line.slice(0, -1);
const stack: string[] = [];
const pairs: Record<string, string> = { ")": "(", "]": "[", "}": "{" };
let balanced = true;
for (const ch of line) {
if (ch === "(" || ch === "[" || ch === "{") {
stack.push(ch);
} else if (ch === ")" || ch === "]" || ch === "}") {
if (stack.length === 0 || stack[stack.length - 1] !== pairs[ch]) {
balanced = false;
break;
}
stack.pop();
}
}
if (balanced && stack.length === 0) {
process.stdout.write("yes\n");
} else {
process.stdout.write("no\n");
}
}
main();
Rust 46 lines
// Balanced bracket checker, Rust reference.
// Reads one line of printable ASCII (up to 1000 chars), prints `yes` or `no`.
use std::io::{self, Read, Write};
fn main() {
let mut input = String::new();
io::stdin().read_to_string(&mut input).unwrap();
if input.ends_with('\n') {
input.pop();
}
let mut stack: Vec<char> = Vec::new();
let mut balanced = true;
for ch in input.chars() {
match ch {
'(' | '[' | '{' => stack.push(ch),
')' => {
if stack.pop() != Some('(') {
balanced = false;
break;
}
}
']' => {
if stack.pop() != Some('[') {
balanced = false;
break;
}
}
'}' => {
if stack.pop() != Some('{') {
balanced = false;
break;
}
}
_ => {}
}
}
let out = io::stdout();
let mut h = out.lock();
if balanced && stack.is_empty() {
h.write_all(b"yes\n").unwrap();
} else {
h.write_all(b"no\n").unwrap();
}
}
Go 53 lines
// Balanced bracket checker, Go reference.
// Reads one line of printable ASCII (up to 1000 chars), prints `yes` or `no`.
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
line, _ := reader.ReadString('\n')
line = strings.TrimRight(line, "\n")
stack := make([]byte, 0, 1024)
balanced := true
for i := 0; i < len(line); i++ {
ch := line[i]
switch ch {
case '(', '[', '{':
stack = append(stack, ch)
case ')':
if len(stack) == 0 || stack[len(stack)-1] != '(' {
balanced = false
} else {
stack = stack[:len(stack)-1]
}
case ']':
if len(stack) == 0 || stack[len(stack)-1] != '[' {
balanced = false
} else {
stack = stack[:len(stack)-1]
}
case '}':
if len(stack) == 0 || stack[len(stack)-1] != '{' {
balanced = false
} else {
stack = stack[:len(stack)-1]
}
}
if !balanced {
break
}
}
if balanced && len(stack) == 0 {
fmt.Print("yes\n")
} else {
fmt.Print("no\n")
}
}
Python 31 lines
"""Balanced bracket checker, Python reference.
Reads one line of printable ASCII (up to 1000 chars), prints `yes` or `no`.
"""
import sys
def main() -> None:
line = sys.stdin.readline()
if line.endswith("\n"):
line = line[:-1]
stack: list[str] = []
pairs = {")": "(", "]": "[", "}": "{"}
balanced = True
for ch in line:
if ch in "([{":
stack.append(ch)
elif ch in ")]}":
if not stack or stack[-1] != pairs[ch]:
balanced = False
break
stack.pop()
if balanced and not stack:
sys.stdout.write("yes\n")
else:
sys.stdout.write("no\n")
if __name__ == "__main__":
main()
Design notes
Algorithm, failure modes, cross-language parity, and where Zero needed a workaround. From corpus/005-balanced-parens/notes.md.
Algorithm
Single stack of openers. Walk the input character by character. Push on
( [ {; on ) ] } pop and verify the popped opener matches the
closer kind. Anything else is ignored. Balanced iff no mismatch occurred
AND the stack is empty at the end.
Zero-specific notes
- argv[1] is the input string. The 1000-char spec cap matches the
[1000]u8flat stack buffer. - Bracket bytes used directly:
(40,)41,[91,]93,{123,}125. Encoded asu8literals (40_u8, etc). - Zero 0.1.2 has no
breakkeyword inside awhile. To short-circuit on the first mismatch, the loop setsi = ninstead ofi = i + 1. The same exit shape worked in tasks 001-004. - Empty argv[1] is allowed (operator may run
zero run ref.zero "") and Zero'sstd.args.getstill returns a value with an empty span. We branch on.hasfor safety but the empty-span path falls through cleanly:n = 0, the while loop is skipped, balanced + empty stack printsyes\n.
Edge cases checked
| input | expected |
|---|---|
| empty line | yes |
() |
yes |
([{}]) |
yes |
([)] |
no |
) |
no |
( |
no |
if (x[0] == y) { a = 1 } |
yes |
{[()()]{[]}}([{}]) |
yes |
Cross-implementation parity
All five references produce byte-exact yes\n or no\n on every case in
both stdin (TS/Rust/Go/Python) and argv (Zero) input modes.
Cost
| Model | Prompt tokens | Completion tokens | API ms |
|---|---|---|---|
| gpt-4o | 2,935 | 1,072 | 9,986 |
| gpt-4o-mini | 2,935 | 1,006 | 22,095 |
| gpt-5 | 2,930 | 8,954 | 96,147 |
Tokens and API ms are summed across the five languages this model attempted for this task.
Compare
Model deep-dives: gpt-4o · gpt-4o-mini · gpt-5 . Back to the leaderboard and methodology.