diff --git a/advent-of-code/2024/day_10/README.md b/advent-of-code/2024/day_10/README.md new file mode 100644 index 0000000..0a4a28e --- /dev/null +++ b/advent-of-code/2024/day_10/README.md @@ -0,0 +1,184 @@ +# Advent of Code 2024 day 10 solution in Ruby + +[Task page](https://adventofcode.com/2024/day/10) + + +## Usage + +Run tests: + +```bash +ruby test.rb +``` + +Run solution: + +```bash +ruby main.rb +``` + + +## Hoof It + +You all arrive at a Lava Production Facility on a floating island in the sky. +As the others begin to search the massive industrial complex, +you feel a small nose boop your leg and look down to discover a reindeer wearing a hard hat. + +The reindeer is holding a book titled "Lava Island Hiking Guide". However, when you open the book, +you discover that most of it seems to have been scorched by lava! As you're about to ask how you can help, +the reindeer brings you a blank topographic map of the surrounding area (your puzzle input) and looks up at you excitedly. + +Perhaps you can help fill in the missing hiking trails? + +The topographic map indicates the height at each position using a scale from 0 (lowest) to 9 (highest). For example: + +``` +0123 +1234 +8765 +9876 +``` + +Based on un-scorched scraps of the book, you determine that a good hiking trail is as long as possible and has an even, gradual, uphill slope. +For all practical purposes, this means that a hiking trail is any path that starts at height 0, ends at height 9, +and always increases by a height of exactly 1 at each step. Hiking trails never include diagonal steps - only up, down, left, or right +(from the perspective of the map). + +You look up from the map and notice that the reindeer has helpfully begun to construct a small pile of pencils, markers, rulers, +compasses, stickers, and other equipment you might need to update the map with hiking trails. + +A trailhead is any position that starts one or more hiking trails - here, these positions will always have height 0. +Assembling more fragments of pages, you establish that a trailhead's score is the number of 9-height positions reachable +from that trailhead via a hiking trail. In the above example, the single trailhead in the top left corner has a score of 1 +because it can reach a single 9 (the one in the bottom left). + +This trailhead has a score of 2: + +``` +...0... +...1... +...2... +6543456 +7.....7 +8.....8 +9.....9 +``` + +(The positions marked . are impassable tiles to simplify these examples; they do not appear on your actual topographic map.) + +This trailhead has a score of 4 because every 9 is reachable via a hiking trail except the one immediately to the left of the trailhead: + +``` +..90..9 +...1.98 +...2..7 +6543456 +765.987 +876.... +987.... +``` + +This topographic map contains two trailheads; the trailhead at the top has a score of 1, while the trailhead at the bottom has a score of 2: + +``` +10..9.. +2...8.. +3...7.. +4567654 +...8..3 +...9..2 +.....01 +``` + +Here's a larger example: + +``` +89010123 +78121874 +87430965 +96549874 +45678903 +32019012 +01329801 +10456732 +``` + +This larger example has 9 trailheads. Considering the trailheads in reading order, they have scores of 5, 6, 5, 3, 1, 3, 5, 3, and 5. +Adding these scores together, the sum of the scores of all trailheads is 36. + +The reindeer gleefully carries over a protractor and adds it to the pile. +What is the sum of the scores of all trailheads on your topographic map? + + +## Part Two + +The reindeer spends a few minutes reviewing your hiking trail map before realizing something, disappearing for a few minutes, +and finally returning with yet another slightly-charred piece of paper. + +The paper describes a second way to measure a trailhead called its rating. +A trailhead's rating is the number of distinct hiking trails which begin at that trailhead. For example: + +``` +.....0. +..4321. +..5..2. +..6543. +..7..4. +..8765. +..9.... +``` + +The above map has a single trailhead; its rating is 3 because there are exactly three distinct hiking trails which begin at that position: + +``` +.....0. .....0. .....0. +..4321. .....1. .....1. +..5.... .....2. .....2. +..6.... ..6543. .....3. +..7.... ..7.... .....4. +..8.... ..8.... ..8765. +..9.... ..9.... ..9.... +``` + +Here is a map containing a single trailhead with rating 13: + +``` +..90..9 +...1.98 +...2..7 +6543456 +765.987 +876.... +987.... +``` + +This map contains a single trailhead with rating 227 (because there are 121 distinct hiking trails that lead +to the 9 on the right edge and 106 that lead to the 9 on the bottom edge): + +``` +012345 +123456 +234567 +345678 +4.6789 +56789. +``` + +Here's the larger example from before: + +``` +89010123 +78121874 +87430965 +96549874 +45678903 +32019012 +01329801 +10456732 +``` + +Considering its trailheads in reading order, they have ratings of 20, 24, 10, 4, 1, 4, 5, 8, and 5. +The sum of all trailhead ratings in this larger example topographic map is 81. + +You're not sure how, but the reindeer seems to have crafted some tiny flags out of toothpicks and bits of paper and is using them +to mark trailheads on your topographic map. What is the sum of the ratings of all trailheads? diff --git a/advent-of-code/2024/day_10/input.txt b/advent-of-code/2024/day_10/input.txt new file mode 100644 index 0000000..f83c587 --- /dev/null +++ b/advent-of-code/2024/day_10/input.txt @@ -0,0 +1,57 @@ +543213210349876210129890176034034565966563210587109092121 +656104101236762121456761789125120677877432101498218187030 +787215678945643012369852652196541986778943452387367256541 +898764101223454921058943543087632345657654363456456349654 +234459814312367838901012634678983954108932276545234438743 +105308765101298987632108768901017873217841189034105698894 +076218965290345676543289457632124561678750025121236787101 +987987874387654989123498398543401410589867014240901223218 +128876210260123478004567212898532323475678923457816314509 +019564320178874565213216500187645654129854503966765405678 +323469834569982104304307431234578765036763212875896876989 +767878706521676235425498120110569834545678923214387932376 +876967017430501543216326013223432728901298012103098541205 +985054328941432652107817154370121112854347543892107670314 +834123217632965469234908965987430004761256556701256789323 +729654306541874678945699874876548123450236789210345430110 +618783210930123012876789103765659874210101654345014521221 +105690129850019823498632212014567865321256789765623012434 +104941010761236710567541003423438978762349809854789923455 +203832123450145623456410212789829569451056012343210854396 +312745898567876514589321345657810438342347898901345765987 +405656776343998105679430103456910123239897687432216705476 +512346785434867234578345612765878762101798576521009812345 +694567698123452105507656709894349656123603401098967826565 +783878981030143245412349814763234341014512032367654983456 +012969976543201236093218923452123210012432145456543452187 +121001876124210187187108765421005391143465434505412341093 +321232565035303298296089012321016789834874328212303433282 +210543458749456334345676521056525470765966019301601214101 +109851239658765478034785435437434321014987458456732105010 +238760548789678969123699876348945610523456367234845256723 +321017656698767056782176501267876525676789210105996367894 +438998765589850145891089437678801234989654101986087458965 +567321996434743234106543228769960145676543243877124349896 +675490887525612103257890119454877658983450112568233210787 +587586716014101678965432001323768943232162103499545012345 +896675105003234567876721017012057890123078213487636776596 +745564234123098656989830398701146321265459812345629889487 +932213047894187765216541235610235430876343501676712012376 +871302120765276894307890344320145210901265430989800193401 +560456961294345653210787653410236389810178125476543287632 +410367854386543464678876544567107458103269076398389326543 +321298765677812104589965433218998567234387681267276410014 +123457654308903243218760129809889234985898790354105569123 +016534567210211038909678978321010125676787063203234678874 +105673898323302347874541065410981589094543154112356787965 +234982765432423456743232456723873672187612267053543298874 +122801894541510161250101365834712543870101348765632107985 +021289843690678870367010212945603434983289659054901001276 +130126732784569965478101204988914301874378778123892104345 +245035011098430156789678345677765210165134589104743077656 +356544324567821025898569101056879321051021678201654988745 +987676543056932110185430202346978432896120214312345679034 +678989432108945523679021312567566543787034305478943456123 +549034549087876654578110453498754694986545456967012987101 +432123678896521783063234569787103785675676567852173985432 +101210510123430192154345478776212656548989656743089876501 diff --git a/advent-of-code/2024/day_10/lib.rb b/advent-of-code/2024/day_10/lib.rb new file mode 100644 index 0000000..869a71b --- /dev/null +++ b/advent-of-code/2024/day_10/lib.rb @@ -0,0 +1,45 @@ +def count_reachable_positions(matrix) + get_score_sum(matrix, true) +end + +def count_hiking_trails(matrix) + get_score_sum(matrix, false) +end + +def get_score_sum(matrix, skip_visited_cells) + count = 0 + + for i in 0..matrix.length - 1 do + for j in 0..matrix[0].length - 1 do + next if matrix[i][j] != 0 + + count += bfs(matrix, i, j, skip_visited_cells) + end + end + + count +end + +def bfs(matrix, i, j, skip_visited_cells) + visits = Array.new(matrix.length) { Array.new(matrix[0].length, false) } + queue = [[i, j]] + matches = 0 + + until queue.empty? + i, j = queue.pop + next if skip_visited_cells && visits[i][j] + + visits[i][j] = true + if matrix[i][j] == 9 + matches += 1 + next + end + + queue.unshift([i - 1, j]) if i > 0 && matrix[i - 1][j] == matrix[i][j] + 1 + queue.unshift([i + 1, j]) if i < matrix.length - 1 && matrix[i + 1][j] == matrix[i][j] + 1 + queue.unshift([i, j - 1]) if j > 0 && matrix[i][j - 1] == matrix[i][j] + 1 + queue.unshift([i, j + 1]) if j < matrix[0].length - 1 && matrix[i][j + 1] == matrix[i][j] + 1 + end + + matches +end diff --git a/advent-of-code/2024/day_10/main.rb b/advent-of-code/2024/day_10/main.rb new file mode 100644 index 0000000..1b15f6c --- /dev/null +++ b/advent-of-code/2024/day_10/main.rb @@ -0,0 +1,12 @@ +require_relative 'lib' + +input = File.readlines('input.txt', chomp: true) +matrix = input.map do |row| + row.split('').map { |n| Integer(n) } +end + +res1 = count_reachable_positions(matrix) +puts("Part 1: #{res1}") + +res2 = count_hiking_trails(matrix) +puts("Part 2: #{res2}") diff --git a/advent-of-code/2024/day_10/test.rb b/advent-of-code/2024/day_10/test.rb new file mode 100644 index 0000000..f0dcc38 --- /dev/null +++ b/advent-of-code/2024/day_10/test.rb @@ -0,0 +1,32 @@ +require_relative 'lib' +require 'test/unit' + +class TestLib < Test::Unit::TestCase + def test_count_reachable_positions + input = [ + [8, 9, 0, 1, 0, 1, 2, 3], + [7, 8, 1, 2, 1, 8, 7, 4], + [8, 7, 4, 3, 0, 9, 6, 5], + [9, 6, 5, 4, 9, 8, 7, 4], + [4, 5, 6, 7, 8, 9, 0, 3], + [3, 2, 0, 1, 9, 0, 1, 2], + [0, 1, 3, 2, 9, 8, 0, 1], + [1, 0, 4, 5, 6, 7, 3, 2] + ] + assert_equal(36, count_reachable_positions(input)) + end + + def test_count_hiking_trails + input = [ + [8, 9, 0, 1, 0, 1, 2, 3], + [7, 8, 1, 2, 1, 8, 7, 4], + [8, 7, 4, 3, 0, 9, 6, 5], + [9, 6, 5, 4, 9, 8, 7, 4], + [4, 5, 6, 7, 8, 9, 0, 3], + [3, 2, 0, 1, 9, 0, 1, 2], + [0, 1, 3, 2, 9, 8, 0, 1], + [1, 0, 4, 5, 6, 7, 3, 2] + ] + assert_equal(81, count_hiking_trails(input)) + end +end