▼問題
▼改善前の問題点とコード
A用の処理とB用の処理が似たような処理であるにもかかわらず、別々に書いていた。そのため、コードの行数が多くなった。また、A,Bそれぞれにリストや変数を用意したため使用したリソースが増えてしまった。
▼改善後の考え方とコード、改善の成果
▽改善後の考え方
新しく考えた内容1.2.を以下に示します。
-
問題文では、盤面は2次元で示されていますが、盤面のマスの内容は1次元のリストSで管理します。例えば3×3の盤面の場合、マスの内容はS[0]~S[8]で管理します。盤面の左上の座標を(y,x)=(0,0)とすると、(y,x)=(0,2)のマスの内容はS[2]で管理します。divmod(Sのindex,W)=div(0,3)の商がy,余りがxになります。(y,x)=(2,1)の要素はS[7]で管理します。上記と同様にdiv(7,3)の商がy,余りがxになります。
-
前の番で勝ち取ったマスの(y,x)の情報をすべてchanges関数に送り、次の番で勝ち取れるマスの(y,x)を計算します。その結果の重複を排除し、再びp[n]に格納します。p[n]のとおり盤面のマスの内容を更新し、n = 1-n でAとBの順番を入れ替えます。while文を用いて上記の処理を、勝ち取ったマスがなくなるまで繰り返します。
▽改善の成果
・改善前がコードの行数が58だったのに対し、改善後は18にすることができました。
▽改善後のコード
############### 関数処理 ###############
H, W = map(int, input().split())
N = input()
# S: 盤面のマスの内容を管理する一次元リスト
S = [s for _ in range(H) for s in input()]
# changes: 前の番で勝ち取ったマスの(y,x)から、次の番で勝ち取れるマスを計算する関数
def changes(positions):
# posisions: 前の番で勝ち取ったマスの(y,x)を格納するリスト
for (y, x) in positions:
# ny,nx :前の番で勝ち取ったマスの(y,x)の上下左右のマスの座標を格納する変数
for ny, nx in (y - 1, x), (y + 1, x), (y, x - 1), (y, x + 1):
if 0 <= ny < H and 0 <= nx < W and S[ny * W + nx] == '.':
yield (ny, nx)
# 考え方1.
# n: n=0ならA、n=1ならBを示す変数
n = 0 if N == "A" else 1
# p: p[0]は、前の番でAが勝ち取ったマスの(y,x)を示す。p[1]はBのものを示す。
p = [
{divmod(s_index, W) for s_index,s_value in enumerate(S) if s_value == "A"},
{divmod(s_index, W) for s_index,s_value in enumerate(S) if s_value == "B"},
]
# 考え方2.
while p[0] or p[1]:
p[n] = set(changes(p[n]))
for y, x in p[n]:
S[y * W + x] = "AB"[n]
n = 1 - n
print(a := S.count("A"), b := S.count("B"))
print("A" if a > b else "B")