the code reuses the 'blot' method to calculate the path length. variables
variables/methods:
Attempt at more detailed explanation:
make a copy of the input string, which we use for finding the length of the path from any given point in the map.
z = s.dup
define a 'ps' (path length) anonymous function (lambda) which takes the map index i as an argument. it returns the length of the path from that point. it does this by calling the 'b' (blot) method to insert x's on a copy of the original map and then counting the number of x's in the returned string.
ps = ->(i){b(z.dup,i).scan('x').size}
the following part iterates over each character in the map (index i, character s[i]). it calls the 'b' (blot) function on map position i if the path length from position i is greater than 2, and if it's not a space or newline character.
(0...s.size).each { |i|
b(s, i) if ![' ',"\n"].include?(s[i]) && ps.call(i) > 2
}
the b (blot) function takes the map string and an index as argument. it initialises @v (visited array) and calls the b2 helper function.
def b(s,i)
@v=[]
b2(s,i,s[i])
end
the b2 function takes the map string, a map position (i), and a character in the current path (c). it calls itself recursively to replace connected sections of digits with the 'x' character. it returns the input string (this is so the ps function can call scan() on the return value).
this if statement is checking that the map position (i) given is within the bounds of the string (0...s.size) and that the character at s[i] is the same as the starting character. also @v[i] is checked to avoid infinite recursion.
if(0...s.size) === i && s[i] == c && !@v[i]
this is the bit that replaces the character at index (i) with the 'x' character. it also marks that index as visited.
@v[i] = s[i] = 'x'
this is where b2 calls itself recursively searching for the path. i+1 is one character to the right, i-1 is one character to the left, i+6 is one row down (5 digits + 1 newline = 6 characters), i-6 is one row up.
[1,-1,6,-6].each { |j| b2(s, i+j, c) }