diff --git a/day_07/1.rb b/day_07/1.rb new file mode 100755 index 0000000..7006f4e --- /dev/null +++ b/day_07/1.rb @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require_relative "graph" + +class Main + def run + input = $stdin.readlines.map(&:chomp) + graph = Graph.new(input) + + total = dfs(graph.start, graph, 0, Set.new) + puts total + end + + def dfs(next_point, graph, total, visited) + if next_point.y > graph.height || visited.include?(next_point) + return total + end + + if graph.at(next_point) == "^" + step_west = Point.new(next_point.x - 1, next_point.y) + step_east = Point.new(next_point.x + 1, next_point.y) + + if graph.at(step_west) == "." || + graph.at(step_east) == "." + total += 1 + end + + # step west then dfs south + total = dfs(step_west, graph, total, visited) # west + # step east then dfs south + total = dfs(step_east, graph, total, visited) # east + return total + elsif graph.at(next_point) == "." + visited.add(next_point) + end + + dfs(Point.new(next_point.x, next_point.y + 1), graph, total, visited) # south + end +end + +Main.new.run diff --git a/day_07/2.rb b/day_07/2.rb new file mode 100755 index 0000000..2f583f7 --- /dev/null +++ b/day_07/2.rb @@ -0,0 +1,41 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require_relative "graph" + +class Main + def run + lines = $stdin.readlines(chomp: true) + graph = Graph.new(lines) + counts = Hash.new(0) + counts[graph.start.x] = 1 + + process_graph(lines, graph, counts) + puts counts.values.sum + end + + def process_graph(lines, graph, counts) + lines.each_with_index do |line, y| + line.chars.each_with_index do |char, x| + current = Point.new(x, y) + + next unless graph.at(current) == "^" + + distribute_counts(x, y, counts) + end + end + end + + # When we encounter a "^", we split the count to the west and east positions + # and reset the current position count to 0. + def distribute_counts(x, y, counts) + peek_west = Point.new(x - 1, y) + peek_east = Point.new(x + 1, y) + + counts[peek_west.x] += counts[x] + counts[peek_east.x] += counts[x] + counts[x] = 0 + end +end + +Main.new.run diff --git a/day_07/graph.rb b/day_07/graph.rb new file mode 100644 index 0000000..7e04549 --- /dev/null +++ b/day_07/graph.rb @@ -0,0 +1,32 @@ +require "forwardable" + +require_relative "point" + +class Graph + attr_reader :start, :height, :width + extend Forwardable + def_delegators :@data, :[] + + def initialize(input) + @data = input.each_with_index.map do |line, y| + if y.zero? + @start = Point.new(line.index("S"), y) + end + line.chars + end + @width = @data[0].size - 1 + @height = @data.size - 1 + end + + def to_s + @data.map { |row| row.join("") }.join("\n") + end + + def at(point) + @data[point.y][point.x] + end + + def out_of_bounds?(point) + point.x < 0 || point.x > @width || point.y < 0 || point.y > @height + end +end diff --git a/day_07/point.rb b/day_07/point.rb new file mode 100644 index 0000000..34072da --- /dev/null +++ b/day_07/point.rb @@ -0,0 +1,24 @@ +class Point + attr_reader :x, :y + + def initialize(x, y) + @x = x + @y = y + end + + def to_s + "(#{x}, #{y})" + end + + def ==(other) + x == other.x && y == other.y + end + + def hash + [x, y].hash + end + + def eql?(other) + self == other + end +end