Friday, December 30, 2016

Project Euler #54 Poker hands - Java

For this particular problem, I borrowed scoring scheme from nayuki.io (https://github.com/nayuki/Project-Euler-solutions/blob/master/java/p054.java)
import java.util.ArrayList;
import java.util.Scanner;

public class Solution {

    public enum LEVEL {
        TWO(1), THREE(2), FOUR(3), FIVE(4), SIX(5), SEVEN(6), EIGHT(7), NINE(8), TEN(9), JACK(10), QUEEN(11), KING(12), ACE(13);

        private final int level;

        private LEVEL(int level) {
            this.level = level;
        }
    }

    public enum TYPE {
        CLOVER(1), HEART(2), DIAMOND(3), SPADE(4);

        private final int level;

        private TYPE(int level) {
            this.level = level;
        }
    }

    private static class Card {

        public LEVEL mLevel;
        public TYPE mType;

        public Card(LEVEL level, TYPE type) {
            mLevel = level;
            mType = type;
        }
    }

    private static class Player {

        private ArrayList<Card> mInHands = new ArrayList<Card>();

        private boolean mIsFlush = false;
        private boolean mIsRoyal = false;

        public void addCard(Card card) {
            mInHands.add(card);
        }

        /**
         * Borrowed idea from Nayuki.io
         * https://github.com/nayuki/Project-Euler-solutions/blob/master/java/p054.java
         */
        public int checkPower() {
            int[] countByCard = new int[13];
            mIsFlush = true;
            TYPE flushCheck = mInHands.get(0).mType;
            for (Card card : mInHands) {
                countByCard[card.mLevel.level - 1]++;
                if (card.mType != flushCheck) {
                    mIsFlush = false;
                }
            }
            int[] countByLevel = new int[6];
            for (int count : countByCard) {
                countByLevel[count]++;
            }
            int bestCards = get5FrequentHighestCards(countByCard, countByLevel);
            int straightHighRank = getStraightHighRank(countByCard);
            mIsRoyal = (countByCard[12] != 0) && (countByCard[11] != 0) && (countByCard[10] != 0) && (countByCard[9] != 0) && (countByCard[8] != 0);

            if (mIsFlush && mIsRoyal)
                return 9 << 20 | bestCards; // Royal flush
            else if (straightHighRank != -1 && mIsFlush)
                return 8 << 20 | straightHighRank; // Straight flush
            else if (countByLevel[4] == 1)
                return 7 << 20 | bestCards; // Four of a kind
            else if (countByLevel[3] == 1 && countByLevel[2] == 1)
                return 6 << 20 | bestCards; // Full house
            else if (mIsFlush)
                return 5 << 20 | bestCards; // Flush
            else if (straightHighRank != -1)
                return 4 << 20 | straightHighRank; // Straight
            else if (countByLevel[3] == 1)
                return 3 << 20 | bestCards; // Three of a kind
            else if (countByLevel[2] == 2)
                return 2 << 20 | bestCards; // Two pairs
            else if (countByLevel[2] == 1)
                return 1 << 20 | bestCards; // One pair
            else
                return 0 << 20 | bestCards;
        }

        private static int get5FrequentHighestCards(int[] ranks, int[] ranksHist) {
            int result = 0;
            int count = 0;
            for (int i = ranksHist.length - 1; i >= 0; i--) {
                for (int j = ranks.length - 1; j >= 0; j--) {
                    if (ranks[j] == i) {
                        for (int k = 0; k < i && count < 5; k++, count++)
                            result = result << 4 | j;
                    }
                }
            }
            return result;
        }

        private static int getStraightHighRank(int[] ranks) {
            outer: for (int i = ranks.length - 1; i >= 3; i--) {
                for (int j = 0; j < 5; j++) {
                    if (ranks[(i - j + 13) % 13] == 0)
                        continue outer; // Current offset is not a straight
                }
                return i; // Straight found
            }
            return -1;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int T = scanner.nextInt();
        while (T-- > 0) {
            Player p1 = new Player();
            for (int i = 0; i < 5; i++) {
                String input = scanner.next();
                TYPE type = getType(input);
                LEVEL level = getLevel(input);
                Card card = new Card(level, type);
                p1.addCard(card);
            }
            Player p2 = new Player();
            for (int i = 0; i < 5; i++) {
                String input = scanner.next();
                TYPE type = getType(input);
                LEVEL level = getLevel(input);
                Card card = new Card(level, type);
                p2.addCard(card);
            }
            if (p1.checkPower() < p2.checkPower()) {
                System.out.println("Player 2");
            } else {
                System.out.println("Player 1");
            }
        }
        scanner.close();
    }

    private static TYPE getType(String input) {
        TYPE type;
        char c = input.charAt(1);
        switch (c) {
            case 'S':
            case 's':
                type = TYPE.SPADE;
                break;
            case 'D':
            case 'd':
                type = TYPE.DIAMOND;
                break;
            case 'H':
            case 'h':
                type = TYPE.HEART;
                break;
            case 'C':
            case 'c':
            default:
                type = TYPE.CLOVER;
                break;
        }
        return type;
    }

    private static LEVEL getLevel(String input) {
        LEVEL level;
        char lc = input.charAt(0);
        switch (lc) {
            case '2':
                level = LEVEL.TWO;
                break;
            case '3':
                level = LEVEL.THREE;
                break;
            case '4':
                level = LEVEL.FOUR;
                break;
            case '5':
                level = LEVEL.FIVE;
                break;
            case '6':
                level = LEVEL.SIX;
                break;
            case '7':
                level = LEVEL.SEVEN;
                break;
            case '8':
                level = LEVEL.EIGHT;
                break;
            case '9':
                level = LEVEL.NINE;
                break;
            case 'T':
            case 't':
                level = LEVEL.TEN;
                break;
            case 'J':
            case 'j':
                level = LEVEL.JACK;
                break;
            case 'Q':
            case 'q':
                level = LEVEL.QUEEN;
                break;
            case 'K':
            case 'k':
                level = LEVEL.KING;
                break;
            case 'A':
            case 'a':
            default:
                level = LEVEL.ACE;
                break;
        }
        return level;
    }
}

Tuesday, December 20, 2016

Project Euler #53 Combinatoric selections - Java

import java.math.BigInteger;
import java.util.Scanner;

public class Solution {

    private static final boolean DEBUG = false;

    /**
     * if n is even (e.g. 4), and if answer exists it will be even if n is odd
     * (e.g. 5), and if answer exists it will be odd
     */
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N2 = scanner.nextInt();
        long K = scanner.nextLong();
        int count = 0;
        for (int N = 1; N <= N2; N++) {
            for (int i = 1; i <= N / 2; i++) {
                BigInteger ret = combination(N, i);
                if (DEBUG) {
                    System.out.println("i:" + i + " ret:" + ret);
                }
                if (ret.compareTo(BigInteger.valueOf(K)) > 0) {
                    count += N - 2 * i + 1;
                    break;
                }
            }
        }
        System.out.println(count);
        scanner.close();
    }

    private static BigInteger combination(int n, int r) {
        BigInteger ret = BigInteger.ONE;
        if (r == 0 || r == n) {
            return ret;
        }
        if (r == 1) {
            return BigInteger.valueOf(n);
        }
        // n! / (r! * (n-r)!)
        if (r > (n - r)) {
            for (int i = r + 1; i <= n; i++) {
                ret = ret.multiply(BigInteger.valueOf(i));
            }
            for (int i = 2; i <= n - r; i++) {
                ret = ret.divide(BigInteger.valueOf(i));
            }
        } else {
            for (int i = n - r + 1; i <= n; i++) {
                ret = ret.multiply(BigInteger.valueOf(i));
            }
            for (int i = 2; i <= r; i++) {
                ret = ret.divide(BigInteger.valueOf(i));
            }
        }
        return ret;
    }
}

Project Euler #52 Permuted multiples - Java

import java.util.Scanner;

public class Solution {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long N = scanner.nextLong();
        int K = scanner.nextInt();
        scanner.close();
        long cur = 0;
        long cur2;
        while (cur <= N) {
            boolean flag = true;
            for (int i = 2; i <= K; i++) {
                cur2 = cur * i;
                if (!isSame(cur, cur2)) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                for (int i = 0; i < K; i++) {
                    System.out.print(cur * (i + 1) + " ");
                }
                System.out.println();
            }
            cur++;
        }
    }

    private static boolean isSame(long cur, long cur2) {
        String s1 = String.valueOf(cur);
        String s2 = String.valueOf(cur2);
        if (s1.length() != s2.length()) {
            return false;
        } else if (s1.endsWith("0") || s2.endsWith("0")) {
            return false;
        }
        char[] cs1 = s1.toCharArray();
        java.util.Arrays.sort(cs1);
        char[] cs2 = s2.toCharArray();
        java.util.Arrays.sort(cs2);
        return String.valueOf(cs1).equals(String.valueOf(cs2));
    }
}

Project Euler #50 Consecutive prime sum - Java

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.TreeMap;

public class Solution {

    private static long[] ARRAY;
    private static int COUNT;
    private static TreeMap<Long, Integer> ANSWERS = new TreeMap<Long, Integer>();
    private static ArrayList<Long> PRIMES = new ArrayList<Long>();

    public static void main(String[] args) {
        generateData();
        generateAnswer();
        Scanner scanner = new Scanner(System.in);
        int T = scanner.nextInt();
        while (T-- > 0) {
            long N = scanner.nextLong();
            int length = Integer.MIN_VALUE;
            long answer = 0;
            for (long sum : ANSWERS.keySet()) {
                if (sum > N) {
                    continue;
                }
                if (length < ANSWERS.get(sum)) {
                    length = ANSWERS.get(sum);
                    answer = sum;
                }
            }
            System.out.println(answer + " " + length);
        }
        scanner.close();
    }

    private static void generateAnswer() {
        for (int i = 0; i < COUNT; i++) {
            for (int j = i + 1; j < COUNT; j++) {
                long sum = 0;
                for (int k = i; k <= j; k++) {
                    sum += ARRAY[k];
                }
                if (isPrime(sum, 4)) {
                    if (!ANSWERS.containsKey(sum) || ANSWERS.get(sum) < (j - i + 1)) {
                        ANSWERS.put(sum, (j - i + 1));
                    }
                }
            }
        }
    }

    private static void generateData() {
        COUNT = 0;
        PRIMES.add(2L);
        long n = 3;
        while (COUNT < 1400) {
            if (isPrime(n, 4)) {
                COUNT++;
                PRIMES.add(n);
            }
            n += 2;
        }
        ARRAY = new long[PRIMES.size()];
        COUNT = 0;
        for (Long l : PRIMES) {
            ARRAY[COUNT++] = l;
        }
    }

    private static boolean isPrime(long n, int k) {
        if (n <= 1 || n == 4) {
            return false;
        }
        if (n <= 3) {
            return true;
        }
        long d = n - 1;
        while (d % 2 == 0) {
            d /= 2;
        }
        for (int i = 0; i < k; i++) {
            if (miillerTest(d, n) == false) {
                return false;
            }
        }
        return true;
    }

    private static boolean miillerTest(long dl, long n) {
        long al = (long) (2 + (Math.random() % (n - 4)));
        BigInteger a = BigInteger.valueOf(al);
        BigInteger nMinusOne = BigInteger.valueOf(n - 1);
        BigInteger x = a.modPow(BigInteger.valueOf(dl), BigInteger.valueOf(n));
        if (x.equals(BigInteger.ONE) || x.equals(nMinusOne)) {
            return true;
        }
        BigInteger d = BigInteger.valueOf(dl);
        while (!d.equals(nMinusOne)) {
            x = x.multiply(x);
            x = x.mod(BigInteger.valueOf(n));
            d = d.multiply(BigInteger.valueOf(2l));
            if (x.equals(BigInteger.ONE)) {
                return false;
            }
            if (x.equals(nMinusOne)) {
                return true;
            }
        }
        return false;
    }
}