▼問題
▼改善前の問題点とコード
8方向の処理がほぼ同じであるにも関わらず、すべて別で書いていた。コードの行数が増え、DRY (Don't Repeat Yourself) 原則に反していた。8方向とは、上下左右と、右上,右下,左上,左下の4方向です。
▼改善後の考え方とコード、改善の成果
▽改善後の考え方
新しく考えた内容1.2.を以下に示します。
-
ほぼ同じ処理はまとめて書きます。8方向の単位ベクトルを1つずつ関数reversi_positionsに渡し、帰り値として、石を置くことができる(y,x)を受け取ります。
-
単位ベクトルを、盤面内かつ石を置くことができる間、拡大させていきます。条件に合致する盤面内の(y,x)は、仮でリストnewpositionsに保存します。
-
実際に盤面に石を置くことができる条件に合致した場合は、newpositionsを返します。合致しなかった場合は(石を置けないので)空を返します。条件とは、盤面内かつ、すでに置かれている石が存在することです。(Y,X)の石とすでに置かれている石で挟む必要があるからです。
▽改善の成果
・改善前がコードの行数が97だったのに対し、改善後は19にすることができました。
▽改善後のコード
############### 関数処理 ###############
# reversi_positions: 新しく石を置くことができる(y,x)を求める関数
def reversi_positions(dy, dx):
# newpositions: 新しく石を置くことができる(y,x)を格納するリスト
newpositions = []
# tmp_y,tmp_x: 単位ベクトルを、Yから1つずつ拡大させるための変数
tmp_y,tmp_x = Y+dy,X+dx
# 考え方2.
while (0 <= tmp_y <= H-1) and (0 <= tmp_x <= W-1) and (S[tmp_y][tmp_x] == "."):
newpositions.append((tmp_y,tmp_x))
tmp_y,tmp_x = tmp_y+dy,tmp_x+dx
# 考え方3.
return newpositions if (0 <= tmp_y <= H-1) and (0 <= tmp_x <= W-1) and (S[tmp_y][tmp_x] == "*") else []
# set_stones: 石を置き盤面を更新する関数
def set_stones():
S[Y][X] = "*"
# 考え方1.
for dy, dx in (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1):
for y, x in reversi_positions(dy, dx):
S[y][x] = "*"
############### メイン関数処理 ###############
H,W,Y,X = map(int, input().split())
S = [list(input()) for _ in range(H)]
set_stones()
for s in S:
print(*s, sep="")