BASHプログラミング
 Computer >> コンピューター >  >> プログラミング >> BASHプログラミング

マインスイーパを構築して高度なBashスキルを磨く

私はプログラミングを教える専門家ではありませんが、何かを上手に使いたいときは、それを楽しむ方法を見つけようとしています。たとえば、シェルスクリプトを上手に使いたいと思ったとき、Bashでマインスイーパゲームのバージョンをプログラミングして練習することにしました。

経験豊富なBashプログラマーで、楽しみながらスキルを磨きたい場合は、ターミナルで独自のバージョンのマインスイーパを作成してください。完全なソースコードは、このGitHubリポジトリにあります。

準備中

コードを書き始める前に、ゲームを作成するために必要な要素の概要を説明しました。

  1. 地雷原を印刷する
  2. ゲームプレイロジックを作成する
  3. 利用可能な地雷原を決定するロジックを作成する
  4. 利用可能で発見された(抽出された)地雷の数を保持する
  5. エンドゲームロジックを作成する
地雷原を印刷する

マインスイーパでは、ゲームの世界は隠されたセルの2D配列(列と行)です。各セルには、爆発性の地雷が含まれる場合と含まれない場合があります。プレイヤーの目的は、地雷を含まないセルを明らかにし、地雷を決して明らかにしないことです。ゲームのbashバージョンは、単純なbash配列を使用して実装された10x10のマトリックスを使用します。

まず、いくつかの確率変数を割り当てます。これらは、地雷をボード上に配置できる場所です。場所の数を制限することで、この上に簡単に構築できます。ロジックはもっと良いかもしれませんが、私はゲームをシンプルで少し未熟に見せたいと思っていました。 (私は楽しみのためにこれを書きましたが、見栄えを良くするためにあなたの貢献を喜んで歓迎します。)

以下の変数はいくつかのデフォルト変数であり、変数a〜gのように、フィールド配置のためにランダムに呼び出すように宣言されています。これらを使用して、抽出可能な地雷を計算します。

# variables
score=0 # will be used to store the score of the game
# variables below will be used to randomly get the extract-able cells/fields from our mine.
a="1 10 -10 -1"
b="-1 0 1"
c="0 1"
d="-1 0 1 -2 -3"
e="1 2 20 21 10 0 -10 -20 -23 -2 -1"
f="1 2 3 35 30 20 22 10 0 -10 -20 -25 -30 -35 -3 -2 -1"
g="1 4 6 9 10 15 20 25 30 -30 -24 -11 -10 -9 -8 -7"
#
# declarations
declare -a room  # declare an array room, it will represent each cell/field of our mine.

次に、列(0-9)と行(a-j)を使用してボードを印刷し、ゲームの地雷原として機能する10x10のマトリックスを形成します。 (M [10] [10]は、インデックスが0〜99の100値の配列です。)Bash配列について詳しく知りたい場合は、 Bashがわからない:Bash配列の概要> 。

それを関数、プラウ、と呼びましょう 最初にヘッダーを印刷します。2つの空白行、列見出し、および競技場の上部の輪郭を描く行:

printf '\n\n'
printf '%s' "     a   b   c   d   e   f   g   h   i   j"
printf '\n   %s\n' "-----------------------------------------"

次に、 rというカウンター変数を設定します。 、入力された水平行の数を追跡します。同じカウンタ変数'rを使用することに注意してください 'ゲームコードの後半の配列インデックスとして。 Bashでfor seqを使用してループします 0から9にインクリメントするコマンド( d%) )行番号($ row、 seq で定義)を表します ):

r=0 # our counter
for row in $(seq 0 9); do
  printf '%d  ' "$row" # print the row numbers from 0-9

ここから先に進む前に、これまでに作ったものを確認しましょう。シーケンスを印刷しました[a-j] 最初に水平方向に最初に、次に [0-9]の範囲の行番号を印刷しました 、これら2つの範囲を使用して、ユーザーが座標を入力し、抽出する鉱山を特定します。

次に、 各行内に列の交差があるので、新しい forを開くときが来ました ループ。これは各列を管理するため、基本的には競技場に各セルを生成します。ソースコードで完全な定義を確認できるヘルパー関数をいくつか追加しました。セルごとに、フィールドを地雷のように見せるための何かが必要なので、 is_null_field というカスタム関数を使用して、空のセルをドット(。)で初期化します。 。また、各セルの値を格納するための配列変数が必要です。事前定義されたグローバル配列変数 roomを使用します インデックス変数r rとして 増分し、セルを繰り返し処理し、途中で地雷をドロップします。

  for col in $(seq 0 9); do
    ((r+=1))  # increment the counter as we move forward in column sequence
    is_null_field $r  # assume a function which will check, if the field is empty, if so, initialize it with a dot(.)
    printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}" # finally print the separator, note that, the first value of ${room[$r]} will be '.', as it is just initialized.
  #close col loop
  done

最後に、各行の下部を線で囲んでボードを明確に定義し、行ループを閉じます。

printf '%s\n' "|"   # print the line end separator
printf '   %s\n' "-----------------------------------------"
# close row for loop
done
printf '\n\n'

完全なすき 関数は次のようになります:

plough()
{
  r=0
  printf '\n\n'
  printf '%s' "     a   b   c   d   e   f   g   h   i   j"
  printf '\n   %s\n' "-----------------------------------------"
  for row in $(seq 0 9); do
    printf '%d  ' "$row"
    for col in $(seq 0 9); do
       ((r+=1))
       is_null_field $r
       printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}"
    done
    printf '%s\n' "|"
    printf '   %s\n' "-----------------------------------------"
  done
  printf '\n\n'
}

is_null_fieldが必要かどうかを判断するのに少し時間がかかりました 、それでは、それが何をするのかを詳しく見てみましょう。ゲームの最初から信頼できる状態が必要です。その選択は任意です。数字または任意の文字である可能性があります。ゲームボードがきれいに見えると思うので、すべてがドット(。)として宣言されていると仮定することにしました。次のようになります:

is_null_field()
{
  local e=$1 # we used index 'r' for array room already, let's call it 'e'
    if [[ -z "${room[$e]}" ]];then
      room[$r]="."  # this is where we put the dot(.) to initialize the cell/minefield
    fi
}

これで、鉱山のすべてのセルが初期化されたので、以下に示す簡単な関数を宣言して後で呼び出すことで、利用可能なすべての鉱山の数を取得します。

get_free_fields()
{
  free_fields=0    # initialize the variable
  for n in $(seq 1 ${#room[@]}); do
    if [[ "${room[$n]}" = "." ]]; then  # check if the cells has initial value dot(.), then count it as a free field.
      ((free_fields+=1))
    fi
  done
}

これが印刷された地雷原です。ここで[a-j] は列であり、[ 0-9 ]は行です。

マインスイーパを構築して高度なBashスキルを磨く

プレーヤーを駆動するロジックを作成します

プレイヤーロジックは、地雷への座標としてstdinからオプションを読み取り、地雷原の正確なフィールドを抽出します。 Bashのパラメーター展開を使用して列と行の入力を抽出し、ボード上の同等の整数表記を指すスイッチに列をフィードします。これを理解するには、変数'o' 以下のswitchcaseステートメントで。たとえば、プレーヤーが c3と入力する場合があります 、Bashは2つの文字に分割されます: c および3 。簡単にするために、無効なエントリの処理方法はスキップします。

  colm=${opt:0:1}  # get the first char, the alphabet
  ro=${opt:1:1}    # get the second char, the digit
  case $colm in
    a ) o=1;;      # finally, convert the alphabet to its equivalent integer notation.
    b ) o=2;;
    c ) o=3;;
    d ) o=4;;
    e ) o=5;;
    f ) o=6;;
    g ) o=7;;
    h ) o=8;;
    i ) o=9;;
    j ) o=10;;
  esac

次に、正確なインデックスを計算し、入力座標のインデックスをそのフィールドに割り当てます。

shufの使用もたくさんあります ここでコマンド、 shuf は、 -iで情報のランダムな順列を提供するように設計されたLinuxユーティリティです。 オプションは、シャッフルするインデックスまたは可能な範囲を示し、 -n 返される最大数または出力を示します。二重括弧はBashでの数学的評価を可能にするため、ここではそれらを多用します。

前の例でc3を受け取ったとしましょう stdin経由。次に、 ro =3 およびo=3 上記のswitchcaseステートメントから変換されたc 同等の整数に変換し、数式に入れて最終的なインデックス'i'を計算します。

  i=$(((ro*10)+o))   # Follow BODMAS rule, to calculate final index. 
  is_free_field $i $(shuf -i 0-5 -n 1)   # call a custom function that checks if the final index value points to a an empty/free cell/field.

この数学をウォークスルーして、最終的なインデックスがどのようになっているのかを理解します' i 'が計算されます:

i=$(((ro*10)+o))
i=$(((3*10)+3))=$((30+3))=33

最終的なインデックス値は33です。上に印刷されているボードでは、最終的なインデックスは33番目のセルを指しており、3番目(0から始まり、それ以外の場合は4番目)の行と3番目(C)の列である必要があります。

利用可能な地雷原を決定するロジックを作成します

地雷を抽出するには、座標がデコードされてインデックスが見つかった後、プログラムはそのフィールドが使用可能かどうかを確認します。そうでない場合、プログラムは警告を表示し、プレーヤーは別の座標を選択します。

このコードでは、セルにドット()が含まれている場合にセルを使用できます。 ) キャラクター。使用可能であると仮定すると、セルの値がリセットされ、スコアが更新されます。セルにドットが含まれていないためにセルが使用できない場合は、変数 not_allowed が設定されています。簡潔にするために、ゲームロジックの警告ステートメントの内容については、ゲームのソースコードを確認することをお任せします。

is_free_field()
{
  local f=$1
  local val=$2
  not_allowed=0
  if [[ "${room[$f]}" = "." ]]; then
    room[$f]=$val
    score=$((score+val))
  else
    not_allowed=1
  fi
}

マインスイーパを構築して高度なBashスキルを磨く

入力した座標が利用できる場合は、以下に示すように地雷が発見されます。 h6の場合 入力として提供され、地雷原にランダムに入力されたいくつかの値。これらの値は、分が抽出された後にユーザーのスコアに追加されます。

マインスイーパを構築して高度なBashスキルを磨く

ここで、最初に宣言した変数[a-g]を思い出してください。ここでは、それらを使用して、変数 mに値を割り当てるランダムな地雷を抽出します。 Bash間接参照を使用します。したがって、入力座標に応じて、プログラムはランダムな追加の数値のセット( m )を選択します。 )ここで i()で表される元の入力座標に追加することにより、(上記のように)入力される追加のフィールドを計算します。 上記で計算

Xの文字に注意してください 以下のコードスニペットでは、これが唯一のGAME-OVERトリガーであり、 shuf の美しさで、ランダムに表示されるようにシャッフルリストに追加しました。 コマンドを実行すると、チャンスがいくつあっても表示される場合もあれば、幸運な当選ユーザーには表示されない場合もあります。

m=$(shuf -e a b c d e f g X -n 1)   # add an extra char X to the shuffle, when m=X, its GAMEOVER
  if [[ "$m" != "X" ]]; then        # X will be our explosive mine(GAME-OVER) trigger
    for limit in ${!m}; do          # !m represents the value of value of m
      field=$(shuf -i 0-5 -n 1)     # again get a random number and
      index=$((i+limit))            # add values of m to our index and calculate a new index till m reaches its last element.
      is_free_field $index $field
    done

表示されたすべてのセルが、プレーヤーによって選択されたセルに隣接している必要があります。

マインスイーパを構築して高度なBashスキルを磨く

利用可能で抽出された鉱山の数を保持します

プログラムは、地雷原で利用可能なセルを追跡する必要があります。それ以外の場合は、すべてのセルが表示された後でも、プレーヤーに入力を求め続けます。これを実装するために、 free_fieldsという変数を作成します 、最初は0に設定します。 for 地雷原で利用可能なセル/フィールドの残りの数によって定義されるループ。 セルにドットが含まれている場合( )、次に free_fieldsの数 インクリメントされます。

get_free_fields()
{
  free_fields=0
  for n in $(seq 1 ${#room[@]}); do
    if [[ "${room[$n]}" = "." ]]; then
      ((free_fields+=1))
    fi
  done
}

待って、もしも、 free_fields =0 ?つまり、ユーザーはすべての地雷を抽出しました。理解を深めるために、正確なコードを自由に見てください。

if [[ $free_fields -eq 0 ]]; then   # well that means you extracted all the mines.
      printf '\n\n\t%s: %s %d\n\n' "You Win" "you scored" "$score"
      exit 0
fi
ゲームオーバーのロジックを作成する

ゲームオーバーの状況では、ターミナルの中央に、それがどのように機能するかを調べるために読者に任せる気の利いたロジックを使用して印刷します。

if [[ "$m" = "X" ]]; then
    g=0                      # to use it in parameter expansion
    room[$i]=X               # override the index and print X
    for j in {42..49}; do    # in the middle of the minefields,
      out="gameover"
      k=${out:$g:1}          # print one alphabet in each cell
      room[$j]=${k^^}
      ((g+=1))
    done
fi

最後に、最も待望されている2行を印刷できます。

if [[ "$m" = "X" ]]; then
      printf '\n\n\t%s: %s %d\n' "GAMEOVER" "you scored" "$score"
      printf '\n\n\t%s\n\n' "You were just $free_fields mines away."
      exit 0
fi

マインスイーパを構築して高度なBashスキルを磨く

それだけです、皆さん!詳細については、GitHubリポジトリからこのマインスイーパゲームやBashの他のゲームのソースコードにアクセスしてください。 Bashをもっと学び、楽しんでいるためのインスピレーションが得られることを願っています。


  1. CSSの高度なセレクター

    CSSのAdvancedSelectorsには、隣接兄弟セレクター、属性セレクター、直接子セレクター、n番目のタイプセレクターなどが含まれます。また、GeneralSiblingSelectorも含まれます。例を以下に示します。 h1 ~ h3 直接子セレクターの例- div > span 以下は、CSSの高度なセレクターを示すコードです- 例 <html> <head> <style> #red {    color: red; } .green {    background: green; } ul:n

  2. マインスイーパを構築して高度なBashスキルを磨く

    私はプログラミングを教える専門家ではありませんが、何かを上手に使いたいときは、それを楽しむ方法を見つけようとしています。たとえば、シェルスクリプトを上手に使いたいと思ったとき、Bashでマインスイーパゲームのバージョンをプログラミングして練習することにしました。 経験豊富なBashプログラマーで、楽しみながらスキルを磨きたい場合は、ターミナルで独自のバージョンのマインスイーパを作成してください。完全なソースコードは、このGitHubリポジトリにあります。 準備中 コードを書き始める前に、ゲームを作成するために必要な要素の概要を説明しました。 地雷原を印刷する ゲームプレイロジックを作成す