Using a Predicate as a key to a Dictionary

Posted by Tom Hines on Geeks with Blogs See other posts from Geeks with Blogs or by Tom Hines
Published on Mon, 28 May 2012 09:47:34 GMT Indexed on 2012/05/30 16:43 UTC
Read the original article Hit count: 400

Filed under:

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;
   3:   
   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
  16:   
  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))},
  20:   
  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))},
  24:   
  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:           };
   8:   
   9:           main[main.Keys.Where(m => m.Invoke(args.Length)).First()].Invoke(Display);
  10:        }

…and there you have it. :)

ZIPPED Project

© Geeks with Blogs or respective owner