AocRbHelpers

Gem Version

This gem provides helper classes and functions to simplify solving Advent of Code puzzles. It is a companion gem to the aoc_rb gem.

Be warned - using this gem might suck the fun out of solving the puzzles yourself!

Getting Started

First of all, install the aoc_rb gem and set up your project.

Next, add this gem to your project Gemfile, and run bundle install.

Open up challenges/shared/solution.rb in your project and require this gem at the top:

# frozen_string_literal: true

require "aoc_rb_helpers"     # <-- Add this line

class Solution
  ...
end

You're good to go!

This gem additionally installs the excellent puts_debuggerer gem, which you can use like this:

pd some_object

You can read more on how you can use pd in their README.

Provided Helper Classes

All documentation is available here - https://rubydoc.info/github/pacso/aoc_rb_helpers.

The provided helper classes are as follows:

AocInput

Provides input manipulation helper methods. Methods are chainable, and directly modify the parsed view of the input data within the @data instance variable.

DotMatrix

Parses and decodes ASCII art text from puzzles. Can output to STDOUT or return the result to your code.

Will turn an input like:

 XX  XXXX X    XXXX X     XX  X   XXXXX  XX   XXX
X  X X    X    X    X    X  X X   XX    X  X X   
X    XXX  X    XXX  X    X  X  X X XXX  X    X   
X    X    X    X    X    X  X   X  X    X     XX 
X  X X    X    X    X    X  X   X  X    X  X    X
 XX  X    XXXX XXXX XXXX  XX    X  X     XX  XXX 

Into the string CFLELOYFCS.

Grid

Provides helper methods for manipulating end querying two-dimensional grids.

grid = Grid.new([[0, 1], [2, 3]])
grid.rotate! # => #<Grid:0x0000ffff8f42f8f8 @grid=[[2, 0], [3, 1]]>

Examples

Below are some examples of how you can use the features of this gem.

Input manipulation

This example solution for 2024 Day 1 shows how the convenience methods can be used to format the puzzle input:

# frozen_string_literal: true

module Year2024
  class Day01 < Solution
    def part_1
      list_1, list_2 = data
      list_1.each_with_index.sum { |item, index| (item - list_2[index]).abs }
    end

    def part_2
      list_1, list_2 = data
      list_1.each.sum { |item| item * list_2.count(item) }
    end

    private

    def data
      aoc_input
        .multiple_lines
        .columns_of_numbers
        .transpose
        .sort_arrays
        .data
    end
  end
end

Where you have different sections of input which need to be handled differently, you can quickly split them into independent instances of AocInput, such as with the pussle from 2024, Day 5:

  page_rules, page_updates = aoc_input.sections
  page_rules_data = page_rules.multiple_lines.columns_of_numbers("|").data
  page_updates_data = page_updates.multiple_lines.columns_of_numbers(",").data

Decoding printed text

text_input = <<~EOF
  X  X XXXX X    X     XX  
  X  X X    X    X    X  X 
  XXXX XXX  X    X    X  X 
  X  X X    X    X    X  X 
  X  X X    X    X    X  X 
  X  X XXXX XXXX XXXX  XX  
EOF

input_array = text_input.lines(chomp: true).map(&:chars)
DotMatrix.decode(input_array) # returns the string "HELLO"