bigjocker's den

FiveThirtyEight – The Puzzle Of The Baseball Division Champs

This week’s FiveThirtyEight‘s puzzle has to do with a Baseball division in which every team has the same probability of winning. Once again, I’m tackling it by simulating the problem a bazillion times and seeing what the average is.

The Puzzle Of The Baseball Division Champs reads:

Assume you have a sport (let’s call it “baseball”) in which each team plays 162 games in a season. Assume you have a division of five teams (call it the “AL East”) where each team is of exact equal ability. Specifically, each team has a 50 percent chance of winning each game. What is the expected value of the number of wins for the team that finishes in first place?

The simulation creates a Division with 4 Teams, and each team faces each other until each one has played 162 games. The odds are really boring:

if (Math.random() >= 0.5) {
	match.winner = team1;
	match.loser = team2;
	team1.won++;
} else {
	match.winner = team2;
	match.loser = team1;
	team2.won++;
}

After all the games the program outputs the average games won for the 1st, 2nd, 3rd and 4th places, along with the standard deviation. So after simulating 100,000,000 leagues, or 32,400,000,000 games (it took 25 minutes in an i7 Macbook Pro) the average for each place is:

trantor:fivethirtyeight ngranek$ time java -Xms4g -Xmx8g -cp bin com.bigjocker.fivethirtyeight.NotBaseball 100000000
88.56,3.61
83.18,2.45
78.82,2.45
73.44,3.61

real	25m39.542s
user	26m46.778s
sys		0m8.018s
trantor:fivethirtyeight ngranek$

(the -Xms4g -Xmx8g is required to store the values in RAM in order to calculate the standard deviation).

The first line is the average number of games won by the team with most wins every season (and the standard deviation). The second, third and fourth lines are the averages for the (you guessed it) second, third and fourth places.

So the answer to the question What is the expected value of the number of wins for the team that finishes in first place? is 88.56.

The averages chart is:

Here’s the source code for the solution:

package com.bigjocker.fivethirtyeight;

import java.util.Collections;
import java.util.LinkedList;

public class NotBaseball {
	public class Team implements Comparable<Team> {
		private LinkedList<Match> matches = new LinkedList<NotBaseball.Match>();
		public int won = 0;

		public void play(Division division, Team team2) {
			Team team1 = this;
			Match match = new Match();

			if (Math.random() >= 0.5) {
				match.winner = team1;
				match.loser = team2;
				team1.won++;
			} else {
				match.winner = team2;
				match.loser = team1;
				team2.won++;
			}

			division.matches.add(match);
			team1.matches.add(match);
			team2.matches.add(match);
		}

		public int compareTo(Team team) {
			if (this.won > team.won) {
				return -1;
			} else if (this.won < team.won) {
				return 1;
			}

			return 0;
		}
	}

	public class Match {
		public Team winner = null;
		public Team loser = null;
	}

	public class Division {
		private Team team1 = new Team();
		private Team team2 = new Team();
		private Team team3 = new Team();
		private Team team4 = new Team();

		public LinkedList<Match> matches = new LinkedList<NotBaseball.Match>();

		public LinkedList<Team> runFullSchedule() {
			while (team1.matches.size() < 162) {
				team1.play(this, team2);
				team1.play(this, team3);
				team1.play(this, team4);
			}

			while (team2.matches.size() < 162) {
				team2.play(this, team3);
				team2.play(this, team4);
			}

			while (team3.matches.size() < 162) {
				team3.play(this, team4);
			}

			LinkedList<Team> teams = new LinkedList<NotBaseball.Team>();

			teams.add(team1);
			teams.add(team2);
			teams.add(team3);
			teams.add(team4);

			Collections.sort(teams);

			return teams;
		}
	}

	public class League {
		public Division division1 = new Division();

		public LinkedList<Team> runFullSchedule() {
			LinkedList<Team> teams = division1.runFullSchedule();
			return teams;
		}
	}

	public static void printStats(double results[]) {
		double sum = 0;
		for (double val : results) {
			sum += val;
		}

		double avg = sum / results.length;

		sum = 0;
		for (double val : results) {
			sum += Math.pow(val - avg, 2);
		}

		double sigma = Math.sqrt(sum / results.length);

		System.out.printf("%.2f,%.2f\n", avg, sigma);
	}

	public void runSimulation(int numCycles) {
		double[] results1 = new double[numCycles];
		double[] results2 = new double[numCycles];
		double[] results3 = new double[numCycles];
		double[] results4 = new double[numCycles];

		for (int i = 0; i < numCycles; i++) {
			League league = new League();
			LinkedList<Team> teams = league.runFullSchedule();

			results1[i] = teams.get(0).won;
			results2[i] = teams.get(1).won;
			results3[i] = teams.get(2).won;
			results4[i] = teams.get(3).won;
		}

		NotBaseball.printStats(results1);
		NotBaseball.printStats(results2);
		NotBaseball.printStats(results3);
		NotBaseball.printStats(results4);
	}

	public static void main(String[] args) {
		new NotBaseball().runSimulation(Integer.parseInt(args[0]));
	}
}

Leave a Reply

Your email address will not be published. Required fields are marked *