Simulating outcomes

As expected the recursion at the core was fun and a little bit magical:

def recursive_schedule_fill(time_sorted_games, cur_index, scoreboard):
    if (cur_index >= len(time_sorted_games)) :
        # every time we get to the end of the recursion calculate a winner and
        # add it to the scoreboard
        standings = build_standings(time_sorted_games)
        ordered_standings = sorted(standings.values(), reverse = True, key = standings_sortfunc)
        break_ties(ordered_standings, time_sorted_games)
        scoreboard.record_winner(ordered_standings[0].team_name)
        return
    else :
        # jump to the node in question and first fill in a home team win
        cur_mcc_game = time_sorted_games[cur_index]
        cur_mcc_game.away_points = 4
        cur_mcc_game.home_points = 55
        recursive_schedule_fill(time_sorted_games, cur_index + 1, scoreboard)
        # then do a road team win
        cur_mcc_game.away_points = 55
        cur_mcc_game.home_points = 4
        recursive_schedule_fill(time_sorted_games, cur_index + 1, scoreboard)

For the faked outcomes we use the very scorigami-ish score of 55-4. Obviously since margins of victory matter in our final tiebreaker system we can either go crazy and simulate many different scores or just pick one for the enumeration.

Here’s the full set of today’s diffs and the new output:

$ python3 ./mcc_schedule.py --verbose
San José State 7 at USC 30 on Sep 04, 2021
Stanford 42 at USC 28 on Sep 11, 2021
Fresno State 40 at UCLA 37 on Sep 18, 2021
UCLA 35 at Stanford 24 on Sep 25, 2021
San Diego State 19 at San José State 13 on Oct 15, 2021
Fresno State 30 at San Diego State 20 on Oct 30, 2021
USC at California on Nov 12, 2021
California at Stanford on Nov 19, 2021
UCLA at USC on Nov 19, 2021
Fresno State at San José State on Nov 24, 2021
California at UCLA on Nov 26, 2021

looks like a tie for the cup
head to head didn't resolve anything
oppo check for Stanford and Fresno State
looks like a tie for the cup
head to head didn't resolve anything
oppo check for Stanford and Fresno State
looks like a tie for the cup
head to head didn't resolve anything
oppo check for Stanford and Fresno State
looks like a tie for the cup
head to head didn't resolve anything
oppo check for Fresno State and California
looks like a tie for the cup
head to head didn't resolve anything
oppo check for Fresno State and California
looks like a tie for the cup
head to head didn't resolve anything
oppo check for Fresno State and California
looks like a tie for the cup
head to head didn't resolve anything
oppo check for Stanford and Fresno State
looks like a tie for the cup
head to head didn't resolve anything
oppo check for Fresno State and California

Possibility scoreboard:
Fresno State 19 [59%]
UCLA 4 [12%]
California 5 [15%]
USC 4 [12%]

Fresno State            2-0
San Diego State         1-1
UCLA                    1-1
Stanford                1-1
USC                     1-1
San José State          0-2
2021, 11, ,

Now that I’ve pasted the words “Possibility scoreboard” they look impossibly dumb and I’m going to change that to “simulated outcomes” or “enumerated outcomes.” The total trials add to 32, since we have 5 games left and we’ve allowed for 2 possible outcomes for each game. As our envelope math in previous posts suggested, Fresno State is the winner in 59% of possible worlds and Cal, USC and UCLA all have small chances.

Since we are enumerating all possible outcomes here we treat the outcome of either team winning any game as equally probable. That is, every possible branch of the 2^n tree of win/loss outcomes is walked equally. This is useful for seeing who is mathematically eliminated and who still has a prayer. The other major tool for simulating a season is to do a Monte Carlo simulation using power rankings. (Or some black box that produces a probability projection of the outcome.) With our current framework we can add Monte Carlo to find_possibilities() with a fresh scoreboard. Instead of a recursive walk through the remaining schedule we just have to iterate through each game and loop through a bunch of random trials on each. However, in the world of California college football the coinflip enumeration is probably pretty close to reality! That is, these teams are not very far apart in strength and it’s hard to imagine any upset that would really be improbable. Thus my expectation for a Monte Carlo simulation is that Fresno State will still be around a 60% shot.

My beloved system of printing tiebreaker noise to stderr is showing some serious downside now. Before, every run was on real data so it made some sense to flag tiebreaker oddities on the output. But now we’re reusing the season-resolution code 32 times on different sets of fake and improbable data. We don’t care what happens under the hood of the simulation in all these different sets, we’re just interested in the big picture probability it rolls up in the scoreboard at the end. So the best thing to do is either carry verbosity all the way into those interior tie breaker methods or just kill the stderr printouts all together.