Stage 3 盤面のクラスの基本機能を作る
3-2 コンストラクタ
普通ならコンストラクタはクラスの冒頭に持ってくるべきなんでしょうけれども、この 2048 では初期設定をする際に数字を 2 個ランダムに入れなければなりませんから、前回の 3-1 で先にその機能を insert メソッドとして実装したんでした。
でもコンストラクタはどうせ作るんやろ
~~~~~~~~~~~~~~~
まずはコードを見ていただきましょう。
def __init__(self, *, size=DEFAULT_SIZE, board=[], goal=DEFAULT_GOAL, logger=local_logger, prob4=DEFAULT_PROB4):
# copying the parameters
self.size = size
self.prob4 = prob4
self.logger = logger
if goal > MAX_GOAL:
self.goal = MAX_GOAL
else:
self.goal = goal
# copying the board
if len(board) == self.size:
self.board = copy.deepcopy(board)
else:
self.board = [[EMPTY for col in range(self.size)] for row in range(self.size)]
self.insert(logger=logger)
self.insert(logger=logger)
logger.debug('in {}, board is {}'.format(self, self.board))
1-1 でもわずかに触れましたが、各種パラメーターは変更が効く方がいいので、
- 盤面のサイズ
- 盤面
- アガリの数
- ロガー
- 4 が挿入される確率
を引数に入れてしまいましょう。
def __init__(self, *, size=DEFAULT_SIZE, board=[], goal=DEFAULT_GOAL, logger=local_logger, prob4=DEFAULT_PROB4):
~~~~~~~~~~~~~~~
中身に入りましょう。まずサイズと 4 が出る確率、ロガーは引数をそのまま使います。
def __init__(self, *, size=DEFAULT_SIZE, board=[], goal=DEFAULT_GOAL, logger=local_logger, prob4=DEFAULT_PROB4):
# copying the parameters
self.size = size
self.prob4 = prob4
self.logger = logger
if goal > MAX_GOAL:
self.goal = MAX_GOAL
else:
self.goal = goal
さて、ここで調節が必要になってくる引数がいくつかありますが、先にアガリの数に取り掛かりましょう。
2-2 で申し上げた通り、このあと扱う盤面表示のサイズの問題で使える数は、このコードでは最大で 5 桁です。なので取りうる値で一番大きい MAX_GOAL と比較して、これを上回るようなことがあれば無理やり MAX_GOAL にしてしまいます。それ以外は引数をそのまま使いましょう。
if goal > MAX_GOAL:
self.goal = MAX_GOAL
else:
self.goal = goal
~~~~~~~~~~~~~~~
次に盤面を入力された場合の対処です。self.size ですでに盤面のサイズは指定しましたから、「もしサイズを満たすリストが board として入力されたら」という条件分岐で対処します。
# copying the board
if len(board) == self.size:
self.board = copy.deepcopy(board)
else:
self.board = [[EMPTY for col in range(self.size)] for row in range(self.size)]
self.insert(logger=logger)
self.insert(logger=logger)
ここで、盤面を引数から受け継ぐときは必ず deepcopy メソッドを使いましょう。Python でリスト型はミュータブルなので、これがないとクラス内の変更が引数として入れただけのリストにまで及んでしまいます。
なるほどね〜理解理解
わからなければリンクから備忘録をご覧になるなり、丁寧な解説を探すなりしてください。
~~~~~~~~~~~~~~~
board として有効なリストが入力されていない場合、つまり引数に盤面を入力しなかった場合は我々の方で盤面を新しく用意してあげる必要があります。盤面のサイズに合わせてまずは全てのマスを EMPTY で埋めつくし、
else:
self.board = [[EMPTY for col in range(self.size)] for row in range(self.size)]
self.insert(logger=logger)
self.insert(logger=logger)
そのあと 2 回に分けて insert メソッドを使って数字を入力します。
else:
self.board = [[EMPTY for col in range(self.size)] for row in range(self.size)]
self.insert(logger=logger)
self.insert(logger=logger)