aoc2025/mark/day4/part1.rb

127 lines
3.0 KiB
Ruby

require 'debug'
# Generic FileHandler
class FileHandler
def initialize(file_path)
@file_path = file_path
end
# Usage:
# FileHandler.new('/path_to_file').read_lines do |line|
# # process line
# end
def read_lines
File.foreach(@file_path, chomp: true).map do |line|
yield(line)
end
end
# Usage:
# file_content = FileHandler.new('/path_to_file').read_file(
def read_file
File.read(@file_path)
end
end
class PuzzleSolver
def initialize(file_handler, debug: false)
@handler = file_handler
@debug = debug
end
def debug(message)
puts message if @debug
end
def print_debug(message)
print message if @debug
end
def solve
raise NotImplementedError, 'Please implement this method in subclasses.'
end
end
# Puzzle-specific
class Grid
attr_reader :cells, :num_rows, :num_columns
# @param [<<Integer>>] an array of arrays of of 1's and 0's e.g., [[1, 0], [0, 1]]
def initialize(grid)
raise "Invalid grid: 0 rows in #{grid}" if grid.length == 0
raise "Invalid grid: 0 columns in #{grid}" if grid[0].length == 0
raise "Invalid grid: inconsistent number of columns in #{grid}" unless grid.all? {|column| column.length == grid[0].length}
@num_rows = grid.length
@num_columns = grid[0].length
@cells = grid
end
# @return [Grid]
def self.from_file_handler(handler)
grid = []
handler.read_lines do |line|
next if line.nil? || line.empty?
grid << line.split('').map {|cell| cell == '@' ? 1 : 0}
end
Grid.new(grid)
end
# @return [<[Integer, Integer]>] list of coordinates of adjacent cells of [x,y].
def adjacent_coordinates(x, y)
adjacent_cells = [-1, 0, 1].flat_map do |x_offset|
[-1, 0, 1].map do |y_offset|
[x + x_offset, y + y_offset]
end
end
adjacent_cells.delete([x, y])
# only return cells on the grid
adjacent_cells.select do |cell|
0 <= cell[0] && cell[0] < @num_rows &&
0 <= cell[1] && cell[1] < @num_columns
end
end
def adjacent_cell_values(x, y)
adjacent_coordinates = adjacent_coordinates(x, y)
adjacent_cell_values = adjacent_coordinates.map {|x, y| @cells[x][y]}
adjacent_cell_values
end
# @return [Integer] the number of rolls in the adjacent positions of cell (x, y)
def num_adjacent_rolls(x, y)
adjacent_cell_values = adjacent_cell_values(x, y)
adjacent_cell_values.sum
end
end
class GridSolver < PuzzleSolver
def solve
grid = Grid.from_file_handler(@handler)
num_accessible_rolls = 0
(0...grid.num_rows).each do |x|
(0...grid.num_columns).each do |y|
num_accessible_rolls += 1 if grid.num_adjacent_rolls(x, y) < 4 and grid.cells[x][y] == 1
end
end
num_accessible_rolls
end
end
if ARGV[0].nil? || ARGV[0].empty?
puts "Usage: ruby part1.rb <file_name> [debug]"
exit 1
end
file_path = ARGV[0]
debug = (ARGV[1] == "debug")
file_handler = FileHandler.new(file_path)
## Puzzle-specific
cls = GridSolver
##
puts "The answer is: #{cls.new(file_handler, debug:).solve}"