## Part A

On Day 14 we have MD5 hashing again. I don’t wont to explain this one in different words. I will just post my solutions

require "digest"

salt = "abc"
index = 0

fives = []
hashes = []

while true
hash = Digest::MD5.hexdigest([salt, index].join)

if hash =~ /(.)\1{4}/
valid = fives.select { |five| five[0] == Regexp.last_match[1] && index <= five[1] }

valid.each do |v|
fives.delete(v)
hashes.push([*v, hash, index])
end
end

if hash =~ /(.)\1{2}/
fives.push([Regexp.last_match[1], index + 1000, hash])
end

if hashes.size == 64
break
end

index += 1
end

hashes.sort { |a, b| a[1] <=> b[1] }.each { |h| puts "#{h[2]} at #{h[1] - 1000}, matching five hash at #{h[3]} value = #{h[4]}" }

## Part B

And here is solution for second part:

require "digest"

salt = "abc"
index = 0

def md5(salt, index)
hash = Digest::MD5.hexdigest([salt, index].join)
2016.times { hash = Digest::MD5.hexdigest(hash) }
hash
end

triplets = []
hashes = []
max_index = nil

while true
hash = md5(salt, index)

if hash =~ /(.)\1{4}/
triplets.select! { |triplet| (index - triplet[:index]) <= 1000 }
triplets.each do |triplet|
if triplet[:char] == Regexp.last_match[1] &&
hashes.push(triplet)
end
end
end

if hash =~ /(.)\1{2}/ && !max_index
triplets.push({ char: Regexp.last_match[1], index: index })
end

if hashes.size >= 64
max_index = index

if triplets.empty?
break
end
end

index += 1

if index % 100 == 0
puts [index, hashes.size].inspect
end
end

puts hashes.sort { |a, b| a[:index] <=> b[:index] }[63].inspect