Showing posts with label Refactoring. Show all posts
Showing posts with label Refactoring. Show all posts

Thursday, May 14, 2015

A Partial Object Update Trick in C#

Intro

At least one time in my life someone has asked me a question that goes like this:

"I have a class with a bunch of properties. I want to update some or all of them, in any combination. How can I do this?"

Well you could just set the values of course, you could call a method that has an optional parameter for each property of the class, and you could of course pay a badger to write some clever new trick for you. We'll go with the badger option! The rest of the blog details what the badger would write.

Note: Sample code is in VS 2013.




Details

Within the class that you wish to update, create a SetAll or SetMany or whatever method where you pass in another instance of your class (source). Check each property and if it's non-null, you set the destination object's property value to the source object's property value. Note that this tactic will depend on nullable types, and assumes you can ignore null values passed into a new setter method. Here's an illustration:

using System;

namespace BlogPartialUpdateTrick
{
    public class SomeClass
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int? HeightInches { get; set; }
        public DateTime? Dob { get; set; }

        public void SetAll(SomeClass source)
        {
            this.FirstName = source.FirstName ?? this.FirstName;
            this.LastName = source.LastName ?? this.LastName;
            this.HeightInches = source.HeightInches ?? this.HeightInches;
            this.Dob = source.Dob ?? this.Dob;
        }

        public override string ToString()
        {
            return String.Format("fn: {0}, ln: {1}, height: {2}, DOB: {3}", FirstName ?? String.Empty, LastName ?? String.Empty, 
                HeightInches.HasValue ? HeightInches.Value.ToString() : "null", Dob.HasValue ? Dob.Value.ToShortDateString() : "null" );
        }
    }
}


In this first code sample, We have my spiffy class SomeClass. It's got 4 properties, all of which are nullable. The noteworthy part of this class is the SetAllMethod where I can pass in a source object which is also of type SomeClass. It sets this instance's property values to the values passed in the source parameter, but only if they're non-null. Here's a 2nd code blurb where I'm using this stuff:

using System;
using System.Windows.Forms;

namespace BlogPartialUpdateTrick
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var destination = new SomeClass() { FirstName = "Freddy", LastName = "Fingers", Dob = DateTime.Parse("01/01/1970"), HeightInches = 72 };
            var source = new SomeClass() { FirstName = null, LastName="Flippers", Dob = null, HeightInches = 80 };
            destination.SetAll(source);
            MessageBox.Show(destination.ToString());
        }
    }
}


Create a destination object, a source object, call the new method, voila! output is this:

"fn: Freddy, ln: Flippers, height: 80, DOB: 1/1/1970"

Thursday, February 20, 2014

A Chess Project, Part 5

Intro

We're on Part 5 now of this large project, and it's time for a little reflection of what's been done as well as a summary of what's left. We've covered the requirements of the project, basic project design, we created the backend web service (WebAPI), we created a sample web-based front-end to exercise the web service, and we have performed request data validation. We're well on the way to stardom! What do we have left? We need to calculate the valid moves that each piece has, we need to discover if any victory or draw conditions have been met, and we will need to do the hardest part so far...write some cheesy AI to figure out a "good" move! We'll crack open this post with valid move calculation. We can't do victory conditions without valid move calculations and vice versa, but we gotta start somewhere so let's calculate basic move actions and we'll put off victory conditions for another time. Onward and forward and such and stuff!

Basic Move Calculation

First step: we need somewhere to put these calculations. You might think that ChessBoard, or even ChessGame are a good place for this, and you'd be right. But hey so am I, I'm going to make a new class for it. I like "The Offspring", so we're gonna keep 'em separated! Go ahead and add a new class called ChessValidMoveCalculator to the BlogChess.Backend project.

This new class will need access to a ChessGame object. Otherwise how will it know of a game and board(s) for which to calculate moves? We'll give it a single private member of type ChessGame as well as a constructor where the caller can pass in a game. Here's the code:

using System;
using System.Collections.Generic;
using System.Linq;

namespace BlogChess.Backend
{
    public class ChessValidMoveCalculator
    {
        private ChessGame m_game;

        public ChessValidMoveCalculator(ChessGame game)
        {
            if (game == null)
                throw new ArgumentNullException("game", "game cannot be null");
            if (game.Positions == null || game.Positions.Count() == 0)
                throw new ArgumentException("game must contain some positions", "game");
            m_game = game;
        }
    }
}



Short and sweet, the code above has just what I said it would have. Note that in the constructor we make sure that the game isn't null and that it has some positions, otherwise there's not much point in trying to calculate moves; there wouldn't be any!

Now it's time to calculate valid moves. I think that sounds like a good method name, so add a method to this class called CalculateValidMoves. I think we're best off with having a return type that is a list of ChessBoards, so give it a return type of IList<ChessBoard>. The method needs no parameters. You should have something like this:

        public IList<ChessBoard> CalculateValidMoves()
        {
            IList<ChessBoard> result = new List<ChessBoard>();
            return result;
        }



I went ahead and created the result variable and returned it, just so the code would compile. Go ahead and try to compile yours too before we get too far.

We're getting closer to the fun part here folks! In my convoluted meat-based thinkin-tool, I believe it would be best to loop through all the squares on the board and see what's there. Then we can base our calculations on what's on the board. So, we need some sort of looping structure in the code that checks what's on what square. We'll need to do this for the last board position of the game, as we don't really care what the valid moves were in the past; we only care right now! Give it a shot yourself first (just create the basic loop structure), then drop on back here to see what I've got:

        
public IList<ChessBoard> CalculateValidMoves()
        {
            IList<ChessBoard> result = new List<ChessBoard>();
            var currentBoard = m_game.Positions.Last().Board;
            var currentStatus = m_game.GameStatus;
            if (currentStatus == GameStatus.BlacksTurn || currentStatus == GameStatus.WhitesTurn)
            {
                //calculate and return moves
                for (short row = 0; row < 8; row++)
                {
                    for (short col = 0; col < 8; col++)
                    {
                    }
                }
            }
            return result;
        }


The next step is determining what type of piece we're looking at. Each piece has its own method of movement which I will assume you know or will look up. But, we need to know the type of piece to know the type of movement, so add that to the loop. Here's my attempt:

                    for (int col = 0; col < 8; col++)
                    {
                        var piece = currentBoard[row, col];
                        switch (piece)
                        {
                            case Constants.Pawn:
                                break;
                            case Constants.Knight:
                                break;
                            case Constants.Bishop:
                                break;
                            case Constants.Rook:
                                break;
                            case Constants.Queen:
                                break;
                            case Constants.King:
                                break;
                        }
                    }


And now our first attempts at determining moves. We're going to start simple here, and pretend there are no other pieces on the board. With that in mind, what can a pawn do? It's got a few options:
  1. Move forward 1 square 
  2. Move forward 2 squares, if haven't moved before
  3. Take a piece forward and left/right
  4. Take another pawn "en passant". This is a weird rule and I might not even both with it in the blog, but hey I have to mention it.
  5. Turn into any type of chess piece when reaching the back rank.
Starting with part 1, how do we code that? First we need to know what color we're looking at. Forward means a different direction for black than it does for white. Picture the board like this:

    col
row  0 1 2 3 4 5 6 7
     1
     2
     3
     4
     5
     6
     7


With the assumption of white starting on rows 6 and 7 (it's 0-based; if we were using 1-based it would be rows 7 and 8) then forward means a decrease in the row. For black starting on rows 0 and 1, forward means an increase in the row. Let's go ahead and code moves 1 and 2 (forward 1 square, forward 2 squares).

                        var piece = currentBoard[row, col];
                        short newRow;
                        short newCol;
                        switch (piece)
                        {
                            case Constants.Pawn:
                                //1 square forward
                                short rowModifier = currentStatus == GameStatus.BlacksTurn ? Constants.BlackTransform : Constants.WhiteTransform;
                                short rowMovementAmount = (short)(1 * rowModifier);
                                newRow = (short)(row + rowMovementAmount);
                                newCol = col;
                                if (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8)
                                {
                                    var futureBoard = (short[,])currentBoard.Clone();
                                    futureBoard[row, col] = Constants.Empty;
                                    futureBoard[newRow, newCol] = piece;
                                    var newBoard = new ChessBoard(true);
                                    newBoard.Board = futureBoard;
                                    result.Add(new ChessBoard(true));
                                }
                                //2 squares forward
                                rowMovementAmount = (short)(2 * rowModifier);
                                newRow = (short)(row + rowMovementAmount);
                                newCol = col;
                                if (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8)
                                {
                                    var futureBoard = (short[,])currentBoard.Clone();
                                    futureBoard[row, col] = Constants.Empty;
                                    futureBoard[newRow, newCol] = piece;
                                    var newBoard = new ChessBoard(true);
                                    newBoard.Board = futureBoard;
                                    result.Add(new ChessBoard(true));
                                }
                                break;
                            case Constants.Knight:
                                break;
                            case Constants.Bishop:
                                break;
                            case Constants.Rook:
                                break;
                            case Constants.Queen:
                                break;
                            case Constants.King:
                                break;
                        }


As you can see, the code is getting stringier. I've got a bit of nearly-duplicated code, but maybe we'll refactor that later. For now you can see that I've got 2 new local variables, newRow and newCol. We'll use these to put our movements in. In the Pawn section of our case statement we've got some logic for 1-square forward movement and 2-square forward movement. We first determine whose turn it is, then we move the piece forward a square. We then check to see if the new square is within the bounds of our board, and if so we add the new position to our result set. I can already tell that the duplicated code is going to bug the crap outta me, and we're going to need this same code for the other pieces' valid moves too, so let's clean this up:

        protected IList<ChessBoard> AddMoveToList(IList<ChessBoard> boards, short oldRow, short oldCol, short newRow, short newCol)
        {
            var resultArray = new ChessBoard[boards.Count];
            boards.CopyTo(resultArray, 0);
            var result = resultArray.ToList();
            if (newRow >= 0 && newRow < 8 && newCol >= 0 && newCol < 8)
            {
                var futureBoard = (short[,])boards.Last().Board.Clone();
                var piece = futureBoard[oldRow, oldCol];
                futureBoard[oldRow, oldCol] = Constants.Empty;
                futureBoard[newRow, newCol] = piece;
                var newBoard = new ChessBoard(true);
                newBoard.Board = futureBoard;
                result.Add(new ChessBoard(true));
            }
            return result;
        }


This is our new method that adds a new board to a list of boards. Nothing fancy. We just took some of the code from CalculateValidMoves and pushed it in here, since we're going to need it many times. Now this is what you have left in CalculateValidMoves:

        public IList<ChessBoard> CalculateValidMoves()
        {
            IList<ChessBoard> result = new List<ChessBoard>();
            var currentBoard = m_game.Positions.Last().Board;
            var currentStatus = m_game.GameStatus;
            if (currentStatus == GameStatus.BlacksTurn || currentStatus == GameStatus.WhitesTurn)
            {
                //calculate and return moves
                for (short row = 0; row < 8; row++)
                {
                    for (short col = 0; col < 8; col++)
                    {
                        var piece = currentBoard[row, col];
                        short newRow;
                        short newCol;
                        switch (piece)
                        {
                            case Constants.Pawn:
                                //1 square forward
                                short rowModifier = currentStatus == GameStatus.BlacksTurn ? Constants.BlackTransform : Constants.WhiteTransform;
                                short rowMovementAmount = (short)(1 * rowModifier);
                                newRow = (short)(row + rowMovementAmount);
                                newCol = col;
                                result = AddMoveToList(result, row, col, newRow, newCol);
                                //2 squares forward
                                rowMovementAmount = (short)(2 * rowModifier);
                                newRow = (short)(row + rowMovementAmount);
                                newCol = col;
                                result = AddMoveToList(result, row, col, newRow, newCol);
                                break;
                            case Constants.Knight:
                                break;
                            case Constants.Bishop:
                                break;
                            case Constants.Rook:
                                break;
                            case Constants.Queen:
                                break;
                            case Constants.King:
                                break;
                        }
                    }
                }
            }
            return result;
        }


Looks a little cleaner neh? We replaced the duplicated code with a couple calls to AddMoveToList. Now we need to add in the forward-left and forward-right diagonals. I won't bore you with too much detail as you're getting the hang of it now, so here's the code:

                                //forward-left diagonal
                                rowMovementAmount = (short)(1 * rowModifier);
                                newRow = (short)(row + rowMovementAmount);
                                newCol = (short)(col - 1);
                                result = AddMoveToList(result, row, col, newRow, newCol);
                                //forward-right diagonal
                                rowMovementAmount = (short)(1 * rowModifier);
                                newRow = (short)(row + rowMovementAmount);
                                newCol = (short)(col + 1);
                                result = AddMoveToList(result, row, col, newRow, newCol);



This is all getting pretty easy huh? Well unfortunately as usual, I've taken up enough of your time without getting terribly far into the code. It's a lot of code and I guess I'm just a little too wordy!

I can't thank you all enough for reading this far, especially if you started from post #1. I really appreciate it folks. Hang in there through a few more posts and we'll have us a working chess api web service!

What's Next?

Next week we'll have to do some more move calculations. I won't go nearly as much into the mechanics of the movement of pieces or the code of it next week, at least not for the basic movements. That horse is already quite dead. I'll probably just push the basic code up here for the rest of the pieces and then we can move on to discussing and coding the funky movements (promoting pawns, taking pieces, castling, etc). I also think I'll end up cleaning up the code even more next week, as I think CalculateValidMoves is going to get a little unwieldy. We'll see how it goes first, but I bet we'll end up putting each individual piece type's calculation into its own method.

If you'd like to skip ahead of the class, try it out yourself! The basic movements are pretty easy for most pieces and I bet you can all get the code working yourself for the remaining pieces if you have the time. Heck even pawn movement #5 (which we didn't cover) isn't that difficult, just remember that the pawn can turn into whatever it wants to (other than a king) when it gets to the back rank!

Resources

No  special resources used this week. Have fun coding!

Tuesday, November 5, 2013

Refactoring in Visual Studio, Part 2

Overview

In addition to renaming which we covered in Part 1, Visual Studio has many other refactoring options including extracting a method from an existing block of code, encapsulating a field within a property, extracting an interface from a class, removing parameters, and reordering parameters. Let's see what they do and how to use them.

Extract Method

The "Extract Method" refactor option lets you move a block of code into a new method. Take a look at the below block of code. This code looks like a commonly used block to construct a database command. I would like to move it into a separate method so I can reuse this same logic elsewhere.


To extract a method from this code, you first must select the code as show above. Next right-click within the selected block and select "Refactor-->Extract Method...".


Now you are presented with a dialog where you name your new method, so type in the new name and hit OK.

Your class now has a new method named CreateCommand(), and the prior location serves only to call the new function.


Encapsulate Field

The Encapsulate Field refactoring option takes a field within a class and encapsulates it within a property. This can save you from writing a lot of plumbing when setting up properties with private members. Let's see how it works.

In this class I have a single private field, m_aField. I want to allow other classes to manipulate this value, but in a noble effort to hide the implementation details of this complex chunk of awesome I have decided I want a public property that clients can use. Refactoring to the rescue!


Right-click the field and select "Refactor-->Encapsulate Field...". Visual Studio will select a name for your new field (feel free to change it if you like). Click OK and your code has a brand-spankin-new public property which encapsulates that private field. Yay!


Extract Interface

Now let's take that useful class from the last refactoring option and mangle it further. I have decided that I want multiple classes with the same interface (public properties and methods) as the class RefactoringStuff. The best way to do this is with an interface, and Refactoring can help you here too. Right-click on the class and choose "Refactor-->Extract Interface...".


Visual Studio kindly gives you an opportunity to name your interface and select the properties and methods that will make up the interface definition, so type/select what you like then click the OK button.


Pretty sweet huh? You have a brand new interface named IRefactoringStuff, and the class RefactoringStuff now implements that new interface.

public class RefactoringStuff : ABDebug.IRefactoringStuff
  {
    private string m_aField;
 
    public string AField
    {
      get { return m_aField; }
      set { m_aField = value; }
    }
  }

  interface IRefactoringStuff
  {
    string AField { getset; }
  }

Remove Parameters

Why would you ever want to use a GUI to remove parameters? If your method is called a few times in a few different units, it can be a pain to first manually remove the parameter then go find and change every place that calls the method. So, Visual Studio helps us out once again with Refactor-->Remove Parameters. Take the class below:

  public class RefactoringStuff
  {
    public string AMethod(string param1, string param2)
    {
      return param1 + " !some text in the middle! " + param2;
    }
 
    public void Caller1()
    {
      string local = AMethod("hey""you");
    }
 
    public void Caller2()
    {
      string local = AMethod("hola""senor");
    }
  }

I want to remove param2 from the method AMethod. Right-click in the method and select "Refactor-->Remove Parameters". Select the parameter you want to remove and click the Remove button. Click OK when done.


You are presented with another dialog where you can preview the changes that Visual Studio is going to make. Review it's plan and click OK when ready.


Boom! code modded. But hey wait just a minute here fella, my code doesn't compile! Yeah well nobody's perfect, including Visual Studio. You'll notice in the code below that param2 is still referenced in AMethod. Just get rid of it manually and move along.

  public class RefactoringStuff
  {
    public string AMethod(string param1)
    {
      return param1 + " !some text in the middle! " + param2;
    }
 
    public void Caller1()
    {
      string local = AMethod("hey");
    }
 
    public void Caller2()
    {
      string local = AMethod("hola");
    }
  }

Reorder Parameters

The last option we'll cover is reordering parameters. I won't get into much in the way of screenshots as you've probably figured out the process by now and are just about tired of reading, so let's just take a quick look at some code. Here we're back to the class RefactoringStuff. I want to switch the order of param1 and param2 in the method AMethod.

  public class RefactoringStuff
  {
    public string AMethod(string param1, string param2)
    {
      return param1 + " !some text in the middle! " + param2;
    }
 
    public void Caller1()
    {
      string local = AMethod("hey""you");
    }
 
    public void Caller2()
    {
      string local = AMethod("hola""senor");
    }
  }

Right-click within the method AMethod and select "Refactor-->Reorder Parameters...". Use the dialog to reorder parameters as you desire, click OK, the preview window then comes up, review your changes, click Apply. The parameters in AMethod have been reordered and all calls to AMethod have had their parameters switch around as well.


    public string AMethod(string param2, string param1)
    {
      return param1 + " !some text in the middle! " + param2;
    }
 
    public void Caller1()
    {
      string local = AMethod("you""hey");
    }
 
    public void Caller2()
    {
      string local = AMethod("senor""hola");
    }
  }

Thanks for your time again folks, and if you enjoyed this post be sure give us a big happy +1 in google, share us on facebook and twitter, subscribe to the blog, tell your neighbors and your neighbor's dog. Comments are encouraged!

Monday, October 28, 2013

Refactoring in Visual Studio, Part 1

Rename

Did you know that there's an easier way to rename properties, methods, variables, etc? This lovely little gem works across all files in the current solution too, so it does more than just a single method or file at a time. Right-click on the item you want to rename and select "Refactor-->Rename".


Type in the new name and hit the OK button.
  


Review the preview if necessary, and click the Apply button when you're ready to process the rename.


 Your code now reflects the changes.