Sunday, April 17, 2011

Greed Kata–Second attempt

When I wrote the post on my first attempt, I mentioned that I thought I was “missing something obvious.” It occurred to me after I put up that post.

A die can only be used in one scoring combination

This is probably obvious to everyone else but I’m only responsible for what goes on in my head.

This realization push me to think that calculating the score using the Pipes and Filters pattern would probably be a good fit. I started with the data that each scorer, the filter, would operate on:

   1: public class GameContext
   2:  {
   3:      public int Score;
   4:      public int[] DiceValues;
   5:  }

Each filter would use the die values stored in the DiceValues field and update the Score field.


For the scorers, I started with the single value rules:



A single one (1) is worth 100 points.
A single five (5) is worth 50 points.


Working through lead to the following:



   1: public class ValueScorer
   2: {
   3:     private readonly int _die;
   4:     private readonly int _value;
   5:  
   6:     public ValueScorer(int die, int value)
   7:     {
   8:         _die = die;
   9:         _value = value;
  10:     }
  11:  
  12:     public GameContext Compute(GameContext context)
  13:     {
  14:         if (0 == context.DiceValues.Length) return context;
  15:         var occurances = Array.FindAll(context.DiceValues, v => v== this._die).Length;
  16:         context.Score += occurances * this._value;
  17:  
  18:         List<int> diceValues = RemoveValuesUsedInAScoringCombination(context.DiceValues, occurances);
  19:         context.DiceValues = diceValues.ToArray();
  20:  
  21:         return context;
  22:     }
  23:  
  24:     private List<int> RemoveValuesUsedInAScoringCombination(int[] currentDiceValues, int occurances)
  25:     {
  26:         var diceValues = new List<int>(currentDiceValues);
  27:         foreach (var ii in Enumerable.Range(1, occurances))
  28:         {
  29:             diceValues.Remove(this._die);
  30:         }
  31:         return diceValues;
  32:     }
  33: }


The next set of rules:


A set of three ones (1) is worth 1000 points
A set of three of any other number is worth 100 time that number (ex. {2,2,2} = 200 points}.

For which I ended up with:

 


   1: public class TripleScorer
   2: {
   3:     public GameContext Compute(GameContext context)
   4:     {
   5:         if (0 == context.DiceValues.Length) return context;
   6:  
   7:         var triples = context.DiceValues.GroupBy(d => d).Where(g => g.Count() >= 3);
   8:  
   9:         context.Score += triples.Sum(g => (g.Count() / 3) * ((1 == g.Key) ? 1000 : g.Key * 100));
  10:  
  11:         List<int> diceValues = RemoveValuesUsedInAScoringCombination(context.DiceValues, triples);
  12:         context.DiceValues = diceValues.ToArray();
  13:  
  14:         return context;
  15:     }
  16:  
  17:     private List<int> RemoveValuesUsedInAScoringCombination(int[] currentDiceValues, IEnumerable<IGrouping<int, int>> triples)
  18:     {
  19:         var diceValues = new List<int>(currentDiceValues);
  20:         foreach (var tripleGroup in triples)
  21:         {
  22:             int digitsToRemove = (tripleGroup.Count()/3)*3;
  23:             foreach (var ii in Enumerable.Range(1,digitsToRemove))
  24:             {
  25:                 diceValues.Remove(tripleGroup.Key);
  26:             }
  27:         }
  28:         return diceValues;
  29:     }
  30: }


The method RemoveValuesUsedInAScoringCombination() is key to making this approach work. This method updates the DiceValues array in the context to remove the values that were used. This piece enforces the constraint that a die is only used once in a scoring combination.


The driver is really straight forward and look like:



   1: public class Scorer
   2: {
   3:     public int Computer(int[] diceValues)
   4:     {
   5:         if (0 == diceValues.Length) return 0;
   6:  
   7:         var tripleScorer = new TripleScorer();
   8:         var oneScorer = new ValueScorer(1,100);
   9:         var fiveScorer = new ValueScorer(5,50);
  10:  
  11:         var context = new GameContext() {DiceValues = diceValues, Score = 0};
  12:  
  13:         context = tripleScorer.Compute(context);
  14:         context = oneScorer.Compute(context);
  15:         context = fiveScorer.Compute(context);
  16:  
  17:         return context.Score;
  18:     }
  19: }

What I find really nice about this approach is that adding additional scoring combinations is just a matter of creating another scorer. For example, say that the ruling body for the game Greed introduces the following rule:



A set of five consecutive numbers (ex. {1,2,3,4,5} or {2,3,4,5,6}) is called a Straight and is worth 2000 points.


This is easily implemented with a Scorer such as:



   1: public class StraightScorer
   2: {
   3:     public GameContext Compute(GameContext context)
   4:     {
   5:         if (0 == context.DiceValues.Length) return context;
   6:  
   7:         foreach (int startingAt in Enumerable.Range(1,2))
   8:         {
   9:             if (this.DiceValuesContainStraight(startingAt, context.DiceValues))
  10:             {
  11:                 context.Score += 2000;
  12:                 context.DiceValues = this.RemoveValuesUsedInAScoringCombination(context.DiceValues, startingAt).ToArray();
  13:             }
  14:         }
  15:  
  16:         return context;
  17:     }
  18:  
  19:     private bool DiceValuesContainStraight(int straightStartsAt, int[] diceValues)
  20:     {
  21:         foreach (var n in Enumerable.Range(straightStartsAt,5))
  22:         {
  23:             if (!diceValues.Contains(n)) return false;
  24:         }
  25:         return true;
  26:     }
  27:  
  28:     private List<int> RemoveValuesUsedInAScoringCombination(int[] currentDiceValues, int startingAt)
  29:     {
  30:         var diceValues = new List<int>(currentDiceValues);
  31:         foreach (var n in Enumerable.Range(startingAt, 5))
  32:         {
  33:             diceValues.Remove(n);
  34:         }
  35:         return diceValues;
  36:     }
  37:  
  38: }

The driver gets modified as:



   1: public class Scorer
   2: {
   3:     public int Computer(int[] diceValues)
   4:     {
   5:         if (0 == diceValues.Length) return 0;
   6:  
   7:         var straightScorer = new StraightScorer();
   8:         var tripleScorer = new TripleScorer();
   9:         var oneScorer = new ValueScorer(1,100);
  10:         var fiveScorer = new ValueScorer(5,50);
  11:  
  12:         var context = new GameContext() {DiceValues = diceValues, Score = 0};
  13:  
  14:         context = straightScorer.Compute(context);
  15:         context = tripleScorer.Compute(context);
  16:         context = oneScorer.Compute(context);
  17:         context = fiveScorer.Compute(context);
  18:  
  19:         return context.Score;
  20:     }
  21: }

Modifying the previous version would not have been nearly as simple.

Wednesday, April 13, 2011

Greed Kata–First attempt

I’ve had this on my TODO list since this year’s CodeMash conference. If you’re not already familiar with the Greed kata, or kata’s in general, take a moment and read the article on Steve Gentile’s site. You can also take a look at his solution.

For my first attempt, I made an effort to stay away from Linq. I had no specific reason for this additional constraint. I was really just curious how the solution would turn out. So with that lead-in, here’s my first attempt:

   1: public class Scorer
   2: {
   3:     public int Compute(int[] diceValues)
   4:     {
   5:         if (0 == diceValues.Length) return 0;
   6:  
   7:         Dictionary<int, int> valueGroups = GroupByDiceValue(diceValues);
   8:  
   9:         int totalScore = 0;
  10:         foreach (KeyValuePair<int, int> group in valueGroups)
  11:         {
  12:             totalScore += ScoreGroup(group.Value, group.Key);
  13:         }
  14:         
  15:         return totalScore;
  16:     }
  17:  
  18:     private int ScoreGroup(int count, int value)
  19:     {
  20:         int groupScore = 0;
  21:         if (count>=3)
  22:         {
  23:             if (value == 1) groupScore += 1000;
  24:             else groupScore += value * 100;
  25:  
  26:             count -= 3;
  27:         }
  28:             
  29:         if (1 == value)
  30:         {
  31:             groupScore += count * 100;
  32:         }
  33:             
  34:         if (5 == value)
  35:         {
  36:             groupScore += count * 50;
  37:         }
  38:         return groupScore;
  39:     }
  40:  
  41:     private Dictionary<int, int> GroupByDiceValue(int[] diceValues)
  42:     {
  43:         Array.Sort(diceValues);
  44:         var valueGroups = new Dictionary<int, int>();
  45:         foreach (int value in diceValues)
  46:         {
  47:             int count = 0;
  48:             valueGroups.TryGetValue(value, out count);
  49:             valueGroups[value] = ++count;
  50:         }
  51:         return valueGroups;
  52:     }
  53: }

And here are the tests:



   1: [TestFixture]
   2: public class ScorerTests
   3: {
   4:     
   5:     [Test]
   6:     public void Compute_WhenNoValues_Score_0()
   7:     {
   8:         var scorer = new Scorer();
   9:         Assert.That(scorer.Compute(new int[]{}), Is.EqualTo(0));
  10:     }
  11:  
  12:     [Test]
  13:     public void Compute_ThreeOnes_Score_1000()
  14:     {
  15:         var scorer = new Scorer();
  16:         Assert.That(scorer.Compute(new int[] {1,1,1,2,3}), Is.EqualTo(1000));
  17:     }
  18:  
  19:     [Test]
  20:     public void Compute_ThreeTwos_Score_200()
  21:     {
  22:         var scorer = new Scorer();
  23:         Assert.That(scorer.Compute(new int[] { 3, 2, 2, 2, 3 }), Is.EqualTo(200));
  24:     }
  25:  
  26:     [Test]
  27:     public void Compute_ThreeThreess_Score_300()
  28:     {
  29:         var scorer = new Scorer();
  30:         Assert.That(scorer.Compute(new int[] { 4, 4, 3, 3, 3 }), Is.EqualTo(300));
  31:     }
  32:  
  33:     [Test]
  34:     public void Compute_ASingleOne_Score_100()
  35:     {
  36:         var scorer = new Scorer();
  37:         Assert.That(scorer.Compute(new int[] { 4, 4, 1, 2, 2 }), Is.EqualTo(100));
  38:     }
  39:  
  40:     [Test]
  41:     public void Compute_ASingleFive_Score_50()
  42:     {
  43:         var scorer = new Scorer();
  44:         Assert.That(scorer.Compute(new int[] { 4, 4, 5, 2, 2 }), Is.EqualTo(50));
  45:     }
  46:  
  47:     [Test]
  48:     public void Compute_FourOnes_Score_1100()
  49:     {
  50:         var scorer = new Scorer();
  51:         Assert.That(scorer.Compute(new int[] { 1, 1, 1, 1, 2 }), Is.EqualTo(1100));
  52:     }
  53:  
  54:     [Test]
  55:     public void Compute_ThreeOnesAndTwoFives_Score_1100()
  56:     {
  57:         var scorer = new Scorer();
  58:         Assert.That(scorer.Compute(new int[] { 5, 5, 1, 1, 1 }), Is.EqualTo(1100));
  59:     }
  60:  
  61:     [Test]
  62:     public void Compute_ThreeThreesAndOneFives_Score_350()
  63:     {
  64:         var scorer = new Scorer();
  65:         Assert.That(scorer.Compute(new int[] { 4, 5, 3, 3, 3 }), Is.EqualTo(350));
  66:     }
  67:  
  68:     [Test]
  69:     public void Compute_NoValidScoringCombinations_Score_0()
  70:     {
  71:         var scorer = new Scorer();
  72:         Assert.That(scorer.Compute(new int[] { 2, 2, 4, 4, 3 }), Is.EqualTo(0));
  73:     }
  74:  
  75: }

I’m not unhappy with the solution but the voice in my head is nagging me that I’m missing something obvious.

Sunday, April 10, 2011

Best constraint in an EULA–ever!

I found this in an End User License Agreement that I was reading though this morning:

You will not use the Software for, and will not permit the Software to be used for, any purposes prohibited by law, including, without limitation, for the development, design, manufacture or production of missiles or nuclear, chemical or biological weapons.

I should read more of this things.

Thursday, March 3, 2011

Setting a GUID to Empty in the Visual Studio 2010 Watch window

This is something that I stumbled upon the other day and I’ve finally gotten a chance to write it up. My current client has an application that uses GUIDs for IDs and there are lots of IDs. There is also a lot of logic in the application that is based on the presence of absence of a GUID value. The absence is indicated by the use of the Empty GUID.

So the other day a co-worker and I were using the debugger to delve into the bowels of the app trying to find the cause of a defect. We came to the conclusion that there was an issue with state around one of the GUIDS. The GUID had a value when it was supposed to be Empty. Luckily this is easy to test since there are a number of way to alter the value of a variable within the debugger.

Unfortunately it took a bit to discover how to set a GUID to empty.

It seems that you can’t just use the value “{00000000-0000-0000-0000-000000000000}”. You’ll be punished with an error message stating “Invalid expression term ‘{‘”. Your next thought might be to remove the braces ({}). In that case you’ll be rewarded with another error message stating “Cannot convert type ‘int’ to ‘System.Guid’.

I was shocked to find out that the answer is to enter ‘Guid.Empty’ for the value:

SNAGHTMLab00d12

Results in:

SNAGHTMLab2217c

Saturday, January 8, 2011

This is where I am

I was assigned to an engagement this summer that had me working a lot of hours. 60-70 was the norm. I even did 97 towards the end, so that batch-processing could be delivered on time. The net effect of all that work was that I had to drop my workouts from my weekly schedule. I didn’t workout for a good six to eight weeks.

I started back to the gym when things calmed down. I was doing the 531 workout before the craziness started so I decided to pick it back up again. Unfortunately I had to backup a couple of cycles.

I just finished another cycle, and since this is the start of a new years, I thought I would post my max lifts for the four main exercises that I do: Standing military press, Deadlift, Bench press and Squat. I’m mainly doing this so that I have an easy way to measure my results this time next year.

Lift Weight Reps Theoretical Max
Military Press 120 7 148
Deadlift 265 10 353
Bench Press 225 6 270
Squat 200 12 280

 

About the Theoretical Max

In the ebook that describes the workout, Wendler provides a formula that can be used to calculate an estimated one-rep maximum – a guess at the most amount of weight that could be moved for one repetition:

Weight x Reps x 0.0333 + Weight = Estimated 1RM

The prescribed purpose of the formula is to provide a means to compare two lifts in order to gauge progress. Which lift is better 215 for 8 or 230 for 5. I use the formula to set rep goals.

I’ll start a new cycle tomorrow. I look forward to seeing where I am in a year.

Saturday, November 27, 2010

Retrieving message counts of a remote MSMQ queue using PowerShell

My current client does work for the retail industry. This weekend is the beginning of the holiday shopping season, a very important period to the retail industry.

This is also the first time that I’ve seen the planning and operations that the Retail IT groups go through. I’m really impressed by the amount of planning and support that is in place to make sure that IT-related issues don’t interfere with holiday shoppers. There are bridge calls that begin at 2am, around the clock monitoring of servers, hourly reports, call-ins every 30 minutes and lots of people are either active or on-call.

My part in this was to spend three hours monitoring 13 remote servers. To make life a little easier, we used a PowerShell script similar to this to retrieve the queue lengths of some remote MSMQ queues.

   1: $queuesToCheck = 'Q1' , 'Q2'
   2: $servers = 'myserver1', 'myserver2'
   3:  
   4: $queues = @()
   5: $servers | ForEach-Object {
   6:     $ServerName = $_
   7:     
   8:     $machineQueuesToCheck = $queuesToCheck | ForEach-Object { "$ServerName\$_".ToLower() }
   9:     $queues += gwmi -class Win32_PerfRawData_MSMQ_MSMQQueue -computerName $ServerName  | Where-Object {
  10:         $machineQueuesToCheck -contains $_.Name.Trim() -and $_.MessagesInQueue -gt 0
  11:     } 
  12: }
  13:  
  14: $queues | Format-Table Name, MessagesInQueue