シェルスクリプト:四目並べ(Connect Four)ゲーム

 シェルスクリプトは、システム管理だけでなく、テキストベースのゲーム作成にも活用できる強力なツールです。ここでは、シェルスクリプトを使って「四目並べ(Connect Four)ゲーム」を作成し、その手順と詳細な解説を行います。四目並べは、縦6行×横7列のグリッドで行われる2人用のボードゲームで、縦・横・斜めのいずれかに自分の色のコマを4つ並べた方が勝利します。この演習を通じて、シェルスクリプトの基本的な構文、配列の操作、条件分岐、ループ、ユーザー入力の処理などの知識を総合的に学ぶことができます。

ゲームの概要

ゲームの目的

  • 自分のコマを縦・横・斜めのいずれかに4つ連続して並べることを目指します。

ゲームのルール

  1. ゲームの進行
    ・プレイヤーとコンピュータは交互にターンを行います。
    ・各ターンで、プレイヤーは列を選択し、自分のコマをその列の最も下の空いているマスに配置します。
    ・グリッドは縦6行×横7列で構成されています。
  2. 勝利条件
    ・自分のコマを縦・横・斜めのいずれかに4つ連続して並べると勝利となります。
    ・全てのマスが埋まっても勝者がいない場合は引き分けです。

connect_four.shの作成から実行までの手順と解説

ステップ1:スクリプトファイルの作成

 ターミナルで以下のコマンドを実行し、新しいスクリプトファイル connect_four.sh を作成します。

user01@ubuntu:~$ nano connect_four.sh

ステップ2:スクリプトの内容を記述

エディタが開いたら、以下のコードをコピーして貼り付けます。

#!/bin/bash

# ボードの初期化
initialize_board() {
    for ((i=0; i<6; i++)); do
        for ((j=0; j<7; j++)); do
            board[$i,$j]="."
        done
    done
}

# ボードの表示
display_board() {
    echo " 0 1 2 3 4 5 6"
    for ((i=0; i<6; i++)); do
        for ((j=0; j<7; j++)); do
            echo -n " ${board[$i,$j]}"
        done
        echo
    done
}

# コマを配置する
place_disk() {
    local column=$1
    local player=$2
    for ((i=5; i>=0; i--)); do
        if [ "${board[$i,$column]}" == "." ]; then
            board[$i,$column]=$player
            last_row=$i
            last_col=$column
            return 0
        fi
    done
    return 1  # 列が埋まっている
}

# 勝利の確認
check_winner() {
    local player=$1
    local directions=(
        "0 1"   # 横方向
        "1 0"   # 縦方向
        "1 1"   # 斜め右下
        "1 -1"  # 斜め左下
    )
    for dir in "${directions[@]}"; do
        dx=${dir% *}
        dy=${dir#* }
        count=1
        for ((k=1; k<4; k++)); do
            nx=$((last_row + dx * k))
            ny=$((last_col + dy * k))
            if [ $nx -ge 0 ] && [ $nx -lt 6 ] && [ $ny -ge 0 ] && [ $ny -lt 7 ] && [ "${board[$nx,$ny]}" == "$player" ]; then
                count=$((count + 1))
            else
                break
            fi
        done
        for ((k=1; k<4; k++)); do
            nx=$((last_row - dx * k))
            ny=$((last_col - dy * k))
            if [ $nx -ge 0 ] && [ $nx -lt 6 ] && [ $ny -ge 0 ] && [ $ny -lt 7 ] && [ "${board[$nx,$ny]}" == "$player" ]; then
                count=$((count + 1))
            else
                break
            fi
        done
        if [ $count -ge 4 ]; then
            return 0  # 勝利
        fi
    done
    return 1  # 勝利ではない
}

# ボードが満杯か確認
is_board_full() {
    for ((j=0; j<7; j++)); do
        if [ "${board[0,$j]}" == "." ]; then
            return 1  # まだ空きがある
        fi
    done
    return 0  # 満杯
}

# メインゲームループ
declare -A board
initialize_board

current_player="X"  # プレイヤーは "X"
computer_player="O"  # コンピュータは "O"

while true; do
    display_board
    while true; do
        read -p "コマを落とす列を選んでください(0〜6): " column
        if ! [[ "$column" =~ ^[0-6]$ ]]; then
            echo "無効な入力です。0〜6の数字を入力してください。"
            continue
        fi
        place_disk "$column" "$current_player"
        if [ $? -eq 0 ]; then
            break
        else
            echo "その列は満杯です。別の列を選んでください。"
        fi
    done
    check_winner "$current_player"
    if [ $? -eq 0 ]; then
        display_board
        echo "おめでとうございます!あなたの勝ちです!"
        exit
    fi
    is_board_full
    if [ $? -eq 0 ]; then
        display_board
        echo "引き分けです!"
        exit
    fi

    # コンピュータのターン
    echo "コンピュータのターンです。"
    sleep 1
    while true; do
        column=$((RANDOM % 7))
        place_disk "$column" "$computer_player"
        if [ $? -eq 0 ]; then
            echo "コンピュータは列 $column にコマを落としました。"
            break
        fi
    done
    check_winner "$computer_player"
    if [ $? -eq 0 ]; then
        display_board
        echo "残念!コンピュータの勝ちです。"
        exit
    fi
    is_board_full
    if [ $? -eq 0 ]; then
        display_board
        echo "引き分けです!"
        exit
    fi
done

ステップ3:スクリプトの内容の解説

1.シェバン行

#!/bin/bash
  • スクリプトが Bash シェルで実行されることを指定します。

2.ボードの初期化関数 initialize_board

initialize_board() {
    for ((i=0; i<6; i++)); do
        for ((j=0; j<7; j++)); do
            board[$i,$j]="."
        done
    done
}
  • 目的:6行×7列のボードを初期化し、全てのマスを "."(空きマス)で埋めます。
  • 解説
    ・二重ループで全てのマスを初期化します。
    ・ボードは連想配列 board を使用して管理します。

3.ボードの表示関数 display_board

display_board() {
    echo " 0 1 2 3 4 5 6"
    for ((i=0; i<6; i++)); do
        for ((j=0; j<7; j++)); do
            echo -n " ${board[$i,$j]}"
        done
        echo
    done
}
  • 目的:現在のボードの状態を表示します。
  • 解説:列番号を表示し、視覚的にボードの状態を確認できます。

4.コマを配置する関数 place_disk

place_disk() {
    local column=$1
    local player=$2
    for ((i=5; i>=0; i--)); do
        if [ "${board[$i,$column]}" == "." ]; then
            board[$i,$column]=$player
            last_row=$i
            last_col=$column
            return 0
        fi
    done
    return 1  # 列が埋まっている
}
  • 目的:指定した列にコマを配置します。
  • 解説
    ・下から上に向かって空きマスを探し、最も下の空きマスにコマを配置します。
    ・配置した位置を last_rowlast_col に保存します。
    ・列が満杯の場合はエラーを返します。

5.勝利の確認関数 check_winner

check_winner() {
    local player=$1
    local directions=(
        "0 1"   # 横方向
        "1 0"   # 縦方向
        "1 1"   # 斜め右下
        "1 -1"  # 斜め左下
    )
    for dir in "${directions[@]}"; do
        dx=${dir% *}
        dy=${dir#* }
        count=1
        # 正方向のチェック
        # 逆方向のチェック
        if [ $count -ge 4 ]; then
            return 0  # 勝利
        fi
    done
    return 1  # 勝利ではない
}
  • 目的:最後に置いたコマから、縦・横・斜めに4つ連続したコマがあるかを確認します。
  • 解説
    ・4つの方向を定義し、各方向に対して同じ色のコマが連続しているかを調べます。
    count が4以上になれば勝利です。

6.ボードが満杯か確認する関数 is_board_full

is_board_full() {
    for ((j=0; j<7; j++)); do
        if [ "${board[0,$j]}" == "." ]; then
            return 1  # まだ空きがある
        fi
    done
    return 0  # 満杯
}
  • 目的:ボードに空きがあるかを確認します。
  • 解説:最上段のマスに空きがあるかを調べ、空きがなければボードは満杯です。

7.メインゲームループ

declare -A board
initialize_board

current_player="X"  # プレイヤーは "X"
computer_player="O"  # コンピュータは "O"

while true; do
    # プレイヤーのターン
    # 勝利と引き分けの確認
    # コンピュータのターン
    # 勝利と引き分けの確認
done

解説

  • ゲームが終了するまで、プレイヤーとコンピュータのターンを繰り返します。
  • 各ターンでコマを配置し、勝利または引き分けを確認します。
  • コンピュータはランダムに列を選択します。

ステップ4:スクリプトに実行権限を付与

スクリプトを保存してエディタを終了したら、実行権限を付与します。

user01@ubuntu:~$ chmod +x connect_four.sh

ステップ5:スクリプトの実行

スクリプトを実行して、四目並べゲームを開始します。

user01@ubuntu:~$ ./connect_four.sh

実行例

 0 1 2 3 4 5 6
 . . . . . . .
 . . . . . . .
 . . . . . . .
 . . . . . . .
 . . . . . . .
 . . . . . . .
コマを落とす列を選んでください(0〜6): 3
コンピュータのターンです。
コンピュータは列 5 にコマを落としました。
 0 1 2 3 4 5 6
 . . . . . . .
 . . . . . . .
 . . . . . . .
 . . . . . . .
 . . . . . . .
 . . . X . O .
コマを落とす列を選んでください(0〜6):

解説

  • プレイヤーは 0〜6 の数字で列を選択し、コマを配置します。
  • コンピュータはランダムに列を選択してコマを配置します。
  • 勝利または引き分けになるとゲームが終了し、結果が表示されます。

ここで作成したファイルの削除

ゲームのテストが終了したら、作成した connect_four.sh ファイルを削除します。

user01@ubuntu:~$ rm connect_four.sh

まとめ

  • シェルスクリプトの応用:四目並べゲームを通じて、シェルスクリプトでのゲーム作成方法を学びました。
  • 配列の操作:二次元配列を使用してボードを管理し、効率的にデータを扱いました。
  • 条件分岐とループif 文や while ループを使って、ゲームの進行とロジックを制御しました。
  • ユーザー入力の処理read コマンドを使用してユーザーの入力を受け取り、入力のバリデーションを行いました。
  • 関数の活用:関連する処理を関数としてまとめ、コードの再利用性と可読性を向上させました。
  • ゲームロジックの実装:四目並べのルールに基づくロジックをシェルスクリプトで実装しました。

 シェルスクリプトは、システム管理以外にも多くの用途で活用できます。今回の四目並べゲームを基に、コンピュータのAIを強化したり、GUIを導入したり、ボードサイズを変更したりして、さらなる機能拡張に挑戦してみてください。