{ }codelper
列挙型多分岐数えるP0198

サイコロ五つの役

サイコロ遊びで、一人ずつサイコロを五つ(目は 1〜6)一回振る。
振った五つの目の役は、次の八つの役のうちあてはまるものの中でいちばん上にあるものである。
上にあるほど強い役である。
- FIVE:五つすべてが同じ目 - FOUR:四つが同じ目 - FULLHOUSE:三つが同じ目で、残りの二つがそれとは違う同じ目 - STRAIGHT:五つの目が 1 2 3 4 5 または 2 3 4 5 6(順番は問わない) - TRIPLE:三つが同じ目で、残りの二つはその目とも互いとも違う - TWOPAIR:違う二つの目が二つずつある - PAIR:同じ目の二つ組が一組だけある - NOTHING:それ以外のすべての場合 一行目に人数 n、続く n 行に行ごとに一人が振った五つの目が空白で区切られて与えられる。
人の番号は 1 から順に付く。
人ごとに役の名前を一行に一つずつ大文字で出力せよ。
最後の行には勝った人の番号を出力せよ。
役がいちばん強い人が勝ち、役が同じなら五つの目の合計が大きい人が勝つ。
それも同じなら番号が小さい人が勝つ。
役を弱いものから強いものまで八つの値を持つ列挙型(enum)にし、役どうしは列挙型の値の大きさで比べてみよう。

入力
1 ≤ n ≤ 1,000、サイコロの目は 1〜6 の整数
出力
n+1 行:人ごとの役の名前、最後の行に勝った人の番号
例 1 · stdin
5
3 3 3 5 5
2 4 3 6 5
6 2 6 2 3
5 5 3 3 3
1 2 3 4 6
stdout
FULLHOUSE
STRAIGHT
TWOPAIR
FULLHOUSE
NOTHING
1
main.py
入力(stdin)

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

$ 準備完了

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

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

この問題は列挙型がある Python・TypeScript・Java・C#・C・C++ だけを受け付けます。
JavaScript には列挙型の構文がなく、Craykon にもありません。
役を弱いものから宣言すれば値の大きさがそのまま強さなので、「より強いか」を > 一つで調べられますが、列挙型を大きさで比べる方法は言語ごとに違います。
Python のただの Enum は <・> を知らないので TypeError になります。
IntEnum にするか .value で比べます。
TypeScript の数値 enum と C# の enum は > でそのまま比べられ、C++ の enum class も同じ型どうしなら <・> が使えます(整数と混ぜるときだけ static_cast が要ります)。
Java の enum は > が使えないので、宣言順(ordinal())で比べる compareTo を使います。
C の enum は名前付きの int 定数なので、そのまま > で比べられます。
名前の出し方も違います:Python h.name、TS 逆引き表 Hand[h]、Java toString()、C# ToString().ToUpperInvariant()(宣言した FullHouse を大文字に)、C は名前表の配列、C++ は switch で名前を返します。
落とし穴は五つ:① Python の IntEnum の値をそのまま print(h) すると、3.11 からは名前ではなく 5 のような数が出ます(ただの Enum なら Hand.FULLHOUSE)。
② ただの Enum に > を使うと実行中に TypeError で止まります。
③ 強い役から順に調べます。
「三つが同じか」をフルハウスより先に調べると、3 3 3 5 5 が TRIPLE になります。
④「最大の目 - 最小の目 == 4」だけではストレートではありません。
1 1 1 3 5 もそうだからです。
五つの目がすべて違う必要があります(そうなら欠けた目が 1 か 6 のときだけ続き番号になります)。
⑤ 役も合計も同じなら前の人が勝つので、入れ替えは > のときだけにし、>= にしてはいけません。
また、列挙型を強いものから宣言した(FIVE が 0)なら、比べる向きも逆にしなければなりません。

Pythonmain.py · 48 行
import sysfrom collections import Counterfrom enum import IntEnum  class Hand(IntEnum):    # 약한 것부터 적어서 값이 클수록 센 족보가 된다(IntEnum이라 > 로 비교할 수 있다)    NOTHING = 0    PAIR = 1    TWOPAIR = 2    TRIPLE = 3    STRAIGHT = 4    FULLHOUSE = 5    FOUR = 6    FIVE = 7  def classify(dice):    counts = sorted(Counter(dice).values(), reverse=True)  # 같은 눈이 몇 개씩인가, 많은 것부터    if counts[0] == 5:        return Hand.FIVE    if counts[0] == 4:        return Hand.FOUR    if counts == [3, 2]:        return Hand.FULLHOUSE    if sorted(dice) in ([1, 2, 3, 4, 5], [2, 3, 4, 5, 6]):        return Hand.STRAIGHT    if counts[0] == 3:        return Hand.TRIPLE    if counts == [2, 2, 1]:        return Hand.TWOPAIR    if counts[0] == 2:        return Hand.PAIR    return Hand.NOTHING  lines = sys.stdin.read().split("\n")n = int(lines[0])best = None  # (족보, 합, 번호)out = []for i in range(1, n + 1):    dice = list(map(int, lines[i].split()))    h = classify(dice)    out.append(h.name)  # print(h)는 IntEnum이라 "7"처럼 수가 나온다    if best is None or (h, sum(dice)) > (best[0], best[1]):        best = (h, sum(dice), i)out.append(str(best[2]))print("\n".join(out))
TypeScriptmain.ts · 48 行
import { readFileSync } from "node:fs"; // 약한 것부터 적으면 값(0, 1, 2…)이 클수록 센 족보가 된다enum Hand {  NOTHING,  PAIR,  TWOPAIR,  TRIPLE,  STRAIGHT,  FULLHOUSE,  FOUR,  FIVE,} function classify(dice: number[]): Hand {  const cnt: number[] = new Array<number>(7).fill(0); // cnt[눈] = 그 눈이 나온 주사위 수  for (const d of dice) cnt[d]++;  const most = Math.max(...cnt);  const pairs = cnt.filter((c) => c === 2).length;  const triple = cnt.includes(3);  if (most === 5) return Hand.FIVE;  if (most === 4) return Hand.FOUR;  if (triple && pairs === 1) return Hand.FULLHOUSE;  // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다  if (most === 1 && (cnt[1] === 0 || cnt[6] === 0)) return Hand.STRAIGHT;  if (triple) return Hand.TRIPLE;  if (pairs === 2) return Hand.TWOPAIR;  if (pairs === 1) return Hand.PAIR;  return Hand.NOTHING;} const lines: string[] = readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const out: string[] = [];let bestHand = Hand.NOTHING, bestSum = -1, winner = 0;for (let i = 1; i <= n; i++) {  const dice = lines[i].trim().split(/\s+/).map(Number);  const h = classify(dice);  const sum = dice.reduce((a, b) => a + b, 0);  out.push(Hand[h]); // h는 수라서 이름은 역방향 표 Hand[h]로 꺼낸다  if (h > bestHand || (h === bestHand && sum > bestSum)) {    bestHand = h;    bestSum = sum;    winner = i;  }}out.push(String(winner));console.log(out.join("\n"));
JavaMain.java · 55 行
import java.io.*;import java.util.*; public class Main {    // 약한 것부터 적으면 선언 차례(ordinal)가 곧 세기 차례다    enum Hand { NOTHING, PAIR, TWOPAIR, TRIPLE, STRAIGHT, FULLHOUSE, FOUR, FIVE }     static Hand classify(int[] dice) {        int[] cnt = new int[7]; // cnt[눈] = 그 눈이 나온 주사위 수        for (int d : dice) cnt[d]++;        int most = 0, pairs = 0;        boolean triple = false;        for (int c : cnt) {            most = Math.max(most, c);            if (c == 2) pairs++;            if (c == 3) triple = true;        }        if (most == 5) return Hand.FIVE;        if (most == 4) return Hand.FOUR;        if (triple && pairs == 1) return Hand.FULLHOUSE;        // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다        if (most == 1 && (cnt[1] == 0 || cnt[6] == 0)) return Hand.STRAIGHT;        if (triple) return Hand.TRIPLE;        if (pairs == 2) return Hand.TWOPAIR;        if (pairs == 1) return Hand.PAIR;        return Hand.NOTHING;    }     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        StringBuilder sb = new StringBuilder();        Hand bestHand = null;        int bestSum = -1, winner = 0;        for (int i = 1; i <= n; i++) {            StringTokenizer st = new StringTokenizer(br.readLine());            int[] dice = new int[5];            int sum = 0;            for (int k = 0; k < 5; k++) {                dice[k] = Integer.parseInt(st.nextToken());                sum += dice[k];            }            Hand h = classify(dice);            sb.append(h).append('\n'); // enum의 toString()은 이름            // enum의 compareTo는 선언 차례로 비교한다            if (bestHand == null || h.compareTo(bestHand) > 0 || (h == bestHand && sum > bestSum)) {                bestHand = h;                bestSum = sum;                winner = i;            }        }        sb.append(winner).append('\n');        System.out.print(sb);    }}
C#Main.cs · 50 行
using System;using System.Linq;using System.Text; // 약한 것부터 적으면 값(0, 1, 2…)이 클수록 센 족보가 된다enum Hand { Nothing, Pair, TwoPair, Triple, Straight, FullHouse, Four, Five } class Program{    static Hand Classify(int[] dice)    {        var cnt = new int[7]; // cnt[눈] = 그 눈이 나온 주사위 수        foreach (int d in dice) cnt[d]++;        int most = cnt.Max();        int pairs = cnt.Count(c => c == 2);        bool triple = cnt.Contains(3);        if (most == 5) return Hand.Five;        if (most == 4) return Hand.Four;        if (triple && pairs == 1) return Hand.FullHouse;        // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다        if (most == 1 && (cnt[1] == 0 || cnt[6] == 0)) return Hand.Straight;        if (triple) return Hand.Triple;        if (pairs == 2) return Hand.TwoPair;        if (pairs == 1) return Hand.Pair;        return Hand.Nothing;    }     static void Main()    {        int n = int.Parse(Console.ReadLine()!.Trim());        var sb = new StringBuilder();        Hand bestHand = Hand.Nothing;        int bestSum = -1, winner = 0;        for (int i = 1; i <= n; i++)        {            int[] dice = Console.ReadLine()!.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();            Hand h = Classify(dice);            int sum = dice.Sum();            sb.Append(h.ToString().ToUpperInvariant()).Append('\n'); // ToString()은 "FullHouse"            if (h > bestHand || (h == bestHand && sum > bestSum))            {                bestHand = h;                bestSum = sum;                winner = i;            }        }        sb.Append(winner).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 63 行
#include <algorithm>#include <array>#include <iostream>#include <string> // 약한 것부터 적으면 선언 차례가 곧 세기 차례다. enum class끼리는 < > 로 바로 비교된다enum class Hand { Nothing, Pair, TwoPair, Triple, Straight, FullHouse, Four, Five }; // enum class는 자기 이름을 모르니 switch로 돌려준다std::string name(Hand h) {    switch (h) {        case Hand::Nothing: return "NOTHING";        case Hand::Pair: return "PAIR";        case Hand::TwoPair: return "TWOPAIR";        case Hand::Triple: return "TRIPLE";        case Hand::Straight: return "STRAIGHT";        case Hand::FullHouse: return "FULLHOUSE";        case Hand::Four: return "FOUR";        case Hand::Five: return "FIVE";    }    return "";} Hand classify(const std::array<int, 5>& dice) {    std::array<int, 7> cnt{}; // cnt[눈] = 그 눈이 나온 주사위 수    for (int d : dice) cnt[d]++;    int most = *std::max_element(cnt.begin(), cnt.end());    int pairs = std::count(cnt.begin(), cnt.end(), 2);    bool triple = std::count(cnt.begin(), cnt.end(), 3) > 0;    if (most == 5) return Hand::Five;    if (most == 4) return Hand::Four;    if (triple && pairs == 1) return Hand::FullHouse;    // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다    if (most == 1 && (cnt[1] == 0 || cnt[6] == 0)) return Hand::Straight;    if (triple) return Hand::Triple;    if (pairs == 2) return Hand::TwoPair;    if (pairs == 1) return Hand::Pair;    return Hand::Nothing;} int main() {    std::ios::sync_with_stdio(false);    int n;    std::cin >> n;    Hand bestHand = Hand::Nothing;    int bestSum = -1, winner = 0;    for (int i = 1; i <= n; i++) {        std::array<int, 5> dice;        int sum = 0;        for (int& d : dice) {            std::cin >> d;            sum += d;        }        Hand h = classify(dice);        std::cout << name(h) << "\n";        if (h > bestHand || (h == bestHand && sum > bestSum)) {            bestHand = h;            bestSum = sum;            winner = i;        }    }    std::cout << winner << "\n";}
Cmain.c · 51 行
#include <stdbool.h>#include <stdio.h> // 약한 것부터 적으면 값(0, 1, 2…)이 클수록 센 족보가 된다enum Hand { NOTHING, PAIR, TWOPAIR, TRIPLE, STRAIGHT, FULLHOUSE, FOUR, FIVE };// C의 enum은 이름을 모르는 int 상수라서 이름표를 따로 둔다(차례를 enum과 똑같이)static const char *NAME[] = {"NOTHING", "PAIR", "TWOPAIR", "TRIPLE", "STRAIGHT", "FULLHOUSE", "FOUR", "FIVE"}; enum Hand classify(const int dice[5]) {    int cnt[7] = {0}; // cnt[눈] = 그 눈이 나온 주사위 수    for (int k = 0; k < 5; k++) cnt[dice[k]]++;    int most = 0, pairs = 0;    bool triple = false;    for (int v = 1; v <= 6; v++) {        if (cnt[v] > most) most = cnt[v];        if (cnt[v] == 2) pairs++;        if (cnt[v] == 3) triple = true;    }    if (most == 5) return FIVE;    if (most == 4) return FOUR;    if (triple && pairs == 1) return FULLHOUSE;    // 다섯 눈이 모두 다르면 빠진 눈은 하나: 1이나 6이 빠졌을 때만 이어진다    if (most == 1 && (cnt[1] == 0 || cnt[6] == 0)) return STRAIGHT;    if (triple) return TRIPLE;    if (pairs == 2) return TWOPAIR;    if (pairs == 1) return PAIR;    return NOTHING;} int main(void) {    int n;    scanf("%d", &n);    enum Hand best_hand = NOTHING;    int best_sum = -1, winner = 0;    for (int i = 1; i <= n; i++) {        int dice[5], sum = 0;        for (int k = 0; k < 5; k++) {            scanf("%d", &dice[k]);            sum += dice[k];        }        enum Hand h = classify(dice);        puts(NAME[h]);        if (h > best_hand || (h == best_hand && sum > best_sum)) {            best_hand = h;            best_sum = sum;            winner = i;        }    }    printf("%d\n", winner);    return 0;}