このページで解説している内容は、以下の YouTube 動画の解説で見ることができます。

Linuxコマンドの基本:シェルスクリプト:三目並べ(Tic-Tac-Toe)ゲーム

シェルスクリプト:三目並べ(Tic-Tac-Toe)ゲーム

 シェルスクリプトは、システム管理やタスクの自動化だけでなく、簡単なゲームを作成するための強力なツールでもあります。ここでは、シェルスクリプトを使用して「三目並べ(Tic-Tac-Toe)ゲーム」を作成し、その手順とコードの詳細な解説を行います。この演習を通じて、シェルスクリプトの基本的な構文、制御構造、配列の操作、関数の定義と利用などを学ぶことができます。

ゲームの概要

  • 目的:ユーザーとコンピューターが交互にマス目を選び、自分のマークを縦・横・斜めのいずれか一列に揃えることを目指します。
  • ルール
    ・3×3のマス目があり、ユーザーは「X」、コンピューターは「O」のマークを使用します。
    ・マス目は1から9の番号で表され、空いているマスを選択できます。
    ・先に自分のマークを一列に揃えた方が勝ちです。
    ・全てのマスが埋まっても勝敗が決まらない場合は引き分けとなります。

スクリプトの作成から実行までの手順と解説

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

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

user01@ubuntu:~$ nano tic_tac_toe.sh

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

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

#!/bin/bash

# 三目並べのボードを初期化
board=(1 2 3 4 5 6 7 8 9)

# ボードを表示する関数
display_board() {
    echo
    echo " ${board[0]} | ${board[1]} | ${board[2]} "
    echo "---+---+---"
    echo " ${board[3]} | ${board[4]} | ${board[5]} "
    echo "---+---+---"
    echo " ${board[6]} | ${board[7]} | ${board[8]} "
    echo
}

# 勝利条件をチェックする関数
check_win() {
    win_combinations=(
        "0 1 2"  # 上段
        "3 4 5"  # 中段
        "6 7 8"  # 下段
        "0 3 6"  # 左列
        "1 4 7"  # 中列
        "2 5 8"  # 右列
        "0 4 8"  # 斜め(左上から右下)
        "2 4 6"  # 斜め(右上から左下)
    )
    for combo in "${win_combinations[@]}"; do
        set -- $combo
        if [ "${board[$1]}" == "${board[$2]}" ] && [ "${board[$2]}" == "${board[$3]}" ]; then
            winner="${board[$1]}"
            return 1
        fi
    done
    return 0
}

# 空いているマスがあるかチェックする関数
is_board_full() {
    for i in "${board[@]}"; do
        if [[ "$i" != "X" && "$i" != "O" ]]; then
            return 1  # 空いているマスがある
        fi
    done
    return 0  # ボードが満杯
}

# ユーザーのターン
user_turn() {
    while true; do
        read -p "あなたのターンです。マスの番号を選んでください(1-9): " choice
        if [[ ! "$choice" =~ ^[1-9]$ ]]; then
            echo "エラー: 1から9の数字を入力してください。"
            continue
        fi
        index=$((choice - 1))
        if [[ "${board[$index]}" == "X" || "${board[$index]}" == "O" ]]; then
            echo "そのマスは既に選ばれています。別のマスを選んでください。"
        else
            board[$index]="X"
            break
        fi
    done
}

# コンピューターのターン(ランダムに選択)
computer_turn() {
    echo "コンピューターのターンです。"
    while true; do
        index=$((RANDOM % 9))
        if [[ "${board[$index]}" != "X" && "${board[$index]}" != "O" ]]; then
            board[$index]="O"
            break
        fi
    done
}

# メインゲームループ
winner=""
while true; do
    display_board
    user_turn
    check_win
    if [ $? -eq 1 ]; then
        display_board
        echo "おめでとうございます!あなたの勝ちです。"
        break
    fi
    is_board_full
    if [ $? -eq 0 ]; then
        display_board
        echo "引き分けです。"
        break
    fi
    computer_turn
    check_win
    if [ $? -eq 1 ]; then
        display_board
        echo "残念ながら、コンピューターの勝ちです。"
        break
    fi
    is_board_full
    if [ $? -eq 0 ]; then
        display_board
        echo "引き分けです。"
        break
    fi
done

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

1.シェバン行

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

2.ボードの初期化

board=(1 2 3 4 5 6 7 8 9)
  • 三目並べのボードを配列 board で表現し、各マスに1から9の番号を割り当てます。

3.ボードを表示する関数

display_board() {
    echo
    echo " ${board[0]} | ${board[1]} | ${board[2]} "
    echo "---+---+---"
    echo " ${board[3]} | ${board[4]} | ${board[5]} "
    echo "---+---+---"
    echo " ${board[6]} | ${board[7]} | ${board[8]} "
    echo
}
  • 現在のボードの状態を視覚的に表示する関数です。

4.勝利条件をチェックする関数

check_win() {
    win_combinations=(
        "0 1 2"  # 上段
        "3 4 5"  # 中段
        "6 7 8"  # 下段
        "0 3 6"  # 左列
        "1 4 7"  # 中列
        "2 5 8"  # 右列
        "0 4 8"  # 斜め(左上から右下)
        "2 4 6"  # 斜め(右上から左下)
    )
    for combo in "${win_combinations[@]}"; do
        set -- $combo
        if [ "${board[$1]}" == "${board[$2]}" ] && [ "${board[$2]}" == "${board[$3]}" ]; then
            winner="${board[$1]}"
            return 1  # 勝者がいる
        fi
    done
    return 0  # 勝者なし
}
  • 勝利条件の組み合わせを定義し、現在のボードが勝利条件を満たしているかをチェックします。

5.ボードが満杯かチェックする関数

is_board_full() {
    for i in "${board[@]}"; do
        if [[ "$i" != "X" && "$i" != "O" ]]; then
            return 1  # 空いているマスがある
        fi
    done
    return 0  # ボードが満杯
}
  • ボード上に空いているマスがあるかを確認します。

6.ユーザーのターン

user_turn() {
    while true; do
        read -p "あなたのターンです。マスの番号を選んでください(1-9): " choice
        if [[ ! "$choice" =~ ^[1-9]$ ]]; then
            echo "エラー: 1から9の数字を入力してください。"
            continue
        fi
        index=$((choice - 1))
        if [[ "${board[$index]}" == "X" || "${board[$index]}" == "O" ]]; then
            echo "そのマスは既に選ばれています。別のマスを選んでください。"
        else
            board[$index]="X"
            break
        fi
    done
}
  • ユーザーからマスの番号を入力してもらい、そのマスに「X」を配置します。
  • 入力値の検証と、既に選択されたマスでないかを確認します。

7.コンピューターのターン

computer_turn() {
    echo "コンピューターのターンです。"
    while true; do
        index=$((RANDOM % 9))
        if [[ "${board[$index]}" != "X" && "${board[$index]}" != "O" ]]; then
            board[$index]="O"
            break
        fi
    done
}
  • コンピューターがランダムに空いているマスを選択し、「O」を配置します。

8.メインゲームループ

winner=""
while true; do
    display_board
    user_turn
    check_win
    if [ $? -eq 1 ]; then
        display_board
        echo "おめでとうございます!あなたの勝ちです。"
        break
    fi
    is_board_full
    if [ $? -eq 0 ]; then
        display_board
        echo "引き分けです。"
        break
    fi
    computer_turn
    check_win
    if [ $? -eq 1 ]; then
        display_board
        echo "残念ながら、コンピューターの勝ちです。"
        break
    fi
    is_board_full
    if [ $? -eq 0 ]; then
        display_board
        echo "引き分けです。"
        break
    fi
done
  • ユーザーとコンピューターのターンを交互に行い、各ターン後に勝利条件やボードの満杯状態をチェックします。

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

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

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

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

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

user01@ubuntu:~$ ./tic_tac_toe.sh

実行例

 1 | 2 | 3 
---+---+---
 4 | 5 | 6 
---+---+---
 7 | 8 | 9 

あなたのターンです。マスの番号を選んでください(1-9): 5

 1 | 2 | 3 
---+---+---
 4 | X | 6 
---+---+---
 7 | 8 | 9 

コンピューターのターンです。

 1 | 2 | 3 
---+---+---
 4 | X | 6 
---+---+---
 7 | O | 9 

あなたのターンです。マスの番号を選んでください(1-9): 1

 X | 2 | 3 
---+---+---
 4 | X | 6 
---+---+---
 7 | O | 9 

コンピューターのターンです。

 X | 2 | O 
---+---+---
 4 | X | 6 
---+---+---
 7 | O | 9 

あなたのターンです。マスの番号を選んでください(1-9): 9

 X | 2 | O 
---+---+---
 4 | X | 6 
---+---+---
 7 | O | X 

おめでとうございます!あなたの勝ちです。

解説

  • ユーザーの入力:ユーザーは1から9の数字を入力してマスを選択します。
  • コンピューターの動き:コンピューターは空いているマスからランダムに選択します。
  • 勝利の判定:各ターン終了後に勝利条件をチェックし、勝敗または引き分けを判定します。

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

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

user01@ubuntu:~$ rm tic_tac_toe.sh

まとめ

  • シェルスクリプトの活用:シェルスクリプトを使用して、三目並べゲームを作成することで、スクリプトの基本構文や制御構造を学びました。
  • 配列の操作:ゲームボードを配列で管理し、マスの状態を効率的に操作しました。
  • 関数の定義と利用:繰り返し使用する処理を関数として定義し、コードの再利用性と可読性を高めました。
  • ユーザー入力のバリデーション:正規表現を用いて、ユーザーの入力が適切かどうかをチェックしました。
  • ゲームロジックの実装:勝利条件や引き分けの判定、ターンの切り替えなど、基本的なゲームロジックを実装しました。

 シェルスクリプトは、システム管理以外にも多くの用途で活用できます。今回の三目並べゲームを基に、コンピューターのアルゴリズムを強化したり、ユーザーインターフェースを改善したりして、さらなる機能拡張に挑戦してみてください。