This blog has moved http://www.sharplogic.com/blogs/ed

This blog has moved here<!--meta http-equiv="refresh" content="0;url=http://www.sharplogic.com/blogs/ed"-->

July 2003 - Posts

Why Does Matthew Roland Refuse To Blog?

He has a blog. He has a cool job. He has interesting stories. He has no problem with promising me he's going to blog and then not actually blog.

I've been on Matthew's case ever since I found out that he has a blog set up at http://blogs.gotdotnet.com/MRoland  and yet has not had a single post yet. Maybe he could use a little "persuasion". If you'd like to harass encourage Matthew to start blogging, email him at MRoland@Microsoft.com. Tell him I sent you.

Posted: Jul 31 2003, 07:56 PM by EdKaim | with 1 comment(s)
Filed under:
The One-Stop Shop For All Your CSV Parsing Needs

I was looking through the referrers page to see where my hits come from, and I noticed two very interesting things (or at least they're interesting to me). First, 90%+ of my hits come from "(none)", which I assume means that they're from aggregators that consume RSS feeds without leaving a http_referrer calling card. The second, and perhaps more interesting stat, is that I am regularly getting hits from people who search google for tips on parsing CSV formats. I figured they must get annoyed when they click through hoping for a juicy code tidbit or some other fun fact, so I decided to try to help out a bit.

Here is a C# function for parsing a CSV file into a DataSet. It should work after a quick copy/paste, but if not, let me know and I'll update it.

/// <summary>

/// Parses a file in the comma separated value format (CSV) and returns the data as a DataSet.

/// </summary>

/// <param name="filePath">The path to the CSV file</param>

/// <returns>A DataSet with the parsed data from "filePath"</returns>

DataSet ParseCSVFileIntoDataSet(string filePath)

{

      // Make a DataSet and add a blank table to it so we can

      // store all the data we're going to get

      DataSet ds = new DataSet("MyDataSet");

      DataTable table = ds.Tables.Add("MyTable");

 

      // Create an instance of StreamReader to read from a file.

      // The using statement also closes the StreamReader.

      // We'll also let it throw a FileNotFoundException if necessary.

      using (StreamReader sr = new StreamReader(filePath))

      {

 

            // If your CSV contains column info as the first row use this first section.

            // If not, use the section below where columns are hardcoded.

#if YOUR_CSV_CONTAINS_COLUMN_NAMES

            string columnLine = sr.ReadLine();

 

            // string.Split will parse each string between the token into separate

            // strings in an array.

            //

            // For example, "FirstColumnName,SecondColumnName,ThirdColumnName"

            // if split on commas will become an array of three strings:

            // "FirstColumnName", "SecondColumnName", "ThirdColumnName".

            //

            // Just be careful that the names can't have commas in them already.

            string[] columns = columnLine.Split(',');

#else

            string[] columns = { "FirstColumnName", "SecondColumnName", "ThirdColumnName" };

#endif

 

            // Make sure we have some columns.

            if (columns.Length == 0)

            {

                  throw new ApplicationException("There are no columns available to parse");

            }

 

            // Iterate through each column name and add to the table.

            foreach (string column in columns)

            {

                  table.Columns.Add(column);

            }

 

            // Iterate through the remainder of the file and parse each row.

            string nextLine;

            while ((nextLine = sr.ReadLine()) != null)

            {

                  // Split the cells in this row.

                  string[] cells = nextLine.Split(',');

 

                  // Make sure we have the right number of cells to match the columns.

                  if (cells.Length != columns.Length)

                  {

                        throw new ApplicationException(

                              string.Format("Error in \"{0}\": Data row {1} has {2} cells when it should have {3}",

                              filePath, table.Rows.Count + 1, cells.Length, columns.Length));

                  }

 

                  // Add the new row with the data.

                  DataRow row = table.Rows.Add(cells);

            }

      }

 

      // Return the filled DataSet

      return ds;

}

Posted: Jul 30 2003, 08:05 PM by EdKaim | with 2 comment(s)
Filed under:
Thanks To All

I was amazed at how many people outside Microsoft took the time to send me advice on the mortgage process. I really do appreciate it.

On the other hand, I can't believe that people are continuing to read my blog. I figured the Matrix preview or Ed Kaim Developer Center would have gotten my RSS feeds knocked off of most people's lists, but I guess I'll have to try harder to be less interesting :-)

Posted: Jul 30 2003, 01:54 PM by EdKaim | with 2 comment(s)
Filed under:
Does Anyone Have Any Loan Tips?

I'm looking into a mortgage loan for my first house and figured some folks might be kind enough to help me benefit from their experience. If so, please let me know at edkaim@microsoft.com. Thanks!

Posted: Jul 29 2003, 06:32 PM by EdKaim | with 1 comment(s)
Filed under:
GDN Workspaces Still Rule

The TBS project is now live at http://www.gotdotnet.com/Community/Workspaces/workspace.aspx?id=1b8ce17a-46e4-4075-9738-bb8c85676d73. Join! Build! Conquer!

Posted: Jul 28 2003, 05:27 AM by EdKaim | with no comments
Filed under:
Hooray--Sort Of

I was able to hack around inside my already hacked-together turn-based strategy app so that it can load AI from custom assemblies. It actually works in a pretty easy way now where you create a class that derives from a base class (AIUser) in the main library assembly. After implementing a few abstract methods you build it and drop the assembly in the same folder as the main library assembly. Then, if you want one of the game's armies to use your new AI, you point their "AI" property as defined in the game's XML file, and run it. The change is pretty simple, such as from

<AI>TBSDefaultAI.TBSDefaultAI</AI>

to

<AI>LandOnlyAI.LandOnlyAI</AI>

Unfortunately, I ran into a few things I'm not too sure how to handle correctly. It seems like you can't cast a dynamically instantiated object into a specific type. For example, I tried to do:

Assembly assembly = Assembly.LoadFile(assemblyPath);

m_AIUser aiUser = (AIUser) assembly.CreateInstance(className, true);

where assemblyPath and className are strings passed into the method and AIUser is the abstract base class of the object created in CreateInstance (but from another assembly). I wanted to just be able to call the abstract methods on the base class cast of the new object in the same way I would call any other, and have them fulfilled by the overriden implementations in the dynamic object. I couldn't seem to hack that in, so I ended up using the Type object and invoking the methods and properties on the object in a very formal way: 

this.m_Type = assembly.GetType(className);

this.m_Type.GetProperty("ActionedUnit").GetValue(this.m_AIUser, null);

Maybe there's an easy way to actually do this cleanly that I've overlooked, but in the meantime I've built a simple proxy class that derives from the AIUser class and does all of this assembly and type work behind the scenes for the consuming portion of the game. I guess I could have a method called "public AIUser GetMe()" that just does a "return this;" and pretend like I was able to easily cast the object from the beginning. Then again, I'm probably just not reading the documentation properly.

I'll probably be able to get the code up by lunch on Monday.

Posted: Jul 26 2003, 05:28 PM by EdKaim | with 3 comment(s)
Filed under:
A New Project

I've started a new project (don't worry, I'll still be spamming about Dimensions as often as possible). It's a turn-based strategy game similar to the old tabletop games with hex cells and model units.

The idea in these games is that you have an army that you can move around the board one unit at a time, with each unit getting one move per turn. The options each unit gets is based on a combination of its type and range, also whether it wants to attack or just move.

The twist I want to add is very much along the lines of Terrarium. Instead of playing the game with typical human thinking, I want to make it such that someone can build an assembly that handles a few defined events (such as "OnUnitTurn" or "OnFactoryCanBuild") and then plug their assembly in as AI. A more ambitous goal is to make it so each AI has 3 or 4 dynamic properties, such as "Aggression" or "ResourceComfort" that can be changed by a player at realtime, which would affect the way the AI plays (assuming the developer accounts for it in code). This way each player isn't actually a hands-on player, but rather like a general who distributes high-level orders to troops (based on the properties), and they go and act on them based on their training (the event handlers).

Here's a screenshot of my first week's worth of work:

I'll post some code soon if anyone is interested.

Posted: Jul 25 2003, 01:49 PM by EdKaim | with 2 comment(s)
Filed under:
Eric Sink Beat Me To It

Then again, I'm sure we've all wanted to spoof http://www.softwarelegends.com. Eric actually got around to doing it first :-) 

Posted: Jul 25 2003, 12:00 PM by EdKaim | with 1 comment(s)
Filed under:
Other Fun Stuff At MGB

Dan, Brian , and I played our first game of Rise Of Nations on Monday night in New Orleans. We have a ton of hands-on labs running during the day where people sit down to work with the products and get technical training, and then they have big LAN parties at night (which is pretty cool, considering 100+ PCs and a ton of XBoxes). The game itself is really cool, and we had a lot of fun because it was brand new to all of us. Although I ended up winning (quite handily, I assure you) I'm not quite sure how "winning" was judged. Brian is a very aggressive player and kept trying to blow my stuff up (sometimes successfully), whereas Dan likes to dabble in the art of weapons of mass destruction, somewhat neutralizing Brian's offense (and buildings).

After the game ended (3 hours later) Brian and Dan decided to burn off some energy. I bet them each $5 that they couldn't run up the down escalators, but they managed to do so pretty quickly.

I'm protesting the results because I'm pretty sure these escalators aren't regulation.

Posted: Jul 24 2003, 03:42 PM by EdKaim | with no comments
Filed under:
Tricks Of The Temperturial Accounting Trade

I'm back from New Orleans. Ironically, I caught a cold while I was down there, so my head hasn't been quite as straight as...well...I guess it's never really that straight these days anyway. Both Dan and Brian got sick as well (and probably got me sick too). Now I'm all hopped up on DayQuil and streaming all kinds of interesting thoughts. How do you catch a cold in New Orleans in summer? It's actually much easier than it sounds.

You see, when people talk about the temperature in New Orleans, they use the "outside temperature"--usually around 90F. If they were to factor in the "inside temperature" (a rarely used temperature accounting trick) they would be able to report a much lower temperature (probably by about 25F) and save a lot of Fahrenheit on income tax. Unfortunately, this method doesn't help end-of-period temperature gain/share, also lowering the overall Fahrenheit flow of the city, resulting in a period loss. As a result, it is rarely acknowledged (other than in footnotes) that you may wake up with frost in your room if not careful. I believe they may be already under investigation by the TEC.

Wow, this is even trippy for me.

More Posts Next page »