At the start, the knight is at (r, c) with probability 1 (and anywhere else with probability 0). Then update those probabilities over K moves.

```
def knightProbability(self, N, K, r, c):
p = {(r, c): 1}
for _ in range(K):
p = {(r, c): sum(p.get((r+i, c+j), 0) + p.get((r+j, c+i), 0) for i in (1, -1) for j in (2, -2)) / 8
for r in range(N) for c in range(N)}
return sum(p.values())
```

Shorter and maybe nicer version, influenced a bit by @flamesofmoon's solution:

```
def knightProbability(self, N, K, r, c):
p = {(r, c): 1}
for _ in range(K):
p = {(r, c): sum(p.get((r+i, c+j), 0) for x in (1, 2) for i in (x, -x) for j in (3-x, x-3)) / 8
for r in range(N) for c in range(N)}
return sum(p.values())
```