Does the water ultimately reach the tank?

Snails, 20 bytes

\S{d(=\#n)?^#},!(t\E

Prints 0 for the falsey value and 1 for the truthy value.

Try it online!

  • \S matches S at the start
  • d sets direction to down
  • {...}, matches the stuff in braces 0 or more times
  • =\# is an assertion which succeeds if there is a # char ahead of the snail, but does not move it
  • n turns 90 degrees in either direction
  • (...)? matches the pattern in parentheses 0 or 1 times
  • \ ​ matches a space and moves the snail onto it
  • !(... is a negative assertion
  • t teleports to any unmatched square in the grid
  • \E matches E

Slip, 20 + 2 = 22 bytes

S>( ^4|^4(?|`#)^T)*E

So Slip's still as broken as ever, but for once this was a challenge it could actually do. It was never really designed to be that golfy though, so it'll never beat Snails at anything :P

Needs the r flag (no repeating cells) to terminate.

Try it online. Output is the path taken for truthy, empty for falsy.

S                 Match S
>                 Rotate pointer downward
(                 Either...
 <space>^4          Match a space and point downwards
 |                  or
 ^4                 Point downwards
 (?|`#)             Match # below then reset pointer
 ^T                 Either turn left or right
)*                ... 0+ times
E                 Match E

Retina, 87 bytes

Byte count assumes ISO 8859-1 encoding.

+mT`E `S`(?<=^(?(1)!)(?<-1>.)*S.*¶(.)*)[E ]|.?S(?=(.)*¶.*#(?<-2>.)*(?(2)!)$)[E ]?
M`E
0

Try it online!

As much as 2D string processing is possible in Retina (or .NET regex in general), it's not exactly concise...

Explanation

+mT`E `S`(?<=^(?(1)!)(?<-1>.)*S.*¶(.)*)[E ]|.?S(?=(.)*¶.*#(?<-2>.)*(?(2)!)$)[E ]?

This is a flood-fill which marks all the cells that are reached by water with S. It does so by matching the characters that can be reached and then transliterating them to S with T-mode. This flood-fill goes through both spaces and E. The + at the beginning repeats this until the output stops changing.

As for the actual regex is contains two separate cases:

(?<=^(?(1)!)(?<-1>.)*S.*¶(.)*)[E ]

This matches a space or E which is exactly one cell below an S. The vertical matching is done by counting the prefix on the current line using balancing groups so we can ensure that the horizontal position is the same. This one takes care of falling water.

.?S(?=(.)*¶.*#(?<-2>.)*(?(2)!)$)[E ]?

This is very similar: it matches an S and if available the character before and after it, provided that the character directly beneath the S is a #. This takes care of water spreading along the ground.

When we're done it's very easy to determine if the water reached E. If it did, then E has been removed from the string in the flood-fill, and if not the E is still there. So let's count the number of Es:

M`E

But now that's 0 (which I'd consider falsy) for truthy test cases and 1 (which I'd consider truthy) for falsy test cases. We can invert this very easily by counting the number of 0s in this result:

0

Done.