Posts tagged ‘C#.NET’

Compound comparison in a LINQ join statement

I’ve been doing pretty much iPhone only postings recently, so this might change it up a bit.

So I am trying to go into our web application’s C# code to make some changes to the administration area of the web site.  (This is usually the only place I feel comfortable making changes, as this is not an area that customers actually use.)  We have a page that uses a store procedure to pull data from our SQL Server database and presents it on the page.

I needed to get more information out of the database than the store procedure was giving me, and I didn’t feel like modifying the procedure and then trying to rebuild the DBML, so I decided to convert it to a LINQ statement and bind to that instead of binding to the results of the stored procedure.

These things never go as planned.  I took a similar LINQ statement that I found in the application, but it did not do exactly what I wanted to do.  Basically, the LINQ statement I found used a simple comparison.  I needed to check for two different things in my comparison, so after a bit of research and trial and error, here is what I came up with:

var p = (from ord in dc.orders
    join ordSt in dc.orderStatus on 
        new { ord.orderID, b = true } equals new { ordSt.orderID, b = ordSt.isDeleted }
    where ord.customerID == custID
    select
        new { ord.orderID, ordSt.deletionDate } );

I had to add the little “b = true” and “b = ordSt.isDeleted” parts because it would not let me use just the “true” in the comparison.  Ah, isn’t it great that LINQ is so simple?

Don’t try, don’t catch

Have you ever had a situation where all of those nested try/catch blocks just get in your way when trying to chase down a problem? I just hate that.

Luckily, in Visual Studio 2008 (and other versions, I am sure), there is a handy dandy way to disable all of the try/catch blocks when you run the application in debug mode from the IDE.  Just go to the Debug menu, select Exceptions, click the box under the Thrown column for Common Language Runtime Exceptions (or others if that is what you are looking for), and click OK.  Now when the code has a problem, you see it right away instead of trying to work backwards through nested try/catch blocks in different classes and modules.

Just don’t forget to put it back to the way it was when you are done. I am not a huge fan of try/catch blocks, but their normal use definitely has its place.

2010 Central Ohio Day of .NET

A co-w0rker and I attended the Central Ohio Day of .NET on June 5, 2010. There was quite a bit of good content at the conference, which is a real tribute to the organizers, volunteers, and presenters.

The highlights of my day were sitting in on Matt Casto’s regular expressions talk, Phil Japikse’s M-V-VM primer, discussing the etymology of the MongoDB project with Sam Corder (I still say it was named such after the character in Blazing Saddles), Michael Eaton’s talk on WPF, and Parag Joshi’s demonstration of XNA/Windows Phone 7 game development.

Demo days (CONDG meeting, December 14, 2009)

The Central Ohio .NET Developers Group held their final meeting of the year last night at the Microsoft office in Polaris. Four people gave short demos of Xbox, Zune HD, Windows Mobile, and iPhone, and talked about developing for each platform.

The highlight of the evening was my name being drawn as winning the year’s final and perhaps most craptastic door prize, which I then gave to my coworker who was attending the meeting with me. He is into free t-shirts.

2009-12-15 09.13.18

Battleship AI contest on Stack Overflow

Recently there was a contest running on Stack Overflow to design the best Battleship AI. Here is a link to the page:

What is the best Battleship AI?

I must admit that I am still smarting over this contest, as my BP7 contest entry did awesomely well and incredibly poor at the same time. Here is the code:

namespace Battleship
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
 
    public class BP7 : IBattleshipOpponent
    {
        public string Name { get { return "BP7"; } }
        public Version Version { get { return this.version; } }
 
        Random rand = new Random();
        Version version = new Version(0, 7);
        Size gameSize;
        List<Point> scanShots;
        List<NextShot> nextShots;
        int wins, losses;
        int totalWins = 0;
        int totalLosses = 0;
        int maxWins = 0;
        int maxLosses = 0;
        int matchWins = 0;
        int matchLosses = 0;
 
        public enum Direction { VERTICAL = -1, UNKNOWN = 0, HORIZONTAL = 1 };
        Direction hitDirection, lastShotDirection;
 
        enum ShotResult { UNKNOWN, MISS, HIT };
        ShotResult[,] board;
 
        public struct NextShot
        {
            public Point point;
            public Direction direction;
            public NextShot(Point p, Direction d)
            {
                point = p;
                direction = d;
            }
        }
 
        public struct ScanShot
        {
            public Point point;
            public int openSpaces;
            public ScanShot(Point p, int o)
            {
                point = p;
                openSpaces = o;
            }
        }
 
        public void NewGame(Size size, TimeSpan timeSpan)
        {
            this.gameSize = size;
            scanShots = new List<Point>();
            nextShots = new List<NextShot>();
            fillScanShots();
            hitDirection = Direction.UNKNOWN;
            board = new ShotResult[size.Width, size.Height];
        }
 
        private void fillScanShots()
        {
            int x;
            for (x = 0; x < gameSize.Width - 1; x++)
            {
                scanShots.Add(new Point(x, x));
            }
 
            if (gameSize.Width == 10)
            {
                for (x = 0; x < 3; x++)
                {
                    scanShots.Add(new Point(9 - x, x));
                    scanShots.Add(new Point(x, 9 - x));
                }
            }
        }
 
        public void PlaceShips(System.Collections.ObjectModel.ReadOnlyCollection<Ship> ships)
        {
            foreach (Ship s in ships)
            {
                s.Place(
                    new Point(
                        rand.Next(this.gameSize.Width),
                        rand.Next(this.gameSize.Height)),
                    (ShipOrientation)rand.Next(2));
            }
        }
 
        public Point GetShot()
        {
            Point shot;
 
            if (this.nextShots.Count > 0)
            {
                if (hitDirection != Direction.UNKNOWN)
                {
                    if (hitDirection == Direction.HORIZONTAL)
                    {
                        this.nextShots = this.nextShots.OrderByDescending(x => x.direction).ToList();
                    }
                    else
                    {
                        this.nextShots = this.nextShots.OrderBy(x => x.direction).ToList();
                    }
                }
 
                shot = this.nextShots.First().point;
                lastShotDirection = this.nextShots.First().direction;
                this.nextShots.RemoveAt(0);
                return shot;
            }
 
            List<ScanShot> scanShots = new List<ScanShot>();
            for (int x = 0; x < gameSize.Width; x++)
            {
                for (int y = 0; y < gameSize.Height; y++)
                {
                    if (board[x, y] == ShotResult.UNKNOWN)
                    {
                        scanShots.Add(new ScanShot(new Point(x, y), OpenSpaces(x, y)));
                    }
                }
            }
            scanShots = scanShots.OrderByDescending(x => x.openSpaces).ToList();
            int maxOpenSpaces = scanShots.FirstOrDefault().openSpaces;
 
            List<ScanShot> scanShots2 = new List<ScanShot>();
            scanShots2 = scanShots.Where(x => x.openSpaces == maxOpenSpaces).ToList();
            shot = scanShots2[rand.Next(scanShots2.Count())].point;
 
            return shot;
        }
 
        int OpenSpaces(int x, int y)
        {
            int ctr = 0;
            Point p;
 
            // spaces to the left
            p = new Point(x - 1, y);
            while (p.X >= 0 && board[p.X, p.Y] == ShotResult.UNKNOWN)
            {
                ctr++;
                p.X--;
            }
 
            // spaces to the right
            p = new Point(x + 1, y);
            while (p.X < gameSize.Width && board[p.X, p.Y] == ShotResult.UNKNOWN)
            {
                ctr++;
                p.X++;
            }
 
            // spaces to the top
            p = new Point(x, y - 1);
            while (p.Y >= 0 && board[p.X, p.Y] == ShotResult.UNKNOWN)
            {
                ctr++;
                p.Y--;
            }
 
            // spaces to the bottom
            p = new Point(x, y + 1);
            while (p.Y < gameSize.Height && board[p.X, p.Y] == ShotResult.UNKNOWN)
            {
                ctr++;
                p.Y++;
            }
 
            return ctr;
        }
 
        public void NewMatch(string opponenet)
        {
            wins = 0;
            losses = 0;
        }
 
        public void OpponentShot(Point shot) { }
 
        public void ShotHit(Point shot, bool sunk)
        {
            board[shot.X, shot.Y] = ShotResult.HIT;
 
            if (!sunk)
            {
                hitDirection = lastShotDirection;
                if (shot.X != 0)
                {
                    this.nextShots.Add(new NextShot(new Point(shot.X - 1, shot.Y), Direction.HORIZONTAL));
                }
 
                if (shot.Y != 0)
                {
                    this.nextShots.Add(new NextShot(new Point(shot.X, shot.Y - 1), Direction.VERTICAL));
                }
 
                if (shot.X != this.gameSize.Width - 1)
                {
                    this.nextShots.Add(new NextShot(new Point(shot.X + 1, shot.Y), Direction.HORIZONTAL));
                }
 
                if (shot.Y != this.gameSize.Height - 1)
                {
                    this.nextShots.Add(new NextShot(new Point(shot.X, shot.Y + 1), Direction.VERTICAL));
                }
            }
            else
            {
                hitDirection = Direction.UNKNOWN;
                this.nextShots.Clear();     // so now this works like gangbusters ?!?!?!?!?!?!?!?!?
            }
        }
 
        public void ShotMiss(Point shot)
        {
            board[shot.X, shot.Y] = ShotResult.MISS;
        }
 
        public void GameWon()
        {
            wins++;
        }
 
        public void GameLost()
        {
            losses++;
        }
 
        public void MatchOver()
        {
            if (wins > maxWins)
            {
                maxWins = wins;
            }
 
            if (losses > maxLosses)
            {
                maxLosses = losses;
            }
 
            totalWins += wins;
            totalLosses += losses;
 
            if (wins >= losses)
            {
                matchWins++;
            }
            else
            {
                matchLosses++;
            }
        }
 
        public void FinalStats()
        {
            Console.WriteLine("Games won: " + totalWins.ToString());
            Console.WriteLine("Games lost: " + totalLosses.ToString());
            Console.WriteLine("Game winning percentage: " + (totalWins * 1.0 / (totalWins + totalLosses)).ToString("P"));
            Console.WriteLine("Game losing percentage: " + (totalLosses * 1.0 / (totalWins + totalLosses)).ToString("P"));
            Console.WriteLine();
            Console.WriteLine("Matches won: " + matchWins.ToString());
            Console.WriteLine("Matches lost: " + matchLosses.ToString());
            Console.WriteLine("Match winning percentage: " + (matchWins * 1.0 / (matchWins + matchLosses)).ToString("P"));
            Console.WriteLine("Match losing percentage: " + (matchLosses * 1.0 / (matchWins + matchLosses)).ToString("P"));
            Console.WriteLine("Match games won high: " + maxWins.ToString());
            Console.WriteLine("Match games lost high: " + maxLosses.ToString());
            Console.WriteLine();
        }
    }
}

The thing I find odd about this was that against the winning entry, Dreadnought, my AI was far and away the most successful, winning about 40% of the individual games. The next closest competitor to Dreadnought was BSKiller, crafted by my compatriot in crime, John Boker, winning 20% in the initial round robin and 12% and 14% in the knockout round.

And yet, BP7 stunk against most of the other real submissions, which is a bit mysterious to me. I understand that there is some random fortune involved here (for example, in the round robin, BSKiller defeated BP7 121 games to 80, even though in my own testing, BP7 was winning about 54% of the games over BSKiller), but to be defeated at almost every turn?

Oh well. Here is my VS2008 solution and class files, if you would care to try it out for yourself:

Battleship solution

Also, when I was first looking into this problem, I created some graph paper to help me visualize certain situations. Here is the PDF file of this graph paper:

Battleship Graph Paper

Happy Thanksgiving everyone! (For those outside the U.S., Happy November 26th.)

Deuces wild???

As a baseball loving youth, I remember with great fondness watching and listening to baseball as called by the voice of baseball, Vin Scully, who is unquestionably one of the greatest baseball announcers.

One thing I can always remember him saying during his calls was “deuces wild”, which he used to describe a situation that occurs with a count of 2 balls, 2 strikes, and 2 outs.

So, I figured I would take a look at the raw statistics and see how often the deuces wild situation actually came up.  Here is the code from my Program.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace RetrosheetReader
{
    class Program
    {
        static List<Team> teamList;
        static List<Player> playerList;
        static List<Event> eventList;
 
        const string DATA = "c:\\baseball_data\\";
 
        static void Main(string[] args)
        {
            Console.WriteLine("Retrosheet Reader");
            Console.WriteLine();
 
            teamList = Team.GetTeamList(DATA);
            playerList = Player.GetPlayerList(DATA);
            eventList = Event.GetEventList(DATA);
 
            Console.WriteLine("Number of teams: " + teamList.Count().ToString());
            Console.WriteLine("Number of players: " + playerList.Count().ToString());
            Console.WriteLine("Number of events: " + eventList.Count().ToString());
 
            int[, ,] pitchCount = new int[4, 3, 3];
            int balls, strikes, totalPitches;
 
            totalPitches = 0;
            foreach (var ev in eventList)
            {
                balls = 0;
                strikes = 0;
                foreach (char c in ev.pitchSequence)
                {
                    if (Functions.IsBallOrStrike(c))
                    {
                        pitchCount[balls, strikes, ev.outs]++;
                        totalPitches++;
                        if (Functions.IsStrike(c))
                        {
                            if (strikes == 2)
                            {
                                if (!Functions.IsFoul(c))
                                    strikes++;
                            }
                            else
                                strikes++;
                        }
                        else
                        {
                            balls++;
                        }
                    }
                }
            }
 
            Console.WriteLine("Total pitches: " + totalPitches.ToString());
            for (int o = 0; o < 3; o++)
                for (int s = 0; s < 3; s++)
                    for (int b = 0; b < 4; b++)
                        Console.WriteLine(String.Format("Total pitches on B{0}-S{1}-O{2}: {3,8}  ({4,6:P})", b, s, o, pitchCount[b, s, o],
                                                    pitchCount[b, s, o] * 1.0 / totalPitches));
 
            Console.WriteLine();
            Console.Write("Strike any key to end...");
            Console.ReadKey();
        }
    }
}

By the way, there is a new Functions.cs file in the project that contains utility functions, and I had to modify the Event.cs file to take into account the fact that the BEVENT application creates duplicate records for a batter if there is some kind of on-base event that happens in the middle of the at-bat, such as a stolen base or pick off.

The results? I ran the application with the 2008 season data, and found that there were 700,242 total pitches. The deuces wild situation happened on only 17,141 pitches, or 2.45%. Of course, the highest percentage occurred with 0 balls, 0 strikes, and 0 outs (the first pitch to any batters that bat in an inning before the first out is recorded, including the first batter of each inning) with 65,050 pitches, or 9.29%.

Here is the zipped up solution:

RetrosheetReader.zip

Best way to not use an enumeration, ever!

So here is some more interesting stuff found in some code that needed some emergency modifications.

The enumeration of this code starts on line 26 of the class file:

public enum City
{
    CLINTON = 78,
    FRANKLIN = 1,
    FAIRVIEW = 59,
    GREENVILLE = 55,
    SALEM = 83,
    MADISON = 81,
    SPRINGFIELD = 14,
    ARLINGTON = 84,
    CLAYTON = 63,
    GEORGETOWN = 85,
    MARION = 15,
    OXFORD = 65,
    BURLINGTON = 5
}

And instead of using the MADISON enumeration, the if statement of this code starts on line 118 of the very same class file:

if (cityID == 0x51)
{
    actual = expected - actual;
}

The names were changed to protect the innocent, thanks to Wikipedia for having an easy to find list of common place names.

Because you never know how many days could be between Monday and Friday

Why do a couple of subtractions when two loops can do the same work?

while (processDate.DayOfWeek != DayOfWeek.Monday)
    processDate = processDate.AddDays(-1);
 
string mondayDate = processDate.ToShortDateString();
 
while (processDate.DayOfWeek != DayOfWeek.Friday)
    processDate = processDate.AddDays(1);
 
string fridayDate = processDate.ToShortDateString();

Retrosheet event record mapping completed

The Retrosheet project has kind of sat around for a while untouched, so I figured I would finish up the reading of the event records. I have decided to break the project into separate files, as if I kept it in one file, it would be obscenely long.

So, here is the main Program.cs file:

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace RetrosheetReader
{
    class Program
    {
        static List<Team> teamList;
        static List<Player> playerList;
        static List<Event> eventList;
 
        const string DATA = "c:\\baseball_data\\";
 
        static void Main(string[] args)
        {
            Console.WriteLine("Retrosheet Reader");
            Console.WriteLine();
 
            teamList = Team.GetTeamList(DATA);
            playerList = Player.GetPlayerList(DATA);
            eventList = Event.GetEventList(DATA);
 
            Console.WriteLine("Number of teams: " + teamList.Count().ToString());
            Console.WriteLine("Number of players: " + playerList.Count().ToString());
            Console.WriteLine("Number of events: " + eventList.Count().ToString());
 
            Console.WriteLine();
            Console.Write("Strike any key to end...");
            Console.ReadKey();
        }
    }
}

There are now 3 class files, one each for a team, player, and event. The event file is the one with the most new stuff going on.

Team.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
 
namespace RetrosheetReader
{
    class Team
    {
        int year;
        string city;
        string nickname;
        string abbreviation;
        string league;
 
        public Team(int y, string[] a)
        {
            year = y;
            abbreviation = a[0];
            league = a[1];
            city = a[2];
            nickname = a[3];
        }
 
        public static List<Team> GetTeamList(string dir)
        {
            int y;
            string s;
            string[] splitLine;
            List<Team> teamList = new List<Team>();
 
            List<string> tfs = Directory.GetFiles(dir, "team*").ToList();
            foreach (string tf in tfs)
            {
                y = Convert.ToInt32(Path.GetFileName(tf).Substring(4));
                StreamReader sr = new StreamReader(tf);
                while ((s = sr.ReadLine()) != null)
                {
                    splitLine = s.Split(',');
                    if (splitLine.Count() == 4)
                    {
                        teamList.Add(new Team(y, splitLine));
                    }
                }
            }
 
            return teamList;
        }
    }
}

Player.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
 
namespace RetrosheetReader
{
    class Player
    {
        int year;
        string team;
        string playerID;
        string firstName;
        string lastName;
        string bats;
        string throws;
        string position;
 
        public Player(int y, string[] a)
        {
            year = y;
            playerID = a[0];
            lastName = a[1];
            firstName = a[2];
            bats = a[3];
            throws = a[4];
            team = a[5];
            position = a[6];
        }
 
        public static List<Player> GetPlayerList(string dir)
        {
            int y;
            string s;
            string[] splitLine;
            List<Player> playerList = new List<Player>();
 
            List<string> rfs = Directory.GetFiles(dir, "*.ros").ToList();
            foreach (string rf in rfs)
            {
                y = Convert.ToInt32(Path.GetFileName(rf).Substring(3).Split('.')[0]);
                StreamReader sr = new StreamReader(rf);
                while ((s = sr.ReadLine()) != null)
                {
                    splitLine = s.Split(',');
                    if (splitLine.Count() == 7)
                    {
                        playerList.Add(new Player(y, splitLine));
                    }
                }
            }
 
            return playerList;
        }
    }
}

Event.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
 
namespace RetrosheetReader
{
    class Event
    {
        string gameID;          // 0, A
        string visitingTeam;    // 1, B
        int inning;             // 2, C
        int battingTeam;        // 3, D
        int outs;               // 4, E
        int balls;              // 5, F
        int strikes;            // 6, G
        string pitchSequence;   // 7, H
        int visitorScore;       // 8, I
        int homeScore;          // 9, J
        string batter;          // 10, K
        string batterHand;      // 11, L
        string resBatter;       // 12, M
        string resBatterHand;   // 13, N
        string pitcher;         // 14, O
        string pitcherHand;     // 15, P
        string resPitcher;      // 16, Q
        string resPitcherHand;  // 17, R
        string catcher;         // 18, S
        string firstBase;       // 19, T
        string secondBase;      // 20, U
        string thirdBase;       // 21, V
        string shortstop;       // 22, W
        string leftField;       // 23, X
        string centerField;     // 24, Y
        string rightField;      // 25, Z
        string firstRunner;     // 26, AA
        string secondRunner;    // 27, AB
        string thirdRunner;     // 28, AC
        string eventText;       // 29, AD
        bool leadoffFlag;       // 30, AE
        bool pinchHitFlag;      // 31, AF
        int defensivePosition;  // 32, AG
        int lineupPosition;     // 33, AH
        int eventType;          // 34, AI
        bool batterEventFlag;   // 35, AJ
        bool abFlag;            // 36, AK
        int hitValue;           // 37, AL
        bool shFlag;            // 38, AM
        bool sfFlag;            // 39, AN
        int outsOnPlay;         // 40, AO
        bool doublePlayFlag;    // 41, AP
        bool triplePlayFlag;    // 42, AQ
        int rbiOnPlay;          // 43, AR
        bool wildPitchFlag;     // 44, AS
        bool passedBallFlag;    // 45, AT
        int fieldedBy;          // 46, AU
        string battedBallType;  // 47, AV
        bool buntFlag;          // 48, AW
        bool foulFlag;          // 49, AX
        string hitLocation;     // 50, AY
        int numErrors;          // 51, AZ
        int firstErrorPlayer;   // 52, BA
        string firstErrorType;  // 53, BB
        int secondErrorPlayer;  // 54, BC
        string secondErrorType; // 55, BD
        int thirdErrorPlayer;   // 56, BE
        string thirdErrorType;  // 57, BF
        int batterDest;         // 58, BG
        int runner1Dest;        // 59, BH
        int runner2Dest;        // 60, BI
        int runner3Dest;        // 61, BJ
        string playOnBatter;    // 62, BK
        string playOnRunner1;   // 63, BL
        string playOnRunner2;   // 64, BM
        string playOnRunner3;   // 65, BN
        bool sbRunner1Flag;     // 66, BO
        bool sbRunner2Flag;     // 67, BP
        bool sbRunner3Flag;     // 68, BQ
        bool csRunner1Flag;     // 69, BR
        bool csRunner2Flag;     // 70, BS
        bool csRunner3Flag;     // 71, BT
        bool poRunner1Flag;     // 72, BU
        bool poRunner2Flag;     // 73, BV
        bool poRunner3Flag;     // 74, BW
        string respPitcher1;    // 75, BX
        string respPitcher2;    // 76, BY
        string respPitcher3;    // 77, BZ
        bool newGameFlag;       // 78, CA
        bool endGameFlag;       // 79, CB
        bool pinchRunner1;      // 80, CC
        bool pinchRunner2;      // 81, CD
        bool pinchRunner3;      // 82, CE
        string removedForPR1;   // 83, CF
        string removedForPR2;   // 84, CG
        string removedForPR3;   // 85, CH
        string removedForPH;    // 86, CI
        int posRemovedForPH;    // 87, CJ
        int fielderWithPO1;     // 88, CK
        int fielderWithPO2;     // 89, CL
        int fielderWithPO3;     // 90, CM
        int fielderWithA1;      // 91, CN
        int fielderWithA2;      // 92, CO
        int fielderWithA3;      // 93, CP
        int fielderWithA4;      // 94, CQ
        int fielderWithA5;      // 95, CR
        int eventNum;           // 96, CS
 
        public Event(string[] a)
        {
            gameID = a[0].Replace("\"", "");
            visitingTeam = a[1].Replace("\"", "");
            inning = Convert.ToInt32(a[2]);
            battingTeam = Convert.ToInt32(a[3]);
            outs = Convert.ToInt32(a[4]);
            balls = Convert.ToInt32(a[5]);
            strikes = Convert.ToInt32(a[6]);
            pitchSequence = a[7].Replace("\"", "");
            visitorScore = Convert.ToInt32(a[8]);
            homeScore = Convert.ToInt32(a[9]);
            batter = a[10].Replace("\"", "");
            batterHand = a[11].Replace("\"", "");
            resBatter = a[12].Replace("\"", "");
            resBatterHand = a[13].Replace("\"", "");
            pitcher = a[14].Replace("\"", "");
            pitcherHand = a[15].Replace("\"", "");
            resPitcher = a[16].Replace("\"", "");
            resPitcherHand = a[17].Replace("\"", "");
            catcher = a[18].Replace("\"", "");
            firstBase = a[19].Replace("\"", "");
            secondBase = a[20].Replace("\"", "");
            thirdBase = a[21].Replace("\"", "");
            shortstop = a[22].Replace("\"", "");
            leftField = a[23].Replace("\"", "");
            centerField = a[24].Replace("\"", "");
            rightField = a[25].Replace("\"", "");
            firstRunner = a[26].Replace("\"", "");
            secondRunner = a[27].Replace("\"", "");
            thirdRunner = a[28].Replace("\"", "");
            eventText = a[29].Replace("\"", "");
            leadoffFlag = a[30].Contains('T');
            pinchHitFlag = a[31].Contains('T');
            defensivePosition = Convert.ToInt32(a[32]);
            lineupPosition = Convert.ToInt32(a[33]);
            eventType = Convert.ToInt32(a[34]);
            batterEventFlag = a[35].Contains('T');
            abFlag = a[36].Contains('T');
            hitValue = Convert.ToInt32(a[37]);
            shFlag = a[38].Contains('T');
            sfFlag = a[39].Contains('T');
            outsOnPlay = Convert.ToInt32(a[40]);
            doublePlayFlag = a[41].Contains('T');
            triplePlayFlag = a[42].Contains('T');
            rbiOnPlay = Convert.ToInt32(a[43]);
            wildPitchFlag = a[44].Contains('T');
            passedBallFlag = a[45].Contains('T');
            fieldedBy = Convert.ToInt32(a[46]);
            battedBallType = a[47].Replace("\"", "");
            buntFlag = a[48].Contains('T');
            foulFlag = a[49].Contains('T');
            hitLocation = a[50].Replace("\"", "");
            numErrors = Convert.ToInt32(a[51]);
            firstErrorPlayer = Convert.ToInt32(a[52]);
            firstErrorType = a[53].Replace("\"", "");
            secondErrorPlayer = Convert.ToInt32(a[54]);
            secondErrorType = a[55].Replace("\"", "");
            thirdErrorPlayer = Convert.ToInt32(a[56]);
            thirdErrorType = a[57].Replace("\"", "");
            batterDest = Convert.ToInt32(a[58]);
            runner1Dest = Convert.ToInt32(a[59]);
            runner2Dest = Convert.ToInt32(a[60]);
            runner3Dest = Convert.ToInt32(a[61]);
            playOnBatter = a[62].Replace("\"", "");
            playOnRunner1 = a[63].Replace("\"", "");
            playOnRunner2 = a[64].Replace("\"", "");
            playOnRunner3 = a[65].Replace("\"", "");
            sbRunner1Flag = a[66].Contains('T');
            sbRunner2Flag = a[67].Contains('T');
            sbRunner3Flag = a[68].Contains('T');
            csRunner1Flag = a[69].Contains('T');
            csRunner2Flag = a[70].Contains('T');
            csRunner3Flag = a[71].Contains('T');
            poRunner1Flag = a[72].Contains('T');
            poRunner2Flag = a[73].Contains('T');
            poRunner3Flag = a[74].Contains('T');
            respPitcher1 = a[75].Replace("\"", "");
            respPitcher2 = a[76].Replace("\"", "");
            respPitcher3 = a[77].Replace("\"", "");
            newGameFlag = a[78].Contains('T');
            endGameFlag = a[79].Contains('T');
            pinchRunner1 = a[80].Contains('T');
            pinchRunner2 = a[81].Contains('T');
            pinchRunner3 = a[82].Contains('T');
            removedForPR1 = a[83].Replace("\"", "");
            removedForPR2 = a[84].Replace("\"", "");
            removedForPR3 = a[85].Replace("\"", "");
            removedForPH = a[86].Replace("\"", "");
            posRemovedForPH = Convert.ToInt32(a[87]);
            fielderWithPO1 = Convert.ToInt32(a[88]);
            fielderWithPO2 = Convert.ToInt32(a[89]);
            fielderWithPO3 = Convert.ToInt32(a[90]);
            fielderWithA1 = Convert.ToInt32(a[91]);
            fielderWithA2 = Convert.ToInt32(a[92]);
            fielderWithA3 = Convert.ToInt32(a[93]);
            fielderWithA4 = Convert.ToInt32(a[94]);
            fielderWithA5 = Convert.ToInt32(a[95]);
            eventNum = Convert.ToInt32(a[96]);
        }
 
        public static List<Event> GetEventList(string dir)
        {
            string s;
            string[] splitLine;
            List<Event> eventList = new List<Event>();
 
            List<string> efs = Directory.GetFiles(dir, "*.csv").ToList();
            foreach (string ef in efs)
            {
                Console.WriteLine("Reading events in " + ef);
                StreamReader sr = new StreamReader(ef);
                while ((s = sr.ReadLine()) != null)
                {
                    splitLine = s.Split(',');
                    if (splitLine.Count() == 97)
                    {
                        eventList.Add(new Event(splitLine));
                    }
                }
            }
 
            return eventList;
        }
    }
}

I have zipped up the solution if you would like to work with it:

RetrosheetReader.zip

Next up will come some actual analysis of the data, now that it is completely being read in and stored.

NetCFSvcUtil.exe error in Windows 7

I have been using Windows 7 for a while now, and always had to keep my Windows XP dev machine handy to help out with my Windows Mobile software development.

It turns out that the NetCFSvcUtil application included in the .NET CF Power Toys did not get along with Windows 7 (neither the RC or the RTM bits), as it gave a cryptic error message of “An error occurred in the tool”.

So just for giggles, I decided to see if there were any updates, and lo and behold, I found a blog post from Habib Heydarian with an updated application:

NetCFSvcUtil.exe and Windows 7

Now I can happily generate the client code on my Windows 7 machine.