「15パズル」移動回数のカウント

学習の目的

  • ・移動回数のカウント

ここでは、移動回数を確認する機能を追加します。

移動回数のカウント

今回修正を加えるのは、プログラム1とプログラム7です。

この二つの修正前のプログラムを確認できるようにしておきますね。

プログラム1:盤面モデルの作成(修正前)

# プログラム1
def init():
    global tiles
    tiles = [
        [1,2,3,4],
        [5,6,7,8],
        [9,10,11,12],
        [13,14,15,0]
    ]

プログラム7:ボタン設定・配置(修正前)

# プログラム7
import ipywidgets as widgets
from IPython.display import display, clear_output
import random
# 表示を更新
def update_display():
    clear_output(wait=True)
    grid = []
    for i in range(4):
        row = []
        for j in range(4):
            num = tiles[i][j]
            label = str(num) if num != 0 else ""
            btn = widgets.Button(description=label, layout=widgets.Layout(width='50px', height='50px'))
            def on_click(b, i=i, j=j):
                if can_move(i, j):
                    move_tile(i, j)
                    update_display()
            btn.on_click(on_click)
            row.append(btn)
        grid.append(row)

    # ステータス表示
    if is_goal():
        status = widgets.HTML(value="You Win!")
    else:
        status = widgets.HTML(value="")

    # リセットボタン
    reset_btn = widgets.Button(description="Reset", layout=widgets.Layout(width='100px'))
    def on_reset(b):
        shuffle()
        update_display()
    reset_btn.on_click(on_reset)

    #「」、数字ボタンの表示
    display(widgets.VBox([
        widgets.GridBox(sum(grid, []), layout=widgets.Layout(grid_template_columns="repeat(4, 50px)")),
        status,
        reset_btn
    ]))

移動回数を記録するための変数が必要になりますよね?

そうですね。まずは変数を作成しましょう。

また、ここからは空欄が出てきます。空欄を埋めながら進めていきましょう。


①変数の作成

プログラム1に、以下の修正を追加して、実行してください。

また、空欄【 A 】に入る適切な字句を入れてください。

# プログラム1
def init():
    global tiles,moves #movesの追加
    tiles = [
        [1,2,3,4],
        [5,6,7,8],
        [9,10,11,12],
        [13,14,15,0]
    ]
    moves = 【 A 】 # 移動回数をカウントする変数

変数「moves」が移動回数を数える変数ですね。

その通りです。

空欄には、最初に入れるべき値ですよね。

まだ1回も移動はしていないわけだから…?


②クリック時に、moves変数に1を加算

プログラム7に、以下の変更を加えます。

また、空欄【 B 】に入る適切な字句を入れてください。

※ここで記載されている部分は、プログラムの一部になるので注意してください。

            def on_click(b, i=i, j=j):
                global moves # movesを関数内で使用するための宣言を追加
                if can_move(i, j):
                    move_tile(i, j)
                    moves = moves + 【 B 】 #movesに加算する処理を追加
                    update_display()

ここでは、クリックし、マスを交換した後にmovesに加算しています。

実際に交換を行うmove_tile関数の中ではダメなのですか?

追加した処理の直前でも実行しているじゃないですか。

move_tile関数は、最初に盤面モデルをバラバラにする、shuffle関数でも使用しています。

そうか、そこだとシャッフルの回数もカウントされるから、最初から移動回数が大変なことになっちゃうね。


③リセット時に、moves変数を初期化

プログラム7に、以下の変更を加えます。

また、空欄【 C 】に入る適切な字句を入れてください。

※ここで記載されている部分は、プログラムの一部になるので注意してください。

②の変更と同じプログラムです。

変更を加えたことで、行番号が変化していますが、ここでは変更前のプログラムの行番号で記載します。

注意をしてください。

    def on_reset(b):
        global moves # movesを関数内で使用するための宣言を追加
        shuffle()
        【 C 】 # movesを初期化する処理を追加
        update_display()

Resetボタンを押した時に実行する関数の中で、movesの値を初期化しましょう。


④画面に移動回数を表示

プログラム7に、以下の変更を加えます。

※ここで記載されている部分は、プログラムの一部になるので注意してください。

ここも、②・③と同じプログラムです。

先ほど同様、元の行番号を記載しているので行番号に注意してください。

    #「」、数字ボタンの表示
    moves_lvl = widgets.HTML(value=f"移動回数: {moves}") # 移動回数を表示する部分を作成
    display(widgets.VBox([
        widgets.GridBox(sum(grid, []), layout=widgets.Layout(grid_template_columns="repeat(4, 50px)")),
        status,
        moves_lvl, # 移動回数を表示する部分を組み込む
        reset_btn]))

これで移動回数が表示されます。

プログラム7を実行したのち、プログラム8を実行して確認しましょう。

以下のような実行例になっていれば、問題ありません。

プログラムの各空欄に入れる答え

【 A 】0


【 B 】1


【 C 】moves = 0


Well done!

次のステップに進みましょう!

次のステップに進む

← 前のステップにもどる