Tabletop Dice Baseball Simulation Using C#

Various versions of tabletop dice baseball have been around for well over 100 years. There are many variations, but in most you roll one or two dice which determine the result of a play, for example, “single”, or “ground out”, or “walk”.

Quite a number of months ago, I wrote a simulation of one particular variation. The version I picked uses two dice and has the following gameplay:

1/1 home run      3/3 single  
1/2 double        3/4 strikeout   
1/3 single        3/5 ground out  
1/4 pop out       3/6 fly out
1/5 ground out*   4/4 walk
1/6 strikeout     4/5 fly out 
2/2 single        4/6 fly out 
2/3 pop out       5/5 base on error
2/4 ground out    5/6 single
2/5 strikeout     6/6 triple
2/6 ground out   

* double play if a force available

I coded my old simulation using Python. One evening while I was sitting in an airport waiting to board a flight, I figured I’d take a stab at the simulation using the C# language.

Here’s some sample output of the beginning of a simulation:

=============================
top of inning 1
---------------------------
  _
_   _
  X

roll: 3 3
single
---------------------------
---------------------------
  _
_   X
  X

roll: 1 3
single
---------------------------
---------------------------
  X
_   X
  X

roll: 2 3
pop out
1 outs
---------------------------
---------------------------
  X
_   X
  X

roll: 6 6
triple
2 run(s) score!
---------------------------
---------------------------
  _
X   _
  X

roll: 1 4
pop out
2 outs
---------------------------
---------------------------
  _
X   _
  X

roll: 3 6
fly out
3 outs
---------------------------

End top of inning 1
runs = 2   hits = 3   errors = 0
=============================

And here’s the end of a simulation:

=============================
top of inning 9
---------------------------
  _
_   _
  X

roll: 1 2
double
---------------------------
---------------------------
  X
_   _
  X

roll: 1 6
strikeout
1 outs
---------------------------
---------------------------
  X
_   _
  X

roll: 3 6
fly out
2 outs
---------------------------
---------------------------
  X
_   _
  X

roll: 1 3
single
---------------------------
---------------------------
  _
X   X
  X

roll: 1 5
sharp grounder
3 outs
---------------------------

End top of inning 9
runs = 0   hits = 2   errors = 0
=============================

**************************

       Runs Hits Errors
Visitor:    2  13  1
Home:       5  11  0

**************************

It was an enjoyable way to kill some time in an airport.



A baseball board game made by Milton Bradley in 1958. The game consists of a field with a giant “spinner” embedded under it. There are nine fielders sitting over small squares on the board, four umpires over additional squares, and a batter. The player at bat then decides to swing, bunt or take the pitch. Depending on the batter’s decision, the umpire or a defensive player is lifted to reveal the outcome. I never played this game. It’s highly sought after by collectors.


Demo code. Replace “lt” (less than), “gt”, “lte”, “gte”, “and” with Boolean operator symbols (my blog editor chokes on symbols).

using System.IO;

namespace DiceBaseball
{
  internal class DiceBaseballProgram
  {
    static void Main(string[] args)
    {
      Random rnd = new Random(0);
      PlayGame(rnd);
      Console.ReadLine();
    } // Main()

    static int AdvanceSingle(bool[] bases)
    {
      int runsScored = 0;

      if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == true)  // bases loaded
      {
        bases[1] = true; bases[2] = true; bases[3] = true;
        runsScored = 1;
      }
      else if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == false)  // runners on 1,2
      {
        bases[1] = true; bases[2] = true; bases[3] = true;
        runsScored = 0;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == true)  // runners on 2,3
      {
        bases[1] = true; bases[2] = false; bases[3] = true;
        runsScored = 1;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == true)  // runners on 1,3
      {
        bases[1] = true; bases[2] = true; bases[3] = false;
        runsScored = 1;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == false)  // runner on 1
      {
        bases[1] = true; bases[2] = true; bases[3] = false;
        runsScored = 0;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == false)  // runner on 2
      {
        bases[1] = true; bases[2] = false; bases[3] = true;
        runsScored = 0;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == true)  // runner on 3
      {
        bases[1] = true; bases[2] = false; bases[3] = false;
        runsScored = 1;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == false)  // bases empty
      {
        bases[1] = true; bases[2] = false; bases[3] = false;
        runsScored = 0;
      }
      return runsScored;
    } // single

    static int AdvanceDouble(bool[] bases)
    {
      int runsScored = 0;

      if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == true)  // bases loaded
      {
        bases[1] = false; bases[2] = true; bases[3] = true;
        runsScored = 2;
      }
      else if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == false)  // runners on 1,2
      {
        bases[1] = false; bases[2] = true; bases[3] = true;
        runsScored = 1;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == true)  // runners on 2,3
      {
        bases[1] = false; bases[2] = true; bases[3] = false;
        runsScored = 2;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == true)  // runners on 1,3
      {
        bases[1] = false; bases[2] = true; bases[3] = true;
        runsScored = 1;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == false)  // runner on 1
      {
        bases[1] = false; bases[2] = true; bases[3] = true;
        runsScored = 0;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == false)  // runner on 2
      {
        bases[1] = false; bases[2] = true; bases[3] = false;
        runsScored = 1;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == true)  // runner on 3
      {
        bases[1] = false; bases[2] = true; bases[3] = false;
        runsScored = 1;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == false)  // bases empty
      {
        bases[1] = false; bases[2] = true; bases[3] = false;
        runsScored = 0;
      }
      return runsScored;
    } // double

    static int AdvanceTriple(bool[] bases)
    {
      int runsScored = 0;
      
      if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == true)  // bases loaded
      {
        bases[1] = false; bases[2] = false; bases[3] = true;
        runsScored = 3;
      }
      else if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == false)  // runners on 1,2
      {
        bases[1] = false; bases[2] = false; bases[3] = true;
        runsScored = 2;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == true)  // runners on 2,3
      {
        bases[1] = false; bases[2] = false; bases[3] = true;
        runsScored = 2;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == true)  // runners on 1,3
      {
        bases[1] = false; bases[2] = false; bases[3] = true;
        runsScored = 2;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == false)  // runner on 1
      {
        bases[1] = false; bases[2] = false; bases[3] = true;
        runsScored = 1;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == false)  // runner on 2
      {
        bases[1] = false; bases[2] = false; bases[3] = true;
        runsScored = 1;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == true)  // runner on 3
      {
        bases[1] = false; bases[2] = false; bases[3] = true;
        runsScored = 1;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == false)  // bases empty
      {
        bases[1] = false; bases[2] = false; bases[3] = true;
        runsScored = 0;
      }

      return runsScored;
    } // triple

    static int AdvanceHomeRun(bool[] bases)
    {
      int runsScored = 0;

      if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == true)  // bases loaded
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        runsScored = 4;
      }
      else if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == false)  // runners on 1,2
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        runsScored = 3;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == true)  // runners on 2,3
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        runsScored = 3;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == true)  // runners on 1,3
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        runsScored = 3;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == false)  // runner on 1
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        runsScored = 2;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == false)  // runner on 2
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        runsScored = 2;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == true)  // runner on 3
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        runsScored = 2;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == false)  // bases empty
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        runsScored = 1;
      }
      return runsScored;
    } // HR

    static int AdvanceWalk(bool[] bases)
    {
      int runsScored = 0;

      if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == true)  // bases loaded
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        runsScored = 1;
      }
      else if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == false)  // runners on 1,2
      {
        bases[1] = true; bases[2] = true; bases[3] = true;
        runsScored = 0;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == true)  // runners on 2,3
      {
        bases[1] = true; bases[2] = true; bases[3] = true;
        runsScored = 0;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == true)  // runners on 1,3
      {
        bases[1] = true; bases[2] = true; bases[3] = true;
        runsScored = 0;
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == false)  // runner on 1
      {
        bases[1] = true; bases[2] = true; bases[3] = false;
        runsScored = 0;
      }
      else if (bases[1] == false "and" bases[2] == true "and"
        bases[3] == false)  // runner on 2
      {
        bases[1] = true; bases[2] = true; bases[3] = false;
        runsScored = 0;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == true)  // runner on 3
      {
        bases[1] = true; bases[2] = false; bases[3] = true;
        runsScored = 0;
      }
      else if (bases[1] == false "and" bases[2] == false "and"
        bases[3] == false)  // bases empty
      {
        bases[1] = true; bases[2] = false; bases[3] = false;
        runsScored = 0;
      }
      return runsScored;
    } // walk

    static int AdvanceError(bool[] bases)
    {
      return AdvanceSingle(bases);
    }

    static int PossibleDoublePlay(bool[] bases)
    {
      int numOuts = 0;
      // on sharp grounder, DP if 1,2,3 or 1,2 or 1
      if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == true)  // bases loaded
      {
        bases[1] = true; bases[2] = true; bases[3] = false;
        numOuts = 2;  // thrown out home and 3rd
      }
      else if (bases[1] == true "and" bases[2] == true "and"
        bases[3] == false)  // runners on 1, 2
      {
        bases[1] = true; bases[2] = false; bases[3] = false;
        numOuts = 2;  // force at 3rd, thown to 2nd
      }
      else if (bases[1] == true "and" bases[2] == false "and"
        bases[3] == false)  // runner on 1
      {
        bases[1] = false; bases[2] = false; bases[3] = false;
        numOuts = 2;  // regular DP
      }
      else
      {
        numOuts = 1;  // no change to runners
      }
      return numOuts;
    }

    static void ShowBases(bool[] bases)
    {
      if (bases[2] == true)
        Console.WriteLine("  X  ");
      else
        Console.WriteLine("  _  ");

      if (bases[1] == true "and" bases[3] == true)
        Console.WriteLine("X   X");
      else if (bases[1] == false "and" bases[3] == true)
        Console.WriteLine("X   _");
      else if (bases[1] == true "and" bases[3] == false)
        Console.WriteLine("_   X");
      else if (bases[1] == false "and" bases[3] == false)
        Console.WriteLine("_   _");

      Console.WriteLine("  X  ");
      Console.WriteLine("");
    }

    static int[] PlayInning(int inning, string tb, Random rnd)
    {
      Console.WriteLine("=============================");
      Console.WriteLine(tb + " of inning " + inning);
      int outs = 0;
      int runs = 0;
      int hits = 0;
      int errors = 0;
      int runsScored = 0; // each inning

      bool[] bases = new bool[] { true, false, false, false };

      while (outs != 3)
      {
        Console.WriteLine("---------------------------");
        ShowBases(bases);
        int d1 = rnd.Next(1, 7);
        int d2 = rnd.Next(1, 7);
        if (d1 "gt" d2)
        {
          int tmp = d1; d1 = d2; d2 = tmp;
        }
        Console.WriteLine("roll: " + d1 + " " + d2);

        if (d1 == 1 "and" d2 == 3 ||
          d1 == 2 "and" d2 == 2 ||
          d1 == 3 "and" d2 == 3 ||
          d1 == 5 "and" d2 == 6)
        {
          Console.WriteLine("single");
          ++hits;
          runsScored = AdvanceSingle(bases);
          if (runsScored == 1)
          {
            Console.WriteLine("run scores!");
            ++runs;
          } // 13 22 33 56
        } // single
        else if (d1 == 1 "and" d2 == 2)
        {
          Console.WriteLine("double");
          ++hits;
          runsScored = AdvanceDouble(bases);
          if (runsScored != 0)
          {
            Console.WriteLine(runsScored + " run(s) score!");
            runs += runsScored;
          }
        } // double
        else if (d1 == 6 "and" d2 == 6)
        {
          Console.WriteLine("triple");
          ++hits;
          runsScored = AdvanceTriple(bases);
          if (runsScored != 0)
          {
            Console.WriteLine(runsScored + " run(s) score!");
            runs += runsScored;
          }
        } // triple
        else if (d1 == 1 "and" d2 == 1)
        {
          Console.WriteLine("home run!");
          ++hits;
          runsScored = AdvanceHomeRun(bases);
          if (runsScored != 0)  // always true
          {
            Console.WriteLine(runsScored + " run(s) score!");
            runs += runsScored;
            if (runsScored == 4)
              Console.WriteLine("GRAND SLAM!!");
          }
        } // HR
        else if (d1 == 4 "and" d2 == 4)
        {
          Console.WriteLine("walk");
          runsScored = AdvanceWalk(bases);
          if (runsScored != 0)
          {
            Console.WriteLine(runsScored + " a run score!");
            runs += runsScored;
          }
        }
        else if (d1 == 5 "and" d2 == 5)
        {
          Console.WriteLine("base on error");
          ++errors;
          runsScored = AdvanceError(bases);
          if (runsScored != 0)
          {
            Console.WriteLine(runsScored + " run(s) score!");
            runs += runsScored;
          }
        }
        else if (d1 == 1 "and" d2 == 4 ||
          d1 == 2 "and" d2 == 3)
        {
          Console.WriteLine("pop out");
          ++outs;
          Console.WriteLine(outs + " outs");
        }
        else if (d1 == 3 "and" d2 == 6 ||
          d1 == 4 "and" d2 == 5 ||
          d1 == 4 "and" d2 == 6)
        {
          Console.WriteLine("fly out");
          ++outs;
          Console.WriteLine(outs + " outs");
        }
        else if (d1 == 2 "and" d2 == 4 ||
          d1 == 2 "and" d2 == 6 ||
          d1 == 3 "and" d2 == 5)
        {
          Console.WriteLine("ground out");
          ++outs;
          Console.WriteLine(outs + " outs");
        }
        else if (d1 == 1 "and" d2 == 5)
        {
          Console.WriteLine("sharp grounder");
          int tmp = PossibleDoublePlay(bases);
          if (outs == 0 || outs == 1 "and" tmp == 2)
          {
            Console.WriteLine("* double play *");
            outs += 2;
          }
          else
          {
            ++outs;
          }
          Console.WriteLine(outs + " outs");
        }
        else if (d1 == 1 "and" d2 == 6 || 
          d1 == 2 "and" d2 == 5 ||
          d1 == 3 "and" d2 == 4)
        {
          Console.WriteLine("strikeout");
          ++outs;
          Console.WriteLine(outs + " outs");
        }
        else
        {
          Console.WriteLine("unhandled roll " +
            d1 + " " + d2); Console.ReadLine();
        }

        Console.WriteLine("---------------------------");

        if (outs == 3)
        {
          Console.WriteLine("\nEnd " + tb + " of inning " +
            inning);
          Console.WriteLine("runs = " + runs + "   hits = " +
            hits + "   errors = " + errors);
        }
        //Console.ReadLine();

      } // while

      Console.WriteLine("=============================");
      int[] rhe = new int[3];
      rhe[0] = runs;
      rhe[1] = hits;
      rhe[2] = errors;
      return rhe;
    } // PlayInning()

    static void PlayGame(Random rnd)
    {
      int[] visitor_r_h_e = new int[3];
      int[] home_r_h_e = new int[3];
      int[] rhe;
      for (int i = 1; i "lte" 9; ++i)
      {
        rhe = PlayInning(i, "top", rnd);
        visitor_r_h_e[0] += rhe[0];
        visitor_r_h_e[1] += rhe[1];
        home_r_h_e[2] += rhe[2];

        if (i == 9 "and" home_r_h_e[0] "gt" visitor_r_h_e[0])
          break;

        rhe = PlayInning(i, "bottom", rnd);
        home_r_h_e[0] += rhe[0];
        home_r_h_e[1] += rhe[1];
        visitor_r_h_e[2] += rhe[2];
      }
      Console.WriteLine("\n**************************\n");
      Console.WriteLine("       Runs Hits Errors");
      Console.WriteLine("Visitor:    " + visitor_r_h_e[0] +
        "  " + visitor_r_h_e[1] + "  " + visitor_r_h_e[2]);
      Console.WriteLine("Home:       " + home_r_h_e[0] +
        "  " + home_r_h_e[1] + "  " + home_r_h_e[2]);
      Console.WriteLine("\n**************************\n");
      Console.ReadLine();
    } // PlayGame()

  } // class Program

} // ns
This entry was posted in Miscellaneous. Bookmark the permalink.

Leave a Reply