#JavaScript (ES6), 175 bytes Takes input in <s>curling</s> currying syntax `([x, y])(a)`, where **x** and **y** are the 0-indexed coordinates of the starting position and **a[ ]** is a matrix of integers, with `0` = ice, `1` = wall, `2` = sand, `3` = hole and `4` = water Returns `0` if there's no solution. <!-- language-all: lang-js --> p=>a=>(r=F=([x,y],n,R=a[y],c=R[x])=>R[c==(R[x]=4)|n>=r||[-1,0,1,2].map(d=>(g=_=>(k=a[v=Y,Y+=d%2][h=X,X+=~-d%2])||g())(X=x,Y=y)>3?0:k>2?r=-~n:F(k>1?[X,Y]:[h,v],-~n)),x]=c)(p)|r [Try it online!](https://tio.run/##zVdbi@IwFH73VxwISxsmBnVmb0JqYWFeF@ZJKWUp1bnszFrR2UFB8tfd9GqbnMTOsg8bQXNOzvU7Jxd/Jm/JLt0@bV6H62y5Ot2L00YEiQj8rbgVfrRnh5it2Z1IIjVJxV20j6kI7qJUCD8nxA09rgOxPR6j4ZiN2JhNYv4r2fhLZeNB/FDfz0r5TSzY4kosP0zi6FHM2fxKyGFO0ePxwafUn4s9W4gDDa5no@lzMJltxVCup7f@czCeRXO2iKfRI3uLmeJSypTjlPobetyeXle7VxCQgAjAH0A@gaQIwd8yWNCcvy3plMG8oFMQArzQgxn4eyU/Z3BQPwsGIwpT8IDwTHr8ab1c7b/f@ylVLpXp@xwQOMTUT@iADgZptt5lLyv@kj343rfs93a3AjL2GOQx@ZHSiDjnHlHDi1lDQtghM9khC@FBTG32J6j9jokQoOsw02ht/aLPa8OnlLJlQYYdinco@EuqayXrULl3R7w3OEY6TrIcOi/UeQowriDrykHx6fK4Qpob9gDxYfg9x@fI6yNWB6nVQn2BhmTINTRNmTwZrW4cuI66vIT8JzvyRO9BhaoaJhdMrizYWhfn0KLcQro/N@sjG6Jc0q9unx2o6M1i@FCV4vmCGaTJLGR1dZ63IJajRFLkmSVDZ4JfXGXHBpo1tH@qgUOhtmRtCaqpBZ@WKY7abEDLP@VmlTbvFZKlJK@tFh8c3lJS2m2WmJfBEZmBPfdLeDqq87Xfcag8hsgWMY4vjMeLLDgiBxd5vMgeQRDt@V66/fz@RzFLxIfs77dXzL15@ZEI8G@urPGoz9HQcc/LgW8DcG97ou11fZWAS7fSz5Utq8WuJubq@XCx@a1OBIJbLp4drlV5wS935Fsp2vJ1rRL3amZZJQ3SWMzNIU9Ij2PO3V7j9948RixGS5H6ItKTOndHe1am2X1vn9PvzExRUj4u2z0JVVUx0dpifVMWDSkN0Xqx7J1KwrGfmuYOq0ur1NHA4lXeiFWiX5Xk3HiFqB0B3kETnLiS9sXfDFu1zgk3E4JbbTYZnB8OqGiVPfJOed91faGpJ72a2nw4208gIHXtsHKBgRVyqpI2kPrfya4BzDhpbXs0tCY2NLR6klkO/BBc2rbQiPO52VUlaN6kj3alj/SS685wo6aBBu9pB2tDnv4A "JavaScript (Node.js) – Try It Online") ###Commented p => a => ( // given the starting position p[] and the matrix a[] r = // r = best result, initialized to a non-numeric value F = ( // F = recursive function taking: [x, y], // (x, y) = current position n, // n = number of shots, initially undefined R = a[y], // R = current row in the matrix c = R[x] // c = value of the current cell ) => // R[ // this will update R[x] once the inner code is executed c == (R[x] = 4) | // set the current cell to 4 (water); abort if it was n >= r || // already set to 4 or n is greater than or equal to r [-1, 0, 1, 2].map(d => // otherwise, for each direction d: (g = _ => ( // g = recursive function performing the shot by k = a[ // saving a backup (h, v) of (X, Y) v = Y, Y += d % 2][ // and updating (X, Y) until we reach a cell h = X, X += ~-d % 2]) // whose value k is not ice (k != 0) || g() // )(X = x, Y = y) // initial call to g() with (X, Y) = (x, y) > 3 ? // if k = 4 (water -> fail): 0 // abort immediately : // else: k > 2 ? // if k = 3 (hole -> success): r = -~n // set r to n + 1 : // else: F( // do a recursive call to F(): k > 1 ? // if k = 2 (sand): [X, Y] // start the next shots from the last cell : // else (wall): [h, v], // start from the last ice cell -~n // increment the number of shots ) // end of recursive call ), x // end of map(); x = actual index used to access R[] ] = c // restore the value of the current cell to c )(p) | r // initial call to F() at the starting position; return r