Mercurial > repos > other > adventofcode2023
view day10b.rb @ 19:1e16a25a9553
Strip down the text to just the puzzle, not the fluff
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Mon, 11 Dec 2023 20:38:55 +0000 |
parents | 92144824cbb7 |
children |
line wrap: on
line source
#! /usr/bin/env ruby if ARGV.length != 1 abort("Incorrect arguments - needs input file") elsif not File.exist? (ARGV[0]) abort("File #{ARGV[0]} did not exist") end file = ARGV[0] charmap = File.open(file, "r").each_line(chomp: true).map {|line| line.each_char.to_a}.to_a $map_height = charmap.length $map_width = charmap[0].length # Ugly way to find the start, because we know there's one (for now) start = charmap.each_with_index.flat_map { |columns, i| j = columns.find_index("S"); if j then [j, i] else nil end }.compact start_x, start_y = start $direction_inversion = {north: :south, south: :north, east: :west, west: :east} $pipemap = charmap.map do |row| row.map do |cell| case cell when "|" [:north, :south] when "-" [:east, :west] when "L" [:north, :east] when "J" [:north, :west] when "7" [:south, :west] when "F" [:south, :east] when "S" # Assume all directions are valid [:north, :south, :east, :west] else [] end end end def valid_position? (x, y) x >= 0 and x < $map_width and y >= 0 and y < $map_height end def get_target_for_step(step) case step.direction when :north then [step.x, step.y-1] when :south then [step.x, step.y+1] when :east then [step.x+1, step.y] when :west then [step.x-1, step.y] end end def get_next_step(step) new_x, new_y = get_target_for_step(step) target_inputs = valid_position?(new_x, new_y) ? $pipemap[new_y][new_x] : [] required_direction = $direction_inversion[step.direction] target_inputs.include?(required_direction) ? Step.new(new_x, new_y, (target_inputs - [required_direction])[0]) : nil end Step = Struct.new(:x, :y, :direction) first_steps = [:north, :south, :east, :west].map {|dir| Step.new(start_x, start_y, dir)} routes = first_steps.map{|v|[v]} while ! routes.any? {|route| last_step = route[-1]; route.length > 1 and last_step.x == start_x and last_step.y == start_y} routes = routes.map do |route| next_step = get_next_step(route[-1]) if next_step route << next_step else nil end end.compact end # We get two routes - the two opposite directions around the same path # so take the first one route = routes[0].map {|v| [v.x, v.y]} in_out_transition = [:north, :south] State = Struct.new(:crossed_lines, :inside_count, :last_switch) # TODO: Replace Source with actual piece based on route actual_start_directions = first_steps.map do |v| step = get_next_step(v) !step.nil? and [route[1], route[-2]].include?([step.x, step.y]) ? v.direction : nil end.filter {|v| v} $pipemap[start_y][start_x] = actual_start_directions cells_inside = $pipemap.each_with_index.map do |row, y| row_state = State.new(0, 0, nil) row.each_with_index do |cell, x| if route.include?([x,y]) if cell == in_out_transition row_state.crossed_lines += 1 elsif cell != [:east, :west] this_switch = (cell & in_out_transition) if row_state.last_switch.nil? row_state.last_switch = this_switch else if this_switch != row_state.last_switch row_state.crossed_lines += 1 end row_state.last_switch = nil end end elsif row_state.crossed_lines % 2.0 != 0 row_state.inside_count += 1 end end row_state end.reduce(0) {|accum, row_state| accum + row_state.inside_count} puts cells_inside