【Python】レッスン4-☆3:マルバツゲームを作ろう

記事内に商品プロモーションを含む場合があります

この記事の練習問題で使用する知識:
1.基礎文法、2.制御構造、3.関数とスコープ、4.データ構造、5.オブジェクト指向

Pythonのゲームコード一覧はこちら

<<前のページ Python記事一覧
次のページ>>

練習問題4-☆2:Pythonでマルバツゲームを作ろう

Pythonを使用してコンピュータと対戦する簡単なマルバツゲームを作成しましょう。

プレイヤーとコンピュータが交互に○と×を選択し、最初に縦・横・斜めのラインを揃えた方が勝ちです。

このプログラムでは、ユーザーからの入力に応じて盤面を更新し、勝利または引き分けを判定します。

ゲームが終了した後は結果を表示します。

問題の詳細条件

以下の要件に従ってコードを完成させてください。

  • 1から9までの数字で構成される3×3のマス目(グリッド)を作成すること。
  • プレイヤーは「○」、コンピュータは「×」を使うこと。
  • ユーザーが指定したマスに「○」を置き、コンピュータは空いているマスをランダムに選んで「×」を置くこと。
  • 縦・横・斜めに同じマークが3つ並んだら、そのマークを使用しているプレイヤーが勝利すること。
  • 引き分けの判定も行うこと(すべてのマスが埋まり、勝者がいない場合)。
  • 各ターンごとに現在の盤面を表示すること。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

マルバツゲームを開始します!
1 | 2 | 3
--+---+--
4 | 5 | 6
--+---+--
7 | 8 | 9
どのマスに置きますか?(1-9で入力してください)> 1
○ | 2 | 3
--+---+--
4 | 5 | 6
--+---+--
7 | 8 | 9
コンピュータのターンです...
コンピュータが選んだマス: 5
○ | 2 | 3
--+---+--
4 | × | 6
--+---+--
7 | 8 | 9

【ヒント】難しいと感じる人だけ見よう

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。
(※下記の□はコード内のインデントを表しています)

1:Randomモジュールのインポート
2:関数display_boardの定義
  □ f文字列を使用して3×3のグリッドを表示
3:関数check_winの定義
  □ 勝利パターン(win_patterns)をリストで定義
  □ リスト内包表記を使い、指定されたパターンとプレイヤーのマークを比較して勝利を判定
4:関数check_drawの定義
  □ リスト内包表記を使い、盤面が全て埋まっているかを判定
5:関数computer_moveの定義
  □ リスト内包表記を使用して空いているマスを抽出
  □ random.choiceで空いているマスから1つをランダムに選択
6:関数play_gameの定義
  □ 盤面を初期化し、プレイヤーとコンピュータが交互にターンを行うループを開始
7:whileループの開始
  □ 盤面を表示するためにdisplay_boardを呼び出し
8:プレイヤーのターンの処理
  □ try-except構文でプレイヤーの入力を取得
  □ 入力されたマスが空いているかを確認し、「○」を配置
9:check_win関数を呼び出してプレイヤーの勝利を判定
  □ プレイヤーが勝利した場合、盤面を表示してゲームを終了
10:check_draw関数を呼び出して引き分けを判定
  □ 引き分けの場合、盤面を表示してゲームを終了
11:コンピュータのターンの処理
  □ computer_move関数を呼び出してコンピュータの選択を決定
  □ コンピュータの選択したマスに「×」を配置
12:check_win関数を呼び出してコンピュータの勝利を判定
  □ コンピュータが勝利した場合、盤面を表示してゲームを終了
13:check_draw関数を呼び出して引き分けを判定
  □ 引き分けの場合、盤面を表示してゲームを終了

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

import random

# グリッドを表示する関数
def display_board(board):
    print(f"{board[ 0]} | {board[ 1]} | {board[ 2]}")
    print("--+---+--")
    print(f"{board[ 3]} | {board[ 4]} | {board[ 5]}")
    print("--+---+--")
    print(f"{board[ 6]} | {board[ 7]} | {board[ 8]}")

# 勝利を判定する関数
def check_win(board, mark):
    """【穴埋め問題1】  
    ここに勝利パターンをリストで定義し、勝利判定を行うコードを書いてください。
    """

# 引き分けを判定する関数
def check_draw(board):
    """【穴埋め問題2】  
    ここに引き分けを判定するリスト内包表記のコードを書いてください。
    """

# コンピュータがランダムにマスを選ぶ関数
def computer_move(board):
    """【穴埋め問題3】  
    ここに空いているマスをランダムに選んで返すコードを書いてください。
    """

# マルバツゲームのメイン関数
def play_game():
    board = [str(i) for i in range(1, 10)]  # 1から9までの番号が入ったグリッド
    print("マルバツゲームを開始します!")

    while True:
        display_board(board)

        # プレイヤーのターン
        while True:
            try:
                player_move = int(input("どのマスに置きますか?(1-9で入力してください)> ")) - 1
                if board[player_move] not in ["○", "×"]:
                    board[player_move] = "○"
                    break
                else:
                    print("そのマスはすでに埋まっています。別のマスを選んでください。")
            except (ValueError, IndexError):
                print("無効な入力です。1から9の数字を入力してください。")

        # 勝利判定
        """【穴埋め問題4】  
        ここにプレイヤーの勝利判定のコードを書いてください。
        """

        # 引き分け判定
        """【穴埋め問題5】  
        ここに引き分けの判定を行うコードを書いてください。
        """

        # コンピュータのターン
        print("コンピュータのターンです...")
        """【穴埋め問題6】  
        ここにコンピュータの選択とそのマスに「×」を配置するコードを書いてください。
        """

        # 勝利判定
        """【穴埋め問題7】  
        ここにコンピュータの勝利判定のコードを書いてください。
        """

        # 引き分け判定
        """【穴埋め問題8】  
        ここに引き分けの判定を行うコードを書いてください。
        """

if __name__ == "__main__":
    play_game()

以上がマルバツゲームの穴埋めコードです。

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

問題の答え合わせと解説

この問題の一つの正解例とそのコードの解説を以下に示します。

一つの正解例

例えば以下のようなプログラムが考えられます。

import random

# グリッドを表示する関数
def display_board(board):
    print(f"{board[ 0]} | {board[ 1]} | {board[ 2]}")
    print("--+---+--")
    print(f"{board[ 3]} | {board[ 4]} | {board[ 5]}")
    print("--+---+--")
    print(f"{board[ 6]} | {board[ 7]} | {board[ 8]}")

# 勝利を判定する関数
def check_win(board, mark):
    win_patterns = [
        [ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8],  # 横
        [ 0, 3, 6], [ 1, 4, 7], [ 2, 5, 8],  # 縦
        [ 0, 4, 8], [ 2, 4, 6]              # 斜め
    ]
    return any(all(board[i] == mark for i in pattern) for pattern in win_patterns)

# 引き分けを判定する関数
def check_draw(board):
    return all(space == "○" or space == "×" for space in board)

# コンピュータがランダムにマスを選ぶ関数
def computer_move(board):
    available_moves = [i for i, space in enumerate(board) if space != "○" and space != "×"]
    return random.choice(available_moves)

# マルバツゲームのメイン関数
def play_game():
    board = [str(i) for i in range(1, 10)]  # 1から9までの番号が入ったグリッド
    print("マルバツゲームを開始します!")

    while True:
        # 現在のグリッドを表示
        display_board(board)

        # プレイヤーのターン
        while True:
            try:
                player_move = int(input("どのマスに置きますか?(1-9で入力してください)> ")) - 1
                if board[player_move] not in ["○", "×"]:
                    board[player_move] = "○"
                    break
                else:
                    print("そのマスはすでに埋まっています。別のマスを選んでください。")
            except (ValueError, IndexError):
                print("無効な入力です。1から9の数字を入力してください。")

        # 勝利判定
        if check_win(board, "○"):
            display_board(board)
            print("プレイヤーの勝ちです!")
            break

        # 引き分け判定
        if check_draw(board):
            display_board(board)
            print("引き分けです!")
            break

        # コンピュータのターン
        print("コンピュータのターンです...")
        comp_move = computer_move(board)
        board[comp_move] = "×"
        print(f"コンピュータが選んだマス: {comp_move + 1}")

        # 勝利判定
        if check_win(board, "×"):
            display_board(board)
            print("コンピュータの勝ちです!")
            break

        # 引き分け判定
        if check_draw(board):
            display_board(board)
            print("引き分けです!")
            break

if __name__ == "__main__":
    play_game()

正解例の詳細解説

このPythonプログラムではプレイヤーとコンピュータが交互に○と×を配置して勝敗を競う「マルバツゲーム」を実装しています。

以下にプログラムの各部分を詳しく解説します。

ライブラリのインポート

import random

randomモジュールはコンピュータが次に置く場所をランダムに選ぶために使用されます。

このモジュールには乱数を生成するための便利な関数が用意されています。

グリッドを表示する関数

def display_board(board):
    print(f"{board[ 0]} | {board[ 1]} | {board[ 2]}")
    print("--+---+--")
    print(f"{board[ 3]} | {board[ 4]} | {board[ 5]}")
    print("--+---+--")
    print(f"{board[ 6]} | {board[ 7]} | {board[ 8]}")

この関数は現在の盤面(グリッド)を表示します。

boardリストには1から9までの数字が入っており、プレイヤーやコンピュータがマークを置くとその位置が○や×に変わります。

f文字列を使って盤面を整った形で表示しています。

勝利を判定する関数

def check_win(board, mark):
    win_patterns = [
        [0, 1, 2], [3, 4, 5], [6, 7, 8],  # 横
        [0, 3, 6], [1, 4, 7], [2, 5, 8],  # 縦
        [0, 4, 8], [2, 4, 6]              # 斜め
    ]
    return any(all(board[i] == mark for i in pattern) for pattern in win_patterns)

check_win関数は指定されたマーク(○や×)が勝利条件を満たしているかを判定します。

勝利条件は、横、縦、斜めのいずれかのラインに同じマークが3つ並ぶことです。

リスト内包表記を使って効率的に判定しています。

引き分けを判定する関数

def check_draw(board):
    return all(space == "○" or space == "×" for space in board)

この関数は盤面が全て埋まっていて、かつどちらも勝っていない場合に引き分けかどうかを判定します。

all関数を使って、全てのマスが○または×で埋まっているか確認しています。

コンピュータの動きを決める関数

def computer_move(board):
    available_moves = [i for i, space in enumerate(board) if space != "○" and space != "×"]
    return random.choice(available_moves)

computer_move関数は空いているマスをランダムに選び、コンピュータがそのマスに×を置くために使います。

enumerateでリストのインデックスと要素を取得し空いているマスをリストに追加します。

その後random.choiceでその中から1つのマスを選びます。

メインのゲームロジック

def play_game():
    board = [str(i) for i in range(1, 10)]  # 1から9までの番号が入ったグリッド
    print("マルバツゲームを開始します!")

    while True:
        display_board(board)

        # プレイヤーのターン
        while True:
            try:
                player_move = int(input("どのマスに置きますか?(1-9で入力してください)> ")) - 1
                if board[player_move] not in ["○", "×"]:
                    board[player_move] = "○"
                    break
                else:
                    print("そのマスはすでに埋まっています。別のマスを選んでください。")
            except (ValueError, IndexError):
                print("無効な入力です。1から9の数字を入力してください。")

play_game関数がゲームのメイン部分です。

boardリストを1から9までの数字で初期化し、プレイヤーとコンピュータが交互に○と×を置きます。

プレイヤーの入力にはエラーチェックを行い、無効な入力があれば再入力を促します。

勝敗や引き分けの判定

        if check_win(board, "○"):
            display_board(board)
            print("プレイヤーの勝ちです!")
            break

        if check_draw(board):
            display_board(board)
            print("引き分けです!")
            break

プレイヤーがマークを置いた後、check_win関数で勝利判定を行い、勝利の場合はゲームが終了します。

また全てのマスが埋まっていれば引き分けと判定されます。

コンピュータのターン

        print("コンピュータのターンです...")
        comp_move = computer_move(board)
        board[comp_move] = "×"
        print(f"コンピュータが選んだマス: {comp_move + 1}")

        if check_win(board, "×"):
            display_board(board)
            print("コンピュータの勝ちです!")
            break

        if check_draw(board):
            display_board(board)
            print("引き分けです!")
            break

コンピュータはcomputer_move関数でランダムにマスを選び、×を置きます。

その後、プレイヤーと同様に勝利や引き分けの判定を行います。

まとめ

このプログラムでは基本的なPythonの構造(関数、リスト、条件分岐、ループ)を学びながら、マルバツゲームのロジックを理解できます。

実際に手を動かして、さらに自分なりにカスタマイズしてみると、より深い理解につながるでしょう。

継続して練習し、コードを書く力を伸ばしていきましょう!

Pythonのゲームコード一覧はこちら

<<前のページ Python記事一覧
次のページ>>

質問用コンタクトフォーム

この記事はAIを用いて書いた記事です。

人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。






    Python記事一覧へ戻る
    トップページへ戻る