Using a Predicate as a key to a Dictionary

I really love Linq and Lambda Expressions in C#.  I also love certain community forums and programming websites like DaniWeb.
A user on DaniWeb posted a question about comparing the results of a game that is like poker (5-card stud), but is played with dice.
The question stemmed around determining what was the winning hand. 
I looked at the question and issued some comments and suggestions toward a potential answer, but I thought it was a neat homework exercise.

[A little explanation]
I eventually realized not only could I compare the results of the hands (by name) with a certain construct – I could also compare the values of the individual dice with the same construct.
That piece of code eventually became a Dictionary with the KEY as a Predicate<int> and the Value a Func<T> that returns a string from the another structure that contains the mapping of an ENUM to a string.  In one instance, that string is the name of the hand and in another instance, it is a string (CSV) representation of of the digits in the hand.
An added benefit is that the digits re returned in the order they would be for a proper poker hand.  For instance the hand 1,2,5,3,1 would be returned as ONE_PAIR (1,1,5,3,2).

[Getting to the point]

   1:  using System;
   2:  using System.Collections.Generic;
   4:  namespace DicePoker
   5:  {
   6:     using KVP_E2S = KeyValuePair<CDicePoker.E_DICE_POKER_HAND_VAL, string>;
   7:     public partial class CDicePoker
   8:     {
   9:        /// <summary>
  10:        /// Magical construction to determine the winner of given hand Key/Value.
  11:        /// </summary>
  12:        private static Dictionary<Predicate<int>, Func<List<KVP_E2S>, string>>
  13:           map_prd2fn = new Dictionary<Predicate<int>, Func<List<KVP_E2S>, string>>
  14:        {
  15:           {new Predicate<int>(i => i.Equals(0)), PlayerTie},//first tie
  17:           {new Predicate<int>(i => i > 0),
  18:              (m => string.Format("Player One wins\n1={0}({1})\n2={2}({3})",
  19:                 m[0].Key, m[0].Value, m[1].Key, m[1].Value))},
  21:           {new Predicate<int>(i => i < 0),
  22:              (m => string.Format("Player Two wins\n2={2}({3})\n1={0}({1})",
  23:                 m[0].Key, m[0].Value, m[1].Key, m[1].Value))},
  25:           {new Predicate<int>(i => i.Equals(0)),
  26:              (m => string.Format("Tie({0}) \n1={1}\n2={2}",
  27:                 m[0].Key, m[0].Value, m[1].Value))}
  28:        };
  29:     }
  30:  }

When this is called, the code calls the Invoke method of the predicate to return a bool.  The first on matching true will have its value invoked.

   1:  private static Func<DICE_HAND, E_DICE_POKER_HAND_VAL> GetHandEval = dh =>
   2:           map_dph2fn[map_dph2fn.Keys.Where(enm2fn => enm2fn(dh)).First()];

After coming up with this process, I realized (with a little modification) it could be called to evaluate the individual values in the dice hand in the event of a tie.

   1:  private static Func<List<KVP_E2S>, string> PlayerTie = lst_kvp =>
   2:           map_prd2fn.Skip(1)
   3:              .Where(x => x.Key.Invoke(RenderDigits(dhPlayerOne).CompareTo(RenderDigits(dhPlayerTwo))))
   4:              .Select(s => s.Value)
   5:              .First().Invoke(lst_kvp);

After that, I realized I could now create a program completely without “if” statements or “for” loops!

   1:        static void Main(string[] args)
   2:        {
   3:           Dictionary<Predicate<int>, Action<Action<string>>> main = new Dictionary<Predicate<int>, Action<Action<string>>>
   4:           {
   5:              {(i => i.Equals(0)), PlayGame},
   6:              {(i => true), Usage}
   7:           };
   9:           main[main.Keys.Where(m => m.Invoke(args.Length)).First()].Invoke(Display);
  10:        }

…and there you have it. :)

ZIPPED Project

posted @ Monday, May 28, 2012 11:47 AM

Comments on this entry:

# re: Using a Predicate as a key to a Dictionary

Left by Jim Benson at 7/1/2013 11:21 AM
Tom, I'm struggling a bit with the PlayGame method. Stepping through, I even get a null reference exception. I think that happens to me because PlayerTie is null when the map_prd2fn dictionary is defined. I'm not sure I understand the way in which ties are determined. But thanks for the challenge! You've taken LINQ and functional programming to a very high level.

# re: Using a Predicate as a key to a Dictionary

Left by Jim Benson at 7/1/2013 11:41 AM
Now I don't get the null reference exception. No idea why I got that in the first place, but now I don't.

Your comment:

(not displayed)


Live Comment Preview: