annotate day10b.rb @ 35:ca54f9702892

Day 24 part 2 instructions and partial solution
author IBBoard <dev@ibboard.co.uk>
date Thu, 18 Apr 2024 19:54:59 +0100
parents 92144824cbb7
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
17
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
1 #! /usr/bin/env ruby
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
2
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
3 if ARGV.length != 1
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
4 abort("Incorrect arguments - needs input file")
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
5 elsif not File.exist? (ARGV[0])
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
6 abort("File #{ARGV[0]} did not exist")
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
7 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
8
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
9 file = ARGV[0]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
10
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
11 charmap = File.open(file, "r").each_line(chomp: true).map {|line| line.each_char.to_a}.to_a
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
12 $map_height = charmap.length
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
13 $map_width = charmap[0].length
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
14
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
15 # Ugly way to find the start, because we know there's one (for now)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
16 start = charmap.each_with_index.flat_map { |columns, i| j = columns.find_index("S"); if j then [j, i] else nil end }.compact
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
17 start_x, start_y = start
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
18
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
19 $direction_inversion = {north: :south, south: :north, east: :west, west: :east}
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
20
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
21 $pipemap = charmap.map do |row|
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
22 row.map do |cell|
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
23 case cell
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
24 when "|"
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
25 [:north, :south]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
26 when "-"
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
27 [:east, :west]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
28 when "L"
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
29 [:north, :east]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
30 when "J"
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
31 [:north, :west]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
32 when "7"
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
33 [:south, :west]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
34 when "F"
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
35 [:south, :east]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
36 when "S"
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
37 # Assume all directions are valid
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
38 [:north, :south, :east, :west]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
39 else
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
40 []
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
41 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
42 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
43 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
44
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
45 def valid_position? (x, y)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
46 x >= 0 and x < $map_width and y >= 0 and y < $map_height
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
47 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
48
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
49 def get_target_for_step(step)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
50 case step.direction
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
51 when :north then [step.x, step.y-1]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
52 when :south then [step.x, step.y+1]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
53 when :east then [step.x+1, step.y]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
54 when :west then [step.x-1, step.y]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
55 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
56 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
57
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
58 def get_next_step(step)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
59 new_x, new_y = get_target_for_step(step)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
60 target_inputs = valid_position?(new_x, new_y) ? $pipemap[new_y][new_x] : []
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
61 required_direction = $direction_inversion[step.direction]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
62 target_inputs.include?(required_direction) ? Step.new(new_x, new_y, (target_inputs - [required_direction])[0]) : nil
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
63 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
64
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
65 Step = Struct.new(:x, :y, :direction)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
66
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
67 first_steps = [:north, :south, :east, :west].map {|dir| Step.new(start_x, start_y, dir)}
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
68 routes = first_steps.map{|v|[v]}
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
69
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
70 while ! routes.any? {|route| last_step = route[-1]; route.length > 1 and last_step.x == start_x and last_step.y == start_y}
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
71 routes = routes.map do |route|
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
72 next_step = get_next_step(route[-1])
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
73 if next_step
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
74 route << next_step
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
75 else
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
76 nil
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
77 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
78 end.compact
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
79 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
80
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
81 # We get two routes - the two opposite directions around the same path
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
82 # so take the first one
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
83 route = routes[0].map {|v| [v.x, v.y]}
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
84
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
85 in_out_transition = [:north, :south]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
86
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
87 State = Struct.new(:crossed_lines, :inside_count, :last_switch)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
88
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
89 # TODO: Replace Source with actual piece based on route
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
90 actual_start_directions = first_steps.map do |v|
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
91 step = get_next_step(v)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
92 !step.nil? and [route[1], route[-2]].include?([step.x, step.y]) ? v.direction : nil
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
93 end.filter {|v| v}
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
94 $pipemap[start_y][start_x] = actual_start_directions
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
95
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
96 cells_inside = $pipemap.each_with_index.map do |row, y|
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
97 row_state = State.new(0, 0, nil)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
98 row.each_with_index do |cell, x|
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
99 if route.include?([x,y])
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
100 if cell == in_out_transition
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
101 row_state.crossed_lines += 1
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
102 elsif cell != [:east, :west]
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
103 this_switch = (cell & in_out_transition)
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
104 if row_state.last_switch.nil?
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
105 row_state.last_switch = this_switch
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
106 else
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
107 if this_switch != row_state.last_switch
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
108 row_state.crossed_lines += 1
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
109 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
110 row_state.last_switch = nil
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
111 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
112 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
113 elsif row_state.crossed_lines % 2.0 != 0
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
114 row_state.inside_count += 1
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
115 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
116 end
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
117 row_state
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
118 end.reduce(0) {|accum, row_state| accum + row_state.inside_count}
92144824cbb7 Add "inside the loop" counting for day 10 part 2
IBBoard <dev@ibboard.co.uk>
parents:
diff changeset
119 puts cells_inside