Advertisement
Guest User

Advent of Code 2023 Day 10 Part 2

a guest
Dec 10th, 2023
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 4.25 KB | Source Code | 0 0
  1. require 'pp'
  2.  
  3. input = File.readlines(ARGV[0] || 'example2').map(&:rstrip)
  4.  
  5. start_row = start_col = 0
  6. input.each_with_index do |line, row|
  7.   if (col = line.index('S'))
  8.     start_row = row
  9.     start_col = col
  10.     break
  11.   end
  12. end
  13.  
  14. puts "start at #{start_row}, #{start_col}"
  15.  
  16. $width = input[0].length
  17. $height = input.length
  18. puts "#{$width} x #{$height} = #{$width*$height}"
  19.  
  20. # start by searching cardinal directions clockwise beacuse we don't
  21. # know what shape pipe 'S' is
  22. paths = []
  23. go = []
  24.  
  25. # up
  26. r, c = start_row-1, start_col
  27. if r >= 0 && r < $height && c >= 0 && c < $width
  28.   if '|7F'.index(input[r][c])
  29.     paths << [r, c]
  30.     go << :up
  31.   end
  32. end
  33. # right
  34. r, c = start_row, start_col+1
  35. if r >= 0 && r < $height && c >= 0 && c < $width
  36.   if '-J7'.index(input[r][c])
  37.     paths << [r, c]
  38.     go << :rt
  39.   end
  40. end
  41. # down
  42. r, c = start_row+1, start_col
  43. if r >= 0 && r < $height && c >= 0 && c < $width
  44.   if '|LJ'.index(input[r][c])
  45.     paths << [r, c]
  46.     go << :dn
  47.   end
  48. end
  49. # left
  50. r, c = start_row, start_col-1
  51. if r >= 0 && r < $height && c >= 0 && c < $width
  52.   if '-LF'.index(input[r][c])
  53.     paths << [r, c]
  54.     go << :lt
  55.   end
  56. end
  57.  
  58. print "initial paths: "
  59. p paths
  60.  
  61. s_is =
  62.   if go.include? :up
  63.     go.include?(:lt) ? 'J' : 'L'
  64.   elsif go.include? :dn
  65.     go.include?(:lt) ? '7' : 'F'
  66.   else
  67.     nil
  68.   end
  69. puts "s is #{s_is}"
  70.  
  71. # clean up map
  72. clean = [nil] * $height
  73. $height.times { clean[_1] = '.' * $width}
  74. clean[start_row][start_col] = 'S'
  75.  
  76. visited = {[start_row, start_col] => true}
  77.  
  78. at = paths[0]
  79. loop do
  80.   #puts "at #{at.join(', ')}"
  81.   visited[at] = true
  82.   r, c = at
  83.   clean[r][c] = input[r][c]
  84.   candidates =
  85.     case input[r][c]
  86.     when '|' then [[r-1, c], [r+1, c]]
  87.     when '-' then [[r, c-1], [r, c+1]]
  88.     when 'L' then [[r-1, c], [r, c+1]]
  89.     when 'J' then [[r-1, c], [r, c-1]]
  90.     when '7' then [[r, c-1], [r+1, c]]
  91.     when 'F' then [[r+1, c], [r, c+1]]
  92.     when 'S' then break
  93.     else
  94.       raise "#{r}, #{c} is #{input[r][c]}"
  95.     end
  96.   #puts "candidates: #{candidates.inspect}"
  97.   nxt = nil
  98.   candidates.each do |pos|
  99.     r, c = pos
  100.     if r < 0 || r >= $height || c < 0 || c >= $width
  101.       raise "#{at.join(', ')} -> #{r}, #{c} (out of bounds)"
  102.     end
  103.     if !visited[pos] # take this path
  104.       #puts "taking [#{r}][#{c}] = #{input[r][c]}"
  105.       nxt = pos
  106.       break
  107.     end
  108.   end
  109.   break unless nxt
  110.   at = nxt
  111.   #puts "\nat #{at}"
  112.   #pp clean
  113. end
  114.  
  115. puts
  116. clean.each {puts _1}
  117.  
  118.  
  119. =begin
  120. # flood fill '.'s from outside
  121. queue = [[0,0]]
  122. until queue.empty?
  123.   r, c = queue.pop
  124.   case clean[r][c]
  125.   when '.'
  126.     clean[r][c] = ' '
  127.     [[-1, 0], [0, 1], [1, 0], [0, -1]].each do |dr, dc|
  128.       r1 = r + dr; c1 = c + dc
  129.       if 0 <= r1 && r1 < $height && 0 <= c1 && c1 < $width
  130.         queue << [r1, c1] if clean[r1][c1] == '.'
  131.       end
  132.     end
  133.   when '|'
  134.   when '-'
  135.   when 'L'
  136.   when 'J'
  137.   when '7'
  138.   when 'F'
  139.   when 'S'
  140.   end
  141. end
  142.  
  143. puts
  144. clean.each {puts _1}
  145. =end
  146.  
  147. =begin
  148. # count remaining '.'s
  149. ndots = 0
  150. clean.each do |line|
  151.   line.each_char {|c| ndots += 1 if c == '.'}
  152. end
  153. puts "\n#{ndots} dots remain"
  154. =end
  155.  
  156. # apply (simplified?) even-odd winding rule
  157.  
  158. unwound = []
  159.  
  160. internal = 0
  161. clean.each do |line|
  162.   next if line =~ /^\.+$/
  163.   x = 0
  164. =begin
  165.   (0...line.length).each do |col|
  166.     case line[col]
  167.     when '|', 'L', 'J', '7', 'F'
  168.       x += 1
  169.     when '.'
  170.       #line[col] = x.even? ? ' ' : '~'
  171.       line[col] = ' ' if x.even?
  172.     when 'S'
  173.       x += 1 if '|LJ7F'.index(s_is)
  174.     end
  175. =end
  176.  
  177.   u = ''
  178.   line.scan(/F(?:-*J)?|L(?:-*7)?|./) do |m|
  179.     case m
  180.     when '|', 'L', 'J', '7', 'F', 'S'
  181.       x += 1
  182.       u << m
  183.     when /F-*J|L-*7/ # these act line one vertical edge
  184.       x += 1
  185.       u << m
  186.     when '.'
  187.       if x.even?
  188.         u << ' '
  189.       else
  190.         u << '.'
  191.         internal += 1
  192.       end
  193.     else
  194.       u << m
  195.     end
  196.   end
  197.   unwound << u
  198. end
  199.  
  200. puts "\nApply even-odd rule:"
  201. unwound.each {puts(_1.gsub('.', "\e[94m@\e[0m"))}
  202.  
  203. puts "\n#{internal} still inside"
  204.  
  205. puts "\nRemap:"
  206. symbols = [
  207.   ['F', "\u250F"],
  208.   ['J', "\u251B"],
  209.   ['L', "\u2517"],
  210.   ['7', "\u2513"],
  211.   ['|', "\u2503"],
  212.   ['-', "\u2501"],
  213. ]
  214. unwound.each do |line|
  215.   symbols.each do |a, b|
  216.     line = line.gsub(a, b)
  217.   end
  218.   puts line
  219. end
  220.  
Tags: aoc 2023
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement