거북이 한 마리가 (0, 0)에서 북쪽을 보고 서 있다. 북쪽으로 한 걸음이면 y가 1 늘고, 동쪽이면 x가 1 늘고, 남쪽이면 y가 1 줄고, 서쪽이면 x가 1 준다. 한 줄에 명령 글자들이 빈칸 없이 주어진다. F는 보는 방향으로 한 걸음, R은 오른쪽으로 90도 돌기, L은 왼쪽으로 90도 돌기, B는 제자리에서 뒤로 돌기(180도)다. 명령을 모두 마친 뒤 거북이의 x, y와 보는 방향의 첫 글자(N·E·S·W 중 하나)를 빈칸 하나씩 띄워 출력하라. 방향은 북·동·남·서 네 값을 시계 방향 차례로 가진 열거형(enum)으로 만들어 풀어 보자.
입력
명령의 길이는 1 이상 100,000 이하, 글자는 F·R·L·B 중 하나
출력
한 줄: x y 방향
예시 1 · stdin
FFRFFLFBFF
stdout
2 1 S
예시 2 · stdin
LF
stdout
-1 0 W
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 6개 언어 풀이
이 문제는 열거형으로 풀 수 있는 Python·TypeScript·Java·C#·C·C++만 받아요. Python은 표준 모듈 enum의 class Dir(Enum)으로 만들어요. JavaScript에는 열거형 문법이 없어서(Object.freeze({...})로 흉내만 내요) 빠지고, 크레이콘에도 열거형이 없어요. TypeScript의 enum Dir { North, East, South, West }는 값이 0~3인 숫자 열거형이라 (d + 1) % 4처럼 수로 계산한 뒤 as Dir로 되돌리고, 역방향 표 Dir[d]가 이름 "North"를 줘요. enum은 타입만 있는 문법이 아니라 실행할 때 쓰는 객체를 만들어 내요. 언어마다 열거형의 속이 달라요. C의 enum Dir { NORTH, EAST, SOUTH, WEST }는 이름 붙은 int 상수 0~3일 뿐이라 실행 중에 이름을 모르고, "NESW"[d]처럼 이름표를 직접 둬요. C++ enum class는 Dir::North로 쓰고 int로 저절로 바뀌지 않아 static_cast<int>(d)가 필요해요. Java enum은 클래스라서 values(), ordinal(), name()을 가지고, C#은 (Dir)(((int)d + 1) % 4)처럼 오가고 d.ToString()이 이름을 줘요. Python은 Dir(값), d.value, d.name이에요. 함정 셋: ① 왼쪽 돌기를 (d - 1) % 4로 쓰면 북쪽(0)에서 C·C++·Java·C#·TypeScript는 -1이 나와요(나머지가 나누어지는 수의 부호를 따라가요). C#은 (Dir)(-1)도 오류 없이 만들어 "-1"을 찍고, TypeScript도 -1 as Dir를 막지 않아 Dir[-1]이 undefined가 돼요. (d + 3) % 4로 써요(Python은 -1 % 4 == 3이라 괜찮아요). ② C·C++(그리고 Java의 옛 case: switch)에서 break를 빠뜨리면 다음 case로 흘러내려 한 걸음에 여러 번 움직여요. C#은 이걸 컴파일 오류로 막고, Java의 case NORTH -> y++; 화살표 switch는 흘러내리지 않아요. ③ Python의 Enum 멤버는 수와 같지 않아서 d == 0은 늘 False예요(IntEnum이면 True). d == Dir.NORTH나 d.value로 비교해요.
Pythonmain.py · 23 줄
from enum import Enumclass Dir(Enum): # 시계 방향 차례 NORTH = 0 EAST = 1 SOUTH = 2 WEST = 3STEP = {Dir.NORTH: (0, 1), Dir.EAST: (1, 0), Dir.SOUTH: (0, -1), Dir.WEST: (-1, 0)}TURN = {"R": 1, "B": 2, "L": 3} # 왼쪽 = 오른쪽으로 세 번x = y = 0d = Dir.NORTHfor c in input().strip(): if c == "F": dx, dy = STEP[d] x += dx y += dy else: d = Dir((d.value + TURN[c]) % 4) # 수로 바꿔 계산하고 다시 열거형으로print(x, y, d.name[0])
TypeScriptmain.ts · 34 줄
import { readFileSync } from "node:fs";enum Dir { // 시계 방향 차례: North = 0, East = 1, South = 2, West = 3 North, East, South, West,}// 숫자 enum은 수로 계산할 수 있다. 결과를 다시 Dir로 돌려놓는다function turn(d: Dir, k: number): Dir { return ((d + k) % 4) as Dir; // 왼쪽은 -1 대신 +3}const s = readFileSync(0, "utf8").trim();let x = 0;let y = 0;let d = Dir.North;for (const c of s) { switch (c) { case "R": d = turn(d, 1); break; case "B": d = turn(d, 2); break; case "L": d = turn(d, 3); break; default: switch (d) { case Dir.North: y++; break; case Dir.East: x++; break; case Dir.South: y--; break; case Dir.West: x--; break; } }}// 역방향 표 Dir[d]가 이름("South")을 준다console.log(`${x} ${y} ${Dir[d].charAt(0)}`);
JavaMain.java · 33 줄
import java.io.BufferedReader;import java.io.InputStreamReader;public class Main { enum Dir { NORTH, EAST, SOUTH, WEST } // 시계 방향 차례 static Dir turn(Dir d, int k) { Dir[] all = Dir.values(); return all[(d.ordinal() + k) % 4]; } public static void main(String[] args) throws Exception { String s = new BufferedReader(new InputStreamReader(System.in)).readLine().trim(); int x = 0, y = 0; Dir d = Dir.NORTH; for (char c : s.toCharArray()) { switch (c) { case 'R' -> d = turn(d, 1); case 'B' -> d = turn(d, 2); case 'L' -> d = turn(d, 3); default -> { switch (d) { // 화살표 switch는 아래로 흘러내리지 않는다 case NORTH -> y++; case EAST -> x++; case SOUTH -> y--; case WEST -> x--; } } } } System.out.println(x + " " + y + " " + d.name().charAt(0)); }}
C#Main.cs · 34 줄
using System;enum Dir { North, East, South, West } // 시계 방향 차례class Program{ static Dir Turn(Dir d, int k) => (Dir)(((int)d + k) % 4); // 열거형 ↔ int는 명시적으로 바꾼다 static void Main() { string s = Console.ReadLine().Trim(); int x = 0, y = 0; Dir d = Dir.North; foreach (char c in s) { switch (c) { case 'R': d = Turn(d, 1); break; case 'B': d = Turn(d, 2); break; case 'L': d = Turn(d, 3); break; default: switch (d) { case Dir.North: y++; break; case Dir.East: x++; break; case Dir.South: y--; break; case Dir.West: x--; break; } break; } } Console.WriteLine($"{x} {y} {d.ToString()[0]}"); }}
C++main.cpp · 34 줄
#include <iostream>#include <string>enum class Dir { North, East, South, West }; // 범위 있는 열거형: Dir::North로 쓰고 int로 저절로 바뀌지 않는다Dir turn(Dir d, int k) { return static_cast<Dir>((static_cast<int>(d) + k) % 4);}char name(Dir d) { return "NESW"[static_cast<int>(d)]; // C++도 열거형의 이름을 실행 중에 모른다}int main() { std::string s; std::cin >> s; int x = 0, y = 0; Dir d = Dir::North; for (char c : s) { switch (c) { case 'R': d = turn(d, 1); break; case 'B': d = turn(d, 2); break; case 'L': d = turn(d, 3); break; default: switch (d) { case Dir::North: y++; break; case Dir::East: x++; break; case Dir::South: y--; break; case Dir::West: x--; break; } } } std::cout << x << " " << y << " " << name(d) << "\n";}
Cmain.c · 32 줄
#include <stdio.h>enum Dir { NORTH, EAST, SOUTH, WEST }; /* 이름 붙은 int 상수 0, 1, 2, 3 */static const char NAME[] = "NESW"; /* C 열거형은 실행 중에 이름을 모른다: 직접 둔다 */enum Dir turn(enum Dir d, int k) { return (enum Dir)((d + k) % 4);}int main(void) { static char s[100002]; scanf("%100001s", s); int x = 0, y = 0; enum Dir d = NORTH; for (int i = 0; s[i]; i++) { switch (s[i]) { case 'R': d = turn(d, 1); break; case 'B': d = turn(d, 2); break; case 'L': d = turn(d, 3); break; default: switch (d) { case NORTH: y++; break; /* break가 없으면 다음 case로 흘러내린다 */ case EAST: x++; break; case SOUTH: y--; break; case WEST: x--; break; } } } printf("%d %d %c\n", x, y, NAME[d]); return 0;}