Skip to content

Instantly share code, notes, and snippets.

@cjavdev
Created December 5, 2022 15:38
Show Gist options
  • Save cjavdev/6519248312ec4d6596ddd320583ba685 to your computer and use it in GitHub Desktop.
Save cjavdev/6519248312ec4d6596ddd320583ba685 to your computer and use it in GitHub Desktop.
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
@cjavdev
Copy link
Author

cjavdev commented Dec 5, 2022

@RomanTurner
Copy link

RomanTurner commented Dec 6, 2022

#--- 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.

@cjavdev
Copy link
Author

cjavdev commented Dec 6, 2022

Nice @RomanTurner Thanks for sharing. Also love referencing "connascence" 💪

@RomanTurner
Copy link

@cjavdev I wasn't coding at the time of Jim Weirich, but he has shaped a lot of the practices of the ruby community and programming as a whole. I stole the phrasing from him yt-source

@cjavdev
Copy link
Author

cjavdev commented Dec 10, 2022

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