Archive for the ‘.NET’ Category.

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.

Cannot enable networking in Windows Mobile emulator on Windows 7

So you are using a new Windows 7 installation and developing a Windows Mobile application, and you have been using it just fine on another dev box or in an earlier version of Windows. You deploy your application, and it needs to communicate over the internet, so you go into the Network tab of the Emulator Properties and enable the network adapter.

Only this time, it comes up with an error message about installing Virtual PC 2007.

And then you find out that Virtual PC 2007 does not play nicely with Windows 7.

Well it all has to do with Virtual Machine Network Services. Here is a blog post from Brian Peek on how to solve the problem:

Windows Virtual PC and the Microsoft Device Emulator

Retrosheet reader

OK, so you just got back from the Ohio LinuxFest 2009  (meh, not exactly a hoppin’ place this year, I was kind of disappointed), and you have your event files converted over to CSV files after you generated the BEVENT batch files per last weekend’s post.

Now, you would like to read in that data and start looking through it for anything useful. Well this weekend’s post will help you with the reading in part, and you can take it from there if you would like.

Here is the C# console code. I have put all of the CSV files, ROS (roster) files, and the TEAM???? file into a folder on my C: drive called baseball_data, if your folder is different then just change the constant defined in the code below:

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];
        }
    }
 
    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];
        }
    }
 
    class Event
    {
        string gameID;
        string visitingTeam;
        int inning;
        string battingTeam;
        int outs;
        int balls;
        int strikes;
        // yeah, there is still some work left here to do
        // maybe next time
 
        public Event(string[] a)
        {
            gameID = a[0];
            visitingTeam = a[1];
            inning = Convert.ToInt32(a[2]);
            battingTeam = a[3];
            outs = Convert.ToInt32(a[4]);
            balls = Convert.ToInt32(a[5]);
            strikes = Convert.ToInt32(a[6]);
        }
    }
 
    class Program
    {
        const string DATA = "c:\\baseball_data\\";
 
        static void Main(string[] args)
        {
            List teamList = new List();
            List playerList = new List();
            List eventList = new List();
 
            string s;
            string[] splitLine;
            int y;
 
            Console.WriteLine("Retrosheet Reader");
            Console.WriteLine();
 
            List tfs = Directory.GetFiles(DATA, "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));
                    }
                }
            }
 
            List rfs = Directory.GetFiles(DATA, "*.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));
                    }
                }
            }
 
            List efs = Directory.GetFiles(DATA, "*.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));
                    }
                }
            }
 
            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();
        }
    }
}

I have an idea as to the first thing that I am going to look for in the Retrosheet data, so tune in next weekend and I will (hopefully) have some interesting insights.

Monty Hall meets Monte Carlo

In honor of CBS canceling The Guiding Light after 72 years, and replacing it with a new incantation of Let’s Make A Deal, I decided to apply a little brute force computing to The Monty Hall problem.

Here is the VB.NET code to run the simulations. I decided to only apply a few different Monty Hall behaviors and a few different player behaviors, but it should be enough to drive home the paradox.

Module Module1
 
    Sub Main()
 
        Dim i, j, ctr As Integer
        Dim doorSwitch As String = "?"
        Dim smartMonty As String = "?"
        Dim prizeDoor(3) As Boolean
        Dim rand As Random = New Random()
        Dim doorMontyOpens As Integer
        Dim doorYouOpen As Integer
        Dim carsWon As Integer = 0
 
        Console.WriteLine("The Monty Hall Problem")
        Console.Write("How many times to run the simulation? ")
        ctr = Val(Console.ReadLine())
        If ctr < 1 Then End
 
        Console.Write("Are you going to switch doors? [Y/N/M] ")
        While Not "YNM".Contains(doorSwitch)
            doorSwitch = Console.ReadKey.KeyChar.ToString.ToUpper
        End While
        Console.WriteLine()
 
        Console.Write("Does Monty know where the car is? [Y/N/M] ")
        While Not "YNM".Contains(smartMonty)
            smartMonty = Console.ReadKey.KeyChar.ToString.ToUpper
        End While
        Console.WriteLine()
 
        For i = 1 To ctr
 
            ' set up the prize doors
            For j = 1 To 3
                prizeDoor(j) = False
            Next
            prizeDoor(rand.Next(1, 4)) = True
 
            Console.Write(i.ToString() + " (")
            For j = 1 To 3
                Console.Write(If(prizeDoor(j), "$", j.ToString))
            Next
            Console.Write(") -- ")
 
            ' Monty shows you a door
            If smartMonty = "Y" Or (smartMonty = "M" And _
                                    rand.NextDouble > 0.5) Then
                doorMontyOpens = If(prizeDoor(2), 3, 2)
            Else
                doorMontyOpens = rand.Next(2, 4)
                If prizeDoor(doorMontyOpens) Then
                    carsWon = carsWon + 1
                    Console.WriteLine("Monty revealed the car!!!!!")
                    Continue For
                End If
            End If
            Console.Write("Monty reveals a goat behind door #" + _
                          doorMontyOpens.ToString + " -- ")
 
            ' pick a door to open
            If doorSwitch = "Y" Or (doorSwitch = "M" And _
                                  rand.NextDouble > 0.5) Then
                doorYouOpen = If(doorMontyOpens = 2, 3, 2)
                Console.Write("You switched to door #" + _
                              doorYouOpen.ToString + " -- ")
            Else
                doorYouOpen = 1
                Console.Write("You stayed with door #1 -- ")
            End If
 
            ' did we win?
            If prizeDoor(doorYouOpen) Then
                Console.WriteLine("You won the car!!!!!")
                carsWon = carsWon + 1
            Else
                Console.WriteLine("You won the goat.")
            End If
 
        Next
 
        Console.WriteLine(" ")
        Console.WriteLine("You won the car " + carsWon.ToString + _
                          " times out of " + ctr.ToString)
        Console.WriteLine("Winning percentage: " + (carsWon * _
                            100.0 / ctr).ToString("##0.0"))
        Console.WriteLine(" ")
        Console.WriteLine("Strike any key to end...")
        Console.ReadKey()
 
    End Sub
 
End Module

Now if CBS ever decides to cancel The Young And The Restless, we are going to have a real problem on our hands.

Retrosheet.org play-by-play baseball data

I have thought for a long time that Retrosheet.org was a pretty neat web site with the potential for a ton of baseball information.

They have loads of stats on their site, but it can be hard to get at sometimes.  As a result, I thought I might do some coding against their data just for fun. (I am doing this mainly because I am bored, because the Steelers are not on TV here in Ohio today, and because cable does not carry the NFL Sunday Ticket.)

The first task is to take their event data files and get them into a format that can be easily read and parsed. There are zip files on the Retrosheet web site to download entire seasons worth of event data, just go to retrosheet.org, hover over Data downloads, and select Play-by-play files.

However, once you look at these event files, you discover that they may need a little interpreting to get them into a nicer format for study. Luckily, Tom Tippett, David Nichols, and David W. Smith wrote a DOS application that does this, you just need to run this BEVENT.EXE file on each of the event files.

And of course, I couldn’t simply do that, I had to write a VB.NET console application to create a batch file do automate this.

Imports System.IO
 
Module Module1
 
    Sub Main()
 
        Console.WriteLine("BEvent Helper")
        Console.Write("Enter the directory of your event files: ")
        Dim d As String = Console.ReadLine()
 
        If d.Trim = "" Or Not Directory.Exists(d) Then GoTo App_end
        If Right(d, 1) <> "\" Then d = d + "\"
 
        Dim eventFilenames As List(Of String)
        eventFilenames = Directory.GetFiles(d, "*.ev?").ToList
 
        Dim s, cmd As String
        Dim sw As StreamWriter = New StreamWriter(d + "BEventHelper.bat")
        For Each f In eventFilenames
            s = Path.GetFileName(f)
            cmd = "bevent.exe -f 0-96 -y " + Left(s, 4) + " " + s + " > " + s + ".csv"
            sw.WriteLine(cmd)
        Next
        sw.WriteLine("pause")
        sw.Close()
 
App_end:
        Console.WriteLine("Press any key to end application...")
        Console.ReadKey()
 
    End Sub
 
End Module

So what you do is download a season zip file (find them on the Play-by-Play Data Files page), unzip the files into a directory, download the bevent.zip file from the Software tools page, unzip it and place the BEVENT.EXE file into the directory with all the event files, run the console application and enter the directory name at the prompt, and when it is all said and done, you have a BEventHelper.bat file in the directory. Once this file is run, you will end up with CSV files that correspond to the event files.

In the next episode, I will begin to read in the data and crank out some preliminary statistics.

Disclaimer: The information used here was obtained free of charge from and is copyrighted by Retrosheet. Interested parties may contact Retrosheet at “www.retrosheet.org”.

My first foray into Code Golf

So I am poking around on Stack Overflow, trying to figure out a way for someone as stupid as me to actually move my reputation up, when I stumble on this post…

Code Golf: Duplicate Character Removal in String (EDIT: Sorry, I had to remove the link as the question was removed by Stack Overflow…)

This seemed simple enough, so here is my VB.NET console application code:

Module Module1
 
    Sub Main()
 
        Dim s As String = "nbHHkRvrXbvkn"
        Console.WriteLine("The original string is: " + s)
        For Each c In s : s = IIf(s.LastIndexOf(c) <> s.IndexOf(c), s.Replace(CStr(c), Nothing), s) : Next
        Console.WriteLine("The modified string is: " + s)
        Console.ReadKey()
 
    End Sub
 
End Module

The line that does all the work is 98 characters, including the spaces that the IDE automagically puts in there for me.

Anyone have any ideas on how to improve it in VB.NET?

Some more Monte Carlo experimentation

Disclaimer: I do not in any way, shape, or form condone gambling. This posting is for entertainment purposes only.

I saw this roulette story on The Daily WTF, and thought that it merited some good ole fashioned brute force computing:

Knocking Me Off The Perch

So here is the VB.NET console application code:

Module Module1
 
    Dim rand As Random
 
    Dim tableResults() As List(Of String)
    Dim theWheel() As String = {"G00", "B2", "R14", "B35", "R23", _
                                "B4", "R16", "B33", "R21", "B6", _
                                "R18", "B31", "R19", "B8", "R12", _
                                "B29", "R25", "B10", "R27", _
                                "G0", "R1", "B13", "R36", "B24", _
                                "R3", "B15", "R34", "B22", "R5", _
                                "B17", "R32", "B20", "R7", "B11", _
                                "R30", "B26", "R9", "B28"}
    Dim wheelCount As Integer
    Dim tableBetAmount() As Integer
    Dim tableBetColor() As String
    Dim tableLostLastTime() As String
 
    Dim tables, stake, bet, matches, goal, attempts As Integer
    Dim cancelBetAfterAWin As String
 
    Function GetASpin() As String
 
        Return theWheel(rand.Next(0, wheelCount))
 
    End Function
 
    Function GetABet(Optional ByVal bigBet As Boolean = False) As Integer
 
        Dim theBet As Integer
 
        If bigBet Then
            theBet = bet * 1.5
        Else
            theBet = bet
        End If
 
        If theBet > stake Then theBet = stake
 
        stake = stake - theBet
 
        Return theBet
 
    End Function
 
    Sub Main()
 
        Dim i, j As Integer
        Dim s As String
 
        rand = New Random
 
        Console.WriteLine("The Perch")
 
        Console.Write("How many tables to watch? (4) ")
        tables = Val(Console.ReadLine)
        If tables = 0 Then tables = 4
        ReDim tableResults(tables)
        ReDim tableBetAmount(tables)
        ReDim tableBetColor(tables)
        ReDim tableLostLastTime(tables)
 
        Dim stakeSave As Integer
 
        Console.Write("How many money to start with? (10) ")
        stakeSave = Val(Console.ReadLine)
        If stakeSave = 0 Then stakeSave = 10
 
        Console.Write("How many money to bet? (10) ")
        bet = Val(Console.ReadLine)
        If bet = 0 Then bet = 10
 
        Console.Write("How many times to hit a color before betting? (4) ")
        matches = Val(Console.ReadLine)
        If matches = 0 Then matches = 4
 
        Console.Write("What is your goal amount? (400) ")
        goal = Val(Console.ReadLine)
        If goal = 0 Then goal = 400
 
        Console.Write("How many times to run the simulation? (1000) ")
        attempts = Val(Console.ReadLine)
        If attempts = 0 Then attempts = 1000
 
        Console.Write("Cancel your bet after a win? (Y) ")
        s = Console.ReadLine.ToUpper.Trim
        If s = "" Then s = "Y"
        cancelBetAfterAWin = (s = "Y")
 
        Dim madeGoal As Integer = 0
 
        wheelCount = theWheel.Count
 
        Dim currAttempt As Integer
        Dim ctr As Integer
        Dim theSpin As String
        Dim spinsSeen As Integer
        Dim result As String
        For currAttempt = 1 To attempts
            ' initialize the table arrays
            stake = stakeSave
            For i = 0 To tables - 1
                tableResults(i) = New List(Of String)
                tableBetAmount(i) = 0
                tableLostLastTime(i) = ""
            Next
            ' initialize the lists
            For j = 1 To matches
                s = String.Format("{0,5}", j.ToString)
                For i = 0 To tables - 1
                    theSpin = GetASpin()
                    tableResults(i).Add(theSpin)
                    s = s + String.Format("{0,5}{1,-5}", "", theSpin)
                Next
                s = s + String.Format("{0,5}", stake.ToString)
                Console.WriteLine(s)
            Next
            spinsSeen = matches
            ' loop
            While (stake > 0 And stake < goal)
                ' place your bets
                For i = 0 To tables - 1
                    If tableLostLastTime(i) <> "" Then
                        ' see if this is the 1st time losing
                        If tableBetAmount(i) = bet Then
                            ' we lost last time out, automatically bet 1.5x
                            tableBetAmount(i) = GetABet(True)
                            tableBetColor(i) = tableLostLastTime(i)
                        Else
                            ' this is the 2nd time losing in a row, so stop betting
                            tableBetAmount(i) = 0
                            tableBetColor(i) = ""
                            tableLostLastTime(i) = ""
                        End If
                    Else
                        ' check to see if the colors match up
                        ctr = 0
                        For Each r In tableResults(i)
                            If Left(r, 1) = "B" Then ctr = ctr + 1
                        Next
                        If ctr = matches Then
                            ' it's coming up black, bet on red
                            tableBetAmount(i) = GetABet()
                            tableBetColor(i) = "R"
                            tableLostLastTime(i) = ""
                        End If
                        ctr = 0
                        For Each r In tableResults(i)
                            If Left(r, 1) = "R" Then ctr = ctr + 1
                        Next
                        If ctr = matches Then
                            ' it's coming up red, bet on black
                            tableBetAmount(i) = GetABet()
                            tableBetColor(i) = "B"
                            tableLostLastTime(i) = ""
                        End If
                    End If
                Next
                ' now spin for each of the tables
                spinsSeen = spinsSeen + 1
                s = String.Format("{0,5}", spinsSeen.ToString)
                For i = 0 To tables - 1
                    ' pop off the oldest spin for each table
                    tableResults(i).RemoveAt(0)
                    ' get a new spin for each table
                    theSpin = GetASpin()
                    tableResults(i).Add(theSpin)
                    If tableBetAmount(i) = 0 Then
                        s = s + String.Format("{0,5}{1,-5}", "", theSpin)
                    Else
                        s = s + String.Format("{0,5}{1,-5}", _
                                              tableBetAmount(i).ToString + _
                                              tableBetColor(i) + ">", theSpin)
                    End If
                    ' check for bets
                    If tableBetColor(i) <> "" Then
                        If Left(tableBetColor(i), 1) = Left(theSpin, 1) Then
                            ' winner
                            stake = stake + tableBetAmount(i) * 2
                            tableLostLastTime(i) = ""
                            If cancelBetAfterAWin Then
                                tableBetAmount(i) = 0
                                tableBetColor(i) = ""
                            End If
                        Else
                            tableLostLastTime(i) = tableBetColor(i)
                        End If
                    End If
                Next
                s = s + String.Format("{0,5}", stake.ToString)
                Console.WriteLine(s)
            End While
            If stake = 0 Then
                result = "Busted"
            Else
                madeGoal = madeGoal + 1
                result = "Won $" + stake.ToString
            End If
            Console.WriteLine("Spins seen: " + spinsSeen.ToString + _
                              "; Result: " + result)
        Next
 
        Console.WriteLine()
        Console.WriteLine("Total simulations: " + attempts.ToString)
        Console.WriteLine("Number of times goal was made: " + madeGoal.ToString)
 
        Console.WriteLine()
        Console.WriteLine("Strike any key to end the program")
        Console.ReadKey()
 
    End Sub
 
End Module

I kind of stumbled into something interesting here. I thought I had coded the application with the rules as described in the posting on The Daily WTF, but the results that I was seeing seemed out of whack to me.  I was running 1,000 simulations and coming up with about 300 times successfully reaching the goal. After I put in the code that breaks down the wheel, bet, and stake status on a spin-by-spin basis, I noticed that I was not cancelling the bet after a win. After fixing it up by adding the code to return to the perch after a winning bet (see the section above with the comment winner), all of a sudden the number of times reaching the goal went from 300 per thousand to 0 to 5 per thousand.

So that you can try it for yourself, I put in an option to control this parameter. From the results, it would appear that if you want to play this way, you should let the bets ride. (But notice that if your bets are riding and you get the required number red or black spins in a row, the bet that is riding could switch colors.)