Posts tagged "coding" - Nate's Website
Skip to content

NBA Schedule Generator (Part 1) Base Case

One of the requirements for my Basketball Simulator project is to create a way to dynamically create schedules for seasons. If you were simulating seasons from the NBA’s past, you could use the actual historical schedules, but we are building an application that will allow the user to simulate seasons well into the future (2022 and beyond).

Ideally, the application will have a schedule generator that can generate a schedule based on any custom league design the user wants. But to start, we’re going to build an NBA Schedule Generator using the same rules and considerations that are used to make the NBA schedule. In this first blog post, I will highlight how to build a base case NBA schedule. Eventually, our schedule generator will factor in such considerations as travel time, team popularity, back-to-backs, and TV broadcast considerations.

One last thing before we get started, there’s been a good deal of research and open-source projects related to the NBA schedule that I have been able to access and learn from. The nba-scheduler Python project has been particularly useful so big thanks to the creator!

So what are the requirements of the NBA Schedule?

First, let’s go over the NBA’s league structure:

  • 30 Teams
  • 2 conferences (15 teams in each conference)
  • 6 divisions (3 divisions in each conference, 5 teams in each division)

Each of these teams must play 82 games and the schedule adheres to the following rules:

  • 4 games against the 4 intra-division teams (16 games, 8 home, 8 away)
  • 2 games against the 15 teams from the other conference (30 games, 15 home, 15 away)
  • 4 games against 6 in-conference, out-of-division teams (24 games, 12 home, 12 away)
  • 3 games against 4 in-conference, out-of-division teams (12 games, 2 teams 2 home, 1 away and 2 teams 2 away, 1 home)

From a coding perspective, the first 2 rules are pretty easy to reconcile. We just need to loop through each team and find the other teams that are in their division and not in their conference. That will get us 46 of the 82 games.

The 3rd and 4th rules is where things are not as simple. Here, we are working with 10 opponent teams that are in the team’s conference but not in their division. We then need to split these 10 teams into two buckets, which we will call common (6 teams) and rare (4 teams). Seems simple enough, right? But how do you do this dynamically?

Solving the Problem

One thing I first realized is that if you could choose the rare opponents for a given team, then you could find out the common opponents by finding those in-conference, out-of-division opponents that are not in the rare bucket. I decided to choose the rare opponents first because there were less of them.

My first attempt at choosing the rare opponents for each team had me doing a simple loop through each team and then getting a random opponent (of the 10 teams) and putting each team in each other’s rare bucket. The problem with this approach is that by the time I reached the end of my loop for each team, the teams at the tail end of the loop didn’t have a sufficient number of teams to choose from to fill out there schedule. So how do you solve this problem?

With recursion! For those that do not know, recursion is a concept in computer programming, where a function/algorithm calls itself until a certain condition is met. So for each of the 30 teams, we call this recursive function and pass the team as a parameter to the function:

What recursion allows us to do is have some more flexibility when choosing our rare opponents. The recursive function (which we are calling setRareNonDivisionOpponents) will only stop calling itself when all 30 teams have 4 teams in its’ rare bucket. To get there, it accounts for when there is less than 4 teams in the bucket and more than 4 teams in the bucket.

When there is less than 4 teams, we get a random opponent, check to make to make sure the teams aren’t already in the team’s rare bucket (otherwise we call our function again), and then add them to each team’s rare bucket.

else if (numScheduledRareGames < 4) {
      const opp = sample(possibleRareOpponents);

      if (!opp) {
        throw new Error(
          "We need a random opponent to continue. If not, the team has no chance of completing"
        );
      }

      //the randomly picked opponent is already a rare opponent, call again to make another choice
      if (
        this.teamSchedulerObj[team.abbrev].rareNonDivisionOpponents.includes(
          opp.abbrev
        ) ||
        this.teamSchedulerObj[opp.abbrev].rareNonDivisionOpponents.includes(
          team.abbrev
        )
      ) {
        this.setRareNonDivisionOpponents(opp);
        this.setRareNonDivisionOpponents(team);
        return;
      }

      // We can use this opponent so push them to each team's holders
      this.teamSchedulerObj[team.abbrev].rareNonDivisionOpponents.push(
        opp.abbrev
      );
      this.teamSchedulerObj[opp.abbrev].rareNonDivisionOpponents.push(
        team.abbrev
      );
      // call this function again for both teams

      this.setRareNonDivisionOpponents(team);
      this.setRareNonDivisionOpponents(opp);
    }

In the case where there is more than 4 teams in the rare bucket, we randomly select one of those teams and remove them from each team’s rare bucket.

    if (numScheduledRareGames > 4) {
      //current team has more than four opponents, need to remove some
      //pick random team from current rare opponents
      const randAbbrev = sample(rareNonDivisionOpponents)!;

      //remove the team from current team and opponents rare opponents
      this.teamSchedulerObj[team.abbrev].rareNonDivisionOpponents =
        this.teamSchedulerObj[team.abbrev].rareNonDivisionOpponents.filter(
          (team: string) => team !== randAbbrev
        );
      this.teamSchedulerObj[randAbbrev].rareNonDivisionOpponents =
        this.teamSchedulerObj[randAbbrev].rareNonDivisionOpponents.filter(
          (randTeam: string) => randTeam !== team.abbrev
        );

      //re-run this function for both teams
      this.setRareNonDivisionOpponents(team);
      this.setRareNonDivisionOpponents(this.getTeamByAbbrev(randAbbrev));
    }

The end result is a recursive function that will add and remove from the rare buckets until it randomly finds the perfect fit. Pretty magical!

If you would like to work with the NBA Schedule generator yourself or would like to checkout the code, please visit the GitHub repo.

Thanks for reading!


Basketball Simulator

I wanted to talk a bit about a project I have been working on over the last couple of months. It’s a basketball simulation engine!

What is a basketball simulation engine?
Oh, it’s just software that can be used to simulate the events and outcomes of fake basketball games.

Why would anyone want to do that?
I don’t know—'cause it’s fun. It’s a project that requires me to further my knowledge in algorithms, data structures, data science, UI design, and artificial intelligence. What one considers fun changes a lot as you get older.

Okay, but seriously why would anyone do that?
Well, the hope is that one day it could be used for a video game, one where you could set up your own little basketball world and simulate the outcomes of that world.

Great, again, why would anyone do that?
Because it’ll be fun! Like seriously, geez. With your own little basketball world, you could simulate these potential scenarios:

What if the NBA dropped 10 teams and switched to a relegation-style league where the bottom 3 teams were forced to go to a lower-tier league and the winners of the lower-tier league got promoted (ala English soccer leagues)?

What if Derrick Rose hadn’t injured his knee on April 28, 2012?

What if you could field a team of your all-time favorite players from any era and have them play a season in any era?

Okay, yeah, this sounds like a geeky basketball thing.
Pretty much. It is pretty geeky. I’ve been playing sports simulation games since 1989 when my family got our first family computer (a Swan!). It is definitely the geekiest thing I do.


If you’re interested in following the project and want to see some of the code, it is open-source and lives at this GitHub repo: https://github.com/NateWritesCode/basketball-simulator

The core of the project is written in Typescript but also makes use of Python and R for some data gathering. Right now, there is no documentation, but I will be adding more as the project develops.

If you have any questions or comments, let me know, and thanks for reading!


On Coding

I wrote this for my nephews and niece to explain what coding is and why I love it.

If you were to randomly come visit me in my super-cool (definitely not sad!) Chicago apartment on some special day, you would likely find me coding. I’d say I probably code or think about coding 50 hours per week (give or take). But what is this thing coding and why do I love to do it so much?

The way I look at it—coding is teaching something as dumb as a computer how to do things. I know when we think about computers, we think, “Oh computers, they’re such braniacs. That egghead computer just helped me do my taxes in 20 minutes. Or I saw that genius robot Watson created by IBM win on Jeopardy that one time.” But really they are pretty dumb if left to their own devices (heyyo!).

If you go to your local Best Buy, pick out the shiniest/most expensive game console, phone, laptop, washing machine whatever, it’d just be an expensive plastic/metal rock if some programmer/team of programmers didn’t teach it how to do something. In fact, I’d argue a real rock from the ground is probably smarter than that electronic device. I mean it’s been around longer, right? Just existing for so long on Earth certainly has to make that rock from the ground wiser. I’d take life advice from a rock.

Me: What should I do with my life?

Rock from the Ground: —–

Me: Great! I’ll do nothing with it.

Rock from the Ground: —–

Me: So wise!

So how do you teach a computer what to do? With language. And unfortunately we’re not at the point where we can just speak the language we learned when we were born to a computer to teach it what to do. I know because I shout at my computer, “JUST WORK!” at least a couple of times per week, and it always just sits there all smug and does nothing. So wise!

There’s a programming language that is great for beginners that sounds super slithery called Python. And one that’s so fresh and exciting that it’s ironic that it bears the name Rust. My language of choice is Javascript. It was initially created to help users interact with elements on a web page, but now it does so much more. It sounds like preparation instructions for your morning cup of coffee. Like, “Herman, why does my cup of coffee taste so bad??? Someone didn’t follow the Javascript! Coffee Morning is ruined!!!”

(If you want to just marvel at the insane number of programming languages people have created over the years, see this list here)

So great, you learn a language so you can teach a computer how to do things. Whoop dee doo. Inherently, there’s nothing super fun about code. Like take this code snippet of a function that will return a random number between a minimum number and a maximum number.

function getRandomNumberBetweenTwoNumbersInclusive (min, max) {
   return Math.floor(Math.random() * (max - min + 1) + min);
}

Yikes! I just want a random number greater than or equal to 1 and less than or equal to 10. What’s all this other stuff? Math.floor? Not fun. In fact, I hate it. And I hate you for making me read it. Seems way too complicated. I stared at that code for a long time and not once in those 20 minutes did I feel any type of fun. On the fun scale, it’s just below putting one container of egg salad in a grocery cart on a Tuesday. (Sidenote: putting 85 containers of egg salad in a grocery cart on a Friday evening would rank pretty high on the fun scale)

Inherently, that code—not fun. What you could potentially do with code like that—really fun. What if I told you random numbers are a huge part of what makes video games so challenging and exciting? Oh wow! Your mind is blown, I know. That’s right, there is not some video game machine in Toledo, Ohio, cranking out the latest fun times. It’s code.

And you can take that code and use it to build things. Things out of this world. Things that haven’t even been imagined yet. Things that create happiness and put smiles on people’s face. Things that cure pain and solve problems that will never have to be solved again. Things that are impossible in the real world but are possible in the virtual world.

I’m not going to lie. It’s not always fun. It can be a lot of work. And it’s really hard at times. I’m not the smartest guy in the world. And a lot of times during the day I feel like banging my head against a wall. And one time I did actually bang my head against the wall, like for real, was in the hospital 4 days but met some amazing fellow coders in the head-injury ward. :)

I’m not like an old man here, but one of the things I’ve learned in life is that being able to create the things you imagine is one of the keys to happiness. Code helps me do that and that is why I love it.

(I just want to note in my earlier indictment of computers as being dumb–I’m of course not referring to those supercomputers coming in the future that will be self-learning, much smarter than humans and will kill all those who ever spoke disparagingly of them. This writing is tongue-in-cheek, don’t kill me and anyone who ever graced my presence Master Super Computer Leader ZYTRIK! I’m a FAN!!!)