/aoclib

Ruby helpers for Advent of Code puzzles

Primary LanguageRubyMIT LicenseMIT

Build Status

logo

aoclib

aoclib is a collection of Ruby helpers for solving Advent of Code puzzles. I've had these hanging around in my personal collection. After reaching 300 stars I decided to clean them up and release as a gem.

Philosophy - Unlike regular Ruby gems, most helpers are added to the global namespace or monkeypatched into standard Ruby classes. I prefer things this way when I'm trying to work quickly. Also, DRY is not important because it can make it harder to quickly figure out how the helpers work. This gem is only for Advent of Code. Please don't write actual gems this way.

Highlights

  • HardGrid and SoftGrid classes for reading and walking maps, AOC style. "Hard" grids have well defined dimensions, like dungeons. "Soft" grids can grow over time, like game of life. These grids can be constructed from map strings and pretty printed. Internal storage is a hash.

  • Point and Point3 for following compass (N, E, S, W) and calculating neighbors.

  • Deque, like the one in Python. A doubly linked list. Operations at head and tail are fast, everything else is slow. Supports rotate. 200 elves are sitting around a table...

  • Numpy-style helpers for Array. You can reshape, rotate, flip, roll, concatenate, etc. Only works with 2d.

  • PriorityQueue for A* search.

  • deep_dup for making copies of arrays, hashes, sets, etc.

Oh, and if your main Ruby file is named 17.rb call aoc_input to read the contents of 17.txt.

Core Extensions

Here are some of the more helpful extensions:

  • Array: Manhattan distance, neighbors (N, E, S, W)
  • Enumerable: identical? and most_common
  • Hash: Sort by key/value, or reverse
  • Integer: prime mixins, digit access, reverse
  • String: extract all ints/floats, MD5

Grid Example

>> GRID =<<EOF.freeze
################
#.....#.......A#
#..####..#..####
#........#..#..#
##########..#..#
#...........#..#
#..#..####..#..#
#..#.....#.....#
#..##########..#
#..#........#..#
#..#..####..#..#
#.....#.....#..#
#..####..####..#
#....Z#..#.....#
################
EOF

>> grid = HardGrid.from_string(GRID)
>> grid.dump(header: true)

   0000000000111111
   0123456789012345
00 ################ 00
01 #.....#.......A# 01
02 #..####..#..#### 02
03 #........#..#..# 03
04 ##########..#..# 04
05 #...........#..# 05
06 #..#..####..#..# 06
07 #..#.....#.....# 07
08 #..##########..# 08
09 #..#........#..# 09
10 #..#..####..#..# 10
11 #.....#.....#..# 11
12 #..####..####..# 12
13 #....Z#..#.....# 13
14 ################ 14
   0123456789012345
   0000000000111111

>> grid.shortest_path_length(grid.find('A'), grid.find('Z'))
27

Numpy-style Examples with Array

# create a 3x3 array and fill with 0...9
>> Array.arange_2d(3, 3).dump

[[0, 1, 2],
 [3, 4, 5],
 [6, 7, 8]]

# rotate entire array 90 degrees CCW
>> Array.arange_2d(3, 3).rot90_2d.dump

[[2, 5, 8],
 [1, 4, 7],
 [0, 3, 6]]

# "concatenate" two arrays
>> Array.concatenate_2d(Array.arange_2d(3, 3), Array.zeros_2d(3, 4), axis: 1).dump

[[0, 1, 2, 0, 0, 0, 0],
 [3, 4, 5, 0, 0, 0, 0],
 [6, 7, 8, 0, 0, 0, 0]]

# flip array horizontally (also see flipud for vertical)
>> Array.arange_2d(3, 3).fliplr_2d.dump

[[2, 1, 0],
 [5, 4, 3],
 [8, 7, 6]]

# rotate cols (or rows with axis: 0, which is the default)
>> Array.arange_2d(3, 3).roll_2d(1, axis: 1).dump

[[2, 0, 1],
 [5, 3, 4],
 [8, 6, 7]]

# toggle a range of cells
>> Array.zeros_2d(3, 3).toggle_2d!(0, 0, 1, 1).toggle_2d!(1, 1, 2, 2).dump

[[1, 1, 0],
 [1, 0, 1],
 [0, 1, 1]]

# get a region
>> Array.arange_2d(3, 3).get_2d(1, 1, 3, 3).dump

[[4, 5],
 [7, 8]]

# set a region using another 2d array
>> Array.zeros_2d(3, 3).set_2d!(1, 1, Array.full_2d(2, 2, 9)).dump

[[0, 0, 0],
 [0, 9, 9],
 [0, 9, 9]]

Changelog

0.0.2 (master)

  • Ruby 3.1, ruby-lsp, standardrb
  • added Numeric#sign (1, -1 or 0)
  • added dup to grid classes

0.0.1 - Nov 2021

  • original release