
Yan Cui
I help clients go faster for less using serverless technologies.
ps. look out for all my other solutions for Advent of Code challenges here.
Day 4
See details of the challenge here.
The input for today’s challenge looks something like this:
bkwzkqsxq-tovvilokx-nozvyiwoxd-172[fstek]
wifilzof-wbiwifuny-yhachyylcha-526[qrazx]
jvyyvzpcl-jhukf-shivyhavyf-487[zhtsi]
kwvacumz-ozilm-kivlg-kwvbiqvumvb-694[gknyw]
mvhkvbdib-kmjezxodgz-mvwwdo-omvdidib-837[dmvbi]
nzydfxpc-rclop-qwzhpc-lnbftdtetzy-171[cptzd]
vhehkyne-unggr-inkvatlbgz-813[gnehk]
tcorcikpi-hnqygt-octmgvkpi-570[nzewo]
xmtjbzidx-wvnfzo-jkzmvodjin-447[uyzlp]
willimcpy-mwupyhayl-bohn-mufym-734[stjoc]
sbejpbdujwf-cvooz-xpsltipq-961[azfnd]…
So our first task is to turn these into a more usable format, eg. a tuple of (encrypted name, sector ID, checksum).
open System | |
open System.IO | |
let input = | |
File.ReadAllLines(__SOURCE_DIRECTORY__ + "/Day04Input.txt") | |
|> Array.map (fun line -> | |
let [| rest; checksum |] = | |
line.Split('[', ']') | |
|> Array.filter (not << String.IsNullOrWhiteSpace) | |
let lastDash = rest.LastIndexOf('-') | |
let sectorId = rest.Substring(lastDash+1) |> int | |
let encryptedName = rest.Substring(0, lastDash) | |
encryptedName, sectorId, checksum) |
To find the real room names, we need to calculate the checksum value from the encrypted name.
let isReal (encryptedName : string) checksum = | |
let checksum' = | |
encryptedName | |
|> Seq.filter ((<>) '-') | |
|> Seq.groupBy id | |
|> Seq.sortBy (fun (c, cs) -> -(Seq.length cs), c) | |
|> Seq.map fst | |
|> Seq.take 5 | |
|> Seq.toArray | |
|> fun chars -> new String(chars) | |
checksum' = checksum | |
let realRooms = | |
input |> Array.filter (fun (name, _, checksum) -> isReal name checksum) | |
let part1 = realRooms |> Array.sumBy (fun (_, sectorId, _) -> sectorId) |
To produce the desired sorting in LINQ, I’d have used OrderByDescending and ThenBy. There is no ThenBy in any of the F# modules, but F# tuples are ordered the way you expect – by first item, then second item, and so on.
So, I can achieve the same result as OrderByDescending + ThenBy with one line instead:
Seq.sortBy (fun (c, cs) -> –(Seq.length cs), c)
pretty neat, right?
Part 2
With all the decoy data out of the way, it’s time to decrypt this list and get
moving.The room names are encrypted by a state-of-the-art shift cipher, which is nearly
unbreakable without the right software. However, the information kiosk designers
at Easter Bunny HQ were not expecting to deal with a master cryptographer like
yourself.To decrypt a room name, rotate each letter forward through the alphabet a number
of times equal to the room’s sector ID. A becomes B, B becomes C, Z becomes A,
and so on. Dashes become spaces.For example, the real name for qzmt-zixmtkozy-ivhz-343 is very encrypted name.
What is the sector ID of the room where North Pole objects are stored?
First, let’s add a decrypt function:
let alphabets = [|'a'..'z'|] | |
let shift c sectorId = | |
let oldIdx = Array.findIndex ((=) c) alphabets | |
let newIdx = (oldIdx + sectorId) % 26 | |
alphabets.[newIdx] | |
let decrypt (encryptedName : string) sectorId = | |
encryptedName | |
|> Seq.map (function | |
| '-' -> ' ' | |
| c -> shift c sectorId) | |
|> fun chars -> new String(chars |> Seq.toArray) |
I found the question “where North Pole objects are stored” ambigious. After a few failed attempts to guess what the room name should be I ended up just printing them all out and did a quick search for “north“. I’m not sure if the author of the challenge expected you to do that, or maybe I missed a clue somewhere..
Anyhow, once I figured out what the room name is, getting the sector ID was easy.
let part2 = | |
realRooms | |
|> Seq.map (fun (encryptedName, sectorId, _) -> | |
decrypt encryptedName sectorId, sectorId) | |
|> Seq.filter (fst >> (=) "northpole object storage") | |
|> Seq.head | |
|> snd |
Links
- Day 4 challenge description
- Advent of Code 2015
- Solution for Day 3
- All my F# solutions for Advent of Code
- Github repo
Whenever you’re ready, here are 3 ways I can help you:
- Production-Ready Serverless: Join 20+ AWS Heroes & Community Builders and 1000+ other students in levelling up your serverless game. This is your one-stop shop for quickly levelling up your serverless skills.
- I help clients launch product ideas, improve their development processes and upskill their teams. If you’d like to work together, then let’s get in touch.
- Join my community on Discord, ask questions, and join the discussion on all things AWS and Serverless.