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 ZeroTypeScriptRustGoPython
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.

  1. gpt-4o Zero compile
    ref.zero:1:1 IMP001: unknown package-local import 'std'
  2. gpt-4o-mini Zero compile
    ref.zero:3:18 PAR100: expected expression
  3. gpt-5 Zero compile
    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]u8 flat stack buffer.
  • Bracket bytes used directly: ( 40, ) 41, [ 91, ] 93, { 123, } 125. Encoded as u8 literals (40_u8, etc).
  • Zero 0.1.2 has no break keyword inside a while. To short-circuit on the first mismatch, the loop sets i = n instead of i = 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's std.args.get still returns a value with an empty span. We branch on .has for safety but the empty-span path falls through cleanly: n = 0, the while loop is skipped, balanced + empty stack prints yes\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.