Pythonプログラミングで

2048を作る

Stage 3 盤面のクラスの基本機能を作る

3-2 コンストラクタ

普通ならコンストラクタクラスの冒頭に持ってくるべきなんでしょうけれども、この 2048 では初期設定をする際に数字を 2 個ランダムに入れなければなりませんから、前回の 3-1 で先にその機能を insert メソッドとして実装したんでした。

でもコンストラクタはどうせ作るんやろ

ということで Board クラスコンストラクタを実装します。

~~~~~~~~~~~~~~~

まずはコードを見ていただきましょう。

                        
    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):
                        
                    

全てキーワード引数にしてしまいました。基本的には 2-2 で設定した定数をデフォルトに入れます。

~~~~~~~~~~~~~~~

中身に入りましょう。まずサイズと 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)
                        
                    

最後にロガーを取ったら、これでコンストラクタのコーディングは終了になります。

NEXT 3-3 インデックスが適正か判定する