Created
December 5, 2022 15:38
-
-
Save cjavdev/6519248312ec4d6596ddd320583ba685 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def read_towers(data) | |
towers = [] | |
data | |
.split("\n") | |
.map { |line| line.split(/\s{4}| /) } | |
.reverse | |
.each_with_index do |level, i| | |
next if i == 0 | |
level | |
.map {|el| el.gsub(/\[|\]/, '') } | |
.each_with_index do |el, j| | |
next if el == '' | |
towers[j] = [] if towers[j].nil? | |
towers[j] << el | |
end | |
end | |
towers | |
end | |
def read_instructions(data) | |
data | |
.split("\n") | |
.map {|line| /move (?<n>\d+) from (?<from>\d+) to (?<to>\d+)/.match(line) } | |
.map {|m| [m[:n].to_i, m[:from].to_i, m[:to].to_i] } | |
end | |
def move(towers, n, from, to) | |
# part 1 n.times { towers[to - 1] << towers[from - 1].pop } | |
towers[to - 1] += towers[from - 1].pop(n) | |
end | |
def move_all(towers, instructions) | |
instructions.each do |instruction| | |
move(towers, *instruction) | |
end | |
end | |
if ARGV.empty? | |
require 'rspec/autorun' | |
RSpec.describe 'Day 5' do | |
before(:all) do | |
@towers, @instructions = DATA.read.split("\n\n") | |
end | |
it 'moves an element' do | |
towers = read_towers(@towers) | |
move(towers, 1, 2, 1) | |
expect(towers[0]).to eq(['Z', 'N', 'D']) | |
expect(towers[1]).to eq(['M', 'C']) | |
expect(towers[2]).to eq(['P']) | |
end | |
it 'works for the full test case' do | |
towers = read_towers(@towers) | |
instructions = read_instructions(@instructions) | |
move_all(towers, instructions) | |
expect(towers[0]).to eq(['C']) | |
expect(towers[1]).to eq(['M']) | |
expect(towers[2]).to eq(['P', 'D', 'N', 'Z']) | |
end | |
it 'reads the towers as expected' do | |
towers = read_towers(@towers) | |
expect(towers.length).to eq(3), towers | |
expect(towers[0].length).to eq(2) | |
expect(towers[0][0]).to eq('Z'), towers | |
expect(towers[0][1]).to eq('N') | |
end | |
it 'reads the instructions' do | |
instructions = read_instructions(@instructions) | |
p instructions | |
expect(instructions.length).to eq(4), instructions | |
expect(instructions).to eq([ | |
[1, 2, 1], | |
[3, 1, 3], | |
[2, 2, 1], | |
[1, 1, 2] | |
]) | |
end | |
end | |
else | |
towers, instructions = File.read(ARGV[0]).split("\n\n") | |
towers = read_towers(towers) | |
instructions = read_instructions(instructions) | |
move_all(towers, instructions) | |
p towers.map(&:last).join | |
end | |
__END__ | |
[D] | |
[N] [C] | |
[Z] [M] [P] | |
1 2 3 | |
move 1 from 2 to 1 | |
move 3 from 1 to 3 | |
move 2 from 2 to 1 | |
move 1 from 1 to 2 |
#--- Day 5: Supply Stacks ---
class DayFive
attr_accessor :stack_file_name, :data_file_name, :stack, :byte_array, :file_name, :moves, :reverse
def initialize(stack_file_name, data_file_name)
@stack_file_name, @data_file_name = stack_file_name, data_file_name
set_up_stack
end
# the resulting data structure: should have just used a matrix instead of an integer keyed hash
# you could change the column headers and it would still work this way though.
# {
# 1 => ['A', 'Y'],
# 2 => ['T', 'D'],
# 3 => ['E', 'F', 'X'],
# 4 => ['M', 'B'],
# }
def set_up_stack
byte_array = File.readlines(@stack_file_name, chomp: true).map(&:bytes)
byte_matrix, byte_headers = byte_array.slice(0, byte_array.size - 1), byte_array.last
headers = byte_headers.map.with_index{|value, index| [value, index] unless[32, 91, 93].include?(value)}.compact!
@stack = headers.inject({}) do |memo, (byte_key, line_location)|
memo[Integer(byte_key.chr)] = []
memo
end
byte_matrix.each do |line|
headers.each do |(hash_key, line_location)|
value = line[line_location]
unless value.nil? || value == 32
@stack[Integer(hash_key.chr)] << value.chr
end
end
end
end
def problem_one
@reverse = true
process_problem
end
def problem_two
@reverse = false
process_problem
end
def process_problem
@moves = File.readlines(@data_file_name, chomp: true).map{|line| line.scan(/\d+/).map(&:to_i)}
process_moves
collect_message
end
def collect_message
@stack.keys.map {|key| @stack[key][0]}.join('')
end
def process_moves
@moves.each do |move|
amount, start, finish = *move
if @stack[start].nil?
next
else
temp = @stack[start].shift(amount)
temp.reverse! if @reverse
@stack[finish].prepend(*temp)
end
end
end
end
class TestDayFive < MiniTest::Test
#todo: you can read it from a single file
#todo: a, b = x.slice(0, x.find_index([])), x.slice(x.find_index([]) + 1, x.size)
def test_set_up_stack
test_stack = {
1 => %w(N Z),
2 => %w(D C M),
3 => %w(P)
}
d5 = DayFive.new('test-stack.txt', 'day-5-test.txt')
assert_equal(d5.stack, test_stack)
end
def test_problem_one
d5 = DayFive.new('test-stack.txt', 'day-5-test.txt')
assert_equal(d5.problem_one, "CMZ")
end
def test_problem_one_data
d5 = DayFive.new('stack.txt', 'day-5-data.txt')
assert_equal(d5.problem_one, "MQSHJMWNH")
end
def test_problem_two_data
d5 = DayFive.new('stack.txt', 'day-5-data.txt')
assert_equal(d5.problem_two, "LLWJRBHVZ")
end
end
A heavy connascence on the column number being in the same column as the values.
Nice @RomanTurner Thanks for sharing. Also love referencing "connascence" 💪
Oh yeah totally. love all of his talks.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://youtu.be/NNd7se8NlrU