Run an n-line program written in a tiny language, line by line. At the start only the outermost block is open. Each line is one of:
- {: open a new block (inside the current one).
- }: close the innermost block. Every name declared in it disappears, and any outer name it was hiding becomes visible again.
- let x v: declare variable x with value v in the current block. If an outer block has the same name, this one hides it until this block closes.
- const x v: like let, but x is a constant.
- set x v: store v in the x that is visible now (the x in the innermost block that has one). If that x is a constant, nothing changes. It never creates a new name.
- print x: print the value of the visible x on its own line.
Nothing except print produces output (with no print at all, the output is empty).
Input
First line n (1 ≤ n ≤ 1000), then n command lines. Names are 1 to 10 lowercase letters, -10^9 ≤ v ≤ 10^9. The outermost block is never closed, and at most 100 blocks are open at once. A name is never declared twice in the same block, and the names in set and print are always visible.
Output
One line per print
Example 1 · stdin
11
let x 1
const y 2
{
let x 10
set y 5
set x 11
print x
print y
}
print x
set x -3
stdout
11
2
1
main.py
Error List00F8 ↓ · ⇧F8 ↑
Input (stdin)
When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).
$ Ready
Open this on a computer to write and run code. On mobile you can read the problem and the solutions.
In other languagesShow solutions by language · 8 languages
Block scope differs between languages. JS/TS let/const and local variables in C/C++ make a new name per block as in this problem, and an inner block may hide an outer name (old JS var ignores blocks and is one per function). Java and C# reject redeclaring, in an inner block, a local that is still alive (Java "already defined", C# CS0136). In Python if and for do not create a scope; only functions do. So handling everything with one dictionary, ignoring blocks, lets the inner let x 10 overwrite the outer x. In Craykon a variable first made inside a block is not visible outside it, but assigning to a name that already exists outside changes the outer variable (there is no separate shadowing declaration). Constants differ too: real languages refuse a second assignment (JS TypeError at run time, TS TS2588, compile errors for Java final, C# const and C/C++ const; Python does not stop it, and Craykon has no constants). In this problem it is silently ignored. The solution is a stack with one dictionary per block (Python dict, JS/TS Map, Java HashMap, C# Dictionary, C++ unordered_map, Craykon Dict()). C has no map, so push declarations onto an array with their block depth and drop them at }. Trap: search from the innermost block (the end of the stack). Searching from the outside, not dropping a block's names at }, or treating set as 'add to the current block' (which is what assignment inside a Python function does) gives wrong values after a block closes.
Pythonmain.py · 25 lines
# 블록마다 사전 하나: 이름 → [값, 상수인가]. 맨 끝이 지금 블록scopes = [{}]def find(name): for scope in reversed(scopes): # 안쪽 블록부터 if name in scope: return scope[name]n = int(input())for _ in range(n): cmd, *rest = input().split() if cmd == "{": scopes.append({}) elif cmd == "}": scopes.pop() elif cmd in ("let", "const"): scopes[-1][rest[0]] = [int(rest[1]), cmd == "const"] elif cmd == "set": var = find(rest[0]) if not var[1]: var[0] = int(rest[1]) else: print(find(rest[0])[0])
JavaScriptmain.js · 24 lines
const lines = require("fs").readFileSync(0, "utf8").split("\n");// 블록마다 Map 하나: 이름 → { value, isConst }. 맨 끝이 지금 블록const scopes = [new Map()];function find(name) { for (let i = scopes.length - 1; i >= 0; i--) { if (scopes[i].has(name)) return scopes[i].get(name); }}const n = Number(lines[0]);const out = [];for (let i = 1; i <= n; i++) { const [cmd, name, v] = lines[i].trim().split(" "); if (cmd === "{") scopes.push(new Map()); else if (cmd === "}") scopes.pop(); else if (cmd === "let" || cmd === "const") scopes.at(-1).set(name, { value: Number(v), isConst: cmd === "const" }); else if (cmd === "set") { const entry = find(name); if (!entry.isConst) entry.value = Number(v); } else out.push(find(name).value);}console.log(out.join("\n"));
TypeScriptmain.ts · 32 lines
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");interface Entry { value: number; readonly isConst: boolean;}// 블록마다 Map 하나. 맨 끝이 지금 블록const scopes: Map<string, Entry>[] = [new Map()];function find(name: string): Entry { for (let i = scopes.length - 1; i >= 0; i--) { const entry = scopes[i].get(name); if (entry !== undefined) return entry; } throw new Error(`${name} is not declared`); // 문제에서 일어나지 않는다}const n: number = Number(lines[0]);const out: number[] = [];for (let i = 1; i <= n; i++) { const [cmd, name, v] = lines[i].trim().split(" "); if (cmd === "{") scopes.push(new Map()); else if (cmd === "}") scopes.pop(); else if (cmd === "let" || cmd === "const") scopes[scopes.length - 1].set(name, { value: Number(v), isConst: cmd === "const" }); else if (cmd === "set") { const entry = find(name); if (!entry.isConst) entry.value = Number(v); } else out.push(find(name).value);}console.log(out.join("\n"));
JavaMain.java · 51 lines
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class Main { static class Entry { int value; final boolean isConst; Entry(int value, boolean isConst) { this.value = value; this.isConst = isConst; } } // 블록마다 HashMap 하나. 맨 끝이 지금 블록 static final List<Map<String, Entry>> scopes = new ArrayList<>(); static Entry find(String name) { for (int i = scopes.size() - 1; i >= 0; i--) { Entry e = scopes.get(i).get(name); if (e != null) return e; } return null; // 문제에서 일어나지 않는다 } public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine().trim()); scopes.add(new HashMap<>()); StringBuilder out = new StringBuilder(); for (int i = 0; i < n; i++) { String[] p = br.readLine().trim().split(" "); switch (p[0]) { case "{" -> scopes.add(new HashMap<>()); case "}" -> scopes.remove(scopes.size() - 1); case "let", "const" -> scopes.get(scopes.size() - 1).put(p[1], new Entry(Integer.parseInt(p[2]), p[0].equals("const"))); case "set" -> { Entry e = find(p[1]); if (!e.isConst) e.value = Integer.parseInt(p[2]); } default -> out.append(find(p[1]).value).append('\n'); } } System.out.print(out); }}
C#Main.cs · 46 lines
using System;using System.Collections.Generic;using System.Text;class Entry{ public int Value; public readonly bool IsConst; public Entry(int value, bool isConst) { Value = value; IsConst = isConst; }}class Program{ // 블록마다 Dictionary 하나. 맨 끝이 지금 블록 static readonly List<Dictionary<string, Entry>> scopes = new() { new() }; static Entry Find(string name) { for (int i = scopes.Count - 1; i >= 0; i--) if (scopes[i].TryGetValue(name, out Entry e)) return e; return null; // 문제에서 일어나지 않는다 } static void Main() { int n = int.Parse(Console.ReadLine()); var sb = new StringBuilder(); for (int i = 0; i < n; i++) { string[] p = Console.ReadLine().Trim().Split(' '); switch (p[0]) { case "{": scopes.Add(new()); break; case "}": scopes.RemoveAt(scopes.Count - 1); break; case "let": case "const": scopes[^1][p[1]] = new Entry(int.Parse(p[2]), p[0] == "const"); break; case "set": Entry e = Find(p[1]); if (!e.IsConst) e.Value = int.Parse(p[2]); break; default: sb.Append(Find(p[1]).Value).Append('\n'); break; } } Console.Write(sb); }}
C++main.cpp · 45 lines
#include <iostream>#include <string>#include <unordered_map>#include <vector>struct Var { int value; bool isConst;};// 블록마다 사전 하나. back()이 지금 블록std::vector<std::unordered_map<std::string, Var>> scopes(1);Var* find(const std::string& name) { for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) { auto found = it->find(name); if (found != it->end()) return &found->second; } return nullptr; // 문제에서 일어나지 않는다}int main() { int n; std::cin >> n; for (int i = 0; i < n; i++) { std::string cmd, name; int v; std::cin >> cmd; if (cmd == "{") { scopes.emplace_back(); } else if (cmd == "}") { scopes.pop_back(); } else if (cmd == "let" || cmd == "const") { std::cin >> name >> v; scopes.back()[name] = Var{v, cmd == "const"}; } else if (cmd == "set") { std::cin >> name >> v; Var* p = find(name); if (!p->isConst) p->value = v; } else { std::cin >> name; std::cout << find(name)->value << '\n'; } }}
Cmain.c · 51 lines
#include <stdio.h>#include <string.h>/* C에는 사전이 없다: 선언을 차례로 쌓고, 블록이 닫히면 그 블록 것만 걷어 낸다 */struct Var { char name[11]; int value; int is_const; int depth;};static struct Var vars[1000];static int count = 0;/* 맨 뒤(가장 안쪽)부터 찾는다 */static struct Var *find(const char *name) { for (int i = count - 1; i >= 0; i--) if (strcmp(vars[i].name, name) == 0) return &vars[i]; return NULL; /* 문제에서 일어나지 않는다 */}int main(void) { int n, depth = 0; char cmd[8], name[11]; int v; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%7s", cmd); if (strcmp(cmd, "{") == 0) { depth++; } else if (strcmp(cmd, "}") == 0) { while (count > 0 && vars[count - 1].depth == depth) count--; depth--; } else if (strcmp(cmd, "let") == 0 || strcmp(cmd, "const") == 0) { scanf("%10s %d", name, &v); struct Var *p = &vars[count++]; strcpy(p->name, name); p->value = v; p->is_const = cmd[0] == 'c'; p->depth = depth; } else if (strcmp(cmd, "set") == 0) { scanf("%10s %d", name, &v); struct Var *p = find(name); if (!p->is_const) p->value = v; } else { scanf("%10s", name); printf("%d\n", find(name)->value); } } return 0;}
Craykonmain.cray · 49 lines
// 블록마다 사전 두 개: 값과 '상수인가'. 맨 끝이 지금 블록이다값들 = [Dict()];상수들 = [Dict()];// 이름을 가진 가장 안쪽 블록의 번호(없으면 -1)찾기(이름){ for (j = 값들.Count - 1; j >= 0; j--) { if (값들[j].Contains(이름)) { return j; } } return -1;}n = Console.ReadLine().ToNumber();for (i = 0; i < n; i++){ parts = Console.ReadLine().Split(); cmd = parts[0]; switch (cmd) { case "{": 값들.Add(Dict()); 상수들.Add(Dict()); break; case "}": 값들.RemoveAt(값들.Count - 1); 상수들.RemoveAt(상수들.Count - 1); break; case "let": case "const": 값들[값들.Count - 1][parts[1]] = parts[2].ToNumber(); 상수들[상수들.Count - 1][parts[1]] = cmd == "const"; break; case "set": b = 찾기(parts[1]); if (!상수들[b][parts[1]]) { 값들[b][parts[1]] = parts[2].ToNumber(); } break; default: Console.WriteLine(값들[찾기(parts[1])][parts[1]]); break; }}