어떤 프로그램이 터미널 화면에 글자를 쓴 출력 명령의 기록이 주어진다.
화면은 처음에 빈 줄 하나뿐이고, 커서는 그 줄의 1번 칸에 있다.
줄의 칸은 왼쪽부터 1번, 2번, 3번, …으로 센다.
명령은 다음 여섯 가지다.
write s는 줄을 바꾸지 않고 문자열 s의 글자를 왼쪽부터 하나씩 쓴다.
글자 하나를 쓸 때, 커서 칸에 이미 글자가 있으면 그 글자를 새 글자로 덮어쓰고, 커서가 줄의 마지막 글자 바로 뒤에 있으면 줄 끝에 붙인다. 그런 다음 커서가 오른쪽으로 한 칸 간다.
아래 명령들은 커서를 줄의 마지막 글자 바로 뒤보다 오른쪽으로 보내지 않으므로, 글자를 쓸 때는 늘 이 두 경우 가운데 하나다.
print s는 write s를 한 다음 nl을 한다.
nl은 지금 줄 아래에 빈 줄을 하나 새로 만들고, 커서를 새 줄의 1번 칸으로 옮긴다.
cr은 커서를 지금 줄의 1번 칸으로 옮긴다. 글자는 지우지 않는다.
back k는 커서를 왼쪽으로 k칸 옮긴다. 커서는 1번 칸보다 왼쪽으로 가지 않고 1번 칸에서 멈춘다. 글자는 지우지 않는다.
erase는 지금 줄에서 커서 칸과 그 오른쪽에 있는 글자를 모두 지운다. 커서는 움직이지 않는다.
커서는 늘 맨 아래 줄에 있다.
첫 줄에 명령 수 q가, 다음 q줄에 명령이 하나씩 주어진다. 명령 이름과 s, k 사이는 빈칸 하나다.
명령을 모두 처리한 뒤 화면의 줄을 위에서부터 차례로 한 줄에 하나씩 출력하라.
글자가 없는 줄은 빈 줄로 출력한다. 다만 맨 아래 줄이 비어 있으면 그 줄은 출력하지 않는다.
입력
1 ≤ q ≤ 2,000. s는 빈칸이 아닌 아스키 글자(코드 33~126)로 된 1~30글자의 문자열이다. 1 ≤ k ≤ 1,000. 어느 줄도 1,000글자를 넘지 않는다. 화면에는 글자가 하나 이상 남는다.
12
write abcdef
back 2
write XY
write Z
back 100
write 1
nl
nl
write hello
back 3
erase
write p!
stdout
1bcdXYZ
hep!
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
줄을 바꾸지 않고 쓰기는 Python print(s, end="")·sys.stdout.write(s), JS·TS process.stdout.write(s)(console.log는 늘 줄을 바꿔요), Java System.out.print(줄을 바꾸려면 println), C# Console.Write(WriteLine이 줄을 바꿔요), C fputs(s, stdout)·printf("%s", s), C++ std::cout << s(std::endl이나 '\n'을 붙여야 줄이 바뀌어요), 크레이콘 콘솔.이어쓰기(s)(콘솔.쓰기는 줄을 바꿔요)예요. 이 문제의 cr은 실제 터미널의 \r이에요. 진행률을 한 줄에서 고쳐 쓰려고 print(f"\r{p}%", end="")처럼 쓰는데, 함정 ① \r은 커서만 옮기고 줄을 지우지 않아요. 짧은 문자열로 덮어쓰면 긴 문자열의 꼬리가 남아서 loading... 위에 done을 쓰면 doneing...이 보여요. 실제로는 빈칸으로 채우거나 erase에 해당하는 \x1b[K를 보내요. ② back은 1번 칸에서 멈춰요. 커서를 0부터 센 수로 두고 그냥 빼면, Python에서는 cur[-1]이 맨 끝 칸이라 오류 없이 엉뚱한 글자를 덮어쓰고, C·C++은 배열 밖에 써요. C++에서 커서를 size_t로 두면 음수가 없어서 아주 큰 수가 되니 빼기 전에 비교해요. ③ erase는 커서 칸부터 오른쪽만 지워요. Python del cur[col:], JS·TS cur.length = col, Java setLength(col), C# Length = col, C++ resize(col), 크레이콘 부분목록(0, col)로 줄일 수 있어요. ④ 덮어쓰기는 끼워 넣기가 아니에요. C++ insert나 Python insert를 쓰면 뒤 글자가 밀려요. ⑤ 이름이 헷갈려요: 이 문제의 print는 줄을 바꾸는데, Java·C#의 print·Write는 줄을 바꾸지 않아요. ⑥ C에서 모은 줄을 printf(cur)로 찍으면 %를 서식으로 읽어서 50%d…가 망가져요. fputs나 printf("%s", cur)를 써요.
Pythonmain.py · 46 줄
import syslines = sys.stdin.read().split("\n")q = int(lines[0])screen = [] # 다 쓴 줄들cur = [] # 지금 줄의 글자들col = 0 # 커서 칸(0부터)def write(s): global col for ch in s: if col < len(cur): cur[col] = ch # 글자가 있으면 덮어쓴다 else: cur.append(ch) # 줄 끝 바로 뒤면 붙인다 col += 1def newline(): global cur, col screen.append("".join(cur)) cur = [] col = 0for line in lines[1:1 + q]: p = line.split() cmd = p[0] if cmd == "write": write(p[1]) elif cmd == "print": write(p[1]) newline() elif cmd == "nl": newline() elif cmd == "cr": col = 0 # 글자는 그대로 두고 커서만 맨 앞으로 elif cmd == "back": col = max(0, col - int(p[1])) # 음수 자리는 맨 끝 칸이 되니 0에서 멈춘다 else: # erase del cur[col:]if cur: screen.append("".join(cur))sys.stdout.write("".join(row + "\n" for row in screen))
JavaScriptmain.js · 33 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const screen = []; // 다 쓴 줄들let cur = []; // 지금 줄의 글자들let col = 0; // 커서 칸(0부터)function write(s) { for (const ch of s) { cur[col] = ch; // 글자가 있으면 덮어쓰고, 줄 끝 바로 뒤면 붙인다 col++; }}function newline() { screen.push(cur.join("")); cur = []; col = 0;}for (const line of lines.slice(1, 1 + q)) { const [cmd, arg] = line.trim().split(" "); if (cmd === "write") write(arg); else if (cmd === "print") { write(arg); newline(); } else if (cmd === "nl") newline(); else if (cmd === "cr") col = 0; // 글자는 그대로, 커서만 맨 앞으로 else if (cmd === "back") col = Math.max(0, col - Number(arg)); else cur.length = col; // erase: 커서 칸부터 뒤를 잘라 낸다}if (cur.length > 0) screen.push(cur.join(""));// console.log는 늘 줄을 바꾼다. 줄 바꿈 없이 쓰려면 process.stdout.writeprocess.stdout.write(screen.map((row) => row + "\n").join(""));
TypeScriptmain.ts · 35 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const screen: string[] = []; // 다 쓴 줄들let cur: string[] = []; // 지금 줄의 글자들let col = 0; // 커서 칸(0부터)function write(s: string): void { for (const ch of s) { cur[col] = ch; // 글자가 있으면 덮어쓰고, 줄 끝 바로 뒤면 붙인다 col++; }}function newline(): void { screen.push(cur.join("")); cur = []; col = 0;}for (const line of lines.slice(1, 1 + q)) { const [cmd, arg] = line.trim().split(" "); if (cmd === "write") write(arg); else if (cmd === "print") { write(arg); newline(); } else if (cmd === "nl") newline(); else if (cmd === "cr") col = 0; // 글자는 그대로, 커서만 맨 앞으로 else if (cmd === "back") col = Math.max(0, col - Number(arg)); else cur.length = col; // erase: 커서 칸부터 뒤를 잘라 낸다}if (cur.length > 0) screen.push(cur.join(""));// console.log는 늘 줄을 바꾼다. 줄 바꿈 없이 쓰려면 process.stdout.writeprocess.stdout.write(screen.map((row) => row + "\n").join(""));
JavaMain.java · 40 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;public class Main { static StringBuilder cur = new StringBuilder(); // 지금 줄 static int col = 0; // 커서 칸(0부터) static void write(String s) { for (char ch : s.toCharArray()) { if (col < cur.length()) cur.setCharAt(col, ch); // 덮어쓴다 else cur.append(ch); // 줄 끝 바로 뒤면 붙인다 col++; } } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(System.out); int q = Integer.parseInt(in.readLine().trim()); for (int t = 0; t < q; t++) { String[] p = in.readLine().trim().split(" "); switch (p[0]) { case "write" -> write(p[1]); case "print", "nl" -> { if (p[0].equals("print")) write(p[1]); out.println(cur); // 다 쓴 줄은 바로 내보낸다 cur.setLength(0); col = 0; } case "cr" -> col = 0; // 글자는 그대로, 커서만 맨 앞으로 case "back" -> col = Math.max(0, col - Integer.parseInt(p[1])); default -> cur.setLength(col); // erase } } if (cur.length() > 0) out.println(cur); out.flush(); }}
C#Main.cs · 58 줄
using System;using System.IO;using System.Text;class Program{ static StringBuilder cur = new StringBuilder(); // 지금 줄 static int col = 0; // 커서 칸(0부터) static void Write(string s) { foreach (char ch in s) { if (col < cur.Length) cur[col] = ch; // 덮어쓴다 else cur.Append(ch); // 줄 끝 바로 뒤면 붙인다 col++; } } static void Main() { var output = new StreamWriter(Console.OpenStandardOutput()); int q = int.Parse(Console.ReadLine().Trim()); for (int t = 0; t < q; t++) { string[] p = Console.ReadLine().Trim().Split(' '); switch (p[0]) { case "write": Write(p[1]); break; case "print": case "nl": if (p[0] == "print") Write(p[1]); output.Write(cur.ToString()); output.Write('\n'); cur.Clear(); col = 0; break; case "cr": col = 0; // 글자는 그대로, 커서만 맨 앞으로 break; case "back": col = Math.Max(0, col - int.Parse(p[1])); break; default: // erase cur.Length = col; break; } } if (cur.Length > 0) { output.Write(cur.ToString()); output.Write('\n'); } output.Flush(); }}
C++main.cpp · 41 줄
#include <algorithm>#include <iostream>#include <string>int main() { std::ios::sync_with_stdio(false); int q; std::cin >> q; std::string cur; // 지금 줄 std::size_t col = 0; // 커서 칸(0부터) std::string out; for (int t = 0; t < q; t++) { std::string cmd, arg; std::cin >> cmd; if (cmd == "write" || cmd == "print") { std::cin >> arg; for (char ch : arg) { if (col < cur.size()) cur[col] = ch; // 덮어쓴다 else cur += ch; // 줄 끝 바로 뒤면 붙인다 col++; } } if (cmd == "print" || cmd == "nl") { out += cur; out += '\n'; cur.clear(); col = 0; } else if (cmd == "cr") { col = 0; // 글자는 그대로, 커서만 맨 앞으로 } else if (cmd == "back") { std::size_t k; std::cin >> k; col = col > k ? col - k : 0; // size_t는 음수가 없어서 빼기 전에 비교한다 } else if (cmd == "erase") { cur.resize(col); } } if (!cur.empty()) out += cur + '\n'; std::cout << out; return 0;}
Cmain.c · 45 줄
#include <stdio.h>#include <string.h>static char cur[1001]; /* 지금 줄(한 줄은 1,000칸 이하) */static int len = 0, col = 0; /* 줄 길이, 커서 칸(0부터) */static void write_text(const char *s) { for (; *s; s++) { cur[col++] = *s; /* 덮어쓰거나, 줄 끝 바로 뒤면 붙인다 */ if (col > len) len = col; }}static void newline(void) { cur[len] = '\0'; fputs(cur, stdout); /* printf(cur)는 안 된다: %를 서식으로 읽는다 */ putchar('\n'); len = col = 0;}int main(void) { int q; char cmd[8], arg[32]; scanf("%d", &q); for (int t = 0; t < q; t++) { scanf("%7s", cmd); if (strcmp(cmd, "write") == 0 || strcmp(cmd, "print") == 0) { scanf("%31s", arg); write_text(arg); if (cmd[0] == 'p') newline(); } else if (strcmp(cmd, "nl") == 0) { newline(); } else if (strcmp(cmd, "cr") == 0) { col = 0; } else if (strcmp(cmd, "back") == 0) { int k; scanf("%d", &k); col = col > k ? col - k : 0; } else { /* erase */ len = col; } } if (len > 0) newline(); return 0;}
Craykonmain.cray · 57 줄
q = 콘솔.줄읽기().수로변환();cur = []; // 지금 줄의 글자들col = 0; // 커서 칸(0부터)쓰기(s){ 각각 (ch 에서 s) { 만약 (col < cur.개수) { cur[col] = ch; // 글자가 있으면 덮어쓴다 } 아니면 { cur.넣기(ch); // 줄 끝 바로 뒤면 붙인다 } col = col + 1; }}줄바꾸기(){ 콘솔.쓰기(cur.잇기("")); cur = []; col = 0;}반복 (t = 0; t < q; t++){ p = 콘솔.줄읽기().공백제거().나누기(" "); 선택 (p[0]) { 경우 "write": 쓰기(p[1]); 그만; 경우 "print": 쓰기(p[1]); 줄바꾸기(); 그만; 경우 "nl": 줄바꾸기(); 그만; 경우 "cr": col = 0; // 글자는 그대로, 커서만 맨 앞으로 그만; 경우 "back": col = 수학.큰수(0, col - p[1].수로변환()); 그만; 그밖에: cur = cur.부분목록(0, col); // erase: 커서 칸부터 뒤를 버린다 그만; }}만약 (cur.개수 > 0){ 콘솔.쓰기(cur.잇기(""));}