{ }codelper
枚举switch 语句P0077

乌龟面朝哪边

一只乌龟站在 (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
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 6 种语言题解

这道题只接受能用枚举来解的 Python、TypeScript、Java、C#、C 和 C++。
Python 用标准模块 enum 的 class Dir(Enum) 来做。
JavaScript 没有枚举语法(只能用 Object.freeze({...}) 模仿),所以不在其中,Craykon 也没有枚举。
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 的箭头 switch case NORTH -> y++; 不会落下去。
③ Python 的 Enum 成员不等于数字,所以 d == 0 永远是 False(用 IntEnum 才是 True);要用 d == Dir.NORTH 或 d.value 来比较。

Pythonmain.py · 23 行
from enum import Enum  class Dir(Enum):  # 시계 방향 차례    NORTH = 0    EAST = 1    SOUTH = 2    WEST = 3  STEP = {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;}