import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

class Euler54 {

    private static class Options {
        String file = "resources/documents/0054_poker.txt";
        boolean runCheckpoints = true;
    }

    private static class Card {
        int rank = 0;
        char suit = 'X';

        Card(int rank, char suit) {
            this.rank = rank;
            this.suit = suit;
        }
    }

    private static class HandRank {
        int category = 0;
        List<Integer> tiebreak = new ArrayList<>();
    }

    private static boolean parseStringAfterPrefix(String arg, String prefix, StringBuilder value) {
        if (!arg.startsWith(prefix)) {
            return false;
        }
        String tail = arg.substring(prefix.length());
        if (tail.isEmpty()) {
            return false;
        }
        value.setLength(0);
        value.append(tail);
        return true;
    }

    private static boolean parseArguments(String[] args, Options options) {
        for (String arg : args) {
            if ("--skip-checkpoints".equals(arg)) {
                options.runCheckpoints = false;
                continue;
            }
            StringBuilder value = new StringBuilder();
            if (parseStringAfterPrefix(arg, "--file=", value)) {
                options.file = value.toString();
                continue;
            }
            System.err.println("Unknown argument: " + arg);
            return false;
        }
        return true;
    }

    private static int rankFromChar(char c) {
        if (c >= '2' && c <= '9') {
            return c - '0';
        }
        switch (c) {
            case 'T': return 10;
            case 'J': return 11;
            case 'Q': return 12;
            case 'K': return 13;
            case 'A': return 14;
            default: return -1;
        }
    }

    private static Card parseCard(String s) {
        if (s.length() != 2) {
            throw new RuntimeException("Invalid card token: " + s);
        }
        int rank = rankFromChar(s.charAt(0));
        char suit = s.charAt(1);
        if (rank < 2 || rank > 14) {
            throw new RuntimeException("Invalid card rank: " + s);
        }
        return new Card(rank, suit);
    }

    private static HandRank evaluateHand(Card[] hand) {
        int[] freq = new int[15];
        List<Integer> ranks = new ArrayList<>();
        boolean flush = true;
        char suit0 = hand[0].suit;

        for (Card c : hand) {
            freq[c.rank]++;
            ranks.add(c.rank);
            if (c.suit != suit0) {
                flush = false;
            }
        }

        Collections.sort(ranks);
        boolean straight = true;
        for (int i = 1; i < 5; i++) {
            if (ranks.get(i) != ranks.get(i - 1) + 1) {
                straight = false;
                break;
            }
        }

        List<int[]> groups = new ArrayList<>();
        for (int r = 2; r <= 14; r++) {
            if (freq[r] > 0) {
                groups.add(new int[]{freq[r], r});
            }
        }

        groups.sort((a, b) -> {
            if (a[0] != b[0]) {
                return Integer.compare(b[0], a[0]);
            }
            return Integer.compare(b[1], a[1]);
        });

        HandRank result = new HandRank();

        if (straight && flush) {
            result.category = 8;
            result.tiebreak.add(ranks.get(4));
            return result;
        }

        if (groups.get(0)[0] == 4) {
            result.category = 7;
            result.tiebreak.add(groups.get(0)[1]);
            result.tiebreak.add(groups.get(1)[1]);
            return result;
        }

        if (groups.get(0)[0] == 3 && groups.get(1)[0] == 2) {
            result.category = 6;
            result.tiebreak.add(groups.get(0)[1]);
            result.tiebreak.add(groups.get(1)[1]);
            return result;
        }

        if (flush) {
            result.category = 5;
            for (int i = 4; i >= 0; i--) {
                result.tiebreak.add(ranks.get(i));
            }
            return result;
        }

        if (straight) {
            result.category = 4;
            result.tiebreak.add(ranks.get(4));
            return result;
        }

        if (groups.get(0)[0] == 3) {
            result.category = 3;
            result.tiebreak.add(groups.get(0)[1]);
            for (int i = 1; i < groups.size(); i++) {
                result.tiebreak.add(groups.get(i)[1]);
            }
            return result;
        }

        if (groups.get(0)[0] == 2 && groups.get(1)[0] == 2) {
            result.category = 2;
            result.tiebreak.add(groups.get(0)[1]);
            result.tiebreak.add(groups.get(1)[1]);
            result.tiebreak.add(groups.get(2)[1]);
            return result;
        }

        if (groups.get(0)[0] == 2) {
            result.category = 1;
            result.tiebreak.add(groups.get(0)[1]);
            for (int i = 1; i < groups.size(); i++) {
                result.tiebreak.add(groups.get(i)[1]);
            }
            return result;
        }

        result.category = 0;
        for (int i = 4; i >= 0; i--) {
            result.tiebreak.add(ranks.get(i));
        }
        return result;
    }

    private static boolean player1Wins(Card[] p1, Card[] p2) {
        HandRank h1 = evaluateHand(p1);
        HandRank h2 = evaluateHand(p2);

        if (h1.category != h2.category) {
            return h1.category > h2.category;
        }

        for (int i = 0; i < h1.tiebreak.size(); i++) {
            if (!h1.tiebreak.get(i).equals(h2.tiebreak.get(i))) {
                return h1.tiebreak.get(i) > h2.tiebreak.get(i);
            }
        }

        return false;
    }

    private static int solve(String filePath) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        String line;
        int wins = 0;

        while ((line = reader.readLine()) != null) {
            if (line.trim().isEmpty()) {
                continue;
            }

            String[] tokens = line.split("\\s+");
            Card[] p1 = new Card[5];
            Card[] p2 = new Card[5];

            for (int i = 0; i < 5; i++) {
                p1[i] = parseCard(tokens[i]);
            }
            for (int i = 0; i < 5; i++) {
                p2[i] = parseCard(tokens[i + 5]);
            }

            if (player1Wins(p1, p2)) {
                wins++;
            }
        }

        reader.close();
        return wins;
    }

    private static boolean runCheckpoints() {
        {
            Card[] p1 = {parseCard("5H"), parseCard("5C"), parseCard("6S"), parseCard("7S"), parseCard("KD")};
            Card[] p2 = {parseCard("2C"), parseCard("3S"), parseCard("8S"), parseCard("8D"), parseCard("TD")};
            if (player1Wins(p1, p2)) {
                System.err.println("Checkpoint failed for example hand 1");
                return false;
            }
        }
        {
            Card[] p1 = {parseCard("4D"), parseCard("6S"), parseCard("9H"), parseCard("QH"), parseCard("QC")};
            Card[] p2 = {parseCard("3D"), parseCard("6D"), parseCard("7H"), parseCard("QD"), parseCard("QS")};
            if (!player1Wins(p1, p2)) {
                System.err.println("Checkpoint failed for example hand 4");
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        Options options = new Options();
        if (!parseArguments(args, options)) {
            System.exit(1);
        }
        if (options.runCheckpoints && !runCheckpoints()) {
            System.exit(2);
        }

        try {
            System.out.println(solve(options.file));
        } catch (Exception ex) {
            System.err.println(ex.getMessage());
            System.exit(3);
        }
    }
}
