{ }codelper
swapping valuessplitting stringsP0272

Calculator cells assigned all at once

A small calculator has 26 cells named by the lowercase letters a to z.
Every cell starts at 0. The first line gives the number of commands q, and the next q lines give one command each.
Words in a command are separated by single spaces. set x v puts the integer v into cell x. swap x y exchanges the values of cells x and y.
x and y may be the same; then nothing changes. rot x y z rotates the values of three different cells: x gets the old value of y, y gets the old value of z, and z gets the old value of x. let x1 x2 … xk = e1 e2 … ek puts the value of term ei into cell xi (i = 1, …, k).
The cell names on the left are all different. All k terms on the right are evaluated first, using the values just before this command, and then the k cells are assigned at once. A term is a single cell name, a single non-negative integer, or u+w or u-w, where u and w are each a cell name or a non-negative integer, with no spaces in between. show x1 x2 … xk prints the values of cells x1, x2, …, xk in this order on one line, separated by single spaces.
The same cell may appear more than once. Process the commands in order and print one line for each show.

Input
1 ≤ q ≤ 2,000.
The v of set is from -1,000,000 to 1,000,000.
Integers inside terms are from 0 to 1,000,000.
The number of cells k in let and show is from 1 to 26.
There are 1 to 200 show commands.
Every cell value always stays from -1,000,000,000 to 1,000,000,000
Output
As many lines as show commands
Example 1 · stdin
7
set a 1
let a b = a+b a
let a b = a+b a
let a b = a+b a
show a b
swap a b
show a b
stdout
3 2
2 3
Example 2 · stdin
9
set x 5
set y -7
set z 9
swap x x
show x
rot x y z
show x y z
let x y z = z-1 x+y 100
show x y z
stdout
5
-7 9 5
4 2 100
main.py
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

Languages swap two values in different ways.
Where there is syntax that assigns all at once, like Python a, b = b, a, JS/TS [a, b] = [b, a] or C# (a, b) = (b, a), the whole right side is evaluated before anything is assigned, so rot is one line too.
C++ has the function std::swap(a, b) instead of syntax, and Java, C and Craykon park one value in a temporary tmp.
Because the number of cells k in let varies, every language first collects the right-hand values in an array (a list in Python and Craykon) and then assigns.
Trap ① assigning each let value as soon as it is computed: in let a b = a+b a, changing a first makes b receive the new a.
② a new name is not a copy: Python old = reg and JS const old = reg point at the same dict/array, so they are not a snapshot.
Copy with dict(reg) or [...reg].
③ the no-temporary swap tricks: XOR (a ^= b; b ^= a; a ^= b) and add/subtract (a = a + b; b = a - b; a = a - b) turn the value into 0 when both names refer to the same cell (swap x x).
Add/subtract can also overflow with big numbers.
④ writing rot without a temporary as x = y; y = z; z = x gives z the already-changed x (the old y).
The direction is easy to mix up too: x is the one that receives y's value.
⑤ the - in a term is always subtraction.
Integers in terms have no sign, so look for + or - after the first character.
In Craykon, if a function assigns to a name that the top level of the program also uses (and it is not a parameter), it changes that outside variable, so give loop variables inside functions names not used outside.

Pythonmain.py · 42 lines
import sys lines = sys.stdin.read().split("\n")q = int(lines[0])reg = {chr(c): 0 for c in range(ord("a"), ord("z") + 1)}  def atom(t):    return reg[t] if t.isalpha() else int(t)  def term(t):    # p+q, p-q, 또는 칸 이름·수 하나. 항 안의 수에는 부호가 없어서 -는 늘 빼기다    for op in "+-":        i = t.find(op)        if i > 0:            a, b = atom(t[:i]), atom(t[i + 1:])            return a + b if op == "+" else a - b    return atom(t)  out = []for line in lines[1:1 + q]:    p = line.split()    cmd = p[0]    if cmd == "set":        reg[p[1]] = int(p[2])    elif cmd == "swap":        x, y = p[1], p[2]        reg[x], reg[y] = reg[y], reg[x]  # x와 y가 같아도 그대로    elif cmd == "rot":        x, y, z = p[1], p[2], p[3]        reg[x], reg[y], reg[z] = reg[y], reg[z], reg[x]    elif cmd == "let":        eq = p.index("=")        targets = p[1:eq]        values = [term(t) for t in p[eq + 1:]]  # 오른쪽을 모두 먼저 계산한다        for x, v in zip(targets, values):            reg[x] = v    else:  # show        out.append(" ".join(str(reg[x]) for x in p[1:]))print("\n".join(out))
JavaScriptmain.js · 40 lines
const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const reg = new Array(26).fill(0);const at = (x) => x.charCodeAt(0) - 97; // 'a' → 0 const atom = (t) => (/^[a-z]$/.test(t) ? reg[at(t)] : Number(t)); function term(t) {  // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다  const i = t.search(/[+-]/);  if (i <= 0) return atom(t);  const a = atom(t.slice(0, i));  const b = atom(t.slice(i + 1));  return t[i] === "+" ? a + b : a - b;} const out = [];for (const line of lines.slice(1, 1 + q)) {  const p = line.trim().split(" ");  const cmd = p[0];  if (cmd === "set") {    reg[at(p[1])] = Number(p[2]);  } else if (cmd === "swap") {    const x = at(p[1]);    const y = at(p[2]);    [reg[x], reg[y]] = [reg[y], reg[x]]; // 구조 분해로 한꺼번에 바꾼다  } else if (cmd === "rot") {    const [x, y, z] = p.slice(1).map(at);    [reg[x], reg[y], reg[z]] = [reg[y], reg[z], reg[x]];  } else if (cmd === "let") {    const eq = p.indexOf("=");    const values = p.slice(eq + 1).map(term); // 오른쪽을 모두 먼저 계산한다    p.slice(1, eq).forEach((x, i) => {      reg[at(x)] = values[i];    });  } else {    out.push(p.slice(1).map((x) => reg[at(x)]).join(" "));  }}console.log(out.join("\n"));
TypeScriptmain.ts · 42 lines
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const reg: number[] = new Array<number>(26).fill(0);const at = (x: string): number => x.charCodeAt(0) - 97; // 'a' → 0 const atom = (t: string): number => (/^[a-z]$/.test(t) ? reg[at(t)] : Number(t)); function term(t: string): number {  // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다  const i = t.search(/[+-]/);  if (i <= 0) return atom(t);  const a = atom(t.slice(0, i));  const b = atom(t.slice(i + 1));  return t[i] === "+" ? a + b : a - b;} const out: string[] = [];for (const line of lines.slice(1, 1 + q)) {  const p = line.trim().split(" ");  const cmd = p[0];  if (cmd === "set") {    reg[at(p[1])] = Number(p[2]);  } else if (cmd === "swap") {    const x = at(p[1]);    const y = at(p[2]);    [reg[x], reg[y]] = [reg[y], reg[x]]; // 구조 분해로 한꺼번에 바꾼다  } else if (cmd === "rot") {    const [x, y, z] = p.slice(1).map(at);    [reg[x], reg[y], reg[z]] = [reg[y], reg[z], reg[x]];  } else if (cmd === "let") {    const eq = p.indexOf("=");    const values: number[] = p.slice(eq + 1).map(term); // 오른쪽을 모두 먼저 계산한다    p.slice(1, eq).forEach((x, i) => {      reg[at(x)] = values[i];    });  } else {    out.push(p.slice(1).map((x) => reg[at(x)]).join(" "));  }}console.log(out.join("\n"));
JavaMain.java · 68 lines
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringJoiner; public class Main {    static int[] reg = new int[26];     static int at(String x) {        return x.charAt(0) - 'a';    }     static int atom(String t) {        return Character.isLetter(t.charAt(0)) ? reg[at(t)] : Integer.parseInt(t);    }     static int term(String t) {        // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다        for (int i = 1; i < t.length(); i++) {            char c = t.charAt(i);            if (c == '+' || c == '-') {                int a = atom(t.substring(0, i));                int b = atom(t.substring(i + 1));                return c == '+' ? a + b : a - b;            }        }        return atom(t);    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int q = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        for (int t = 0; t < q; t++) {            String[] p = in.readLine().trim().split(" ");            switch (p[0]) {                case "set" -> reg[at(p[1])] = Integer.parseInt(p[2]);                case "swap" -> {                    int x = at(p[1]), y = at(p[2]);                    int tmp = reg[x]; // Java에는 a, b = b, a가 없어서 임시 변수를 쓴다                    reg[x] = reg[y];                    reg[y] = tmp;                }                case "rot" -> {                    int x = at(p[1]), y = at(p[2]), z = at(p[3]);                    int tmp = reg[x];                    reg[x] = reg[y];                    reg[y] = reg[z];                    reg[z] = tmp;                }                case "let" -> {                    int eq = 1;                    while (!p[eq].equals("=")) eq++;                    int k = eq - 1;                    int[] values = new int[k]; // 오른쪽을 모두 먼저 계산해 둔다                    for (int i = 0; i < k; i++) values[i] = term(p[eq + 1 + i]);                    for (int i = 0; i < k; i++) reg[at(p[1 + i])] = values[i];                }                default -> {                    StringJoiner sj = new StringJoiner(" ");                    for (int i = 1; i < p.length; i++) sj.add(String.valueOf(reg[at(p[i])]));                    out.append(sj).append('\n');                }            }        }        System.out.print(out);    }}
C#Main.cs · 62 lines
using System;using System.Linq;using System.Text; class Program{    static int[] reg = new int[26];     static int At(string x) => x[0] - 'a';     static int Atom(string t) => char.IsLetter(t[0]) ? reg[At(t)] : int.Parse(t);     static int Term(string t)    {        // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다        int i = t.IndexOfAny(new[] { '+', '-' }, 1);        if (i < 0) return Atom(t);        int a = Atom(t.Substring(0, i));        int b = Atom(t.Substring(i + 1));        return t[i] == '+' ? a + b : a - b;    }     static void Main()    {        int q = int.Parse(Console.ReadLine().Trim());        var sb = new StringBuilder();        for (int t = 0; t < q; t++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            switch (p[0])            {                case "set":                    reg[At(p[1])] = int.Parse(p[2]);                    break;                case "swap":                {                    int x = At(p[1]), y = At(p[2]);                    (reg[x], reg[y]) = (reg[y], reg[x]); // 튜플로 한꺼번에 바꾼다                    break;                }                case "rot":                {                    int x = At(p[1]), y = At(p[2]), z = At(p[3]);                    (reg[x], reg[y], reg[z]) = (reg[y], reg[z], reg[x]);                    break;                }                case "let":                {                    int eq = Array.IndexOf(p, "=");                    // 오른쪽을 모두 먼저 계산해 배열로 받아 둔다                    int[] values = p.Skip(eq + 1).Select(Term).ToArray();                    for (int i = 0; i < values.Length; i++) reg[At(p[1 + i])] = values[i];                    break;                }                default:                    sb.Append(string.Join(" ", p.Skip(1).Select(x => reg[At(x)]))).Append('\n');                    break;            }        }        Console.Write(sb);    }}
C++main.cpp · 58 lines
#include <array>#include <iostream>#include <sstream>#include <string>#include <utility>#include <vector> std::array<int, 26> reg{}; int atom(const std::string &t) {    return std::isalpha(static_cast<unsigned char>(t[0])) ? reg[t[0] - 'a'] : std::stoi(t);} int term(const std::string &t) {    // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다    std::size_t i = t.find_first_of("+-", 1);    if (i == std::string::npos) return atom(t);    int a = atom(t.substr(0, i)), b = atom(t.substr(i + 1));    return t[i] == '+' ? a + b : a - b;} int main() {    std::string line;    std::getline(std::cin, line);    int q = std::stoi(line);    std::string out;    for (int c = 0; c < q; c++) {        std::getline(std::cin, line);        std::istringstream ss(line);        std::vector<std::string> p;        for (std::string w; ss >> w;) p.push_back(w);        if (p[0] == "set") {            reg[p[1][0] - 'a'] = std::stoi(p[2]);        } else if (p[0] == "swap") {            std::swap(reg[p[1][0] - 'a'], reg[p[2][0] - 'a']);        } else if (p[0] == "rot") {            int &x = reg[p[1][0] - 'a'], &y = reg[p[2][0] - 'a'], &z = reg[p[3][0] - 'a'];            int tmp = x;            x = y;            y = z;            z = tmp;        } else if (p[0] == "let") {            std::size_t eq = 1;            while (p[eq] != "=") eq++;            std::vector<int> values; // 오른쪽을 모두 먼저 계산한다            for (std::size_t i = eq + 1; i < p.size(); i++) values.push_back(term(p[i]));            for (std::size_t i = 0; i < values.size(); i++) reg[p[1 + i][0] - 'a'] = values[i];        } else {            for (std::size_t i = 1; i < p.size(); i++) {                if (i > 1) out += ' ';                out += std::to_string(reg[p[i][0] - 'a']);            }            out += '\n';        }    }    std::cout << out;    return 0;}
Cmain.c · 60 lines
#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <string.h> static int reg[26]; static int atom(const char *t, int len) {    if (isalpha((unsigned char)t[0])) return reg[t[0] - 'a'];    int v = 0;    for (int i = 0; i < len; i++) v = v * 10 + (t[i] - '0');    return v;} /* p+q, p-q, 또는 칸 이름·수 하나. 항 안의 수에는 부호가 없다 */static int term(const char *t) {    int n = (int)strlen(t);    for (int i = 1; i < n; i++)        if (t[i] == '+' || t[i] == '-') {            int a = atom(t, i), b = atom(t + i + 1, n - i - 1);            return t[i] == '+' ? a + b : a - b;        }    return atom(t, n);} int main(void) {    static char line[1024];    char *tok[64];    fgets(line, sizeof line, stdin);    int q = atoi(line);    for (int c = 0; c < q; c++) {        fgets(line, sizeof line, stdin);        int k = 0;        for (char *s = strtok(line, " \r\n"); s; s = strtok(NULL, " \r\n")) tok[k++] = s;        if (strcmp(tok[0], "set") == 0) {            reg[tok[1][0] - 'a'] = atoi(tok[2]);        } else if (strcmp(tok[0], "swap") == 0) {            int x = tok[1][0] - 'a', y = tok[2][0] - 'a';            int tmp = reg[x]; /* 임시 칸에 하나를 맡겨 둔다 */            reg[x] = reg[y];            reg[y] = tmp;        } else if (strcmp(tok[0], "rot") == 0) {            int x = tok[1][0] - 'a', y = tok[2][0] - 'a', z = tok[3][0] - 'a';            int tmp = reg[x];            reg[x] = reg[y];            reg[y] = reg[z];            reg[z] = tmp;        } else if (strcmp(tok[0], "let") == 0) {            int eq = 1;            while (strcmp(tok[eq], "=") != 0) eq++;            int n = eq - 1, values[26];            for (int i = 0; i < n; i++) values[i] = term(tok[eq + 1 + i]); /* 먼저 모두 계산 */            for (int i = 0; i < n; i++) reg[tok[1 + i][0] - 'a'] = values[i];        } else {            for (int i = 1; i < k; i++) printf(i > 1 ? " %d" : "%d", reg[tok[i][0] - 'a']);            putchar('\n');        }    }    return 0;}
Craykonmain.cray · 77 lines
q = Console.ReadLine().ToNumber();reg = Dict();for (i = 0; i < 26; i++){    reg[Str.FromCode(97 + i)] = 0;} 하나(t){    if (reg.Contains(t))    {        return reg[t];    }    return t.ToNumber();} // p+q, p-q, 또는 칸 이름·수 하나. 항 안의 수에는 부호가 없다항(t){    // 함수 안에서 넣은 이름이 밖에도 있으면 밖의 변수가 바뀌니, 밖에서 안 쓰는 이름(w)을 쓴다    for (w = 1; w < t.Length; w++)    {        if (t[w] == "+" || t[w] == "-")        {            가 = 하나(t.Substring(0, w));            나머지 = 하나(t.Substring(w + 1));            if (t[w] == "+")            {                return 가 + 나머지;            }            return 가 - 나머지;        }    }    return 하나(t);} for (c = 0; c < q; c++){    p = Console.ReadLine().Trim().Split(" ");    switch (p[0])    {        case "set":            reg[p[1]] = p[2].ToNumber();            break;        case "swap":            임시 = reg[p[1]]; // 크레이콘에는 한꺼번에 넣기가 없어서 임시 변수에 맡긴다            reg[p[1]] = reg[p[2]];            reg[p[2]] = 임시;            break;        case "rot":            임시 = reg[p[1]];            reg[p[1]] = reg[p[2]];            reg[p[2]] = reg[p[3]];            reg[p[3]] = 임시;            break;        case "let":            eq = p.IndexOf("=");            값들 = []; // 오른쪽을 모두 먼저 계산해 둔다            for (i = eq + 1; i < p.Count; i++)            {                값들.Add(항(p[i]));            }            for (i = 0; i < 값들.Count; i++)            {                reg[p[1 + i]] = 값들[i];            }            break;        default:            보일것 = [];            for (i = 1; i < p.Count; i++)            {                보일것.Add(reg[p[i]]);            }            Console.WriteLine(보일것.Join(" "));            break;    }}