Let's play Fairy Chess!

You have an $n\times n$ chessboard. An $\boldsymbol{\mathrm{~S~}}$-leaper is a chess piece which can move from some square $(x_0,y_0)$ to some square $(x_{1},y_{1})$ if $abs(x_0-x_1)+abs(y_0-y_1)\leq s$; however, its movements are restricted to up ($\uparrow$), down ($\downarrow$), left ($\leftarrow\right.$), and right ($\rightarrow$) within the confines of the chessboard, meaning that diagonal moves are not allowed. In addition, the leaper cannot leap to any square that is occupied by a pawn.

Given the layout of the chessboard, can you determine the number of ways a leaper can move $m$ times within the chessboard?

Note: $abs(x)$ refers to the absolute value of some integer, $\boldsymbol{x}$.

Input Format

The first line contains an integer, $\textit{q}$, denoting the number of queries. Each query is described as follows:

The first line contains three space-separated integers denoting $n$, $m$, and $\boldsymbol{\mathrm{~S~}}$, respectively.
Each line $\boldsymbol{i}$ of the $n$ subsequent lines contains $n$ characters. The $j^{th}$ character in the $i^{\mbox{th}}$ line describes the contents of square $(i,j)$ according to the following key:
. indicates the location is empty.
P indicates the location is occupied by a pawn.
L indicates the location of the leaper.

Constraints

$1\leq q\leq10$
$1\leq m\leq200$
There will be exactly one L character on the chessboard.
The $\boldsymbol{\mathrm{~S~}}$-leaper can move up ($\uparrow$), down ($\downarrow$), left ($\leftarrow\right.$), and right ($\rightarrow$) within the confines of the chessboard. It cannot move diagonally.

Output Format

For each query, print the number of ways the leaper can make $m$ moves on a new line. Because this value can be quite large, your answer must be modulo $10^9+7$.

Sample Input 0
3
4 1 1
....
.L..
.P..
....
3 2 1
...
...
..L
4 3 2
....
...L
..P.
P...

Sample Output 0
4
11
385

Explanation 0

You must perform two queries, outlined below. The green cells denote a cell that was leaped to by the leaper, and coordinates are defined as $(row,column)$.

The leaper can leap to the following locations: 

Observe that the leaper cannot leap to the square directly underneath it because it's occupied by a pawn. Thus, there are $4$ ways to make $1$ move and we print $4$ on a new line. 
The leaper can leap to the following locations: 

Thus, we print $\mbox{11}$ on a new line.

Note: Don't forget that your answer must be modulo $10^9+7$.

Source: hackerrank | Difficulty: HARD
Tags: Dynamic programming


Solutions:
def main():
	i = input().split()
	(size, moves, reach) = (int(i[0]), int(i[1]), int(i[2]))
	board = []
	for r in range(size):
		data = input()
		if data.find('L') != -1:
			locationR = r
			locationC = data.find('L')
		board.append(data)
	ways = []
	for moveNum in range(moves + 1):
		tboard = []
		if moveNum == 0:
			for i in range(size):
				row = []
				for j in range(size):
					if board[i][j] != 'P':
						row.append(1)
					else:
						row.append(0)
				tboard.append(row)
		else:
			for i in range(size):
				row = []
				for j in range(size):
					if board[i][j] == 'P':
						row.append(0)
						continue
					total = 0
					for r in range(max(0, i - reach), min(size, i + reach + 1)):
						for c in range(max(0, j - reach + abs(r - i)), min(size, j + reach - abs(r - i) + 1)):
							total += ways[moveNum - 1][r][c]
					row.append(total)
				tboard.append(row)
		ways.append(tboard)
	return ways[-1][locationR][locationC]
for _ in range(int(input())):
	print(main())


m = 1000000007
board = None
maxjump = None
dynways = None

def valid(x, y):
	return x >= 0 and x < len(board) and (y >= 0) and (y < len(board))

def places(x, y):
	for i in range(-maxjump + x, maxjump + x + 1):
		for j in range(-maxjump + y, maxjump + y + 1):
			if valid(i, j) and abs(x - i) + abs(y - j) <= maxjump and (board[i][j] != 'P'):
				yield (i, j)

def ways(moves, x, y):
	if dynways[moves - 1][x][y] > 0:
		return dynways[moves - 1][x][y]
	if moves == 0:
		return 1
	s = 0
	for (i, j) in places(x, y):
		s += ways(moves - 1, i, j)
	dynways[moves - 1][x][y] = s
	return s

def findpos():
	for i in range(len(board)):
		for j in range(len(board[i])):
			if board[i][j] == 'L':
				return (i, j)
for t in range(int(input())):
	(n, m, maxjump) = map(int, input().split())
	board = [input() for i in range(n)]
	dynways = [[[0] * n for i in range(n)] for j in range(m)]
	print(ways(m, *findpos()))


import sys

def possible_spots(arr, lr, lc, S, N):
	lst = [[lr, lc]]
	i = 0
	j = 0
	while i <= S:
		j = 0
		while j <= S:
			if i + j <= S:
				if i == 0 and j != 0:
					if lc + j < N and arr[lr][lc + j] != 2:
						lst.append([lr, lc + j])
					if lc - j >= 0 and arr[lr][lc - j] != 2:
						lst.append([lr, lc - j])
				elif j == 0 and i != 0:
					if lr + i < N and arr[lr + i][lc] != 2:
						lst.append([lr + i, lc])
					if lr - i >= 0 and arr[lr - i][lc] != 2:
						lst.append([lr - i, lc])
				elif j != 0 and i != 0:
					if lr + i < N and lc + j < N and (arr[lr + i][lc + j] != 2):
						lst.append([lr + i, lc + j])
					if lr - i >= 0 and lc + j < N and (arr[lr - i][lc + j] != 2):
						lst.append([lr - i, lc + j])
					if lr + i < N and lc - j >= 0 and (arr[lr + i][lc - j] != 2):
						lst.append([lr + i, lc - j])
					if lr - i >= 0 and lc - j >= 0 and (arr[lr - i][lc - j] != 2):
						lst.append([lr - i, lc - j])
			j = j + 1
		i = i + 1
	return lst

def calculate(arr, lr, lc, M, S, N, darr, spot_arr):
	if spot_arr[lr][lc]:
		lst = spot_arr[lr][lc]
	else:
		lst = possible_spots(arr, lr, lc, S, N)
		spot_arr[lr][lc] = lst
	if M == 0:
		return len(lst)
	ans = 0
	for entry in lst:
		if darr[M - 1][entry[0]][entry[1]] != -1:
			ans = ans + darr[M - 1][entry[0]][entry[1]]
		else:
			darr[M - 1][entry[0]][entry[1]] = calculate(arr, entry[0], entry[1], M - 1, S, N, darr, spot_arr)
			ans = ans + darr[M - 1][entry[0]][entry[1]]
	return ans
input = sys.stdin.readlines()
numtest = int(input[0])
i = 1
for k in range(numtest):
	tmp = input[i].split()
	N = int(tmp[0])
	M = int(tmp[1])
	S = int(tmp[2])
	arr = []
	for row in range(N):
		arr.append([0] * N)
	spot_arr = []
	for r in range(N):
		rr = []
		for c in range(N):
			rr.append([])
		spot_arr.append(rr)
	darr = []
	for q in range(M):
		qq = []
		for a in range(N):
			qqq = []
			for z in range(N):
				qqq.append(-1)
			qq.append(qqq)
		darr.append(qq)
	r = 0
	i = i + 1
	lr = 0
	lc = 0
	while r < N:
		line = input[i]
		c = 0
		while c < N:
			if line[c] == 'P':
				arr[r][c] = 2
			if line[c] == 'L':
				lr = r
				lc = c
				arr[r][c] = 1
			c = c + 1
		r = r + 1
		i = i + 1
	print(calculate(arr, lr, lc, M - 1, S, N, darr, spot_arr))


def Moves(N, M, S, pos, board):
	if M == 0:
		return 1
	moves = 0
	for x in range(max(pos[0] - S, 0), min(pos[0] + S + 1, N)):
		for y in range(max(pos[1] - S + abs(x - pos[0]), 0), min(pos[1] + S - abs(x - pos[0]) + 1, N)):
			if board[x][y] != 'P':
				moves += Moves(N, M - 1, S, (x, y), board)
	return moves

def DoTest():
	(N, M, S) = input().split(' ')
	N = int(N)
	M = int(M)
	S = int(S)
	pos = (-2, -2)
	board = []
	for x in range(0, N):
		row = input()
		if 'L' in row:
			pos = (x, row.find('L'))
		board.append(row)
	print(Moves(N, M, S, pos, board))
T = int(input())
for test in range(0, T):
	DoTest()


from copy import deepcopy

def locate_leaper(board, n):
	l = (0, 0)
	for i in range(n):
		for j in range(n):
			if board[i][j] == 'L':
				l = (i, j)
				break
	return l

def one_move_counts(counts, s, n):
	out = deepcopy(counts)
	for i in range(n):
		for j in range(n):
			if counts[i][j] > -1:
				for x in range(0, s + 1):
					for y in range(0, s + 1 - x):
						if x + y >= 1 and x + y <= s:
							if i - x > -1:
								if j + y < n:
									i_prime = i - x
									j_prime = j + y
									if counts[i_prime][j_prime] > -1:
										out[i][j] += counts[i_prime][j_prime]
								if y > 0 and j - y > -1:
									i_prime = i - x
									j_prime = j - y
									if counts[i_prime][j_prime] > -1:
										out[i][j] += counts[i_prime][j_prime]
							if x > 0 and i + x < n:
								if j + y < n:
									i_prime = i + x
									j_prime = j + y
									if counts[i_prime][j_prime] > -1:
										out[i][j] += counts[i_prime][j_prime]
								if y > 0 and j - y > -1:
									i_prime = i + x
									j_prime = j - y
									if counts[i_prime][j_prime] > -1:
										out[i][j] += counts[i_prime][j_prime]
	return out

def main():
	q = int(input().strip())
	for query in range(q):
		[n, m, s] = [int(t) for t in input().strip().split()]
		board = []
		for i in range(n):
			board.append(list(input().strip()))
		counts = [[-1 if board[i][j] == 'P' else 1 for j in range(n)] for i in range(n)]
		for i in range(m):
			counts = one_move_counts(counts, s, n)
		l = locate_leaper(board, n)
		print(counts[l[0]][l[1]])
main()