T minus time to ransom!
Python 2, 90 bytes
g=lambda a:min(min(a))or-~g(map(lambda*c:map(max,(0,)+c[:-1],c,c[1:]),*a))
lambda a:g(a)/2
Try it online!
Accepts a matrix as a list of lists of 0 and 1.
How it works
g=lambda a:min(min(a))or…
If the smallest element of the matrix is 1 (it is completely infected), return 1; otherwise…
-~g(… )
return 1 plus the recursive result on the following modified matrix…
map(lambda*c:… ,*a)
for each old column c
…
map(max,(0,)+c[:-1],c,c[1:])
produce a new row by zipping max
over the down-shifted, original, and up-shifted versions of c
. (map
fills in the gap at the end of c[1:]
with None
, which is falsy and smaller than both 0
and 1
.)
Each iteration of g
computes all vertical infections, then transposes the matrix. This way, every 2 iterations of g
compute all horizontal, vertical, and diagonal infections.
lambda a:g(a)/2
Because the base case of g
with a fully infected matrix gave 1 rather than 0, the parity works out such that floored division by 2 always gives the correct result.