シェルスクリプト:数独ゲーム
数独(Sudoku)は、縦横9×9のマス目に1から9までの数字を入れていくパズルゲームです。縦・横・各3×3のブロック内に同じ数字が入らないように埋めていくのがルールです。ここでは、シェルスクリプトを使って数独ゲームを作成し、その手順と詳細な解説を行います。シェルスクリプトでゲームを作成することで、配列の操作、条件分岐、ループ、ユーザー入力の処理などのスキルを磨くことができます。
数独ゲームの概要
ゲームの目的
- 縦・横・各ブロックに1から9までの数字が重複しないようにマスを埋めていき、全てのマスを正しく完成させることを目指します。
ゲームのルール
- ゲームの進行
・9×9のマス目に一部の数字が初期配置されています。
・プレイヤーは空いているマスに1から9までの数字を入れていきます。 - 数字の配置ルール
・各行(横列)に1から9までの数字が重複せずに入る。
・各列(縦列)に1から9までの数字が重複せずに入る。
・各3×3のブロック(全9ブロック)に1から9までの数字が重複せずに入る。 - 勝利条件
・全てのマスが正しく埋められ、上記のルールを満たすとゲームクリアとなります。
sudoku.sh
の作成から実行までの手順と解説
ステップ1:スクリプトファイルの作成
ターミナルで以下のコマンドを実行し、新しいスクリプトファイルsudoku.sh
を作成します。
user01@ubuntu:~$ nano sudoku.sh
ステップ2:スクリプトの内容を記述
エディタが開いたら、以下のコードをコピーして貼り付けます。
#!/bin/bash
# 初期ボードの定義(0は空きマス)
board=(
5 3 0 0 7 0 0 0 0
6 0 0 1 9 5 0 0 0
0 9 8 0 0 0 0 6 0
8 0 0 0 6 0 0 0 3
4 0 0 8 0 3 0 0 1
7 0 0 0 2 0 0 0 6
0 6 0 0 0 0 2 8 0
0 0 0 4 1 9 0 0 5
0 0 0 0 8 0 0 7 9
)
# ボードの表示関数
display_board() {
echo " 0 1 2 3 4 5 6 7 8"
for ((i=0; i<9; i++)); do
if (( i % 3 == 0 )); then
echo " -------------------------"
fi
echo -n "$i "
for ((j=0; j<9; j++)); do
if (( j % 3 == 0 )); then
echo -n "| "
fi
value=${board[$((i * 9 + j))]}
if [ "$value" -eq 0 ]; then
echo -n ". "
else
echo -n "$value "
fi
done
echo "|"
done
echo " -------------------------"
}
# 入力の検証関数
is_valid_move() {
local row=$1
local col=$2
local num=$3
# 行と列の検証
for ((k=0; k<9; k++)); do
if [ "${board[$((row * 9 + k))]}" -eq "$num" ]; then
return 1
fi
if [ "${board[$((k * 9 + col))]}" -eq "$num" ]; then
return 1
fi
done
# ブロックの検証
local start_row=$(( (row / 3) * 3 ))
local start_col=$(( (col / 3) * 3 ))
for ((i=0; i<3; i++)); do
for ((j=0; j<3; j++)); do
if [ "${board[$(((start_row + i) * 9 + start_col + j))]}" -eq "$num" ]; then
return 1
fi
done
done
return 0
}
# ゲームのメインループ
echo "=== 数独ゲームへようこそ! ==="
while true; do
display_board
read -p "行番号(0-8)を入力してください(終了するにはqを入力): " row
if [ "$row" == "q" ]; then
echo "ゲームを終了します。"
exit 0
fi
read -p "列番号(0-8)を入力してください: " col
read -p "数字(1-9)を入力してください: " num
# 入力のバリデーション
if ! [[ "$row" =~ ^[0-8]$ ]] || ! [[ "$col" =~ ^[0-8]$ ]] || ! [[ "$num" =~ ^[1-9]$ ]]; then
echo "無効な入力です。0-8の行・列番号と1-9の数字を入力してください。"
continue
fi
index=$((row * 9 + col))
if [ "${board[$index]}" -ne 0 ]; then
echo "そのマスには既に数字が入っています。"
continue
fi
is_valid_move "$row" "$col" "$num"
if [ $? -eq 0 ]; then
board[$index]=$num
else
echo "その数字は置けません。ルールを確認してください。"
fi
# ゲームクリアのチェック
is_complete=true
for cell in "${board[@]}"; do
if [ "$cell" -eq 0 ]; then
is_complete=false
break
fi
done
if $is_complete; then
display_board
echo "おめでとうございます!数独を完成させました!"
exit 0
fi
done
ステップ3:スクリプトの内容の解説
1.シェバン行
#!/bin/bash
- 目的:スクリプトがBashシェルで実行されることを指定します。
2.初期ボードの定義
board=(
5 3 0 0 7 0 0 0 0
6 0 0 1 9 5 0 0 0
0 9 8 0 0 0 0 6 0
8 0 0 0 6 0 0 0 3
4 0 0 8 0 3 0 0 1
7 0 0 0 2 0 0 0 6
0 6 0 0 0 0 2 8 0
0 0 0 4 1 9 0 0 5
0 0 0 0 8 0 0 7 9
)
- 目的:9×9の数独ボードを一次元配列で定義します。
0
は空きマスを表します。 - 解説:ボードは81要素の配列で、行と列を計算する際にインデックスを使用します。
3.ボードの表示関数 display_board
display_board() {
echo " 0 1 2 3 4 5 6 7 8"
for ((i=0; i<9; i++)); do
if (( i % 3 == 0 )); then
echo " -------------------------"
fi
echo -n "$i "
for ((j=0; j<9; j++)); do
if (( j % 3 == 0 )); then
echo -n "| "
fi
value=${board[$((i * 9 + j))]}
if [ "$value" -eq 0 ]; then
echo -n ". "
else
echo -n "$value "
fi
done
echo "|"
done
echo " -------------------------"
}
- 目的:現在のボードの状態を表示します。
- 解説:
・行と列の番号を表示し、3×3のブロックごとに線を引いて見やすくしています。
・空きマスは.
で表示されます。
4.入力の検証関数 is_valid_move
is_valid_move() {
local row=$1
local col=$2
local num=$3
# 行と列の検証
for ((k=0; k<9; k++)); do
if [ "${board[$((row * 9 + k))]}" -eq "$num" ]; then
return 1
fi
if [ "${board[$((k * 9 + col))]}" -eq "$num" ]; then
return 1
fi
done
# ブロックの検証
local start_row=$(( (row / 3) * 3 ))
local start_col=$(( (col / 3) * 3 ))
for ((i=0; i<3; i++)); do
for ((j=0; j<3; j++)); do
if [ "${board[$(((start_row + i) * 9 + start_col + j))]}" -eq "$num" ]; then
return 1
fi
done
done
return 0
}
- 目的:指定された位置に指定された数字を置くことが可能かをチェックします。
- 解説:
・行の検証:同じ行に同じ数字がないかを確認します。
・列の検証:同じ列に同じ数字がないかを確認します。
・ブロックの検証:同じ3×3のブロックに同じ数字がないかを確認します。
・条件に違反する場合はreturn 1
(無効な手)、問題なければreturn 0
(有効な手)を返します。
5.ゲームのメインループ
echo "=== 数独ゲームへようこそ! ==="
while true; do
display_board
read -p "行番号(0-8)を入力してください(終了するにはqを入力): " row
if [ "$row" == "q" ]; then
echo "ゲームを終了します。"
exit 0
fi
read -p "列番号(0-8)を入力してください: " col
read -p "数字(1-9)を入力してください: " num
# 入力のバリデーション
if ! [[ "$row" =~ ^[0-8]$ ]] || ! [[ "$col" =~ ^[0-8]$ ]] || ! [[ "$num" =~ ^[1-9]$ ]]; then
echo "無効な入力です。0-8の行・列番号と1-9の数字を入力してください。"
continue
fi
index=$((row * 9 + col))
if [ "${board[$index]}" -ne 0 ]; then
echo "そのマスには既に数字が入っています。"
continue
fi
is_valid_move "$row" "$col" "$num"
if [ $? -eq 0 ]; then
board[$index]=$num
else
echo "その数字は置けません。ルールを確認してください。"
fi
# ゲームクリアのチェック
is_complete=true
for cell in "${board[@]}"; do
if [ "$cell" -eq 0 ]; then
is_complete=false
break
fi
done
if $is_complete; then
display_board
echo "おめでとうございます!数独を完成させました!"
exit 0
fi
done
解説
- ユーザーから行番号、列番号、数字を入力してもらいます。
- 入力のバリデーションを行い、不正な入力の場合は再度入力を求めます。
- 指定したマスが空きマスであり、
is_valid_move
関数で有効な手であれば、数字を配置します。 - 毎ターンごとにゲームクリアのチェックを行い、全てのマスが埋まっていればゲームを終了します。
ステップ4:スクリプトに実行権限を付与
スクリプトを保存してエディタを終了したら、以下のコマンドで実行権限を付与します。
user01@ubuntu:~$ chmod +x sudoku.sh
ステップ5:スクリプトの実行
スクリプトを実行して、数独ゲームを開始します。
user01@ubuntu:~$ ./sudoku.sh
実行例
=== 数独ゲームへようこそ! ===
0 1 2 3 4 5 6 7 8
-------------------------
0 | 5 3 . | . 7 . | . . . |
1 | 6 . . | 1 9 5 | . . . |
2 | . 9 8 | . . . | . 6 . |
-------------------------
3 | 8 . . | . 6 . | . . 3 |
4 | 4 . . | 8 . 3 | . . 1 |
5 | 7 . . | . 2 . | . . 6 |
-------------------------
6 | . 6 . | . . . | 2 8 . |
7 | . . . | 4 1 9 | . . 5 |
8 | . . . | . 8 . | . 7 9 |
-------------------------
行番号(0-8)を入力してください(終了するにはqを入力):
解説
- ボードが表示され、ユーザーは行番号、列番号、数字を順に入力します。
- 正しい入力であればボードに数字が反映されます。
- 全てのマスを正しく埋めるとゲームクリアとなります。
ここで作成したファイルの削除
ゲームのテストが終了したら、作成したsudo.sh
ファイルを削除します。
user01@ubuntu:~$ rm sudoku.sh
まとめ
- シェルスクリプトの応用:数独ゲームを通じて、シェルスクリプトでのゲーム開発手法を学びました。
- 配列の操作:一次元配列を使用して二次元のボードを管理し、効率的なデータ操作を行いました。
- 関数の活用:
display_board
やis_valid_move
などの関数を定義し、コードの再利用性と可読性を向上させました。 - 条件分岐とループ:
if
文やfor
ループを駆使して、ゲームのロジックとフローを制御しました。 - ユーザー入力の処理:
read
コマンドでユーザーからの入力を取得し、入力のバリデーションを行いました。 - ゲームロジックの実装:数独のルールに基づく検証機能を実装し、ゲーム性を高めました。
シェルスクリプトはシステム管理だけでなく、さまざまな用途で活用できます。今回の数独ゲームを基に、難易度選択機能を追加したり、自動解答機能を実装したりして、さらなる機能拡張に挑戦してみてください。