シェルスクリプト:迷路ゲーム

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

迷路ゲームの概要

ゲームの目的

  • 迷路を出口まで進み、ゴールを目指します。

ゲームのルール

  • 迷路の設定
    ・迷路は二次元配列で表現されます。
    ・壁は #、通路は空白 で表現されます。
    ・プレイヤーの位置は P、ゴールは G で表します。
  • ゲームの進行
    ・プレイヤーは上下左右に移動できます。
    ・壁の位置には移動できません。
    ・ゴールに到達するとゲームクリアです。

迷路の例

#######
#     #
# ### #
# #   #
# #G# #
# ### #
#P    #
#######

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

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

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

user01@ubuntu:~$ nano maze.sh

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

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

#!/bin/bash

# 迷路の定義
maze=(
"#######"
"#     #"
"# ### #"
"# #   #"
"# #G# #"
"# ### #"
"#P    #"
"#######"
)

# プレイヤーの初期位置を取得
get_player_position() {
    for i in "${!maze[@]}"; do
        row="${maze[$i]}"
        col_index=$(expr index "$row" "P")
        if [ $col_index -ne 0 ]; then
            player_row=$i
            player_col=$((col_index - 1))
            return
        fi
    done
}

# 迷路の表示
display_maze() {
    clear
    for row in "${maze[@]}"; do
        echo "$row"
    done
}

# 移動の処理
move_player() {
    local new_row=$player_row
    local new_col=$player_col
    case $1 in
        w) new_row=$((player_row - 1)) ;;
        s) new_row=$((player_row + 1)) ;;
        a) new_col=$((player_col - 1)) ;;
        d) new_col=$((player_col + 1)) ;;
        *) echo "無効な入力です。w(上), a(左), s(下), d(右) のいずれかを入力してください。"; return ;;
    esac
    # 移動先の取得
    line="${maze[$new_row]}"
    target_char="${line:$new_col:1}"
    if [ "$target_char" == "#" ]; then
        echo "壁にぶつかりました。別の方向を試してください。"
    else
        # ゴール判定
        if [ "$target_char" == "G" ]; then
            echo "おめでとうございます!ゴールに到達しました。"
            exit
        fi
        # プレイヤーの位置を更新
        maze[$player_row]="${maze[$player_row]:0:$player_col} ${maze[$player_row]:$((player_col + 1))}"
        maze[$new_row]="${maze[$new_row]:0:$new_col}P${maze[$new_row]:$((new_col + 1))}"
        player_row=$new_row
        player_col=$new_col
    fi
}

# ゲーム開始
get_player_position
display_maze

# メインループ
while true; do
    read -n1 -p "移動方向を入力してください (w:上, a:左, s:下, d:右): " direction
    echo
    move_player "$direction"
    display_maze
done

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

1.シェバン行

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

2.迷路の定義

maze=(
"#######"
"#     #"
"# ### #"
"# #   #"
"# #G# #"
"# ### #"
"#P    #"
"#######"
)
  • 目的:迷路を二次元配列として定義します。
  • 解説
    ・迷路は文字列の配列として表現されます。
    # が壁、 (スペース)が通路、P がプレイヤー、G がゴールです。

3.プレイヤーの初期位置を取得する関数 get_player_position

get_player_position() {
    for i in "${!maze[@]}"; do
        row="${maze[$i]}"
        col_index=$(expr index "$row" "P")
        if [ $col_index -ne 0 ]; then
            player_row=$i
            player_col=$((col_index - 1))
            return
        fi
    done
}
  • 目的:迷路内からプレイヤーの初期位置を特定します。
  • 解説
    ・各行を調べて、P の位置を見つけます。
    expr index コマンドを使用して文字の位置を取得します。

4.迷路を表示する関数 display_maze

display_maze() {
    clear
    for row in "${maze[@]}"; do
        echo "$row"
    done
}
  • 目的:迷路を画面に表示します。
  • 解説
    clear コマンドで画面をクリアします。
    ・迷路の各行を順に表示します。

5.プレイヤーを移動する関数 move_player

move_player() {
    local new_row=$player_row
    local new_col=$player_col
    case $1 in
        w) new_row=$((player_row - 1)) ;;
        s) new_row=$((player_row + 1)) ;;
        a) new_col=$((player_col - 1)) ;;
        d) new_col=$((player_col + 1)) ;;
        *) echo "無効な入力です。w(上), a(左), s(下), d(右) のいずれかを入力してください。"; return ;;
    esac
    # 移動先の取得
    line="${maze[$new_row]}"
    target_char="${line:$new_col:1}"
    if [ "$target_char" == "#" ]; then
        echo "壁にぶつかりました。別の方向を試してください。"
    else
        # ゴール判定
        if [ "$target_char" == "G" ]; then
            echo "おめでとうございます!ゴールに到達しました。"
            exit
        fi
        # プレイヤーの位置を更新
        maze[$player_row]="${maze[$player_row]:0:$player_col} ${maze[$player_row]:$((player_col + 1))}"
        maze[$new_row]="${maze[$new_row]:0:$new_col}P${maze[$new_row]:$((new_col + 1))}"
        player_row=$new_row
        player_col=$new_col
    fi
}
  • 目的:ユーザーの入力に基づいてプレイヤーを移動させます。
  • 解説
    case 文で入力された方向に応じて新しい位置を計算します。
    ・移動先が壁 # の場合、移動をキャンセルします。
    ・ゴール G に到達した場合、ゲームを終了します。
    ・プレイヤーの位置を更新し、迷路を更新します。

6.ゲーム開始の準備

get_player_position
display_maze

解説

プレイヤーの初期位置を取得し、迷路を表示します。

7.メインループ

while true; do
    read -n1 -p "移動方向を入力してください (w:上, a:左, s:下, d:右): " direction
    echo
    move_player "$direction"
    display_maze
done
  • 目的:ユーザーからの入力を待ち、プレイヤーを移動させます。
  • 解説
    read -n1 で1文字の入力を受け取ります。
    ・入力された方向に基づいて move_player 関数を呼び出します。
    ・迷路を再表示します。

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

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

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

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

スクリプトを実行して、迷路ゲームを開始します。

user01@ubuntu:~$ ./maze.sh

実行例

#######
#     #
# ### #
# #   #
# #G# #
# ### #
#P    #
#######
移動方向を入力してください (w:上, a:左, s:下, d:右): d

#######
#     #
# ### #
# #   #
# #G# #
# ### #
# P   #
#######
移動方向を入力してください (w:上, a:左, s:下, d:右): d

#######
#     #
# ### #
# #   #
# #G# #
# ### #
#  P  #
#######
(中略)
おめでとうございます!ゴールに到達しました。

解説

  • ユーザーは wasd キーを使用してプレイヤーを移動させます。
    w:上に移動
    a:左に移動
    s:下に移動
    d:右に移動
  • # にぶつかった場合、移動できません。
  • ゴール G に到達するとゲームクリアとなります。

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

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

user01@ubuntu:~$ rm maze.sh

まとめ

  • シェルスクリプトの応用:迷路ゲームを通じて、シェルスクリプトでのゲーム作成方法を学びました。
  • 配列の操作:迷路を二次元配列で管理し、効率的にデータを扱いました。
  • 関数の定義と利用:コードを関数に分割し、可読性と再利用性を向上させました。
  • ユーザー入力の処理read コマンドを使用してユーザーの入力を受け取りました。
  • 条件分岐とループif 文や case 文、while ループを使って、ゲームの進行とロジックを制御しました。
  • 文字列操作:文字列の部分抽出や置換を行い、迷路の更新を行いました。

 シェルスクリプトは、システム管理以外にも多くの用途で活用できます。今回の迷路ゲームを基に、迷路のサイズや複雑さを変更したり、アイテムや敵キャラクターを追加したりして、さらなる機能拡張に挑戦してみてください。