{ }codelper
하나씩 반복삼항 연산자멈추기·건너뛰기P0140

다트 점수 줄이기 게임

두 선수가 같은 점수 P에서 시작해 다트로 맞힌 점수만큼 자기 점수를 줄여 가는 게임을 한다. 1번 선수부터 번갈아 차례를 가지고, 한 차례에 다트를 최대 세 개 던진다. 던진 다트는 던진 차례대로 한 줄에 모두 주어진다. 다트 하나는 M, S, D, T 중 한 글자로 시작한다. M은 빗나감으로 0점이다. S, D, T 뒤에는 1부터 20까지의 수 k가 붙고, 각각 k점, 2k점, 3k점이다.
k는 앞에 0을 붙이지 않고 쓴다. SB는 25점, DB는 50점이다(TB는 없다). D로 시작하는 다트(DB 포함)를 더블이라고 한다. 다트를 하나 던질 때마다 그 선수의 점수에서 다트의 점수를 뺀다. 뺀 결과가 0이고 그 다트가 더블이면 그 선수가 이기고 게임이 끝난다.
남은 다트는 무시한다. 그렇지 않고 뺀 결과가 2보다 작으면(더블이 아닌 다트로 0이 되었거나, 1이나 음수가 되면) 터진 것이다. 터지면 그 선수의 점수는 이번 차례를 시작할 때의 점수로 돌아가고, 차례가 바로 끝난다.
그 차례에 남은 다트는 없고, 다음 다트는 상대 선수의 첫 다트다. 터지지 않았으면 뺀 결과가 새 점수가 되고, 이번 차례의 세 번째 다트였으면 차례가 끝난다. 차례가 끝날 때마다 그 차례를 가진 선수의 점수를 한 줄에 출력한다. 이긴 차례에는 0을 출력한다. 아무도 이기지 않았는데 차례가 끝나기 전에(그 차례의 첫째나 둘째 다트 뒤에) 다트가 다 떨어지면, 그 차례도 그 선수의 지금 점수로 한 줄 출력한다. 마지막 줄에는 이긴 선수의 번호(1 또는 2)를 출력하고, 아무도 이기지 못했으면 0을 출력한다. 첫 줄에 P, 둘째 줄에 다트 수 n, 셋째 줄에 다트 n개가 빈칸 하나씩을 사이에 두고 주어진다.

입력
2 ≤ P ≤ 1,001, 1 ≤ n ≤ 5,000, 다트는 M, SB, DB, 또는 S·D·T 뒤에 1 ~ 20
출력
차례마다 한 줄(그 차례 끝의 점수), 마지막 줄에 이긴 선수 번호 또는 0
예시 1 · stdin
101
11
T20 D10 S1 T20 T20 S19 T19 D20 S4 D10 T20
stdout
20
101
20
101
0
1
예시 2 · stdin
60
5
SB M M D20 S5
stdout
35
15
0
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

다트를 하나씩 도는 반복 안에서 규칙대로 멈추고 건너뛰어요.
이기면 break로 남은 다트를 보지 않고, 차례가 아직 안 끝났으면 continue로 출력과 선수 바꾸기를 건너뛰어요(크레이콘 그만;, 건너뛰기;).
하나씩 도는 반복: Python for t in throws, JS·TS for (const t of throws), Java for (String t : throwsList)(Java에서 throws는 예약어라 쓸 수 없어요), C# foreach (string t in throws), C++ for (const std::string& t : throws), 크레이콘 각각 (t 에서 다트들).
C에는 for-each가 없어서 번호로 돌며 하나씩 scanf로 읽어요.
점수 배수는 삼항 연산자를 이어 써요: C 계열·JS·TS·크레이콘 isD ? 2 : isT ? 3 : 1(오른쪽부터 묶여서 괄호가 없어도 돼요), Python은 2 if isD else 3 if isT else 1로 순서가 달라요.
Java·C#·C·C++는 t.charAt(0), t[0]이 한 글자(char)라 'D'와 비교하고, Python·JS·TS·크레이콘은 한 글자짜리 문자열이라 "D"와 비교해요.
가장 흔한 실수는 터졌을 때 마지막 다트만 없던 일로 하는 거예요.
차례를 시작할 때의 점수를 따로 적어 두었다가 그 점수로 되돌려요(첫 예시의 두 번째 줄: 41이 아니라 101).
0이 되었다고 바로 이기게 하거나(더블만 끝낼 수 있음), 1이 남는 것을 허용하거나(더블로는 1을 지울 수 없어 터짐), DB를 더블로 치지 않는 것도 함정이에요.

Pythonmain.py · 46 줄
import sys data = sys.stdin.read().split()start = int(data[0])n = int(data[1])throws = data[2:2 + n] scores = [start, start]player = 0               # 0이 1번 선수, 1이 2번 선수turn_start = start       # 이번 차례를 시작할 때의 점수(터지면 여기로 돌아간다)darts = 0                # 이번 차례에 던진 다트 수winner = 0out = [] for t in throws:    if t == "M":        value, is_double = 0, False    else:        ring, num = t[0], t[1:]        base = 25 if num == "B" else int(num)        mult = 2 if ring == "D" else 3 if ring == "T" else 1        value, is_double = base * mult, ring == "D"    darts += 1    left = scores[player] - value     if left == 0 and is_double:          # 더블로 딱 0: 이긴다        scores[player] = 0        winner = player + 1        break                            # 남은 다트는 보지 않는다    if left < 2:                         # 0(더블 아님), 1, 음수: 터짐        scores[player] = turn_start        end_turn = True    else:        scores[player] = left        end_turn = darts == 3    if not end_turn:        continue    out.append(scores[player])    player = 1 - player    turn_start = scores[player]    darts = 0 if winner != 0 or darts > 0:             # 이긴 차례나 다 못 던진 차례도 한 줄    out.append(scores[player])out.append(winner)print("\n".join(map(str, out)))
JavaScriptmain.js · 49 줄
const data = require("fs").readFileSync(0, "utf8").trim().split(/\s+/);const start = Number(data[0]);const n = Number(data[1]);const throws = data.slice(2, 2 + n); const scores = [start, start];let player = 0; // 0이 1번 선수, 1이 2번 선수let turnStart = start; // 이번 차례를 시작할 때의 점수(터지면 여기로 돌아간다)let darts = 0; // 이번 차례에 던진 다트 수let winner = 0;const out = []; for (const t of throws) {  let value = 0;  let isDouble = false;  if (t !== "M") {    const ring = t[0];    const num = t.slice(1);    const base = num === "B" ? 25 : Number(num);    const mult = ring === "D" ? 2 : ring === "T" ? 3 : 1;    value = base * mult;    isDouble = ring === "D";  }  darts++;  const left = scores[player] - value;   if (left === 0 && isDouble) { // 더블로 딱 0: 이긴다    scores[player] = 0;    winner = player + 1;    break; // 남은 다트는 보지 않는다  }  let endTurn;  if (left < 2) { // 0(더블 아님), 1, 음수: 터짐    scores[player] = turnStart;    endTurn = true;  } else {    scores[player] = left;    endTurn = darts === 3;  }  if (!endTurn) continue;  out.push(scores[player]);  player = 1 - player;  turnStart = scores[player];  darts = 0;} if (winner !== 0 || darts > 0) out.push(scores[player]); // 이긴 차례나 다 못 던진 차례도 한 줄out.push(winner);console.log(out.join("\n"));
TypeScriptmain.ts · 50 줄
import { readFileSync } from "node:fs";const data: string[] = readFileSync(0, "utf8").trim().split(/\s+/);const start: number = Number(data[0]);const n: number = Number(data[1]);const throws: string[] = data.slice(2, 2 + n); const scores: number[] = [start, start];let player = 0; // 0이 1번 선수, 1이 2번 선수let turnStart = start; // 이번 차례를 시작할 때의 점수(터지면 여기로 돌아간다)let darts = 0; // 이번 차례에 던진 다트 수let winner = 0;const out: number[] = []; for (const t of throws) {  let value = 0;  let isDouble = false;  if (t !== "M") {    const ring = t[0];    const num = t.slice(1);    const base = num === "B" ? 25 : Number(num);    const mult = ring === "D" ? 2 : ring === "T" ? 3 : 1;    value = base * mult;    isDouble = ring === "D";  }  darts++;  const left = scores[player] - value;   if (left === 0 && isDouble) { // 더블로 딱 0: 이긴다    scores[player] = 0;    winner = player + 1;    break; // 남은 다트는 보지 않는다  }  let endTurn: boolean;  if (left < 2) { // 0(더블 아님), 1, 음수: 터짐    scores[player] = turnStart;    endTurn = true;  } else {    scores[player] = left;    endTurn = darts === 3;  }  if (!endTurn) continue;  out.push(scores[player]);  player = 1 - player;  turnStart = scores[player];  darts = 0;} if (winner !== 0 || darts > 0) out.push(scores[player]); // 이긴 차례나 다 못 던진 차례도 한 줄out.push(winner);console.log(out.join("\n"));
JavaMain.java · 57 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int start = Integer.parseInt(br.readLine().trim());        int n = Integer.parseInt(br.readLine().trim());        String[] throwsList = br.readLine().trim().split("\\s+");         int[] scores = {start, start};        int player = 0; // 0이 1번 선수, 1이 2번 선수        int turnStart = start; // 이번 차례를 시작할 때의 점수(터지면 여기로 돌아간다)        int darts = 0; // 이번 차례에 던진 다트 수        int winner = 0;        StringBuilder out = new StringBuilder();         for (String t : throwsList) {            int value = 0;            boolean isDouble = false;            if (!t.equals("M")) {                char ring = t.charAt(0);                String num = t.substring(1);                int base = num.equals("B") ? 25 : Integer.parseInt(num);                int mult = ring == 'D' ? 2 : ring == 'T' ? 3 : 1;                value = base * mult;                isDouble = ring == 'D';            }            darts++;            int left = scores[player] - value;             if (left == 0 && isDouble) { // 더블로 딱 0: 이긴다                scores[player] = 0;                winner = player + 1;                break; // 남은 다트는 보지 않는다            }            boolean endTurn;            if (left < 2) { // 0(더블 아님), 1, 음수: 터짐                scores[player] = turnStart;                endTurn = true;            } else {                scores[player] = left;                endTurn = darts == 3;            }            if (!endTurn) continue;            out.append(scores[player]).append('\n');            player = 1 - player;            turnStart = scores[player];            darts = 0;        }         if (winner != 0 || darts > 0) out.append(scores[player]).append('\n'); // 이긴 차례나 다 못 던진 차례도 한 줄        out.append(winner).append('\n');        System.out.print(out);    }}
C#Main.cs · 63 줄
using System;using System.Text; class Program{    static void Main()    {        int start = int.Parse(Console.ReadLine().Trim());        int n = int.Parse(Console.ReadLine().Trim());        string[] throws = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);         int[] scores = { start, start };        int player = 0; // 0이 1번 선수, 1이 2번 선수        int turnStart = start; // 이번 차례를 시작할 때의 점수(터지면 여기로 돌아간다)        int darts = 0; // 이번 차례에 던진 다트 수        int winner = 0;        var sb = new StringBuilder();         foreach (string t in throws)        {            int value = 0;            bool isDouble = false;            if (t != "M")            {                char ring = t[0];                string num = t.Substring(1);                int baseValue = num == "B" ? 25 : int.Parse(num);                int mult = ring == 'D' ? 2 : ring == 'T' ? 3 : 1;                value = baseValue * mult;                isDouble = ring == 'D';            }            darts++;            int left = scores[player] - value;             if (left == 0 && isDouble) // 더블로 딱 0: 이긴다            {                scores[player] = 0;                winner = player + 1;                break; // 남은 다트는 보지 않는다            }            bool endTurn;            if (left < 2) // 0(더블 아님), 1, 음수: 터짐            {                scores[player] = turnStart;                endTurn = true;            }            else            {                scores[player] = left;                endTurn = darts == 3;            }            if (!endTurn) continue;            sb.Append(scores[player]).Append('\n');            player = 1 - player;            turnStart = scores[player];            darts = 0;        }         if (winner != 0 || darts > 0) sb.Append(scores[player]).Append('\n'); // 이긴 차례나 다 못 던진 차례도 한 줄        sb.Append(winner).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 54 줄
#include <array>#include <iostream>#include <string>#include <vector> int main() {    int start, n;    std::cin >> start >> n;    std::vector<std::string> throws(n);    for (auto& t : throws) std::cin >> t;     std::array<int, 2> scores = {start, start};    int player = 0;        // 0이 1번 선수, 1이 2번 선수    int turnStart = start; // 이번 차례를 시작할 때의 점수(터지면 여기로 돌아간다)    int darts = 0;         // 이번 차례에 던진 다트 수    int winner = 0;     for (const std::string& t : throws) {        int value = 0;        bool isDouble = false;        if (t != "M") {            char ring = t[0];            std::string num = t.substr(1);            int base = num == "B" ? 25 : std::stoi(num);            int mult = ring == 'D' ? 2 : ring == 'T' ? 3 : 1;            value = base * mult;            isDouble = ring == 'D';        }        darts++;        int left = scores[player] - value;         if (left == 0 && isDouble) { // 더블로 딱 0: 이긴다            scores[player] = 0;            winner = player + 1;            break; // 남은 다트는 보지 않는다        }        bool endTurn;        if (left < 2) { // 0(더블 아님), 1, 음수: 터짐            scores[player] = turnStart;            endTurn = true;        } else {            scores[player] = left;            endTurn = darts == 3;        }        if (!endTurn) continue;        std::cout << scores[player] << '\n';        player = 1 - player;        turnStart = scores[player];        darts = 0;    }     if (winner != 0 || darts > 0) std::cout << scores[player] << '\n'; // 이긴 차례나 다 못 던진 차례도 한 줄    std::cout << winner << '\n';}
Cmain.c · 54 줄
#include <stdbool.h>#include <stdio.h>#include <stdlib.h>#include <string.h> int main(void) {    int start, n;    scanf("%d %d", &start, &n);    int scores[2] = {start, start};    int player = 0;         /* 0이 1번 선수, 1이 2번 선수 */    int turn_start = start; /* 이번 차례를 시작할 때의 점수(터지면 여기로 돌아간다) */    int darts = 0;          /* 이번 차례에 던진 다트 수 */    int winner = 0;     /* C에는 for-each가 없다: 다트를 하나씩 읽으며 번호로 돈다 */    for (int i = 0; i < n; i++) {        char t[8];        scanf("%7s", t);        int value = 0;        bool is_double = false;        if (strcmp(t, "M") != 0) {            char ring = t[0];            int base = strcmp(t + 1, "B") == 0 ? 25 : atoi(t + 1);            int mult = ring == 'D' ? 2 : ring == 'T' ? 3 : 1;            value = base * mult;            is_double = ring == 'D';        }        darts++;        int left = scores[player] - value;         if (left == 0 && is_double) { /* 더블로 딱 0: 이긴다 */            scores[player] = 0;            winner = player + 1;            break; /* 남은 다트는 보지 않는다 */        }        bool end_turn;        if (left < 2) { /* 0(더블 아님), 1, 음수: 터짐 */            scores[player] = turn_start;            end_turn = true;        } else {            scores[player] = left;            end_turn = darts == 3;        }        if (!end_turn) continue;        printf("%d\n", scores[player]);        player = 1 - player;        turn_start = scores[player];        darts = 0;    }     if (winner != 0 || darts > 0) printf("%d\n", scores[player]); /* 이긴 차례나 다 못 던진 차례도 한 줄 */    printf("%d\n", winner);    return 0;}
Craykonmain.cray · 58 줄
시작점수 = 콘솔.줄읽기().수로변환();콘솔.줄읽기(); // 다트 수 n(목록 개수로 알 수 있다)다트들 = 콘솔.줄읽기().공백제거().나누기(); 점수 = [시작점수, 시작점수];선수 = 0; // 0이 1번 선수, 1이 2번 선수차례시작 = 시작점수; // 이번 차례를 시작할 때의 점수(터지면 여기로 돌아간다)던진수 = 0; // 이번 차례에 던진 다트 수승자 = 0; 각각 (t 에서 다트들){    값 = 0;    더블 = 거짓;    만약 (t != "M")    {        고리 = t[0];        수 = t.부분문자열(1);        기본 = 수 == "B" ? 25 : 수.수로변환();        배수 = 고리 == "D" ? 2 : 고리 == "T" ? 3 : 1;        값 = 기본 * 배수;        더블 = 고리 == "D";    }    던진수++;    남은 = 점수[선수] - 값;     만약 (남은 == 0 && 더블)    {        점수[선수] = 0;        승자 = 선수 + 1;        그만; // 남은 다트는 보지 않는다    }    차례끝 = 거짓;    만약 (남은 < 2)    {        점수[선수] = 차례시작;        차례끝 = 참;    }    아니면    {        점수[선수] = 남은;        차례끝 = 던진수 == 3;    }    만약 (!차례끝)    {        건너뛰기;    }    콘솔.쓰기(점수[선수]);    선수 = 1 - 선수;    차례시작 = 점수[선수];    던진수 = 0;} 만약 (승자 != 0 || 던진수 > 0){    콘솔.쓰기(점수[선수]);}콘솔.쓰기(승자);