シェルスクリプト:マスターマインドゲーム
シェルスクリプトは、システム管理やタスクの自動化だけでなく、簡単なゲームやツールを作成するための強力なツールです。ここでは、シェルスクリプトを使って「マスターマインドゲーム」を作成し、その手順と詳細な解説を行います。このゲームを通じて、シェルスクリプトの基本的な構文、配列の操作、関数の定義、ループ、条件分岐、入力のバリデーションなど、さまざまなスクリプトのテクニックを学ぶことができます。
マスターマインドゲームの概要
- 目的:コンピューターがランダムに選んだ4桁の数字を、ユーザーが推測して当てるゲームです。
- ルール:
・コンピューターは1から6までの数字を使って、重複しない4桁の数字を生成します。
・ユーザーは4桁の数字を入力して推測します。
・各試行ごとに、以下のフィードバックが与えられます:
・ヒット:数字と位置の両方が正しい数。
・ブロー:数字は正しいが、位置が間違っている数。
・ユーザーはフィードバックをもとに、制限回数内に正解を当てることを目指します。
フィードバックの例
ユーザーの推測 | ヒット | ブロー | フィードバックの意味 |
---|---|---|---|
1234 | 1 | 2 | 1つの数字が位置も数字も正しく、2つの数字が位置は間違いだが数字は正しい |
1356 | 0 | 3 | 正しい数字が3つあるが、全て位置が間違っている |
2465 | 2 | 0 | 2つの数字が位置も数字も正しい |
スクリプトの作成から実行までの手順と解説
ステップ1:スクリプトファイルの作成
ターミナルで以下のコマンドを実行し、新しいスクリプトファイル mastermind.sh
を作成します。
user01@ubuntu:~$ nano mastermind.sh
ステップ2:スクリプトの内容を記述
エディタが開いたら、以下のコードをコピーして貼り付けます。
#!/bin/bash
# 1から6の数字を使って、重複なしの4桁の数字を生成
generate_secret() {
numbers=(1 2 3 4 5 6)
secret=()
for i in {1..4}; do
index=$((RANDOM % ${#numbers[@]}))
secret+=("${numbers[$index]}")
unset 'numbers[$index]'
numbers=("${numbers[@]}")
done
}
# ヒットとブローを計算
calculate_hit_blow() {
local guess=("$@")
hit=0
blow=0
for i in {0..3}; do
if [ "${guess[$i]}" -eq "${secret[$i]}" ]; then
hit=$((hit + 1))
elif [[ " ${secret[@]} " =~ " ${guess[$i]} " ]]; then
blow=$((blow + 1))
fi
done
}
# ゲームの開始
generate_secret
attempts=0
max_attempts=10
echo "マスターマインドゲームへようこそ!1から6の数字を使った重複なしの4桁の数字を当ててください。"
echo "あなたには合計 $max_attempts 回の試行があります。"
# メインゲームループ
while [ $attempts -lt $max_attempts ]; do
attempts=$((attempts + 1))
while true; do
read -p "推測を入力してください(例:1234): " input
# 入力のバリデーション
if [[ ! "$input" =~ ^[1-6]{4}$ ]]; then
echo "エラー: 1から6の数字を使った4桁の数字を入力してください。"
continue
fi
# 重複チェック
unique_check=$(echo "$input" | grep -o . | sort | uniq -d)
if [ -n "$unique_check" ]; then
echo "エラー: 数字は重複しないようにしてください。"
continue
fi
break
done
# ヒットとブローの計算
guess=($(echo "$input" | grep -o .))
calculate_hit_blow "${guess[@]}"
if [ $hit -eq 4 ]; then
echo "おめでとうございます!正解を当てました。"
break
else
echo "ヒット: $hit, ブロー: $blow"
echo "残り試行回数: $((max_attempts - attempts))"
fi
done
if [ $hit -ne 4 ]; then
echo "ゲームオーバー。正解は ${secret[@]} でした。"
fi
ステップ3:スクリプトの内容の解説
1.シェバン行
#!/bin/bash
- スクリプトが Bash シェルで実行されることを指定します。
2.秘密の数字を生成する関数
generate_secret() {
numbers=(1 2 3 4 5 6)
secret=()
for i in {1..4}; do
index=$((RANDOM % ${#numbers[@]}))
secret+=("${numbers[$index]}")
unset 'numbers[$index]'
numbers=("${numbers[@]}")
done
}
目的:1から6の数字を使って、重複しない4桁の秘密の数字を生成します。
解説
numbers
配列に1から6の数字を格納します。- ループを4回繰り返し、各回で以下を行います。
・RANDOM % ${#numbers[@]}
でnumbers
配列の範囲内でランダムなインデックスを生成します。
・secret
配列に選ばれた数字を追加します。
・unset
コマンドで選ばれた数字をnumbers
配列から削除し、重複を避けます。
3.ヒットとブローを計算する関数
calculate_hit_blow() {
local guess=("$@")
hit=0
blow=0
for i in {0..3}; do
if [ "${guess[$i]}" -eq "${secret[$i]}" ]; then
hit=$((hit + 1))
elif [[ " ${secret[@]} " =~ " ${guess[$i]} " ]]; then
blow=$((blow + 1))
fi
done
}
目的:ユーザーの推測と秘密の数字を比較し、ヒットとブローの数を計算します。
解説
guess
配列にユーザーの入力を格納します。- 0から3までのループで各桁を比較します。
・同じ位置で数字が一致すればhit
をカウントアップ。
・数字が秘密の数字に含まれていれば(位置は異なる)、blow
をカウントアップ。
4.ゲームの開始と変数の初期化
generate_secret
attempts=0
max_attempts=10
echo "マスターマインドゲームへようこそ!1から6の数字を使った重複なしの4桁の数字を当ててください。"
echo "あなたには合計 $max_attempts 回の試行があります。"
解説
generate_secret
関数を呼び出して、秘密の数字を生成します。attempts
は現在の試行回数を示し、初期値は0です。max_attempts
はユーザーが推測できる最大回数です。- ゲームのルールと試行回数をユーザーに表示します。
5.メインゲームループ
while [ $attempts -lt $max_attempts ]; do
attempts=$((attempts + 1))
while true; do
read -p "推測を入力してください(例:1234): " input
# 入力のバリデーション
if [[ ! "$input" =~ ^[1-6]{4}$ ]]; then
echo "エラー: 1から6の数字を使った4桁の数字を入力してください。"
continue
fi
# 重複チェック
unique_check=$(echo "$input" | grep -o . | sort | uniq -d)
if [ -n "$unique_check" ]; then
echo "エラー: 数字は重複しないようにしてください。"
continue
fi
break
done
# ヒットとブローの計算
guess=($(echo "$input" | grep -o .))
calculate_hit_blow "${guess[@]}"
if [ $hit -eq 4 ]; then
echo "おめでとうございます!正解を当てました。"
break
else
echo "ヒット: $hit, ブロー: $blow"
echo "残り試行回数: $((max_attempts - attempts))"
fi
done
解説
試行回数が最大試行回数に達するまでループを続けます。
- ユーザー入力のバリデーション
・正規表現^[1-6]{4}$
を使用して、1から6の数字4桁であることを確認します。
・grep
とuniq
を使って、数字が重複していないかをチェックします。 - ヒットとブローの計算
・ユーザーの入力を1文字ずつ分割してguess
配列に格納します。
・calculate_hit_blow
関数を呼び出して、ヒットとブローを計算します。 - 結果の表示
・ヒットが4であれば、ユーザーの勝利としてゲームを終了します。
・そうでなければ、ヒットとブローの数、および残りの試行回数を表示します。
6.ゲームオーバーの判定
if [ $hit -ne 4 ]; then
echo "ゲームオーバー。正解は ${secret[@]} でした。"
fi
解説
最大試行回数に達してもヒットが4にならなかった場合、ゲームオーバーとして正解を表示します。
ステップ4:スクリプトに実行権限を付与
スクリプトを保存してエディタを閉じたら、実行権限を付与します。
user01@ubuntu:~$ chmod +x mastermind.sh
ステップ5:スクリプトの実行
スクリプトを実行して、マスターマインドゲームを開始します。
user01@ubuntu:~$ ./mastermind.sh
実行例
マスターマインドゲームへようこそ!1から6の数字を使った重複なしの4桁の数字を当ててください。
あなたには合計 10 回の試行があります。
推測を入力してください(例:1234): 1234
ヒット: 1, ブロー: 2
残り試行回数: 9
推測を入力してください(例:1234): 1456
ヒット: 2, ブロー: 1
残り試行回数: 8
推測を入力してください(例:1234): 1546
おめでとうございます!正解を当てました。
解説
- ユーザーの推測:ユーザーは重複しない1から6の数字4桁を入力します。
- フィードバック:ヒットとブローの数が表示されます。
- 推測の繰り返し:フィードバックをもとに、ユーザーは次の推測を行います。
- ゲームの終了:ヒットが4になるとゲームに勝利します。最大試行回数に達するとゲームオーバーです。
ここで作成したファイルの削除
演習が終了したら、作成した mastermind.sh
ファイルを削除します。
user01@ubuntu:~$ rm mastermind.sh
まとめ
- シェルスクリプトの応用:マスターマインドゲームを通じて、シェルスクリプトでのゲーム作成方法を学びました。
- 配列の操作:配列を使って秘密の数字やユーザーの推測を管理し、効率的なデータ処理を行いました。
- 関数の定義と活用:再利用可能なコードを関数として定義し、コードの可読性と保守性を向上させました。
- 入力のバリデーション:正規表現やコマンドを使って、ユーザーの入力が正しい形式であるかを確認しました。
- ループと条件分岐:
while
ループやif
文を使って、ゲームの進行と終了条件を制御しました。 - 文字列操作とコマンドの活用:
grep
、sort
、uniq
などのコマンドを使って、文字列の解析や重複チェックを行いました。
シェルスクリプトは、システム管理以外にも多くの用途で活用できます。今回のマスターマインドゲームを基に、数字の範囲や桁数を変更したり、難易度を調整したり、GUI を導入したりして、さらなる機能拡張に挑戦してみてください。