Mercurial > repos > other > adventofcode2023
changeset 20:fac484765bc9
Implement Day 13 mirror line finding
Walking in a loop didn't work, but consecutive pairs give a great
starting point. And there might even be a more Ruby-ish version
of the WHILE loop using zip, reverse and array ranges.
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Wed, 13 Dec 2023 20:32:13 +0000 |
parents | 1e16a25a9553 |
children | 46fb65f2cb94 |
files | day13.rb day13.txt day13b.rb |
diffstat | 3 files changed, 170 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/day13.rb Wed Dec 13 20:32:13 2023 +0000 @@ -0,0 +1,30 @@ +#! /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] + +maps = File.open(file, "r").each_line().map(&:chomp).chunk_while {|before, after| before.length == after.length}.filter {|chunk| chunk != [""]}.map {|chunk| chunk.map{|row| row.each_char.to_a}} + +def find_reflection(data) + candidate_start = data.each_cons(2).with_index.flat_map {|vals,idx| a,b = vals; a == b ? [idx] : []} + valid_starts = candidate_start.flat_map do |start| + pos = start + reflected = start + 1 + match = true + while pos > 0 and reflected < data.length - 1 + pos -= 1 + reflected += 1 + match = data[pos] == data[reflected] + break unless match + end + match ? [start + 1] : [] + end + valid_starts[0] +end + +puts maps.flat_map {|data| [find_reflection(data).to_i * 100, find_reflection(data.transpose()).to_i]}.sum \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/day13.txt Wed Dec 13 20:32:13 2023 +0000 @@ -0,0 +1,105 @@ +--- Day 13: Point of Indicence --- + +There is an area with mirrored layouts. For example: + +#.##..##. +..#.##.#. +##......# +##......# +..#.##.#. +..##..##. +#.#.##.#. + +#...##..# +#....#..# +..##..### +#####.##. +#####.##. +..##..### +#....#..# + +To find the reflection in each pattern, you need to find a perfect reflection across either a horizontal line between two rows or across a vertical line between two columns. + +In the first pattern, the reflection is across a vertical line between two columns; arrows on each of the two columns point at the line between the columns: + +123456789 + >< +#.##..##. +..#.##.#. +##......# +##......# +..#.##.#. +..##..##. +#.#.##.#. + >< +123456789 + +In this pattern, the line of reflection is the vertical line between columns 5 and 6. Because the vertical line is not perfectly in the middle of the pattern, part of the pattern (column 1) has nowhere to reflect onto and can be ignored; every other column has a reflected column within the pattern and must match exactly: column 2 matches column 9, column 3 matches 8, 4 matches 7, and 5 matches 6. + +The second pattern reflects across a horizontal line instead: + +1 #...##..# 1 +2 #....#..# 2 +3 ..##..### 3 +4v#####.##.v4 +5^#####.##.^5 +6 ..##..### 6 +7 #....#..# 7 + +This pattern reflects across the horizontal line between rows 4 and 5. Row 1 would reflect with a hypothetical row 8, but since that's not in the pattern, row 1 doesn't need to match anything. The remaining rows match: row 2 matches row 7, row 3 matches row 6, and row 4 matches row 5. + +To summarize your pattern notes, add up the number of columns to the left of each vertical line of reflection; to that, also add 100 multiplied by the number of rows above each horizontal line of reflection. In the above example, the first pattern's vertical line has 5 columns to its left and the second pattern's horizontal line has 4 rows above it, a total of 405. + +Find the line of reflection in each of the patterns in your notes. What number do you get after summarizing all of your notes? + +--- Part 2 --- + +Every mirror line has exactly one smudge: exactly one . or # should be the opposite type. + +In each pattern, you'll need to locate and fix the smudge that causes a different reflection line to be valid. (The old reflection line won't necessarily continue being valid after the smudge is fixed.) + +Here's the above example again: + +#.##..##. +..#.##.#. +##......# +##......# +..#.##.#. +..##..##. +#.#.##.#. + +#...##..# +#....#..# +..##..### +#####.##. +#####.##. +..##..### +#....#..# + +The first pattern's smudge is in the top-left corner. If the top-left # were instead ., it would have a different, horizontal line of reflection: + +1 ..##..##. 1 +2 ..#.##.#. 2 +3v##......#v3 +4^##......#^4 +5 ..#.##.#. 5 +6 ..##..##. 6 +7 #.#.##.#. 7 + +With the smudge in the top-left corner repaired, a new horizontal line of reflection between rows 3 and 4 now exists. Row 7 has no corresponding reflected row and can be ignored, but every other row matches exactly: row 1 matches row 6, row 2 matches row 5, and row 3 matches row 4. + +In the second pattern, the smudge can be fixed by changing the fifth symbol on row 2 from . to #: + +1v#...##..#v1 +2^#...##..#^2 +3 ..##..### 3 +4 #####.##. 4 +5 #####.##. 5 +6 ..##..### 6 +7 #....#..# 7 + +Now, the pattern has a different horizontal line of reflection between rows 1 and 2. + +Summarize your notes as before, but instead use the new different reflection lines. In this example, the first pattern's new horizontal line has 3 rows above it and the second pattern's new horizontal line has 1 row above it, summarizing to the value 400. + +In each pattern, fix the smudge and find the different line of reflection. What number do you get after summarizing the new reflection line in each pattern in your notes? \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/day13b.rb Wed Dec 13 20:32:13 2023 +0000 @@ -0,0 +1,35 @@ +#! /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] + +maps = File.open(file, "r").each_line().map(&:chomp).chunk_while {|before, after| before.length == after.length}.filter {|chunk| chunk != [""]}.map {|chunk| chunk.map{|row| row.each_char.to_a}} + +def count_num_changes(row_a, row_b) + row_a.zip(row_b).map {|a,b| (a != b) ? 1 : 0}.sum +end + +def find_imperfect_reflection(data) + candidate_start = data.each_cons(2).with_index.flat_map {|vals,idx| count_num_changes(*vals) <= 1 ? [idx] : []} + valid_starts = candidate_start.flat_map do |start| + pos = start + reflected = start + 1 + num_changes = count_num_changes(data[pos], data[reflected]) + while pos > 0 and reflected < data.length - 1 + pos -= 1 + reflected += 1 + num_changes_in_row = count_num_changes(data[pos], data[reflected]) + num_changes += num_changes_in_row + break unless num_changes <= 1 + end + num_changes == 1 ? [start + 1] : [] + end + valid_starts[0] +end + +puts maps.flat_map {|data| [find_imperfect_reflection(data).to_i * 100, find_imperfect_reflection(data.transpose()).to_i]}.sum \ No newline at end of file