Evil Science A whole load of stuff

31Aug/130

Project Euler Problem 54

Here's my solution to Project Euler Problem 54, it's written in C Sharp and outputs the winner of each hand and how they won. It can optimised, but is still very fast.

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

namespace Euler54b
{
    class Program
    {
        static List<string> Ranks = new List<string>() { "High Card", "One Pair", "Two Pairs", "Three of a Kind", "Straight", "Flush", "Full House", "Four of a Kind", "Straight Flush", "Royal Flush" };

        /// <summary>
        /// Start Here
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {

            int p1HighestCard;
            int p2HighestCard;
            int p1Hand;
            int p2Hand;

            int p1win = 0;
            int p2win = 0;

            string hand;

            using (StreamReader sr = new StreamReader("poker.txt"))
            {
                while (!sr.EndOfStream)
                {
                    hand = sr.ReadLine();

                    ProcessHands(hand, out p1Hand, out p2Hand, out  p1HighestCard, out p2HighestCard);

                    if (p1Hand > p2Hand)
                    {
                        p1win++;
                        Console.WriteLine("    Player 1: {0}", Ranks[p1Hand]);
                    }
                    else if (p2Hand > p1Hand | p2HighestCard > p1HighestCard)
                    {
                        p2win++;
                        Console.WriteLine("    Player 1: {0}", Ranks[p2Hand]);
                    }
                    else
                    {
                        if ( p1HighestCard > p2HighestCard)
                        {
                            Console.WriteLine("    Player 1 highest card {0}", GetCard(p1HighestCard));
                            p1win++;
                        }
                        else
                        {
                            Console.WriteLine("    Player 2 highest card {0}", GetCard(p2HighestCard));
                            p2win++;
                        }
                    }

                    Console.WriteLine();

                }
            }

            Console.WriteLine();
            Console.WriteLine("Player 1 win: {0} Player 2 win: {1}", p1win, p2win);
            Console.ReadLine();
        }

        /// <summary>
        /// Build the hand and sort it by rank
        /// </summary>
        /// <param name="pHand">String containing hand</param>
        /// <returns>Generic list of hand</returns>
        static List<string> GetHand(string pHand)
        {
            return pHand.Split(new string[] { " " }, StringSplitOptions.None).OrderBy(c => GetCardValue(c)).ToList();
        }

        /// <summary>
        /// Return a numeric value representing the provided card
        /// </summary>
        /// <param name="pCard">Card to examine</param>
        /// <returns>Numeric value</returns>
        static int GetCardValue(string pCard)
        {
            int result;
            int.TryParse(pCard.Substring(0, 1), out result);

            if (result == 0)
            {
                switch (pCard.Substring(0, 1))
                {
                    case "T":
                        return 9;
                    case "J":
                        return 10;
                    case "Q":
                        return 11;
                    case "K":
                        return 12;
                    case "A":
                        return 13;

                }
            }

            return result;
        }

        /// <summary>
        /// Get a string representing a card value from its numeric value
        /// </summary>
        /// <param name="pValue">Numeric value of card</param>
        /// <returns>String value</returns>
        static string GetCard(int pValue)
        {
            if (pValue < 9)
                return pValue.ToString();
            else
            {
                switch (pValue)
                {
                    case 9:
                        return "T";
                    case 10:
                        return "J";
                    case 11:
                        return "Q";
                    case 12:
                        return "K";
                    case 13:
                        return "A";
                }
            }

            return "";
        }


        /// <summary>
        /// Process the player hands
        /// </summary>
        /// <param name="pHands">String representing the player hands</param>
        /// <param name="p1Hand">Out variable: the rank of hand 1</param>
        /// <param name="p2Hand">Out variable: the rank of hand 2</param>
        /// <param name="p1HighestCard">Out variable: highest card in hand 1</param>
        /// <param name="p2HighestCard">Out variable: highest card in hand 2</param>
        static void ProcessHands(string pHands, out int p1Hand, out int p2Hand, out int p1HighestCard, out int p2HighestCard)
        {

            List<string> Player1 = GetHand(pHands.Substring(0, 14));
            List<string> Player2 = GetHand(pHands.Substring(15, 14));

            Console.WriteLine("Player 1: {0}", string.Join(" ", Player1.ToArray()));
            Console.WriteLine("Player 2: {0}", string.Join(" ", Player2.ToArray()));

            p1Hand = RankHand(Player1, out p1HighestCard);
            p2Hand = RankHand(Player2, out p2HighestCard);

            if ((p1Hand == p2Hand))
            {
                while (p1HighestCard == p2HighestCard)
                {
                    p1HighestCard = GetHighestValue(Player1, p1HighestCard);
                    p2HighestCard = GetHighestValue(Player2, p2HighestCard);
                };
            }
        }


        /// <summary>
        /// Get the highest value in the hand that occurs before the current highest card
        /// </summary>
        /// <param name="hand">Hand to examine</param>
        /// <param name="pHighestCardIndex">Current highest card</param>
        /// <returns></returns>
        static int GetHighestValue(List<string> hand, int pHighestCardIndex)
        {
            //create a list of the cards with an accompanying index of it's value
            var vals = from h in hand
                      select new { card = h, index = GetCardValue(h) };

            //if the current highest card is the lowest in the list, then return that.
            if (pHighestCardIndex == vals.First().index)
                return pHighestCardIndex;
            else
                //get the last value in the above list that is lower that current highest card
                return (from v in vals
                        where v.index < pHighestCardIndex
                        select v.index).Last();
        }

        /// <summary>
        /// Rank the provided hand
        /// </summary>
        /// <param name="pHand">Hand to rank</param>
        /// <param name="pHighestValue">Highest value in the hand</param>
        /// <returns>The rank of hand</returns>
        static int RankHand(List<string> pHand, out int pHighestValue)
        {
            //check for consecutive values
            bool straight = true;
            for (int i = 1; i < pHand.Count(); i++)
                if (GetCardValue(pHand[i]) - 1 != GetCardValue(pHand[i - 1]))
                    straight = false;

            //check for same suit
            bool samesuit = pHand.Select(h => h.Substring(1, 1)).Distinct().Count() == 1;

            //is it royal
            bool royal = String.Join("", pHand.Select(h => h.Substring(1, 1)).ToArray()) == "TJQKA";

            //the current haighest value is the last
            pHighestValue = GetCardValue(pHand.Last());

            if (samesuit &amp; royal)
                return 9;//royal flush
            else if (samesuit &amp; straight)
                return 8;//straight flush
            else if (samesuit)
                return 5;//flush
            else if (straight)
                return 4; //straight



            //count the occurences of cards
            var c = from h in pHand
                    group h by h.Substring(0, 1) into g
                    orderby g.Count()
                    select new { card = g.Key, cnt = g.Count() };

            pHighestValue = GetCardValue(c.Last().card);

            if (c.Count() == 5) //all values different
            {
                pHighestValue = GetCardValue(pHand.Last());
                return 0;
            }
            else if (c.Count() == 4)
            {
                return 1; //one pair
            }
            else if (c.Count() == 3)
            {
                if (c.Last().cnt == 3)
                    return 3; //three of a kind
                else
                    return 2;//two pairs
            }
            else
            {
                if (c.Last().cnt == 4)
                    return 7;//four of kind
                else
                    return 6;//full house (three of a kind and a pair)
            }

        }
    }
}
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

No trackbacks yet.