{ }codelper
switch 文入れ子の条件P0242

テレビのリモコンキー

チャンネルが 1 番から c 番まであるテレビをリモコンで操作する。
最初、テレビは消えていて、チャンネルは 1 番、音量は 10、消音はオフで、前のチャンネルはなく、ためた数字もない。
キーは一文字で、押した順に一行で与えられる。
テレビが消えているあいだは P と ? 以外のキーをすべて無視する。
消えているとき P はテレビをつけ、? は OFF を一行に出力する。
つけたとき、チャンネル・音量・消音・前のチャンネルは消したときのままだ。
ついているとき、数字キー 0~9 はその数字をためた数字の末尾につける。
ためた数字が三桁になったらすぐに「数字処理」をする。
ついているとき、数字でないキーはまず「数字処理」をし、それから自分の仕事をする。
「数字処理」はためた数字があるときだけ行い、ためた数字を数として読んで(007 は 7)空にする。
その数が 1 以上 c 以下ならそのチャンネルへ行く。
範囲外ならどのチャンネルへも行かない。
ついているときの各キーの仕事は次のとおりだ。
- #:何もしない(数字処理だけをする)。
- P:テレビを消す。
- U:次のチャンネルへ行く。
c 番の次は 1 番だ。
- D:前の番号のチャンネルへ行く。
1 番の前は c 番だ。
- B:前のチャンネルへ行く。
前のチャンネルがなければ何もしない。
- +:音量を 1 上げる(30 より大きくならない)。
消音を解く。
- -:音量を 1 下げる(0 より小さくならない)。
消音を解く。
- M:消音を切り替える。
- ?:消音がオンなら CH チャンネル MUTE、そうでなければ CH チャンネル VOL 音量 を一行に出力する。
あるチャンネルへ「行く」とは、そのチャンネルが今のチャンネルと違うときだけ、今のチャンネルを前のチャンネルとして覚え、そのチャンネルを今のチャンネルにすることだ。
今のチャンネルと同じなら何も変わらない。
キーをすべて押したあとに残った数字は処理しない。
一行目に c、二行目にキーが空白なしで与えられる。
? ごとに一行ずつ出力せよ。

入力
2 ≤ c ≤ 999。
キーは 1~10,000 個で、0~9、#、P、U、D、B、+、-、M、?
のどれかだ。
?
は一つ以上ある
出力
?
の数だけの行
例 1 · stdin
50
?P?37?U?BB?M?+?D5#?P?9P?
stdout
OFF
CH 1 VOL 10
CH 37 VOL 10
CH 38 VOL 10
CH 38 VOL 10
CH 38 MUTE
CH 38 VOL 11
CH 5 VOL 11
OFF
CH 5 VOL 11
例 2 · stdin
3
PD?UU?B?000#?40#?+M?M?
stdout
CH 3 VOL 10
CH 2 VOL 10
CH 1 VOL 10
CH 1 VOL 10
CH 1 VOL 10
CH 1 MUTE
CH 1 VOL 11
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

キー一つで分岐を選ぶ switch です。
一文字で選ぶ形は C・C++・Java・C#・JS・TS switch (k) { case 'U': … }(JS・TS は文字列 "U")、Python 3.10+ match k: case "U":、Craykon 選択 (k) { 場合 "U": … 抜ける; } です。
十個の数字のように同じ仕事をする場合をまとめるのは C・C++・JS・TS・C#(空の case のみ)case '0': case '1': …、Java のアロー case '+', '-' ->、Python case "+" | "-":、Craykon 場合 "0", "1", …: です。
落とし穴 ① フォールスルー:C・C++・JS・TS と Java の古い case: 文は break がないと次の case まで実行します。
U の後の break を忘れると D まで実行してチャンネルが元に戻ります。
C# はこれをコンパイルエラーで防ぎ、Java のアロー switch・Python match・Craykon 選択 はフォールスルーしません。
Craykon の 抜ける は選択だけを抜けます。
② 1 番で D:(ch - 2) % c + 1 は C・C++・Java・C#・JS・TS・Craykon では % が負の数を残すので 0 番になります。
(ch - 2 + c) % c + 1 か Java Math.floorMod を使います(Python の % は常に 0 以上)。
③ 入れ子の条件の順序:「消えているか」を switch より先に聞かないと、消えているあいだに音量やチャンネルが変わります。
④ 数字でないキーはすべて、まずためた数字を処理します(# だけではありません)。
だから 5U は 5 番の次の 6 番です。
⑤ 同じチャンネルへ行くときは前のチャンネルを上書きしません。
⑥ +・- は消音を解きます。

Pythonmain.py · 60 行
c = int(input())keys = input().strip() power = Falsech, vol, muted = 1, 10, Falseprev = 0      # 바로 전 채널(0이면 아직 없음)buf = ""      # 누른 숫자를 모아 둔 것out = []  def go(to):    """채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다."""    global ch, prev    if to != ch:        prev, ch = ch, to  def commit():    global buf    if buf:        v = int(buf)  # "007"은 7        buf = ""        if 1 <= v <= c:            go(v)  for k in keys:    if not power:        # 꺼져 있으면 P와 ? 말고는 듣지 않는다        if k == "P":            power = True        elif k == "?":            out.append("OFF")        continue    if k.isdigit():        buf += k        if len(buf) == 3:            commit()        continue    commit()  # 숫자가 아닌 키는 모아 둔 숫자부터 처리한다    match k:        case "#":            pass        case "P":            power = False        case "U":            go(ch % c + 1)        case "D":            go((ch - 2) % c + 1)  # Python의 %는 늘 0 이상이라 1번 → c번        case "B":            if prev:                go(prev)        case "+" | "-":            vol = min(30, vol + 1) if k == "+" else max(0, vol - 1)            muted = False        case "M":            muted = not muted        case "?":            out.append(f"CH {ch} MUTE" if muted else f"CH {ch} VOL {vol}")print("\n".join(out))
JavaScriptmain.js · 62 行
const [cLine, keysLine] = require("fs").readFileSync(0, "utf8").split("\n");const c = Number(cLine);const keys = keysLine.trim(); let power = false;let ch = 1, vol = 10, muted = false;let prev = 0; // 바로 전 채널(0이면 아직 없음)let buf = ""; // 누른 숫자를 모아 둔 것const out = []; const go = (to) => {  if (to !== ch) [prev, ch] = [ch, to]; // 지금과 같으면 바꾼 것이 아니다};const commit = () => {  if (buf === "") return;  const v = Number(buf); // "007"은 7  buf = "";  if (v >= 1 && v <= c) go(v);}; for (const k of keys) {  if (!power) {    // 꺼져 있으면 P와 ? 말고는 듣지 않는다    if (k === "P") power = true;    else if (k === "?") out.push("OFF");    continue;  }  if (k >= "0" && k <= "9") {    buf += k;    if (buf.length === 3) commit();    continue;  }  commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다  switch (k) {    case "#":      break;    case "P":      power = false;      break;    case "U":      go((ch % c) + 1);      break;    case "D":      go(((ch - 2 + c) % c) + 1); // JS의 %는 음수를 남기니 c를 더해 둔다      break;    case "B":      if (prev !== 0) go(prev);      break;    case "+":    case "-": // 두 경우가 같은 일을 하도록 일부러 이어 내려간다      vol = k === "+" ? Math.min(30, vol + 1) : Math.max(0, vol - 1);      muted = false;      break;    case "M":      muted = !muted;      break;    case "?":      out.push(muted ? `CH ${ch} MUTE` : `CH ${ch} VOL ${vol}`);      break;  }}console.log(out.join("\n"));
TypeScriptmain.ts · 64 行
import { readFileSync } from "node:fs"; const [cLine, keysLine]: string[] = readFileSync(0, "utf8").split("\n");const c = Number(cLine);const keys = keysLine.trim(); let power = false;let ch = 1, vol = 10, muted = false;let prev = 0; // 바로 전 채널(0이면 아직 없음)let buf = ""; // 누른 숫자를 모아 둔 것const out: string[] = []; const go = (to: number): void => {  if (to !== ch) [prev, ch] = [ch, to]; // 지금과 같으면 바꾼 것이 아니다};const commit = (): void => {  if (buf === "") return;  const v = Number(buf); // "007"은 7  buf = "";  if (v >= 1 && v <= c) go(v);}; for (const k of keys) {  if (!power) {    // 꺼져 있으면 P와 ? 말고는 듣지 않는다    if (k === "P") power = true;    else if (k === "?") out.push("OFF");    continue;  }  if (k >= "0" && k <= "9") {    buf += k;    if (buf.length === 3) commit();    continue;  }  commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다  switch (k) {    case "#":      break;    case "P":      power = false;      break;    case "U":      go((ch % c) + 1);      break;    case "D":      go(((ch - 2 + c) % c) + 1); // JS의 %는 음수를 남기니 c를 더해 둔다      break;    case "B":      if (prev !== 0) go(prev);      break;    case "+":    case "-": // 두 경우가 같은 일을 하도록 일부러 이어 내려간다      vol = k === "+" ? Math.min(30, vol + 1) : Math.max(0, vol - 1);      muted = false;      break;    case "M":      muted = !muted;      break;    case "?":      out.push(muted ? `CH ${ch} MUTE` : `CH ${ch} VOL ${vol}`);      break;  }}console.log(out.join("\n"));
JavaMain.java · 62 行
import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException; public class Main {    static int c, ch = 1, vol = 10, prev = 0;    static boolean muted = false;    static StringBuilder buf = new StringBuilder(); // 누른 숫자를 모아 둔 것     // 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다    static void go(int to) {        if (to != ch) {            prev = ch;            ch = to;        }    }     static void commit() {        if (buf.length() == 0) return;        int v = Integer.parseInt(buf.toString()); // "007"은 7        buf.setLength(0);        if (v >= 1 && v <= c) go(v);    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        c = Integer.parseInt(in.readLine().trim());        String keys = in.readLine().trim();        boolean power = false;        StringBuilder out = new StringBuilder();        for (char k : keys.toCharArray()) {            if (!power) {                // 꺼져 있으면 P와 ? 말고는 듣지 않는다                if (k == 'P') power = true;                else if (k == '?') out.append("OFF\n");                continue;            }            if (Character.isDigit(k)) {                buf.append(k);                if (buf.length() == 3) commit();                continue;            }            commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다            // 화살표 switch는 이어 내려가지 않아 break가 필요 없다            switch (k) {                case '#' -> { }                case 'P' -> power = false;                case 'U' -> go(ch % c + 1);                case 'D' -> go(Math.floorMod(ch - 2, c) + 1); // floorMod는 늘 0 이상                case 'B' -> { if (prev != 0) go(prev); }                case '+', '-' -> {                    vol = k == '+' ? Math.min(30, vol + 1) : Math.max(0, vol - 1);                    muted = false;                }                case 'M' -> muted = !muted;                case '?' -> out.append("CH ").append(ch).append(muted ? " MUTE" : " VOL " + vol).append('\n');                default -> { }            }        }        System.out.print(out);    }}
C#Main.cs · 82 行
using System;using System.Text; class Program{    static int c, ch = 1, vol = 10, prev = 0;    static bool muted = false;    static string buf = ""; // 누른 숫자를 모아 둔 것     // 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다    static void Go(int to)    {        if (to != ch)        {            prev = ch;            ch = to;        }    }     static void Commit()    {        if (buf == "") return;        int v = int.Parse(buf); // "007"은 7        buf = "";        if (v >= 1 && v <= c) Go(v);    }     static void Main()    {        c = int.Parse(Console.ReadLine().Trim());        string keys = Console.ReadLine().Trim();        bool power = false;        var sb = new StringBuilder();        foreach (char k in keys)        {            if (!power)            {                // 꺼져 있으면 P와 ? 말고는 듣지 않는다                if (k == 'P') power = true;                else if (k == '?') sb.Append("OFF\n");                continue;            }            if (char.IsDigit(k))            {                buf += k;                if (buf.Length == 3) Commit();                continue;            }            Commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다            // C#은 case 끝에 break가 없으면 컴파일 오류라서 이어 내려가는 실수가 없다            switch (k)            {                case '#':                    break;                case 'P':                    power = false;                    break;                case 'U':                    Go(ch % c + 1);                    break;                case 'D':                    Go((ch - 2 + c) % c + 1); // C#의 %는 음수를 남기니 c를 더해 둔다                    break;                case 'B':                    if (prev != 0) Go(prev);                    break;                case '+':                case '-': // 빈 case는 다음 case와 묶을 수 있다                    vol = k == '+' ? Math.Min(30, vol + 1) : Math.Max(0, vol - 1);                    muted = false;                    break;                case 'M':                    muted = !muted;                    break;                case '?':                    sb.Append(muted ? $"CH {ch} MUTE\n" : $"CH {ch} VOL {vol}\n");                    break;            }        }        Console.Write(sb);    }}
C++main.cpp · 73 行
#include <algorithm>#include <iostream>#include <string> int c, ch = 1, vol = 10, prev = 0;bool muted = false;std::string buf; // 누른 숫자를 모아 둔 것 // 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다void go(int to) {    if (to != ch) {        prev = ch;        ch = to;    }} void commit() {    if (buf.empty()) return;    int v = std::stoi(buf); // "007"은 7    buf.clear();    if (v >= 1 && v <= c) go(v);} int main() {    std::string keys, out;    std::cin >> c >> keys;    bool power = false;    for (char k : keys) {        if (!power) {            // 꺼져 있으면 P와 ? 말고는 듣지 않는다            if (k == 'P') power = true;            else if (k == '?') out += "OFF\n";            continue;        }        if (k >= '0' && k <= '9') {            buf += k;            if (buf.size() == 3) commit();            continue;        }        commit(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다        switch (k) {        case '#':            break;        case 'P':            power = false;            break;        case 'U':            go(ch % c + 1);            break;        case 'D':            go((ch - 2 + c) % c + 1); // C++의 %는 음수를 남기니 c를 더해 둔다            break;        case 'B':            if (prev) go(prev);            break;        case '+':            vol = std::min(30, vol + 1);            muted = false;            break;        case '-':            vol = std::max(0, vol - 1);            muted = false;            break;        case 'M':            muted = !muted;            break;        case '?':            out += "CH " + std::to_string(ch) + (muted ? " MUTE" : " VOL " + std::to_string(vol)) + "\n";            break;        }    }    std::cout << out;}
Cmain.c · 81 行
#include <stdio.h>#include <stdlib.h> static int c, ch = 1, vol = 10, muted = 0, prev = 0;static char buf[4];static int blen = 0; /* 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다 */static void go(int to) {    if (to != ch) {        prev = ch;        ch = to;    }} static void commit(void) {    if (blen == 0) return;    buf[blen] = '\0';    int v = atoi(buf); /* "007"은 7 */    blen = 0;    if (v >= 1 && v <= c) go(v);} static char keys[10002]; int main(void) {    int power = 0;    scanf("%d %10001s", &c, keys);    for (char *p = keys; *p; p++) {        char k = *p;        if (!power) {            /* 꺼져 있으면 P와 ? 말고는 듣지 않는다 */            if (k == 'P') power = 1;            else if (k == '?') puts("OFF");            continue;        }        switch (k) {        /* 숫자 열 개는 case를 잇대어 써서 한 곳으로 모은다(일부러 이어 내려감) */        case '0': case '1': case '2': case '3': case '4':        case '5': case '6': case '7': case '8': case '9':            buf[blen++] = k;            if (blen == 3) commit();            continue; /* 아래의 commit을 건너뛰고 다음 키로 */        default:            break;        }        commit(); /* 숫자가 아닌 키는 모아 둔 숫자부터 처리한다 */        switch (k) {        case '#':            break;        case 'P':            power = 0;            break;        case 'U':            go(ch % c + 1);            break;        case 'D':            go((ch - 2 + c) % c + 1); /* C의 %는 음수를 남기니 c를 더해 둔다 */            break;        case 'B':            if (prev) go(prev);            break;        case '+':            vol = vol < 30 ? vol + 1 : 30;            muted = 0;            break;        case '-':            vol = vol > 0 ? vol - 1 : 0;            muted = 0;            break;        case 'M':            muted = !muted;            break;        case '?':            if (muted) printf("CH %d MUTE\n", ch);            else printf("CH %d VOL %d\n", ch, vol);            break;        }    }    return 0;}
Craykonmain.cray · 111 行
c = コンソール.行読み().数に();keys = コンソール.行読み().空白除去(); power = 偽;ch = 1;vol = 10;muted = 偽;prev = 0; // 바로 전 채널(0이면 아직 없음)buf = ""; // 누른 숫자를 모아 둔 것 // 채널을 to로 바꾼다. 지금과 같으면 바꾼 것이 아니다가기(to){    もし (to != ch)    {        prev = ch;        ch = to;    }} 모은숫자처리(){    もし (buf != "")    {        v = buf.数に(); // "007"은 7        buf = "";        もし (v >= 1 && v <= c)        {            가기(v);        }    }} 繰り返す (i = 0; i < keys.長さ; i++){    k = keys[i];    もし (!power)    {        // 꺼져 있으면 P와 ? 말고는 듣지 않는다        もし (k == "P")        {            power = 真;        }        でなければ もし (k == "?")        {            コンソール.書く("OFF");        }        次へ;    }    選択 (k)    {        場合 "0":        場合 "1":        場合 "2":        場合 "3":        場合 "4":        場合 "5":        場合 "6":        場合 "7":        場合 "8":        場合 "9":            buf = buf + k;            もし (buf.長さ == 3)            {                모은숫자처리();            }            抜ける;        それ以外:            모은숫자처리(); // 숫자가 아닌 키는 모아 둔 숫자부터 처리한다            選択 (k)            {                場合 "P":                    power = 偽;                    抜ける;                場合 "U":                    가기(ch % c + 1);                    抜ける;                場合 "D":                    가기((ch - 2 + c) % c + 1); // %는 음수를 남기니 c를 더해 둔다                    抜ける;                場合 "B":                    もし (prev != 0)                    {                        가기(prev);                    }                    抜ける;                場合 "+":                    vol = 数学.小さい方(30, vol + 1);                    muted = 偽;                    抜ける;                場合 "-":                    vol = 数学.大きい方(0, vol - 1);                    muted = 偽;                    抜ける;                場合 "M":                    muted = !muted;                    抜ける;                場合 "?":                    もし (muted)                    {                        コンソール.書く("CH " + ch + " MUTE");                    }                    でなければ                    {                        コンソール.書く("CH " + ch + " VOL " + vol);                    }                    抜ける;            }            抜ける;    }}