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
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. :)
© Geeks with Blogs or respective owner