二人の選手が同じ点数 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
エラー一覧00F8 ↓ · ⇧F8 ↑
入力(stdin)
実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。
$ 準備完了
コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。
ほかの言語では?言語別の解答を見る · 8 言語の解答
ダーツを一本ずつ回るループの中で、規則どおりに止めたり飛ばしたりします。 勝ったら break で残りのダーツを見ず、番がまだ終わっていなければ continue で出力と選手の交代を飛ばします(Craykon 抜ける;、次へ;)。 一つずつ回るループ: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)、Craykon それぞれ (t の中 ダーツたち)。 C には for-each がないので、番号で回りながら一本ずつ scanf で読みます。 倍率は三項演算子をつなげて書きます:C 系・JS・TS・Craykon 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・Craykon は一文字の文字列なので "D" と比べます。 いちばん多い間違いは、バーストのとき最後のダーツだけをなかったことにすることです。 番を始めたときの点数を別に覚えておき、その点数に戻します(最初の例の二行目:41 ではなく 101)。 0 になったらすぐ勝ちにしたり(ダブルでしか終われない)、1 が残るのを許したり(ダブルでは 1 を消せないのでバースト)、DB をダブルと数えなかったりするのも落とし穴です。
Pythonmain.py · 46 行
import sysdata = 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 = 0if 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){ コンソール.書く(점수[선수]);}コンソール.書く(승자);