python 表上で移動するコマの最大移動可能回数を求める

横M-1×縦N-1の表があり、左上から0,1,2とマス目番号が振られています。
※M,Nは適当に与えられます。
はじめにv(マス目番号)にコマが置かれます。
コマは下の写真のパターンで移動できます。1回の着手で移動できるマスを1マス選んでコマを進めます。ただし,コマは盤の外に出ることはできません。

コマの移動パターン

この時、vに置かれたコマの最大移動回数を再帰的に求める関数fを作成しました。
v2xy,xy2vはそれぞれ横位置x,縦位置yをマス目番号に戻す、それの逆を行う関数
enum_movesはマス目番号を与えてそこから移動できるマス目番号をリストにして返す関数
となっています。
関数fの中でmemoという変数を使用していますが、これは同じマス目に来た時に計算を再び行わないで済むように作りました。

聞きたいことは
①関数f内で再起を使用しているがmemoの中身が再帰された時にどのように作用しているのかが分からない
②関数fを改善できるとするならどうするべきか
です。

関数fが再帰的に関数を呼び出し移動回数を呼び出された度に追加し最大移動回数を求めている。memoを使って同じマス目に来た時に繰り返し処理をしなくてもいいようにしている。という表面上の動作の理解はしています。しかし実際にmemo値をどのように参照しているのか、元を言えば実際に値を入れて計算した時どのような順序でこの関数が動いているのかが分かってません。
教えていただけたら幸いです。

python

1def v2xy(M, v):2 y = v // M 3 x = v % M 4 return x, y 5 6def xy2v(M, x, y):7 return y * M + x 8 9def enum_moves(M, N, v):10 x, y = v2xy(M, v)11 moves = []12 13 # 左に2マス進み上に1マス (x - 2, y - 1)14 if x - 2 >= 0 and y - 1 >= 0:15 moves.append(xy2v(M, x - 2, y - 1))16 17 # 左に2マス進み下に1マス (x - 2, y + 1)18 if x - 2 >= 0 and y + 1 < N:19 moves.append(xy2v(M, x - 2, y + 1))20 21 # 上に2マス進み右に1マス (x + 1, y - 2)22 if x + 1 < M and y - 2 >= 0:23 moves.append(xy2v(M, x + 1, y - 2))24 25 # 上に2マス進み左に1マス (x - 1, y - 2)26 if x - 1 >= 0 and y - 2 >= 0:27 moves.append(xy2v(M, x - 1, y - 2))28 29 return moves 30 31def f(M, N, v, memo=None):32 if memo is None:33 memo = {}34 35 if v in memo:36 return memo[v]37 38 moves = enum_moves(M, N, v)39 40 if not moves:41 memo[v] = 042 return 043 44 max_moves = 045 for move in moves:46 max_moves = max(max_moves, f(M, N, move, memo))47 48 memo[v] = max_moves + 149 return memo[v]50 51 52 53 54M = 1055N = 856v =2357moves = enum_moves(M, N, v)58print(f"{v} から1回の着手で移動可能なマス目番号: {moves}")59max_moves = f(M, N, v)60print(f"{v} からこれ以上移動できなくなるまでの最大着手回数: {max_moves}")

コメントを投稿

0 コメント