Revision fa2cd768-66fd-49f4-a3f3-57d59e010e3e - Code Golf Stack Exchange
# [MATL](https://github.com/lmendo/MATL), <s>48</s> <s>44</s> <s>42</s> <s>37</s> 33 bytes
_Quite a few bytes saved thanks to [rahnnema's idea (Octave answer)](http://codegolf.stackexchange.com/a/104702/36398) of collapsing two convolutions into one_
t5BQ4B&vX^Z+*ssGt3Y6Z+1=*&fdwdYy/
This takes the input as a binary matrix, with `;` as row separator. `1` corresponds to hash and `0` to space.
[Try it online!](https://tio.run/nexus/matl#@19i6hRo4qRWFhEXpa1VXOxeYhxpFqVtaKullpZSnhJZqf//f7SBAio0BEMYbahggA1ao@tBpQ2w68OhC68eBUMydBmSYZchhgtxmIzJszbEEgLo6gzRQ9QaFtr49eEKQ5xxgw3GAgA) Or [verify all test cases](https://tio.run/nexus/matl#zVa7DsIwDNz5ik4MdCAnHovFgtg6ITHwUBED4gdAIL6@SJWKaBrbaZpIKENVXRzH57Ody76oHov1dr4eP/fnYz6534vH7LA85lhNxrfr63p4T6vNrjqZrL1Qr@aLzLgW2Tbtr3HbMVaiTYYAKwT4QueGzMndP4KDAXsfbEapYVu24zhkc@Na5egknk59UWPFweIBKAJvBUFrps0zuTPkUkHHmjiWIUSEQJ6HxutVeclRRuP0WxuGRfkOJKNG7V5al8IAlIvXp7JNXL919UPqGCT3L8V7Dxwh@dKyHQnX9RSDHz1/snJ8qnA4rnUXnwmhzQgI8UPwP5Q/JNNvetxPX@n1Y3lh8y@/Ar57SH6/QMShnK/O7Oj67Tmd/w5PVz/x@l/3Ld0/v98d5Qc).
[Here's](https://tio.run/nexus/matl#tZVBDoMgEEX3nmKSn5R9t249QnetSe9/CRsQlRm@CJiaGM0bGD9/Bly@w/PzmKbhtSxvJ/EC4G/IcblRtjDiLTgNmyiKYRRnI02eTtofPgyYLwb9OKT5dxW3ytVqk4XNw@FLnObGEhFkJMosElxmhhACS7A6pvLAfj0jwOW66vRoArlP0sIFgrRWkahOpUSQEd3ALmuMM2L0sDFVmZM8ocv0jvPDwHWX0xMNxALiUwtiDtdKZVbkntLWqESkN@lWJXvVjtqL0qgeXRXqR9zofle3ucav/CQL0KJw5huUj6LnUnOFCifRn1BftRv6fv91XZizWjj/AA) a format converter that takes inputs as 2D char arrays (again, with `;` as separator) and produces string representations of the corresponding binary matrices.
###Explanation
This was fun! The code uses <s>three</s> two 2D-convolutions, each for a different purpose:
1. To detect vertical and horizontal neighbours, which contribute a distance of `1`, the requires mask would be
0 1 0
1 0 1
0 1 0
But we only want each _pair_ of neighbours to be detected once. So we take half the mask (and the last row of zeros can be removed):
0 1 0
1 0 0
To detect diagonal neighbours, which contribute a distance of `sqrt(2)`, the mask would be
1 0 1
0 0 0
1 0 1
but by the same reasoning as above it becomes
1 0 1
0 0 0
If mask is multiplied by `sqrt(2)` and added to the first, the two convolutions can be replaced by one with the mask
sqrt(2) 1 sqrt(2)
1 0 0
2. To detect start and end points. These are by definition the points with only one neighbour. Se we convolve with
1 1 1
1 0 1
1 1 1
and see which points give `1` as result.
To generate mask 1 it's shorter to produce its square and then take the square root. Mask 2 is a predefined literal.
t % Take input matrix implicitly. Duplicate
5B % 5 in binary: [1 0 1]
Q % Add 1; [2 1 2]
4B % 4 in binary: [1 0 0]
&v % Concatenate vertically
X^ % Square root of each entry
Z+ % 2D convolution, maintaining size
* % Multiply, to only keep results corresponding to 1 in the input
ss % Sum of all matrix entries. This gives total distance
Gt % Push input again. Duplicate
3Y6 % Predefined literal. This gives third mask
Z+ % 2D convolution, maintaining size
1= % Values different than 1 are set to 0
* % Multiply, to only keep results corresponding to 1 in the input
&f % Push array of row indices and array of column indices of nonzeros
d % Difference. This is the horizontal difference between start and end
wd % Swap, difference. This is the vertical difference between start and end
Yy % Hypothenuse. This gives total distance in straight line
/ % Divide. Display implicitly