Earlier this week I was curious if I could create a program that would help me make my Fantasy Premier League selections: a list of players with the highest scores for the anticipated gameweek (a set of fixtures). Initially I wanted it to consider form (a player’s average score over the last thirty days) and the difficulty of each fixture. I wrote a first version in a couple of hours .
Writing programs that consume APIs in Go usually requires creating a series of structs that mirror the structure of the API. You “unmarshal” JSON onto these. In my first iteration, when I wanted to add my own additional computed values I would just add these as new fields, omitting the json struct tags. When I came to add more features a few days later the code was hard to read so I prefixed my API structs with “api” and then created a series of new types designed on the structure of data I wanted to output. I then iterated over the API values, mapping the data onto the new types. The data was much easier to work with in that way.
My program works like this: Initially I create a selection of “likely winners”: teams whose expected difficulty is less than that of the teams they’re facing. I then take all the players from these teams and sort them by form, their ICT index (a metric created by the league), their average starts and the difficulty of the fixture.
But I encountered an interesting problem. The game requires you to play a certain number of players in each position. Between three and five defenders, two and five midfielders and one and three forwards. There’s always one goalkeeper. These bounds mean that (for example) one week the “ideal” team might consist of four defenders and five midfielders because the midfielders are higher scoring than the defenders and forwards. I attempted various different solutions including maintaining state across an ordered slice and a map of players by position. Even ChatGPT couldn’t produce viable code. Ultimately I ended up calculating the total scores for each combination of players (a formation) and picking the formation with the highest score; though I’m sure this isn’t the most efficient method - if you have a better idea please email me.
I still continue to enjoy writing code with Go. My language (pending name timlang) is still in development and I’ve been adding some new features to my blog. I can’t imagine having worked on this tool any other way, especially when the compiled run time is ~100ms.
Edit: 21st Aug
In studying the API data, today I also decided to include the likelihood of a player starting in a given round as part of their “score”, so as to downgrade injured players. I’m also now displaying the score in the results, an arbitrary number whose meaning is unclear to the uninitiated. Some players seem to rank higher on this score than others in much better form, which might not make sense at first. In some ways the “meaning” of the data, what I’m really trying to convey when I say the “perfect team”, has been distilled; Adding more variables to my ranking order is not as simple as just form on its own nor am I under any illusion that having more variables presents a “complete” picture. That picture may be complex but I suspect that most of my predictions will be wrong.
 Latest version: https://github.com/notoriousbfg/simple-fantasy