You can’t have a basketball league without the players, teams and a ten-foot hoop. But, we also need a way to organize all the games being played! Crafting an effective game scheduler is a central concept in any sports league, and we’re going to build one today.
A quick note.
This post is a continuation of my basketball simulation Swift app, of which I have written about previously. You can find the first post here. Rather than arbitrarily deciding how much progress should warrant a blog post, I’m organizing these posts a bit differently. Basically, I’ll center a post around a single core feature, and the related methods/classes/files needed to support that feature. This way should be much clearer, and can hopefully help people in the future who want to build similar features of their own. Now, let’s get started.
What is an NBA Season Scheduler?
Let’s provide some quick context for this feature, and why we need it to build a basketball simulation. Looking at the National Basketball Association, it is a league composed of 30 teams. The league is in session for a set period of time every year, or a season. Each team plays a total of 82 games, and they only play during this season. That seems simple enough, but then how do we decide which team plays who? This is where a scheduler comes in to organize this whole affair, according to a set list of requirements agreed upon by the league officials. An example of these rules include:
- Every team should play each other at least once
- Every team should play an equal number of home games and away games
- No team should play twice in a day
If you’re interested in learning more about the NBA’s scheduling design, I encourage you to take a look at We Are Basket’s article on it. Ours may not be as complicated, but we can definitely design one! I will be working in the same Xcode project I started with in my first article.
Creating our NBA League
Before we create our scheduler, we should consider the design of our league overall. What information will we need? We want to know the teams in our league. Also, we want to keep track of the win and loss records for each team. We also want might want to know what year it is in our league. Since we will likely want to keep track of many different variables pertaining to our league, and we may want our league to perform important functions, we should create a class. Create a new file called MyLeague.swift, and create a new class with these member variables:
Going from top-down, the static let sharedInstance declaration follows the singleton pattern. In short, we’ll only have one instance of a league in the lifetime of our application, so we should make sure only one is created and worked with. We’ll keep track of all possible games between teams in a Game array. I previously defined a Game class, but just know that each one is initialized with two teams, and it has functionality to simulate a basketball game for us. Next, what’s a league without stats? LeagueStats is a user-defined struct that we’ll use to keep our class definition simple and clear. We’ll hold all important stats for our teams and players here. Look at what’s in mine:
We want to keep track of the teams in our league of course, so leagueTeams will store an array of Teams. The last two variables, currentDay and gameSchedule, will go hand in hand with creating our game scheduler.
How Our Scheduler Will Work
Let’s say we want to make a league. We want a simple ordering of games between all of our teams, but we also want some rules to apply to our scheduler. Our gameSchedule will be in the form of a dictionary, mapping our season’s days (Int) to all the games scheduled for that day (array of Games). We’ll navigate it with our currentDay variable as a key, and we’ll go through our season and play through all games in a given day. Next, what rules should apply to our scheduler?
1. We want each team to play against every other team once.
We obviously don’t want a team to play against itself either. So if we have 30 teams and each one will play against each other once, we should have 870 games in total. So, when our seasons is ready to start, the leagueGames variable should hold all the possible games within our league:
2. We’re ok with more than one game happening in a single day in our season, but we want a limit of five games a day. Teams also shouldn’t play more than once a day.
After we collect all possible games in our league, we should then schedule them according to any kinds of rules we decide on. For each game, we’ll add them to our season schedule:
The addGameToDay function will apply our preset conditions to add a game to a certain day.
We’ll fill out our opening day with a full slate of games. Afterwards, we’ll randomly pick a day in our season, and see if we can schedule a game that day. LeagueConstants is another struct to hold information about our league that will not be changing during our simulation:
Now, we would only have to change the value here, instead of everywhere we reference the days in our season. The canScheduleGame function will also make sure that a team involved in a game isn’t already set to play another game on the same day:
3. Some days, like Christmas or New Year’s, that occur during our season shouldn’t have any games scheduled.
As I’m writing this post, I just thought of this possible rule. Although I didn’t implement this in my league, this is simple enough to do. When we randomly select a day to schedule games, we check to see if that number happens to be a pre-defined holiday number. If so, find another day. We could even store an Array of these holidays in our LeagueConstant struct.
Progressing Through Our Season
Now that we have the core functionality for our scheduler set up, let’s add some functionality to our league to use it! We’ll need a method to progress through the days in our season, and play all the games scheduled for that day if there are any:
While we’re at it, we can make some more functions to progress through a whole week, or even the entire season:
I think we’re ready to test it out.
Results of Using Our Scheduler
Return to our ViewController.swift file. Because of the beauty of abstraction, we can create our league, set it up, and play an entire season in just three lines of code in our viewDidLoad method:
Below is some of the console output:
Looks good to me, at least for now.
Now, there’s a lot that isn’t perfect about our current scheduler. Most leagues have teams play every team more than once in a season. Some teams have way more away games than home games. One team doesn’t have any home games, I think. But the core foundation is solid, and we’ve done our part to build our scheduler in a way that it can be iterated on easily. Aside from building out an important feature for the basketball simulation app, I hope this post can be used as a resource for anyone looking to build their own sports projects. Either as a reference to learn more about how games are scheduled, or as inspiration to make it way better than mine. Regardless, feel free to let me know what you think!