Challenge: Number Letter Counts

Posted on: July 9, 2016 2:02:04 PM

This challenge wants you to get the count of the number of letters in the numbers 1 to 1000. This was a bit of an extra challenge for me because it wants the numbers in a "British compliance" format. This means the word 'and' is included in the number. I didn't do any research on the exact specifics on when the 'and' should be used, I just looked at their example of how to handle the hundreds because we're only trying to get to 1000.

IntToWordHelper.cs
using System.Collections.Generic;
using System.Text;

namespace ProjectEuler_17
{
    public static class IntToWordHelper
    {
        private const string And = "and";
        private const string Space = " ";

        private static readonly string[] BaseNumbers =
        {
            "zero",
            "one",
            "two",
            "three",
            "four",
            "five",
            "six",
            "seven",
            "eight",
            "nine",
            "ten",
            "eleven",
            "twelve",
            "thirteen",
            "fourteen",
            "fifteen",
            "sixteen",
            "seventeen",
            "eighteen",
            "nineteen"
        };

        private static readonly string[] HundredMultiplierNames =
        {
            null, // pad the array so the values line up properly
            "hundred",
            "thousand",
            "million",
            "billion"
        };

        private static readonly string[] TensNames =
                {
            null, // pad the array so the values line up properly
            null,
            "twenty",
            "thirty",
            "forty",
            "fifty",
            "sixty",
            "seventy",
            "eighty",
            "ninety"
        };

        public static string ConvertToWord(int number, bool includeAnd = false)
        {
            List result = new List();

            int[] intArray = GetIntArray(number);

            if (intArray.Length == 0)
            {
                return BaseNumbers[0];
            }

            if (intArray.Length == 1)
            {
                return BaseNumbers[intArray[0]];
            }

            int index = 0;
            int hundredsMultiplierIndex = 0;
            while (index < intArray.Length)
            {
                // take 3 numbers at a time
                int one = intArray[index++];
                int ten = index < intArray.Length ? intArray[index++] : 0;
                int hundred = index < intArray.Length ? intArray[index++] : 0;

                string words = ProcessNumber(hundred, ten, one, includeAnd);

                if (hundredsMultiplierIndex++ > 0 && !string.IsNullOrEmpty(words))
                {
                    words += Space + HundredMultiplierNames[hundredsMultiplierIndex];
                }

                if (!string.IsNullOrEmpty(words))
                {
                    result.Add(words);
                }
            }

            // the words are reversed at this point
            result.Reverse();
            return string.Join(Space, result);
        }

        private static int[] GetIntArray(int num)
        {
            List listOfInts = new List();
            while (num > 0)
            {
                listOfInts.Add(num % 10);
                num = num / 10;
            }

            // the array is reversed, but this helps
            return listOfInts.ToArray();
        }

        private static string ProcessNumber(int hundred, int ten, int one, bool includeAnd)
        {
            StringBuilder sb = new StringBuilder();

            if (hundred > 0)
            {
                sb.Append(BaseNumbers[hundred]).Append(Space).Append(HundredMultiplierNames[1]);

                if (includeAnd)
                {
                    if (ten > 0 || one > 0)
                    {
                        sb.Append(Space).Append(And);
                    }
                }

                sb.Append(Space);
            }

            if (ten > 0)
            {
                if (ten == 1)
                {
                    return sb.Append(BaseNumbers[(ten * 10) + one]).ToString();
                }

                sb.Append(TensNames[ten]).Append(Space);
            }

            if (one > 0)
            {
                sb.Append(BaseNumbers[one]);
            }

            return sb.ToString().Trim();
        }
    }
}

You'll notice that I handle the number in groups of 3, this is because hundreds are always labeled the same regardless of where it is. This allows me to use far less code than would otherwise be needed. The next bit of code needed is the actual counting of the words with the loop of numbers.

Program.cs
using System;

namespace ProjectEuler_17
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            int count = 0;
            for (int i = 1; i <= 1000; i++)
            {
                string word = IntToWordHelper.ConvertToWord(i, true);

                count += word.Replace(" ", "").Length;
            }

            Console.WriteLine("Count: {0}", count);
        }
    }
}

Lastly, as a good practice, some unit tests to prove the functionality.

Tests.cs
using NUnit.Framework;

namespace ProjectEuler_17.Tests
{
    [TestFixture]
    public class Tests
    {
        private static object[] TestValues =
        {
            new object[] {0, "zero", false},
            new object[] {11, "eleven", false},
            new object[] {20, "twenty", false},
            new object[] {47, "forty seven", false},
            new object[] {673, "six hundred seventy three", false},
            new object[] {8172, "eight thousand one hundred seventy two", false},
            new object[] {900000002, "nine hundred million two", false},
            new object[] {123456789, "one hundred twenty three million four hundred fifty six thousand seven hundred eighty nine", false},
            new object[] {int.MaxValue, "two billion one hundred forty seven million four hundred eighty three thousand six hundred forty seven", false}, //2 147 483 647
            new object[] {4019, "four thousand nineteen", false},
            new object[] {28600, "twenty eight thousand six hundred", false },
            new object[] {0, "zero", true},
            new object[] {11, "eleven", true},
            new object[] {20, "twenty", true},
            new object[] {47, "forty seven", true},
            new object[] {673, "six hundred and seventy three", true},
            new object[] {8172, "eight thousand one hundred and seventy two", true},
            new object[] {900000002, "nine hundred million two", true},
            new object[] {123456789, "one hundred and twenty three million four hundred and fifty six thousand seven hundred and eighty nine", true},
            new object[] {int.MaxValue, "two billion one hundred and forty seven million four hundred and eighty three thousand six hundred and forty seven", true}, //2 147 483 647
            new object[] {4019, "four thousand nineteen", true},
            new object[] {28600, "twenty eight thousand six hundred", true },
            new object[] {342, "three hundred and forty two", true }
        };

        [Test, TestCaseSource("TestValues")]
        public void Euler17Test(int number, string expectedResult, bool includeAnd)
        {
            string result = IntToWordHelper.ConvertToWord(number, includeAnd);

            Assert.That(result, Is.EqualTo(expectedResult));
        }
    }
}

Poker Logic

Posted on: June 7, 2016 1:31:50 AM

Another programming challenge that I decided to do was a poker challenge The goal of this challenge is to parse 1000 random poker hands of 2 players and determine how many times the first player wins. This was actually quite a fun challenge and I suggest you try to do it on your own even though I'm posting my code.

I decided to do this in a more TDD way than I normally do. So just as I started, I'll start by posting all of my unit tests. Granted, I didn't have them all at the time of development, but I don't think it's necessary to post what I did every step of the way.

PokerTests.cs
using NUnit.Framework;
using Poker_Kata;

namespace Poker_Tests
{
    [TestFixture]
    public class PokerTests
    {
        private Player P1;
        private Player P2;

        [Test]
        public void P13OfAKind()
        {
            P1.SetHand("3D", "3H", "3C", "4D", "7D");
            P2.SetHand("2S", "2D", "2C", "AS", "KS");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P1));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.ThreeKind));
        }

        [Test]
        public void P1FourKind()
        {
            P1.SetHand("2D", "2S", "2C", "2H", "TD");
            P2.SetHand("2S", "AS", "4S", "5S", "6S");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P1));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.FourKind));
        }

        [Test]
        public void P1HighCard()
        {
            P1.SetHand("2D", "3D", "4D", "5D", "8C");
            P2.SetHand("2C", "3S", "4S", "5S", "7S");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P1));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.HighCard));
        }

        [Test]
        public void P1HighPair()
        {
            P1.SetHand("3D", "3H", "4D", "5D", "6D");
            P2.SetHand("2S", "2C", "QS", "KD", "AS");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P1));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.Pair));
        }

        [Test]
        public void P1Pair()
        {
            P1.SetHand("2D", "2H", "4D", "5D", "7D");
            P2.SetHand("2C", "3S", "4S", "5S", "7S");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P1));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.Pair));
        }

        [Test]
        public void P1RoyalFlush()
        {
            P1.SetHand("AD", "TD", "KD", "QD", "JD");
            P2.SetHand("AS", "2S", "3S", "4S", "5S");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P1));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.StraightFlush));
        }

        [Test]
        public void P1Straight()
        {
            P1.SetHand("2D", "3H", "4C", "5D", "6D");
            P2.SetHand("2S", "2D", "2C", "AS", "AS");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P1));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.Straight));
        }

        [Test]
        public void P1TwoPair()
        {
            P1.SetHand("2D", "2H", "3D", "3D", "7D");
            P2.SetHand("2S", "3S", "4S", "AS", "AS");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P1));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.TwoPair));
        }

        [Test]
        public void P1TwoPairHighCard()
        {
            P1.SetHand("4C", "4S", "2D", "AD", "2H");
            P2.SetHand("4S", "4D", "2S", "KS", "2C");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P1));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.TwoPair));
        }

        [Test]
        public void P2AceHighCard()
        {
            P1.SetHand("2D", "3D", "4S", "5D", "7D");
            P2.SetHand("2S", "3S", "6D", "5S", "AS");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.HighCard));
        }

        [Test]
        public void P2Flush()
        {
            P1.SetHand("AD", "KH", "QC", "JD", "TD");
            P2.SetHand("2S", "TS", "4S", "5S", "6S");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.Flush));
        }

        [Test]
        public void P2FullHouse()
        {
            P1.SetHand("AD", "AH", "AC", "3D", "7D");
            P2.SetHand("2S", "2D", "2C", "3S", "3D");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.FullHouse));
        }

        [Test]
        public void P2FullHouse3CardHigher()
        {
            P1.SetHand("3D", "3H", "3C", "AD", "AD");
            P2.SetHand("4S", "4D", "4C", "2S", "2D");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.FullHouse));
        }

        [Test]
        public void P2HighCard2()
        {
            P1.SetHand("8C", "TS", "KC", "9H", "4S");
            P2.SetHand("7D", "2S", "5D", "3S", "AC");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.HighCard));
        }

        [Test]
        public void P2HighCard3()
        {
            P1.SetHand("4D", "5H", "TH", "QS", "KS");
            P2.SetHand("2H", "3D", "4S", "6C", "AD");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.HighCard));
        }

        [Test]
        public void P2HighFlush()
        {
            P1.SetHand("4D", "KD", "QD", "JD", "TD");
            P2.SetHand("2S", "AS", "4S", "5S", "6S");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.Flush));
        }

        [Test]
        public void P2LowStraight()
        {
            P1.SetHand("AD", "2H", "3C", "4D", "5C");
            P2.SetHand("2D", "3H", "4C", "5D", "6D");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.Straight));
        }

        [Test]
        public void P2StraightFlush()
        {
            P1.SetHand("AD", "2H", "3C", "4D", "5C");
            P2.SetHand("AS", "2S", "3S", "4S", "5S");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.StraightFlush));
        }

        [Test]
        public void P2TwoPair()
        {
            P1.SetHand("2D", "2H", "3D", "3D", "7D");
            P2.SetHand("4S", "4D", "2S", "AS", "2C");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(1));
            Assert.That(winners[0].Player, Is.EqualTo(P2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.TwoPair));
        }

        [Test]
        public void PairTie()
        {
            P1.SetHand("2D", "2H", "4D", "5D", "6D");
            P2.SetHand("2S", "2C", "4S", "5S", "6S");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.Pair));
        }

        [OneTimeSetUp]
        public void TestsSetup()
        {
            P1 = new Player { Name = "P1" };
            P2 = new Player { Name = "P2" };
        }

        [Test]
        public void Tie()
        {
            P1.SetHand("2D", "3D", "4D", "5D", "6D");
            P2.SetHand("2S", "3S", "4S", "5S", "6S");

            var winners = Poker.DetermineWinner(P1, P2);

            Assert.That(winners.Length, Is.EqualTo(2));
            Assert.That(winners[0].Hand, Is.EqualTo(Hand.StraightFlush));
        }
    }
}

Now we'll need the Card, Player, and PokerHand helper classes. These are simple POCO helpers just to hold some information for whatever is utilizing the code.

Card.cs
namespace Poker_Kata
{
    public enum Faces
    {
        Club,
        Diamond,
        Spade,
        Heart
    }

    public class Card
    {
        public Card()
        {
        }

        public Card(int value, Faces face)
        {
            Value = value;
            Face = face;
        }

        public Card(string card)
        {
            switch (card[0])
            {
                case '2':
                    Value = 2;
                    break;

                case '3':
                    Value = 3;
                    break;

                case '4':
                    Value = 4;
                    break;

                case '5':
                    Value = 5;
                    break;

                case '6':
                    Value = 6;
                    break;

                case '7':
                    Value = 7;
                    break;

                case '8':
                    Value = 8;
                    break;

                case '9':
                    Value = 9;
                    break;

                case 'T':
                    Value = 10;
                    break;

                case 'J':
                    Value = 11;
                    break;

                case 'Q':
                    Value = 12;
                    break;

                case 'K':
                    Value = 13;
                    break;

                case 'A':
                    Value = 14;
                    break;
            }

            switch (card[1])
            {
                case 'H':
                    Face = Faces.Heart;
                    break;

                case 'D':
                    Face = Faces.Diamond;
                    break;

                case 'C':
                    Face = Faces.Club;
                    break;

                case 'S':
                    Face = Faces.Spade;
                    break;
            }
        }

        public Faces Face { get; set; }

        public int Value { get; set; }

        public override string ToString()
        {
            return Value + " " + Face.ToString();
        }
    }
}
Player.cs
using System.Collections.Generic;

namespace Poker_Kata
{
    public class Player
    {
        public Card[] Hand { get; set; }

        public string Name { get; set; }

        public void SetHand(params string[] cards)
        {
            List hand = new List();

            foreach (string card in cards)
            {
                hand.Add(new Card(card));
            }

            Hand = hand.ToArray();
        }
    }
}
PokerHand.cs
namespace Poker_Kata
{
    public class PokerHand
    {
        public Card[] Cards { get; set; }

        public Hand Hand { get; set; }

        public Player Player { get; set; }
    }
}

Next is the heart of the project, the Poker class. This class will hold all the of the logic and rules of poker and allow you to pass in a number of players with their hands and will determine what hands they hold along with who won the hand. I didn't make this work with just any poker game, although it wouldn't take much work to do so, I only did enough to handle each player having 5 cards.

Poker.cs
using System.Linq;

namespace Poker_Kata
{
    public enum Hand
    {
        HighCard,
        Pair,
        TwoPair,
        ThreeKind,
        FullHouse,
        Straight,
        Flush,
        FourKind,
        StraightFlush
    }

    public static class Poker
    {
        public static PokerHand[] DetermineWinner(params Player[] players)
        {
            PokerHand[] pokerHands = new PokerHand[players.Length];

            for (int i = 0; i < players.Length; i++)
            {
                var hand = GetHand(players[i].Hand);
                hand.Player = players[i];

                pokerHands[i] = hand;
            }

            pokerHands = pokerHands.Where(p => p.Hand == pokerHands.Max(p1 => p1.Hand)).ToArray();

            if (pokerHands.Length > 1)
            {
                pokerHands = FilterByHigherHand(pokerHands);

                if (pokerHands.Length > 1)
                {
                    pokerHands = FilterByHighCard(pokerHands);
                }
            }

            return pokerHands;
        }

        public static PokerHand GetHand(Card[] hand)
        {
            PokerHand pokerHand = new PokerHand();
            pokerHand.Cards = hand = hand.OrderByDescending(c => c.Value).ToArray();
            pokerHand.Hand = (hand.CountBy(c => c.Face == hand[0].Face) >= 5) ? Hand.Flush : Hand.HighCard;

            if (CheckIsStraight(hand))
            {
                pokerHand.Hand = pokerHand.Hand == Hand.Flush ? Hand.StraightFlush : Hand.Straight;
            }

            int previousCard = 0;

            foreach (var card in hand)
            {
                if (previousCard == card.Value) continue;

                int valueCount = hand.CountBy(c => c.Value == card.Value);

                if (valueCount == 2)
                {
                    if (pokerHand.Hand == Hand.Pair)
                    {
                        pokerHand.Hand = Hand.TwoPair;
                    }
                    else if (pokerHand.Hand == Hand.ThreeKind)
                    {
                        pokerHand.Hand = Hand.FullHouse;
                    }
                    else
                    {
                        pokerHand.Hand = Hand.Pair;
                    }
                }
                else if (valueCount == 3)
                {
                    if (pokerHand.Hand == Hand.Pair)
                    {
                        pokerHand.Hand = Hand.FullHouse;
                    }
                    else
                    {
                        pokerHand.Hand = Hand.ThreeKind;
                    }
                }
                else if (valueCount == 4)
                {
                    pokerHand.Hand = Hand.FourKind;
                }

                previousCard = card.Value;
            }

            return pokerHand;
        }

        private static bool CheckIsStraight(Card[] hand)
        {
            int previousValue = 0;

            foreach (var card in hand.OrderBy(c => c.Value))
            {
                if (previousValue > 0)
                {
                    if (card.Value == 14 && previousValue == 5) break;

                    if (card.Value != previousValue + 1)
                    {
                        return false;
                    }
                }

                previousValue = card.Value;
            }

            return true;
        }

        private static PokerHand[] FilterByHighCard(PokerHand[] pokerHands)
        {
            foreach (var hand in pokerHands)
            {
                hand.Cards = hand.Cards.OrderByDescending(c => c.Value).ToArray();

                if ((hand.Hand == Hand.Straight || hand.Hand == Hand.StraightFlush) &&
                    (hand.Cards.Max(c => c.Value) == 14 && hand.Cards.Min(c => c.Value) == 2))
                {
                    hand.Cards[0].Value = 1;
                    hand.Cards = hand.Cards.OrderByDescending(c => c.Value).ToArray();
                }
            }

            for (int i = 0; i < pokerHands[0].Cards.Length; i++)
            {
                int highCard = pokerHands.Select(p => p.Cards[i]).Max(c => c.Value);

                pokerHands = pokerHands.Where(p => p.Cards[i].Value == highCard).ToArray();

                if (pokerHands.Length == 1) break;
            }

            return pokerHands;
        }

        private static PokerHand[] FilterByHigherHand(PokerHand[] pokerHands)
        {
            switch (pokerHands[0].Hand)
            {
                case Hand.Pair:
                    pokerHands = FilterBySet(pokerHands, 2);
                    break;

                case Hand.TwoPair:
                    pokerHands = FilterBySet(pokerHands, 2);

                    if (pokerHands.Length > 1)
                    {
                        pokerHands = FilterBySet(pokerHands, 2, false);
                    }
                    break;

                case Hand.ThreeKind:
                case Hand.FullHouse:
                    pokerHands = FilterBySet(pokerHands, 3);
                    break;

                case Hand.FourKind:
                    pokerHands = FilterBySet(pokerHands, 4);
                    break;
            }

            return pokerHands;
        }

        private static PokerHand[] FilterBySet(PokerHand[] pokerHands, int setCount, bool checkMax = true)
        {
            var groupedCards = pokerHands.Select(p => p.Cards.GroupBy(c => c.Value).Where(g => g.Count() == setCount));
            int checkDigit;

            if (checkMax)
            {
                checkDigit = groupedCards.SelectMany(g => g).Max(g => g.Key);
            }
            else
            {
                checkDigit = groupedCards.SelectMany(g => g).Min(g => g.Key);
            }

            pokerHands = pokerHands.Where(p => p.Cards.CountBy(c => c.Value == checkDigit) == setCount).ToArray();

            return pokerHands;
        }
    }
}

In order for this code to compile, you'll need one more helper class that holds the extension CountBy.

Extensions.cs
using System;
using System.Collections.Generic;

namespace Poker_Kata
{
    public static class Extensions
    {
        public static int CountBy(this IEnumerable source, Func comparer)
        {
            int count = 0;

            foreach (var s in source)
            {
                if (comparer(s))
                {
                    count++;
                }
            }

            return count;
        }
    }
}

I believe this logic should be able to handle any 5 card poker hand, if not, please post a comment on what hand it fails on and I will happily take a look.

Now that we have all the logic and the unit tests passing, we need to read in the .txt document that the challenge provides that holds all the hands. I did this in the Program class, so when the program executes, it completes the challenge assuming you give the argument of the .txt document.

Program.cs

using System;
using System.IO;
using System.Linq;

namespace Poker_Kata
{
    internal class Program
    {
        private static string[] LoadFile(string file)
        {
            string[] contents;

            using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read))
            using (var sr = new StreamReader(fs))
            {
                contents = sr.ReadToEnd().Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            }

            return contents;
        }

        private static void Main(string[] args)
        {
            if (args.Length > 0)
            {
                int p1Wins = 0;
                int p2Wins = 0;
                int ties = 0;

                var cards = LoadFile(args[0]);

                Player p1 = new Player() { Name = "P1" };
                Player p2 = new Player() { Name = "P2" };

                foreach (var hand in cards)
                {
                    var game = hand.Split(' ');

                    p1.SetHand(game.Take(5).ToArray());
                    p2.SetHand(game.Skip(5).Take(5).ToArray());

                    var winners = Poker.DetermineWinner(p1, p2);

                    p1.Hand = p1.Hand.OrderBy(c => c.Value).ToArray();
                    p2.Hand = p2.Hand.OrderBy(c => c.Value).ToArray();

                    if (winners.Length == 2)
                    {
                        ties++;
                    }
                    else if (winners[0].Player.Equals(p1))
                    {
                        p1Wins++;
                    }
                    else
                    {
                        p2Wins++;
                    }
                }

                Console.WriteLine("P1: {0}\r\nP2: {1}\r\nTies: {2}", p1Wins, p2Wins, ties);
            }
        }
    }
}

I do hope, once again, that you attempt this challenge properly without just using my code to get the answer. I know that my code could be optimized further, but I see no need to do so at this time. Thanks for reading and happy coding.

Eratasthenes Sieve

Posted on: April 30, 2016 6:58:52 PM

Another programming challenge was to determine the 5000th prime number. A common way to quickly calculate prime numbers is using a sieve. There are several that you can choose from, I chose to implement Eratasthenes sieve. The code below will allow you to get all the prime numbers up to a limit.

    public class EratosthenesSieve
    {
        public static IEnumerable PrimeNumbers(int limit)
        {
            // add 1 to the limit to determine the limit number itself as well
            BitArray bitArray = new BitArray(limit + 1, true);

            bitArray[0] = false;
            bitArray[1] = false;
            bitArray[2] = true;

            yield return 2;

            for (int i = 4; i < bitArray.Length; i += 2)
            {
                bitArray[i] = false;
            }

            for (int i = 3; i < bitArray.Length; i++)
            {
                if (bitArray[i])
                {
                    yield return i;

                    for (int x = i * 2; x < bitArray.Length; x += i)
                    {
                        bitArray[x] = false;
                    }
                }
            }
        }
    }

Luhn Algorithm

Posted on: April 25, 2016 11:52:19 PM

I recently came across some programming challenges online that I decided to try out. They are heavily math based and took me quite a bit of research. This particular challenge was to both calculate a check digit on a credit card and validate a credit card number. The algorithm I found that does this best is called Luhn Algorithm.

Luhn Algorithm is described as the following (via Wikipedia):

  1. From the right most digit, which is the check digit, moving left, double the value of every second digit; if the product of this doubling operation is greater than 9 (e.g., 8 × 2 = 16), then sum the digits of the products (e.g., 16: 1 + 6 = 7, 18: 1 + 8 = 9) or alternatively subtract 9 from the product (e.g., 16: 16 - 9 = 7, 18: 18 - 9 = 9).
  2. Take the sum of all the digits.
  3. If the total modulo 10 is equal to 0 (if the total ends in zero) then the number is valid according to the Luhn formula; else it is not valid.

Based on this description, I came up with the following code:

    public static class LuhnAlgorithm
    {
        private static readonly int[] DoubleDigitCalculation = { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 };

        public static int GetLuhnsCheckDigit(this string account)
        {
            int checkValue = LuhnsCalculation(account.Select(c => c - '0').ToArray(), false);

            return checkValue == 0 ? 0 : 10 - checkValue;
        }

        public static bool LuhnsPass(this string account)
        {
            return LuhnsCalculation(account.Select(c => c - '0').ToArray(), true) == 0;
        }

        private static int LuhnsCalculation(int[] digits, bool includesCheckDigit)
        {
            int index = 0;
            int modIndex = includesCheckDigit ? digits.Length % 2 : digits.Length % 2 == 1 ? 0 : 1;

            return digits.Sum(d => index++ % 2 == modIndex ? DoubleDigitCalculation[d] : d) % 10;
        }
    }

This bit of code passed all the tests and is very fast. Although it doesn't have a ton of use, it was fun to come up with.

In part 2 of the MAF example, I'm going to walk through adding an event. Events can be very tricky to move across the isolation layer and still have it act like an event. I'm going to continue on the project from the first example which is also located in GitHub. I'm going to be only showing code snippets necessary to get the events working, there is more to the project than what is being shown like the class attributes necessary for the pipeline to work. These are shown in the first example.

I'm going to start in the ContractV2 project. We're going to need to add in 2 methods in the interface and add a new interface to handle the delegate pass through.

IContractV2.cs
public interface IContractV2 : IContract
{
...
	void OnEventAdd(IEventHandlerContractV2 handler);

	void OnEventRemove(IEventHandlerContractV2 handler);
}

public interface IEventHandlerContractV2 : IContract
{
	void Handle(string message);
}

We now need to update the Views on both the adapter and the host side with the same new event.

IV2.cs
public interface IV2
{
...
	event EventHandler OnEvent;
}

Next we're going to modify the HostAdapterV2 project. We're going to modify HostAdapter.cs and add a new class to handle the conversion of the event. Starting with the new conversion class.

EventHandlerViewToContractAdapter.cs
using ContractV2.V2;
using System;
using System.AddIn.Pipeline;

namespace HostAdapterV2
{
	internal class EventHandlerViewToContractAdapter : ContractBase, IEventHandlerContractV2
	{
		private Action _event;

		public EventHandlerViewToContractAdapter(Action @event)
		{
			_event = @event;
		}

		public void Handle(string message)
		{
			_event(message);
		}
	}
}
HostAdapter.cs
public class HostAdapter : IV2
{
...
	public event EventHandler OnEvent
	{
		add
		{
			if (_OnEvent == null)
			{
				_contract.OnEventAdd(new EventHandlerViewToContractAdapter(FireOnEvent));
			}

			_OnEvent += value;
		}
		remove
		{
			_OnEvent -= value;

			if (_OnEvent == null)
			{
				_contract.OnEventRemove(new EventHandlerViewToContractAdapter(FireOnEvent));
			}
		}
	}

	private event EventHandler _OnEvent;

	private void FireOnEvent(string message)
	{
		if (_OnEvent != null)
		{
			_OnEvent(this, message);
		}
	}
}

Next we are going to play in the AddinAdapter project. This is going to be very similar to the HostAdapter with a few changes

EventHandlerContractToViewAdapter.cs
using ContractV2.V2;
using System.AddIn.Pipeline;

namespace AddinAdapterV2
{
	internal class EventHandlerContractToViewAdapter
	{
		private IEventHandlerContractV2 _contract;
		private ContractHandle _handle;

		public EventHandlerContractToViewAdapter(IEventHandlerContractV2 contract)
		{
			_contract = contract;
			_handle = new ContractHandle(_contract);
		}

		internal void Handler(object sender, string message)
		{
			_contract.Handle(message);
		}
	}
}
EventHandlerAdapter.cs
using ContractV2.V2;
using System;

namespace AddinAdapterV2
{
	internal class EventHandlerAdapter
	{
		internal static EventHandler ContractToViewAdapter(IEventHandlerContractV2 handler)
		{
			return new EventHandlerContractToViewAdapter(handler).Handler;
		}
	}
}
AddinAdapter.cs
public class AddinAdapter : ContractBase, IContractV2
{
...
	public void OnEventAdd(IEventHandlerContractV2 handler)
	{
		EventHandler adaptedEvent = EventHandlerAdapter.ContractToViewAdapter(handler);
		_eventHandlers.Add(handler, adaptedEvent);
		_view.OnEvent += adaptedEvent;
	}

	public void OnEventRemove(IEventHandlerContractV2 handler)
	{
		EventHandler adaptedEvent;
		if (_eventHandlers.TryGetValue(handler, out adaptedEvent))
		{
			_eventHandlers.Remove(handler);
			_view.OnEvent -= adaptedEvent;
		}
	}
}

Now because this is a V2, we need to modify the V1 to V2 adapter.

AddinAdapterV1ToV2.cs
public class AddinAdapterV1ToV2 : ContractBase, IContractV2
{
...
	public void OnEventAdd(IEventHandlerContractV2 handler)
	{
	}

	public void OnEventRemove(IEventHandlerContractV2 handler)
	{
	}
}

Now we can register to the event from the Views and fire the event just like we normally would. Starting with the ConsoleHost project.

Program.cs
private static void Main(string[] args)
{
...
	if (token != null)
	{
		// Activate the selected AddInToken in a new application domain
		// with the Internet trust level.
		IV2 v2 = token.Activate(AddInSecurityLevel.Internet);
		v2.OnEvent += (sender, message) => { Console.WriteLine("Event Fired: {0}", message); };
		v2.Initialize(new CallbackHandler());

		// Run the add-in.
		v2.WriteToConsole("Hello World From Host!");
		Console.WriteLine(v2.GetName());

		//var test = (Stopwatch)v2.GetSource();

		//Task.Delay(500).Wait();

		//test.Stop();
		//Console.WriteLine(test.ElapsedTicks);
	}
}

Lastly, we fire the event, we'll set it up to fire on the initialize method because it's always going to be called.

Addin.cs
public class Addin : IV2
{
...
	public event EventHandler OnEvent;
...
	public void Initialize(ICallbackV2 callback)
	{
		_callback = callback;

		if (OnEvent != null)
		{
			OnEvent(this, "Initialized called from Plugin");
		}
	}
}

There we have it, an event all the way through the pipeline that fires and handles as if it was done within the same AppDomain.