What are protohackers?
Back in December 2023 I was taking on two coding challenges: Advent of Code and Protohackers. While I fully finished the former, I gave up with the latter after successfully solving problem 6 out of 11. I was solving both exclusively in Perl.
Protohackers is a server programming challenge. I consider it a better sport than AoC simply because it requires you to do more than just produce a single number. You need to host your server publicly somewhere, and it will be bombarded by requests from the protohackers "checker" program (which I heard is also written in Perl). Your server needs to handle corner cases, multiple connections, have decent performance, correctly handle bad data and more - depending on the problem.
Protohackers consists of 11 (+1) problems, slowly increasing in difficulty. Each problem is completely unique and require you to implement a different type of client/server interaction with communication over either TCP or UDP. Similar to AoC, place on the leaderboard depends on how fast you solved the problem, but since the competition is much smaller and the event is ongoing, solving them all gives a guaranteed place in the top 100. For the time being, no new problems are being introduced since early 2023.
My protohackers solutions
I came back to solving protohackers about a week ago. What I had was a working system based on slightly hacked Mojolicious. My changes to the framework allows it to handle UDP and to introduce custom code on one-side close from client side (the EOF). I modified it to use the newest perl 5.42 and started hacking.
In my protohackers system, each problem is a different package in lib/Modules
directory (and a full namespace under it). The main module package contains a map which lets me run it with a number instead of name. I have a test suite which quickly tests the most basic things in the solutions. When ready to put it to a test, I deploy it to my VPS using Rex and point protohackers to the correct IP and port.
Within a week, I managed to solve the remaining problems from 7 to 11. Without spoiling it too much, problem 7 used a custom protocol over UDP, while remaining problems used TCP. Problem 8 required passing the input and output through multiple encryption layers. Problem 9 was a JSON-based priority queue with a couple interesting spins and up to 1000 concurrent connections. Problem 10 was probably the most unique, as it consisted of reverse-engineering a live system with no documentation. The last problem required a three-way connection, where your solution works both as a server and as a client to another server. These problems were quite complex and each required multiple fixes on my part to get all the details straight.
You probably wonder how well did Perl do. As usual, it was quite easy to craft the initial solutions, but the hard part was making the checkers satisfied with all the corner cases. I had absolutely no performance problems, not even on a task which served 1000 concurrent connections and had a minute to process 50,000 tasks. I did not even actively think about performance, except for one case where I added an insertion sort to an array serving as priority queue using binary search with the very cool List::BinarySearch. I used new syntax quite heavily, stuff you would not normally use in legacy systems or CPAN distributions: signatures, postfix dereferencing, state arrays and hashes, builtin functions, keys @array
, my sub
and the new ->&
operator. I took some shortcuts to finish the solutions faster, and considered the solution good enough once the checkers showed a pass.
Finishing the challenge yielded me the 60th place on the leaderboard and a great sense of accomplishment. I recommend taking part as well if you wish to learn more about network programming.
Comments? Suggestions? Send to bbrtj.pro@gmail.com
Published on 2025-07-12