Computer >> कंप्यूटर >  >> प्रोग्रामिंग >> बाश प्रोग्रामिंग

माइनस्वीपर का निर्माण करके उन्नत बैश कौशल विकसित करें

मैं प्रोग्रामिंग सिखाने का कोई विशेषज्ञ नहीं हूं, लेकिन जब मैं किसी चीज में बेहतर होना चाहता हूं, तो मैं इसके साथ मस्ती करने का एक तरीका खोजने की कोशिश करता हूं। उदाहरण के लिए, जब मैं शेल स्क्रिप्टिंग में बेहतर होना चाहता था, तो मैंने बैश में माइनस्वीपर गेम के एक संस्करण की प्रोग्रामिंग करके अभ्यास करने का फैसला किया।

यदि आप एक अनुभवी बैश प्रोग्रामर हैं और मस्ती करते हुए अपने कौशल को सुधारना चाहते हैं, तो टर्मिनल में माइनस्वीपर का अपना संस्करण लिखने के लिए अनुसरण करें। संपूर्ण स्रोत कोड इस GitHub रिपॉजिटरी में पाया जाता है।

तैयार होना

इससे पहले कि मैं कोई कोड लिखना शुरू करूं, मैंने अपना गेम बनाने के लिए आवश्यक सामग्री की रूपरेखा तैयार की:

  1. माइनफ़ील्ड प्रिंट करें
  2. गेमप्ले लॉजिक बनाएं
  3. उपलब्ध माइनफ़ील्ड निर्धारित करने के लिए तर्क बनाएँ
  4. उपलब्ध और खोजी गई (निकाले गए) खानों की गिनती रखें
  5. एंडगेम लॉजिक बनाएं

माइनस्वीपर में, खेल की दुनिया छिपी हुई कोशिकाओं की एक 2D सरणी (स्तंभ और पंक्तियाँ) है। प्रत्येक सेल में विस्फोटक खदान हो भी सकती है और नहीं भी। खिलाड़ी का उद्देश्य उन कोशिकाओं को प्रकट करना है जिनमें कोई खदान नहीं है, और कभी भी खदान को प्रकट नहीं करना है। गेम का बैश संस्करण 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) और पंक्तियों (ए-जे) के साथ प्रिंट करता हूं, जिससे खेल के लिए माइनफील्ड के रूप में काम करने के लिए 10x10 मैट्रिक्स बनता है। (एम [10] [10] इंडेक्स 0-99 के साथ एक 100-मान सरणी है।) यदि आप बैश सरणियों के बारे में अधिक जानना चाहते हैं, तो पढ़ें आप बैश को नहीं जानते:बैश सरणियों के लिए एक परिचय

आइए इसे एक फ़ंक्शन कहते हैं, हल, हम पहले हेडर प्रिंट करते हैं:दो खाली लाइनें, कॉलम हेडिंग, और खेल मैदान के शीर्ष को रेखांकित करने के लिए एक लाइन:

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

इसके बाद, मैं एक काउंटर वैरिएबल स्थापित करता हूं, जिसे r . कहा जाता है , ट्रैक करने के लिए कि कितनी क्षैतिज पंक्तियों को आबाद किया गया है। ध्यान दें, हम समान काउंटर वेरिएबल 'r . का उपयोग करेंगे ' बाद में गेम कोड में हमारी सरणी अनुक्रमणिका के रूप में। एक बैश में के लिए लूप, seq . का उपयोग करके 0 से 9 तक बढ़ने की आज्ञा, मैं एक अंक प्रिंट करता हूं (d% ) पंक्ति संख्या का प्रतिनिधित्व करने के लिए ($ पंक्ति, जिसे 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] , हम इन दो श्रेणियों का उपयोग अपने उपयोगकर्ता इनपुट निर्देशांक के रूप में कार्य करने के लिए करेंगे ताकि खदान को निकालने के लिए पता लगाया जा सके। 

अगला,  प्रत्येक पंक्ति के भीतर, एक स्तंभ चौराहा होता है, इसलिए यह एक नया के लिए . खोलने का समय है फंदा। यह प्रत्येक कॉलम का प्रबंधन करता है, इसलिए यह अनिवार्य रूप से खेल के मैदान में प्रत्येक सेल को उत्पन्न करता है। मैंने कुछ सहायक कार्य जोड़े हैं जिन्हें आप स्रोत कोड में पूरी परिभाषा देख सकते हैं। प्रत्येक सेल के लिए, हमें फ़ील्ड को खदान जैसा दिखने के लिए कुछ चाहिए, इसलिए हम खाली वाले को एक डॉट (.) के साथ शुरू करते हैं, जिसे एक कस्टम फ़ंक्शन का उपयोग करके is_null_field कहा जाता है। . साथ ही, हमें प्रत्येक सेल के लिए मान को स्टोर करने के लिए एक सरणी चर की आवश्यकता होती है, हम पूर्वनिर्धारित वैश्विक सरणी चर का उपयोग करेंगे कमरा एक इंडेक्स वैरिएबल r . के साथ . r . के रूप में वृद्धि, हम रास्ते में खानों को छोड़ते हुए, कोशिकाओं पर पुनरावृति करते हैं।

$(seq 0 9) में कॉल के लिए
  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 ] पंक्तियाँ हैं।

माइनस्वीपर का निर्माण करके उन्नत बैश कौशल विकसित करें

खिलाड़ी को चलाने के लिए लॉजिक बनाएं

खिलाड़ी तर्क खानों के समन्वय के रूप में स्टड से एक विकल्प पढ़ता है और खदान पर सटीक क्षेत्र निकालता है। यह कॉलम और पंक्ति इनपुट को निकालने के लिए बैश के पैरामीटर विस्तार का उपयोग करता है, फिर कॉलम को एक स्विच में फीड करता है जो बोर्ड पर इसके समकक्ष पूर्णांक नोटेशन को इंगित करता है, इसे समझने के लिए, वेरिएबल 'o' नीचे दिए गए स्विच केस स्टेटमेंट में। उदाहरण के लिए, एक खिलाड़ी c3 . दर्ज कर सकता है , जिसे बैश दो वर्णों में विभाजित करता है: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

फिर यह सटीक सूचकांक की गणना करता है और उस क्षेत्र में इनपुट निर्देशांक के सूचकांक को निर्दिष्ट करता है।

शफ . का भी बहुत उपयोग होता है यहां कमांड करें, शफ एक Linux उपयोगिता है जिसे सूचना का एक यादृच्छिक क्रमपरिवर्तन प्रदान करने के लिए डिज़ाइन किया गया है जहां -i विकल्प अनुक्रमित या संभावित श्रेणियों को फेरबदल करने के लिए दर्शाता है और -n वापस दी गई अधिकतम संख्या या आउटपुट को दर्शाता है। डबल कोष्ठक बैश में गणितीय मूल्यांकन की अनुमति देते हैं, और हम उनका यहां भरपूर उपयोग करेंगे।

आइए मान लें कि हमारे पिछले उदाहरण को c3 . प्राप्त हुआ है स्टड के माध्यम से। फिर, ro=3 और o=3 उपरोक्त स्विच केस स्टेटमेंट से रूपांतरित 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 वीं) पंक्ति और तीसरा (सी) कॉलम होना चाहिए।

उपलब्ध माइनफील्ड को निर्धारित करने के लिए लॉजिक बनाएं

एक खदान निकालने के लिए, निर्देशांक डिकोड किए जाने और सूचकांक मिलने के बाद, प्रोग्राम जाँचता है कि क्या वह फ़ील्ड उपलब्ध है। यदि ऐसा नहीं है, तो प्रोग्राम एक चेतावनी प्रदर्शित करता है, और खिलाड़ी दूसरा निर्देशांक चुनता है।

इस कोड में, एक सेल उपलब्ध होता है यदि उसमें एक बिंदु (. .) होता है ) चरित्र। यह मानते हुए कि यह उपलब्ध है, सेल में मान रीसेट हो गया है और स्कोर अपडेट हो गया है। यदि कोई सेल अनुपलब्ध है क्योंकि उसमें डॉट नहीं है, तो एक वैरिएबल 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
}

माइनस्वीपर का निर्माण करके उन्नत बैश कौशल विकसित करें

यदि दर्ज किया गया निर्देशांक उपलब्ध है, तो खदान की खोज की जाती है, जैसा कि नीचे दिखाया गया है। जब h6 इनपुट के रूप में प्रदान किया जाता है, हमारे माइनफील्ड्स पर यादृच्छिक आबादी में कुछ मान, मिनट निकालने के बाद इन मूल्यों को उपयोगकर्ताओं के स्कोर में जोड़ा जाता है।

माइनस्वीपर का निर्माण करके उन्नत बैश कौशल विकसित करें

अब उन चरों को याद रखें जिन्हें हमने शुरुआत में घोषित किया था, [a-g], अब मैं उनका उपयोग यहाँ यादृच्छिक खानों को निकालने के लिए करूँगा जो चर m को उनका मान निर्दिष्ट करते हैं। बैश अप्रत्यक्ष का उपयोग करना। इसलिए, इनपुट निर्देशांक के आधार पर, प्रोग्राम अतिरिक्त संख्याओं का एक यादृच्छिक सेट चुनता है (m ) अतिरिक्त फ़ील्ड की गणना करने के लिए (जैसा कि ऊपर दिखाया गया है) उन्हें मूल इनपुट निर्देशांक में जोड़कर, यहां i ( द्वारा दर्शाया गया है) ऊपर गणना की गई)

कृपया वर्ण X . पर ध्यान दें नीचे दिए गए कोड स्निपेट में, हमारा एकमात्र गेम-ओवर ट्रिगर है, हमने इसे शफ की सुंदरता के साथ यादृच्छिक रूप से प्रदर्शित करने के लिए अपनी फेरबदल सूची में जोड़ा है। कमांड, यह कई अवसरों के बाद प्रकट हो सकता है या हमारे भाग्यशाली विजेता उपयोगकर्ता के लिए भी प्रकट नहीं हो सकता है।

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

मैं चाहता हूं कि सभी प्रकट सेल खिलाड़ी द्वारा चुने गए सेल से जुड़े हों।

माइनस्वीपर का निर्माण करके उन्नत बैश कौशल विकसित करें

उपलब्ध और निकाली गई खानों की गिनती रखें

कार्यक्रम को माइनफील्ड में उपलब्ध कोशिकाओं का ट्रैक रखने की जरूरत है; अन्यथा, यह सभी कोशिकाओं के प्रकट होने के बाद भी खिलाड़ी से इनपुट मांगता रहता है। इसे लागू करने के लिए, मैं free_fields . नामक एक वैरिएबल बनाता हूं , प्रारंभ में इसे 0 पर सेट करना। एक के लिए . में हमारे माइनफील्ड्स में उपलब्ध सेल/फ़ील्ड की शेष संख्या द्वारा परिभाषित लूप। यदि किसी सेल में एक बिंदु है (. ), फिर 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

अंत में, हम उन दो पंक्तियों को प्रिंट कर सकते हैं जिनकी सबसे अधिक प्रतीक्षा है।

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

माइनस्वीपर का निर्माण करके उन्नत बैश कौशल विकसित करें

बस इतना ही, दोस्तों! यदि आप अधिक जानना चाहते हैं, तो मेरे GitHub रेपो से इस माइनस्वीपर गेम और बैश के अन्य खेलों के स्रोत कोड तक पहुंचें। मुझे आशा है कि यह आपको और अधिक बैश सीखने और ऐसा करते समय मज़े करने के लिए कुछ प्रेरणा देता है।


  1. CSS में उन्नत चयनकर्ता

    CSS में उन्नत चयनकर्ताओं में आसन्न सहोदर चयनकर्ता, विशेषता चयनकर्ता, प्रत्यक्ष बाल चयनकर्ता, nth-of-type चयनकर्ता आदि शामिल हैं। इसमें सामान्य सहोदर चयनकर्ता भी शामिल है, एक उदाहरण नीचे दिखाया गया है: h1 ~ h3 प्रत्यक्ष बाल चयनकर्ता का उदाहरण - div > span CSS में उन्नत चयनकर्ताओं को दिखाने वाला

  1. माइनस्वीपर का निर्माण करके उन्नत बैश कौशल विकसित करें

    मैं प्रोग्रामिंग सिखाने का कोई विशेषज्ञ नहीं हूं, लेकिन जब मैं किसी चीज में बेहतर होना चाहता हूं, तो मैं इसके साथ मस्ती करने का एक तरीका खोजने की कोशिश करता हूं। उदाहरण के लिए, जब मैं शेल स्क्रिप्टिंग में बेहतर होना चाहता था, तो मैंने बैश में माइनस्वीपर गेम के एक संस्करण की प्रोग्रामिंग करके अभ्यास

  1. 6 बैश सशर्त अभिव्यक्ति उदाहरण ( -e, -eq, -z, !=, [, [[ ..)

    बैश एक्सप्रेशन एक बैश कंडीशनल स्टेटमेंट बनाने के लिए उपयोग किए जाने वाले ऑपरेटरों, सुविधाओं या मूल्यों का संयोजन है। कंडीशनल एक्सप्रेशन बाइनरी या यूनरी एक्सप्रेशन हो सकता है जिसमें न्यूमेरिक, स्ट्रिंग या कोई भी कमांड शामिल होता है जिसकी सफलता के समय वापसी की स्थिति शून्य होती है। कई सशर्त अभिव्यक्त