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 & royal) return 9;//royal flush else if (samesuit & 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) } } } }
Leave a comment