Skip to content

mattbaker/protohackers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Protohacker

Solutions for Protohackers :)

Problem -1: lib/protohacker/tcp_listener.ex

A generic TCP listener that passes client requests to a client "server".

Servers generally live in lib/protohacker/*/server.ex.

Problem: 0 lib/protohacker/echo

The Elixir intro docs help you get started here.

I struggled at first because I was trying to use ngrok. It seems ngrok does something to your TCP traffic along the way that causes the test to fail. I had to open a port in my firewall (temporarily) and I passed the test that way. A VPS would work too.

Problem: 1 lib/protohacker/prime

The fact that gen_tcp's default buffer size is pretty low caught me, it caused big messages to get cut off. I had to make the buffer size much bigger (see .../prime/supervisor.ex).

I also tried out Stream.drop_while to do the prime checker, the algorithm was lifed from some Java solution I found online somewhere :)

I used Jason for JSON parsing.

Problem: 2 lib/protohacker/bank

Erlang/Elixir's binary pattern matching was super userful here. It made it easy to parse the messages and interpret the bytes (signed integer 32s). The docs for binary pattern matching are kind of hard to find.

With gen_tcp you can specify the number of bytes you want to read at a time, in our case we needed 9 bytes.

I used ETS to store the asset price entries with the timestamp as the key, with one table per client. I used matchspecs to define a match that included the max/min test. This worked pretty well and was plenty fast enough. ETS is a pretty optimized data store so I had a feeling it would handle the job.

Problem: 3 lib/protohacker/chat

I created a GenServer representing the room. This made it easy to have a central process that could control receiving and broadcasting across users as needed.

Since a process handles the messages in its process inbox sequentially it also forced async user communication to become synchronous since it was acting as a central conduit. I had a feeling this could help me avoid some race conditions so I went for it. The test didn't create the kind of load that would overwhelm this "single process architecture."

Problem: 4 lib/protohacker/unusual_database

I used :gen_udp in active mode this time, so I handled incoming packets as messages being sent to the process (I used a GenServer). I wonder if this only worked well because each request was a single UDP packet, seems like otherwise I would need to do buffering (in which case I might go for passive mode).

There didn't seem to be anything too tricky this time, just learning :gen_udp which was very similar to gen_tcp. The only thing that tripped me up was my Regex, which wasn't allowing for newlines, I fixed this by adding the s modified to the pattern.

Problem: 5 lib/protohacker/mitm

This was cool because I had a good use for "active mode". By making sure both the client and server sockets were owned by the current process my genserver could respond to traffic from either as messages flowing through handle_info/2 which felt like an intuitive way to deal with traffic coming from two sources.

I got some very strange results by forgetting to set restart: :temporary on the GenServer processes I created per-user and it took me a long time to figure that out. I'm still not sure exactly what was going on there but it looked like some kind of race condition. Once I added the missing restart: :temporary setting things worked just fine.

About

Solutions for protohackers.com

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published