Lichess Winrate per Hour
Diego Andriano (not AI)
20-06-2023
1306 / 250wpm = 5.2m (without code, with expanded)
Introduction
Hello everyone! Have you ever wanted to - be better? Have you ever wanted to excel in some specific something you typically do? follow these simple steps, pay me $5000 and get your results NOW!
I'm joking, of course. No one has the tools to fix you. Back to the article, i'm an avid chess player. Not very good at it, but i do enjoy it. This particular Sunday, i started my morning with 2 rapid games of chess. I lost both of them, quite badly. The day goes on, and in the afternoon i'm winning 3 games straight.
Am i *better* at the afternoon? Or is it just plain coincidence? Let's find that out! We're going to be connecting to Lichess, creating some nice code, and testing it all out with PHPUnit.
What we're making
We're creating a Laravel command. When you feed this command with enough data, it will tell you how good do you do in different time frames. How will we see that? It's all about win rate. We'll compare win rates.
This command will return all the win rates separated by hours (7.00: 56%, 8.00: 42%). Will this be conclusive? probably not, but if you ever bet your house on a chess game, my command will be here free for your consulting ;)
Okay, i think if you ever get in a high stakes board game you'll appreciate if this was an API instead of a random command. So let's make that API!
Tools
- Laravel
- Lichess API
Starting point and pre-steps
First off, we need to get some games. From Lichess' API we can get all the games on a given account (it obviously has to exist on lichess, you can't ask for the chess.com games of the same account). We see some limitations, namely the reqs per second, but this is not a concern for what i'm gonna do.
Want to read more things like this? Subscribe!
Okay, that sounds great! If you were to download the games right now, you'd see it is in PGN format (it can be treated as a string). Not JSON. You can download it in ndjson format, but i think we'll be able to read it in pgn. Maybe some performance issues, but i'm not expecting so many people to use it, and this is the kind of things you use once and never touch again in your life, so... it might be kinda slow, get over it.
On Laravel and code review
I could start copying and pasting and trying to explain meanwhile, but i think it's easier to repeat the process i've already applied in the Spotify post. Here's the URL for the whole code. To see it working, this is the URL
For the most part, i just start coding and see where it takes me. All the time i'm stopping and refactoring and creating tests of whatever i'm trying to achieve. All the time i'm thinking about whether what i'm doing is the right way or isn't. Even then, i don't ever know if i reach "the right way", or if there even is one. It's just one way.
There are some things about the process that i knew how to face though. The general structure (gateway, service, controller) i already had in mind. It's how i structure most of my projects. I had in mind the possibility of a couple objects, and even some methods it would definitely would need.
-- Http ---- Gateway ------ Lichess.php ------ ILichess.php ---- Controllers ------ LichessTimeframeController.phpILichess is the interface that Lichess will be implementing. It simply has a get method, and will take a user and a format. It will return a Games object. Lichess will be in charge of the connection with the Lichess API. LichessTimeframeController will be the... controller. You know, the one to get the data and return it to the view. MVC and all that.
-- app ---- Service ------ LichessService.phpLichessService will be the one to process all data related to the Lichess class. The controller will not interact with the gateway, rather to the service. This is to ensure a level of abstraction, and to make sure that the gateway doesn't do anything else apart from bringing the data and returning it for someone else to process it.
-- app ---- Models ------ Games.php ------ Game.phpThe Games object will be the one who carries all of the games, and the Game object will be one single game. Also, they'll process their own data. To be clear, Games will get the winrate over all games, and Game will return who won a certain game.
-- tests ---- Fakes ------ Lichess.php ---- Unit ------ GamesTest.php ------ GameTest.phpFakes/Lichess.php will implement ILichess, and it's a fake gateway. This means that it will return a predefined data, instead of getting real data from the real API. This is to be able to test without taking the time to wait for the API to answer, and we can tinker the data however we want to test certain scenarios. GamesTest and GameTest will be the tests for those classes.
-- storage ---- testData ------ lichess.txtlichess.txt is the data to be returned by Fakes/Lichess.php
# $soughtResult = 'win' $this->$soughtResult($player, $game) # Is the same as # $this->win($player, $game)
Last words.
Initially, the idea was to write as i code. That way, you could experience the whole process. Midway through though, i realized the code was subpar, and the writing was even worse. It's like the saying
Any man who can drive safely while kissing a pretty girl is simply not giving the kiss the attention it deserves.
So i decided to go for this route again. Hope you forgive me :D.
Do you have any notes? Do you think there's a better way? Comment it out on the gist and let's talk about it, i'm all in for getting better as a dev. Also, hope you enjoyed reading, see you next time!.