Samir Parikh · Blog · Git


Originally published on 20 December 2022

A few weeks ago, I wrote about how I was getting ready for this year’s Advent of Code competition. In my research, I found a few industrious people who have built some rather clever scripts to help them expedite the tedious tasks of creating the directory and subdirectory structure I explained in my earlier post. As someone who considers himself more of a “hobbyist” programmer, I thought I would try to replicate something like this in Perl to take me one step closer from journeyman Padawan to Jedi Master. So, over the past several weeks, instead of actually trying to solve this year’s Advent of Code challenges, I have been assiduously working on writing a Perl script that would make short work of dealing with all of the laborious file and directory operations by automatically creating a series of folders for each day’s challenges, downloading my input, and prepopulating some boilerplate Perl code to help me jump start solving the actual challenge.

Ladies and gentlemen, just in time for the 2023 edition of the Advent of Code, I proudly present, aocinit!

In all seriousness, I probably should have just written it as a shell script and have been done with it but I wanted to learn more about how Perl handles filesystem operations and, more importantly, how to download URLs working with modules such as LWP::UserAgent and Mojo::UserAgent. (You can find examples using both of these modules in this git repo.)

The code for aocinit can be found here. The script is pretty straightforward as it’s nothing more than a few subroutines containing basic directory and file operations. You place the file somewhere within your system’s PATH after which it can be invoked with:

aocinit <year> <day>

where year is the two-digit year (e.g. 22) and day is the two-digit day within the month of December. Therefore, if you were solving today’s puzzle, you’d invoke it with:

aocinit 22 20

The script then creates a directory for the year’s event and a subdirectory for the day. It will place some boilerplate code (e.g. day01.pl) to get you started along with automatically downloading that day’s input as input. You ultimately end up with a directory structure as follows:

aoc2022/
├── day01
│   ├── day01.pl
│   └── input
├── day02
│   ├── day02.pl
│   └── input
└── day03
    ├── day03.pl
    └── input

The location of the event directory (e.g. aoc2022) within your $HOME directory is set by the $PATH_FROM_HOME variable defined in line 24. You can also set a prefix for the directory name via the $DIR_PREFIX variable which is defined on line 25. You also need to set the environment variable $SESSIONID with the value of the session cookie that logs you into the Advent of Code website. We’ll use this ID later in the script to download the puzzle input. You can find this value using your browser’s developer tools function. It’s probably not the most secure way to do this but at least I don’t have to store the session ID in plain text within the script itself. If you have suggestions on how I can improve this, please let me know!

The first important subroutine in the script, process_arguments checks to confirm whether or not we passed exactly two arguments to the script and whether those arguments are valid. Both $year and $day must be numbers, with the year being between 15 (the first Advent of Code event was in 2015) and the last two digits of the current year. They day must be between 1 and 24. If the day was entered as a single digit (e.g. ‘7’), we prepend a zero (e.g. ‘07’). The cool (to me) trick here was to make use of the Term::ANSIColor module to provide a bit of terminal flair in the error message.

The next couple of subroutines, create_year_directory and create_day_subdirectory create the folders for the event’s year and day respectively after checking that they do not already exist.

The read_boilerplate function defines the initial boilerplate template which will be used as the starting point for all of our programs. It uses the qq quote-like operator to create a template which is eventually passed to the create_boilerplate_file subroutine to place a file called dayXX.pl in the appropriate directory.

Finally, we download the day’s input file in the subroutine download_input. This subroutine makes use of the Mojo::UserAgent module discussed above as well as the Mojo::Cookie::Response container to send the cookie information we need for authentication. This is the part of the script I’m most proud of as it took me the longest to figure out. The friendly folks over in the Mojolicious community also provided a helping hand!

So, in the end, was going to all of this trouble to automate the simple creation of a few directories and files really worth it? According to the official prognosticators of the internet, definitely not. But it was a good learning lesson for me to improve my fledgling Perl skills.

And now that it’s finished, I can finally crack on with Day 1!