シェルスクリプト:メモリーカードゲーム

 シェルスクリプトは、システム管理だけでなく、テキストベースのゲームの作成にも活用できる強力なツールです。ここでは、シェルスクリプトを使って「メモリーカードゲーム」を作成し、その手順と詳細な解説を行います。この演習を通じて、シェルスクリプトの基本的な構文、配列の操作、条件分岐、ループ、ユーザー入力の処理などの知識を総合的に学ぶことができます。

メモリーカードゲームの概要

ゲームの目的

  • 隠されたカードのペアを見つける記憶力ゲームです。

ゲームのルール

  • ゲームの進行
    ・4×4のグリッドに合計8組のペアのカードが隠れています。
    ・プレイヤーはターンごとに2枚のカードを選択します。
    ・選択したカードの絵柄が一致すれば、そのカードはオープンされたままになります。
    ・一致しなければ、カードは再び伏せられます。
  • 勝利条件
    ・全てのペアを見つけるとゲームクリアとなります。

ゲームの流れ

  • グリッド上のカードは番号で識別されます。
  • プレイヤーは番号を入力してカードを選択します。
  • 選択したカードの絵柄が表示され、一致するかどうかが判定されます。
  • 一致しない場合、数秒後にカードは伏せられます。

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

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

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

user01@ubuntu:~$ nano memory_game.sh

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

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

#!/bin/bash

# カードの絵柄を定義
symbols=("🍎" "🍌" "🍇" "🍓" "🍒" "🍍" "🥝" "🍉")
# カードのペアを作成し、シャッフル
cards=(${symbols[@]} ${symbols[@]})
cards=($(shuf -e "${cards[@]}"))

# カードの状態を保持(伏せられている場合は "#" を表示)
status=("#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#")

# ゲーム開始のメッセージ
echo "=== メモリーカードゲームへようこそ! ==="
echo "隠されたカードのペアを見つけてください。"

# グリッドを表示する関数
display_grid() {
    echo
    for i in {0..15}; do
        if [ "${status[$i]}" == "#" ]; then
            printf "%2d " $((i + 1))
        else
            printf " %s " "${status[$i]}"
        fi
        if [ $(( (i + 1) % 4 )) -eq 0 ]; then
            echo
        fi
    done
    echo
}

# ゲーム終了の判定
is_game_over() {
    for s in "${status[@]}"; do
        if [ "$s" == "#" ]; then
            return 1  # ゲーム続行
        fi
    done
    return 0  # ゲームオーバー
}

# メインループ
while true; do
    display_grid
    read -p "1枚目のカードを選んでください(1〜16): " first_choice
    if ! [[ "$first_choice" =~ ^[1-9]$|^1[0-6]$ ]]; then
        echo "無効な入力です。1〜16の数字を入力してください。"
        continue
    fi
    first_index=$((first_choice - 1))
    if [ "${status[$first_index]}" != "#" ]; then
        echo "そのカードはすでにオープンされています。別のカードを選んでください。"
        continue
    fi

    # 1枚目のカードをオープン
    status[$first_index]="${cards[$first_index]}"
    display_grid

    read -p "2枚目のカードを選んでください(1〜16): " second_choice
    if ! [[ "$second_choice" =~ ^[1-9]$|^1[0-6]$ ]]; then
        echo "無効な入力です。1〜16の数字を入力してください。"
        status[$first_index]="#"  # カードを伏せる
        continue
    fi
    second_index=$((second_choice - 1))
    if [ "$second_index" -eq "$first_index" ]; then
        echo "同じカードを選ぶことはできません。"
        status[$first_index]="#"  # カードを伏せる
        continue
    fi
    if [ "${status[$second_index]}" != "#" ]; then
        echo "そのカードはすでにオープンされています。別のカードを選んでください。"
        status[$first_index]="#"  # カードを伏せる
        continue
    fi

    # 2枚目のカードをオープン
    status[$second_index]="${cards[$second_index]}"
    display_grid

    # 一致の判定
    if [ "${cards[$first_index]}" == "${cards[$second_index]}" ]; then
        echo "ペアが見つかりました!"
    else
        echo "ペアではありません。カードを伏せます。"
        sleep 2
        status[$first_index]="#"
        status[$second_index]="#"
    fi

    if is_game_over; then
        echo "おめでとうございます!全てのペアを見つけました!"
        exit
    fi
done

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

1.シェバン行

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

2.カードの絵柄を定義

symbols=("🍎" "🍌" "🍇" "🍓" "🍒" "🍍" "🥝" "🍉")
  • 目的:ゲームで使用する8種類の果物の絵文字を配列として定義します。

3.カードのペアを作成し、シャッフル

cards=(${symbols[@]} ${symbols[@]})
cards=($(shuf -e "${cards[@]}"))
  • 目的:各絵柄を2枚ずつ用意し、合計16枚のカードをシャッフルします。
  • 解説
    ${symbols[@]} ${symbols[@]} でペアを作成。
    shuf -e コマンドで配列をシャッフル。

4.カードの状態を保持

status=("#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#")
  • 目的:カードが伏せられているかオープンされているかを管理します。
  • 解説:初期状態では全てのカードが伏せられており、"#" で表現します。

5.ゲーム開始のメッセージ

echo "=== メモリーカードゲームへようこそ! ==="
echo "隠されたカードのペアを見つけてください。"
  • ゲーム開始の挨拶とルールの説明を表示します。

6.グリッドを表示する関数 display_grid

display_grid() {
    echo
    for i in {0..15}; do
        if [ "${status[$i]}" == "#" ]; then
            printf "%2d " $((i + 1))
        else
            printf " %s " "${status[$i]}"
        fi
        if [ $(( (i + 1) % 4 )) -eq 0 ]; then
            echo
        fi
    done
    echo
}
  • 目的:現在のカードの状態を4×4のグリッドで表示します。
  • 解説
    ・カードが伏せられている場合はカード番号を表示。
    ・カードがオープンされている場合は絵柄を表示。
    ・4列ごとに改行を挿入。

7.ゲーム終了の判定関数 is_game_over

is_game_over() {
    for s in "${status[@]}"; do
        if [ "$s" == "#" ]; then
            return 1  # ゲーム続行
        fi
    done
    return 0  # ゲームオーバー
}
  • 目的:全てのカードがオープンされているかをチェックします。

8.メインループ

while true; do
    # ゲームの進行
done
  • ゲームが終了するまで繰り返します。

9.プレイヤーの入力とカードの選択

read -p "1枚目のカードを選んでください(1〜16): " first_choice

解説

  • プレイヤーに1枚目のカードを選択してもらいます。
  • 入力のバリデーションを行い、不正な入力を防ぎます。

10.カードのオープンと一致の判定

# 1枚目と2枚目のカードをオープン
# カードの一致を判定し、結果に応じて処理を行う

解説

  • 選択されたカードをオープンし、display_grid で表示します。
  • カードの絵柄が一致すれば、そのままオープン状態を維持します。
  • 一致しなければ、数秒後にカードを伏せます。

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

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

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

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

スクリプトを実行して、メモリーカードゲームを開始します。

user01@ubuntu:~$ ./memory_game.sh

実行例

=== メモリーカードゲームへようこそ! ===
隠されたカードのペアを見つけてください。

 1  2  3  4 
 5  6  7  8 
 9 10 11 12 
13 14 15 16 

1枚目のカードを選んでください(1〜16): 5

 1  2  3  4 
 🍌  6  7  8 
 9 10 11 12 
13 14 15 16 

2枚目のカードを選んでください(1〜16): 12

 1  2  3  4 
 🍌  6  7  8 
 9 10 11 🍎 
13 14 15 16 

ペアではありません。カードを伏せます。

 1  2  3  4 
 5  6  7  8 
 9 10 11 12 
13 14 15 16 

(以下続く)

解説

  • プレイヤーはカード番号を入力してカードを選択します。
  • 選択したカードが表示され、一致するかどうかが判定されます。
  • 全てのペアを見つけるまでゲームが続きます。

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

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

user01@ubuntu:~$ rm memory_game.sh

まとめ

  • シェルスクリプトの応用:メモリーカードゲームを通じて、シェルスクリプトでのゲーム作成方法を学びました。
  • 配列の操作:カードの絵柄や状態を配列で管理し、効率的にデータを扱いました。
  • ランダム性の導入shuf コマンドを使用して、カードをランダムに配置しました。
  • 条件分岐とループif 文や while ループを使って、ゲームの進行とロジックを制御しました。
  • ユーザー入力の処理read コマンドを使用してユーザーの入力を受け取り、入力のバリデーションを行いました。
  • 文字列操作:カードの表示や一致判定など、文字列の操作を行いました。

 シェルスクリプトは、システム管理以外にも多くの用途で活用できます。今回のメモリーカードゲームを基に、グリッドのサイズを変更したり、絵柄の種類を増やしたり、得点システムを導入したりして、さらなる機能拡張に挑戦してみてください。