I hope no one ever thinks that the Tabletop Score Calculator is just a physical calculator that is too big to stick in your pocket!
The Tabletop Score Calculator is an iOS app I’m working on that will have virtual score sheets for various tabletop games. After another paragraph on scoring the various games, this post will cover some iOS development stuff and describes how I built a sort of plug-in mechanism for handling the score sheets for various games.
The app is fairly simple and has no graphical eye candy. The home screen is where a game is selected and if players need to be added or selected for scoring, that is done by tapping the “N Players” button the upper right corner of the page. I already see a problem with this idea because there’s no way to see which players are selected without going into or out of the players page. I also see no obvious way to improve this other than to show a list of the selected player names before going to the page for scoring a specific game.
The players page has a shuffle feature to reorder the players randomly. Selected payers are shown at the top of the list the the names are shuffled because there’s no reason to worry about players not playing the game. It’s a very quick and dirty first player selector. Players can be unselected so they are not scored; This avoids having to enter names for each new game.
A horizontal scrolling page viewer is shown for the selected game. Pages are scrolled into and out of view horizontally with one page per player and one final score page. If there is a lot of input on a page, it will scroll vertically.
Some of the games have more complicated score pages. The Wingspan game is just a calculator and some of the information, like the total score of all bird cards, needs to be added up by the player before entering the total in the app. A game like Container requires the the player selected the information on their personal score goal card in order to then calculate container points from the container counts. Container even discards a specific score value based on some fairly simple “what you have the most of…” rule.
I don’t show a picture of it here but if the score keeper scrolls to the last page, it shows the players names and their scores all sorted by highest to lowest. Some of the game score pages even have an entry or two that get used as tie breakers and not for normal scoring.
The app is written for iOS in Swift. I’m writing it on my Mac using Xcode. For the list of games and the list of players, I use the UITableView class from Apple and there’s nothing clever or interesting going on there. The app keeps track of players using the simple UserDefaults feature provided by Apple. I opted to avoid Core Data since it is more complicated with no benefit over storing one list of names as a setting. The settings are actually stored as an XML “file” in the
The game pages are more interesting in how they work. The first thing I did was to create a protocol called “GamePageView” that defines some common functions and variables for all of the game pages. I also have a protocol called “NibLoadable” because the content of these game page views comes from separate XIB files (XIB files are
The NibLoadable.swift file code is shown above. This is some common code that let’s me easily initialize the view from the XIB file.
The GamePageView.swift file is very simple. The delegate will be used to notify a delegate class that the score changed for a player. This allows the totals to be tracked for the final score page.
The workhorse that manages the score pages is the GameScoreController class. This is a UIViewController class and it manages the page that does the scrolling.
In the above bit of code from the MainViewController class, you can see a class that is used to define each game. The definition includes a name, a color for the page background, a type variable for a UIView, and a segue name for showing a custom page of help/info data. The type for the UIView was the tricky part of the code for me to figure out. I wanted to store the game info in an array and then pass the game information to the GameScoreController so it could add the correct game pages for scoring each player. I tried using the Swift AnyType type of variable and that didn’t work. For some reason, I had to be much more specific. I think that I may have tried to be even more specific and use the GamePageView protocol for storing the type information; But if I did, it didn’t work because that is a protocol. You can see that all I needed to do was store the “type” for each of the game page classes in the array. This is the plug-in style programming I mentioned earlier. To add a new game, I just add an entry to this array and also write the code for the game score page class. I usually just copy the Wingspan.swift and Wingspan.xib files, rename them, and alter them for the new game. It’s quick and easy until I need to worry about the actually score calculations.
This code is still in development but you can clearly see that the GameScoreController class iterates through the active players and creates and adds the appropriate game scoring pages to the horizontal scroll container. Oh yeah, there’s a horizontal scroll view that is derived from a UIScrollView class and it manages the page snapping and calls a delegate when a new page is displayed. Notice that none of the code in this controller knows about the specific game being scored. All of the interaction happens the same for all games because of the way the delegates are used.
Above is the Agricola score page. The pages all look similar because I always start with one of the other pages and then modify the new page code to be specific to the game I’m adding. Agricola is interesting because all of the Fields through Cattle scoring is done using an array of scores that are based on the number of items. If you have 4 sheep, they are worth 2 points. Most of the items score different from the others but each has its own unique array of scores in the code. The other items use the same scoring array but only one element of the array is used as the score for every item of that type. Each family member scores 3 points at the end of the game. This Agricola page takes a count, shows a score, and also shows a total score for the player.
The Final Score page just shows the active players sorted by score and with their score next to their name.
I hope to add some more games soon but I can only add games that I’ve player or that have well defined score calculations that I can find online. 7 Wonders will be my next addition since it is very similar to 7 Wonders Duel (which I play more often than the original 7 Wonders).
I have this app available as a beta test app for anyone willing to give me their Apple ID (email address for signing onto their iOS device).