티스토리 툴바


Programming Challenges라는 책에 나오는 열번째 문제인 Poker Hands를 풀어보았습니다.

문제 자체는 간단합니다.

다만 문제를 참신한 알고리즘으로 바라보기 보다는

단순한 비지니스 로직으로 해석하고 있는 자신을 다시 보게 되었습니다.

나이가 들어서 머리가 굳은 것인지, 사용을 안해서 굳은 것인지 슬픈 일입니다.

문제는 다음에서 확인하실 수 있습니다.


소스는 다음과 같습니다.

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

class Main implements Runnable {
    static String ReadLn(int maxLength) {
        byte line[] = new byte[maxLength];
        int length = 0;
        int input = -1;
        try {
            while (length < maxLength) {
                input = System.in.read();
                if ((input < 0) || (input == '\n'))
                    break;
                line[length++] += input;
            }

            if ((input < 0) && (length == 0))
                return null;
            return new String(line, 0, length);
        } catch (IOException e) {
            return null;
        }
    }

    public static void main(String args[]) {
        Main myWork = new Main();
        myWork.run();
    }

    public void run() {
        new myStuff().run();
    }
}

class myStuff implements Runnable {
    static class Card implements Comparable<Card> {
        Value value;
        Suit suit;

        public Card(Value value, Suit suit) {
            this.value = value;
            this.suit = suit;
        }

        public static Card getCard(Value value, Suit suit) {
            return new Card(value, suit);
        }

        @Override
        public int compareTo(Card o) {
            return this.value.compareTo(o.value);
        }

        @Override
        public String toString() {
            return "(" + value + "," + suit + ")";
        }
    }

    enum Value {
        VALUE_2('2'), //
        VALUE_3('3'), //
        VALUE_4('4'), //
        VALUE_5('5'), //
        VALUE_6('6'), //
        VALUE_7('7'), //
        VALUE_8('8'), //
        VALUE_9('9'), //
        VALUE_10('T'), //
        VALUE_JACK('J'), //
        VALUE_QUEEN('Q'), //
        VALUE_KING('K'), //
        VALUE_ACE('A');

        private char c;

        private Value(char c) {
            this.c = c;
        }

        private static final Map<Character, Value> cAndValueMap = new HashMap<Character, Value>();
        static {
            for (Value value : values()) {
                cAndValueMap.put(value.c, value);
            }
        }

        public static Value getValue(char c) {
            return cAndValueMap.get(c);
        }
    }

    enum Suit {
        CLUB('C'), //
        DIAMOND('D'), //
        HEART('H'), //
        SPADE('S');

        private char c;

        private static final Map<Character, Suit> cAndSuitMap = new HashMap<Character, Suit>();
        static {
            for (Suit suit : values()) {
                cAndSuitMap.put(suit.c, suit);
            }
        }

        private Suit(char c) {
            this.c = c;
        }

        public static Suit getSuit(char c) {
            return cAndSuitMap.get(c);
        }
    }

    enum Rank {
        HIGH_CARD, //
        PAIR, //
        TWO_PAIRS, //
        THREE_OF_A_KIND, //
        STRAIGHT, //
        FLUSH, //
        FULL_HOUSE, //
        FOUR_OF_A_KIND, //
        STRAIGHT_FLUSH;
    }

    static class RankResult {
        Rank rank;
        Value[] valueOfGroup;

        public RankResult(Rank rank, Value... valueOfGroup) {
            this.rank = rank;
            this.valueOfGroup = valueOfGroup;
        }

        @Override
        public String toString() {
            return rank + "," + Arrays.asList(valueOfGroup);
        }
    }

    // Assume that all cards are sorted.
    public static boolean isStraight(Card[] cards) {
        Value prevValue = cards[0].value;
        for (int i = 1; i < cards.length; i++) {
            Value value = cards[i].value;
            if (value.ordinal() != prevValue.ordinal() + 1) {
                return false;
            }
            prevValue = value;
        }
        return true;
    }

    public static boolean isFlush(Card[] cards) {
        Suit suit = cards[0].suit;
        for (int i = 1; i < cards.length; i++) {
            if (cards[i].suit != suit) {
                return false;
            }
        }
        return true;
    }

    // Assume that all cards are sorted.
    public static boolean isStraightFlush(Card[] cards) {
        return isStraight(cards) && isFlush(cards);
    }

    enum Result {
        BLACK_WIN("Black wins."), WHITE_WIN("White wins."), TIE("Tie.");

        String message;

        private Result(String message) {
            this.message = message;
        }

        public String toString() {
            return message;
        }
    }

    private static final int MAX_LENGTH = 1024 * 100;

    private static final int MAX_CARDS = 5;

    private Card[] blackHand = new Card[MAX_CARDS];
    private Card[] whiteHand = new Card[MAX_CARDS];

    public void run() {
        String line;
        while ((line = Main.ReadLn(MAX_LENGTH)) != null) {
            line = line.trim();
            if (line.isEmpty()) {
                continue;
            }
            String[] splitLine = line.split("\\s+");
            Result result = process(splitLine);
            System.out.println(result);
        }
    }

    public static Card getCard(String card) {
        Value value = Value.getValue(card.charAt(0));
        Suit suit = Suit.getSuit(card.charAt(1));
        return Card.getCard(value, suit);
    }

    public Result process(String[] cards) {
        int index = 0;
        for (int i = 0; i < blackHand.length; i++) {
            blackHand[i] = getCard(cards[index++]);
        }
        for (int i = 0; i < whiteHand.length; i++) {
            whiteHand[i] = getCard(cards[index++]);
        }
        return war(blackHand, whiteHand);
    }

    public static Result war(Card[] blackHand, Card[] whiteHand) {
        Arrays.sort(blackHand);
        Arrays.sort(whiteHand);
        RankResult blackHandRankResult = getRankResult(blackHand);
        RankResult whiteHandRankResult = getRankResult(whiteHand);
        return war(blackHandRankResult, whiteHandRankResult);
    }

    // Assume that all cards are sorted.
    public static Result war(RankResult blackHandRankResult,
            RankResult whiteHandRankResult) {
        Rank blackHandRank = blackHandRankResult.rank;
        Rank whiteHandRank = whiteHandRankResult.rank;
        int result = blackHandRank.compareTo(whiteHandRank);
        if (result > 0) {
            return Result.BLACK_WIN;
        } else if (result < 0) {
            return Result.WHITE_WIN;
        } else {
            Value[] valueOfGroupOfBlackHand = blackHandRankResult.valueOfGroup;
            Value[] valueOfGroupOfWhiteHand = whiteHandRankResult.valueOfGroup;
            for (int i = 0; i < valueOfGroupOfBlackHand.length; i++) {
                result = valueOfGroupOfBlackHand[i]
                        .compareTo(valueOfGroupOfWhiteHand[i]);
                if (result > 0) {
                    return Result.BLACK_WIN;
                } else if (result < 0) {
                    return Result.WHITE_WIN;
                }
            }
            return Result.TIE;
        }
    }

    // Assume that all cards are sorted.
    public static RankResult getRankResult(Card[] cards) {
        Value[] reverseValues = new Value[cards.length];
        for (int i = cards.length - 1; i >= 0; i--) {
            reverseValues[cards.length - 1 - i] = cards[i].value;
        }

        if (isStraightFlush(cards)) {
            return new RankResult(Rank.STRAIGHT_FLUSH,
                    cards[MAX_CARDS - 1].value);
        }
        if (isFlush(cards)) {
            return new RankResult(Rank.FLUSH, reverseValues);
        }
        if (isStraight(cards)) {
            return new RankResult(Rank.STRAIGHT, cards[MAX_CARDS - 1].value);
        }

        int maxCardsInGroup = -1;
        int indexOfMaxCardsInGroup = -1;
        int groupCount = 0;
        Value[] valueOfGroup = new Value[2];

        int cardsInGroup = 1;
        Value prevValue = cards[0].value;
        for (int i = 1; i < cards.length; i++) {
            Value value = cards[i].value;
            if (value.ordinal() == prevValue.ordinal()) {
                cardsInGroup++;
            } else {
                if (cardsInGroup >= 2) {
                    valueOfGroup[groupCount] = cards[i - cardsInGroup].value;
                    groupCount++;

                    if (cardsInGroup > maxCardsInGroup) {
                        maxCardsInGroup = cardsInGroup;
                        indexOfMaxCardsInGroup = i - cardsInGroup;
                    }

                    cardsInGroup = 1;
                }
            }
            prevValue = value;
        }

        if (cardsInGroup >= 2) {
            valueOfGroup[groupCount] = cards[cards.length - cardsInGroup].value;
            groupCount++;

            if (cardsInGroup > maxCardsInGroup) {
                maxCardsInGroup = cardsInGroup;
                indexOfMaxCardsInGroup = cards.length - cardsInGroup;
            }
        }

        if (maxCardsInGroup == 4) {
            return new RankResult(Rank.FOUR_OF_A_KIND,
                    cards[indexOfMaxCardsInGroup].value);
        }
        if (maxCardsInGroup == 3) {
            if (groupCount == 2) {
                return new RankResult(Rank.FULL_HOUSE,
                        cards[indexOfMaxCardsInGroup].value);
            } else {
                return new RankResult(Rank.THREE_OF_A_KIND,
                        cards[indexOfMaxCardsInGroup].value);
            }
        }
        if (groupCount == 2) {
            Value other = null;
            for (Value value : reverseValues) {
                if (value != valueOfGroup[0] && value != valueOfGroup[1]) {
                    other = value;
                    break;
                }
            }
            return new RankResult(Rank.TWO_PAIRS, valueOfGroup[0],
                    valueOfGroup[1], other);
        }
        if (groupCount == 1) {
            Value[] others = new Value[3];
            int indexOfOthers = 0;
            for (Value value : reverseValues) {
                if (value != valueOfGroup[0]) {
                    others[indexOfOthers++] = value;
                }
            }
            return new RankResult(Rank.PAIR, valueOfGroup[0], others[0],
                    others[1], others[2]);
        }
        return new RankResult(Rank.HIGH_CARD, reverseValues);
    }
}

테스트는 다음과 같습니다.

import org.junit.Test;

import util.MainTestHelper;

public class MainTest {
    @Test
    public void test() throws Exception {
        String inputFilename = "src/test/resources/p110202/110202.inp";
        String answerFilename = "src/test/resources/p110202/110202.oup";

        MainTestHelper.checkAnswer(new Runnable() {
            @Override
            public void run() {
                Main.main(null);
            }
        }, inputFilename, answerFilename);
    }
}

마찬가지로 Programming Challenges 사이트에서는 안되고, UVa 사이트에서 확인하실 수 있습니다.

UVa 사이트는 다음과 같습니다.


UVa 사이트에서 이 문제의 ID는 10315입니다.

Posted by izeye