Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Bash प्रोग्रामिंग

बैश स्क्रिप्टिंग में महारत: अपना खुद का टर्मिनल माइनस्वीपर गेम बनाएं

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

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

तैयार होना

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

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

माइनस्वीपर में, गेम वर्ल्ड छुपे हुए सेल का एक 2D ऐरे (कॉलम और रो) होता है। प्रत्येक सेल में एक विस्फोटक माइन हो भी सकती है और नहीं भी। खिलाड़ी का उद्देश्य उन सेल को प्रकट करना है जिनमें कोई माइन नहीं है, और कभी भी माइन को प्रकट नहीं करना है। गेम का बैश संस्करण 10x10 मैट्रिक्स का उपयोग करता है, जिसे सिंपल बैश ऐरे का उपयोग करके लागू किया जाता है।

सबसे पहले, मैं कुछ रैंडम वेरिएबल असाइन करता हूं। ये वे स्थान हैं जहां माइन बोर्ड पर रखी जा सकती हैं। स्थानों की संख्या को सीमित करके, इस पर निर्माण करना आसान होगा। लॉजिक बेहतर हो सकती है, लेकिन मैं गेम को सरल और थोड़ा अपरिपक्व दिखाना चाहता था। (मैंने इसे मज़े के लिए लिखा था, लेकिन मैं इसे बेहतर दिखाने के लिए आपके योगदान का खुशी से स्वागत करूंगा।)

नीचे दिए गए वेरिएबल कुछ डिफ़ॉल्ट वेरिएबल हैं, जिन्हें हमारे माइन से निकालने योग्य सेल/फील्ड को रैंडमली प्राप्त करने के लिए कॉल करने के लिए घोषित किया गया है, जैसे वेरिएबल a-g, हम उनका उपयोग अपने निकालने योग्य माइन्स की गणना के लिए करेंगे:

# variables
score=0 # गेम के स्कोर को स्टोर करने के लिए उपयोग किया जाएगा
# नीचे दिए गए वेरिएबल का उपयोग हमारे माइन से निकालने योग्य सेल/फील्ड को रैंडमली प्राप्त करने के लिए किया जाएगा।
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 # एक ऐरे room घोषित करें, यह हमारे माइन के प्रत्येक सेल/फील्ड का प्रतिनिधित्व करेगा।

अगला, मैं कॉलम (0-9) और रो (a-j) के साथ अपना बोर्ड प्रिंट करता हूं, जो गेम के लिए माइनफील्ड के रूप में काम करने वाला एक 10x10 मैट्रिक्स बनाता है। (M[10][10] इंडेक्स 0-99 के साथ एक 100-मूल्य वाला ऐरे है।) यदि आप बैश ऐरे के बारे में अधिक जानना चाहते हैं, तो You don't know Bash: An introduction to Bash arrays पढ़ें।

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

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

अगला, मैं एक काउंटर वेरिएबल स्थापित करता हूं, जिसे r कहा जाता है, यह ट्रैक करने के लिए कि कितनी क्षैतिज रो भरी गई हैं। ध्यान दें कि, हम बाद में गेम कोड में उसी काउंटर वेरिएबल 'r' का उपयोग अपने ऐरे इंडेक्स के रूप में करेंगे। बैश for लूप में, seq कमांड का उपयोग करके 0 से 9 तक बढ़ाकर, मैं एक अंक (d%) प्रिंट करता हूं जो रो नंबर ($row, जो seq द्वारा परिभाषित है) का प्रतिनिधित्व करता है:

r=0 # हमारा काउंटर
for row in $(seq 0 9); do
printf '%d ' "$row" # 0-9 से रो नंबर प्रिंट करें

यहां से आगे बढ़ने से पहले, आइए देखें कि हमने अब तक क्या बनाया है। हमने अनुक्रम [a-j] को क्षैतिज रूप से पहले प्रिंट किया और फिर [0-9] रेंज में रो नंबर प्रिंट किए, हम इन दो रेंज का उपयोग अपने उपयोगकर्ता इनपुट निर्देशांक के रूप में माइन का पता लगाने और निकालने के लिए करेंगे।

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

for col in $(seq 0 9); do
((r+=1)) # कॉलम अनुक्रम में आगे बढ़ते हुए काउंटर बढ़ाएं
is_null_field $r # एक फंक्शन मान लें जो जांचता है कि क्या फील्ड खाली है, यदि हां, तो इसे डॉट(.) से इनिशियलाइज़ करें
printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}" # अंत में सेपरेटर प्रिंट करें, ध्यान दें कि ${room[$r]} का पहला मान '.' होगा, क्योंकि यह अभी इनिशियलाइज़ हुआ है।
#क्लोज कॉलम लूप
done

अंत में, मैं प्रत्येक रो के नीचे एक लाइन के साथ बोर्ड को अच्छी तरह से परिभाषित रखता हूं, और फिर रो लूप को बंद करता हूं:

printf '%s\n' "|" # लाइन एंड सेपरेटर प्रिंट करें
printf ' %s\n' "-----------------------------------------"
# क्लोज रो फॉर लूप
done
printf '\n\n'

पूरा plough फंक्शन इस तरह दिखता है:

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 # हमने ऐरे रूम के लिए इंडेक्स 'r' का उपयोग पहले ही किया है, आइए इसे 'e' कहें
if [[ -z "${room[$e]}" ]];then
room[$r]="." # यह वह जगह है जहां हम सेल/माइनफील्ड को इनिशियलाइज़ करने के लिए डॉट(.) डालते हैं
fi
}

अब जबकि, मेरे माइन में सभी सेल इनिशियलाइज़ हो गए हैं, मुझे नीचे दिखाए गए एक सरल फंक्शन को घोषित करके और बाद में कॉल करके सभी उपलब्ध माइन्स की गिनती मिलती है:

get_free_fields()
{
free_fields=0 # वेरिएबल इनिशियलाइज़ करें
for n in $(seq 1 ${#room[@]}); do
if [[ "${room[$n]}" = "." ]]; then # जांचें कि क्या सेल में प्रारंभिक मान डॉट(.) है, तो इसे फ्री फील्ड के रूप में गिनें।
((free_fields+=1))
fi
done
}

यहां प्रिंटेड माइनफील्ड है, जहां [a-j] कॉलम हैं, और [0-9] रो हैं।

बैश स्क्रिप्टिंग में महारत: अपना खुद का टर्मिनल माइनस्वीपर गेम बनाएं

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

प्लेयर लॉजिक stdin से एक विकल्प पढ़ता है जो माइन्स के निर्देशांक के रूप में होता है और माइनफील्ड पर सटीक फील्ड निकालता है। यह कॉलम और रो इनपुट निकालने के लिए बैश के पैरामीटर एक्सपेंशन का उपयोग करता है, फिर कॉलम को एक स्विच में फीड करता है जो बोर्ड पर इसके समकक्ष पूर्णांक संकेतन की ओर इंगित करता है, इसे समझने के लिए, नीचे स्विच केस स्टेटमेंट में वेरिएबल 'o' को असाइन किए जा रहे मान देखें। उदाहरण के लिए, एक खिलाड़ी c3 दर्ज कर सकता है, जिसे बैश दो कैरेक्टर में विभाजित करता है: c और 3। सरलता के लिए, मैं अमान्य प्रविष्टि को कैसे संभाला जाता है, इस पर छोड़ रहा हूं।

colm=${opt:0:1} # पहला कैरेक्टर प्राप्त करें, वर्णमाला
ro=${opt:1:1} # दूसरा कैरेक्टर प्राप्त करें, अंक
case $colm in
a ) o=1;; # अंत में, वर्णमाला को उसके समकक्ष पूर्णांक संकेतन में बदलें।
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 विकल्प इंडेक्स या शफल करने के लिए संभावित रेंज को दर्शाता है और -n वापस दिए जाने वाले अधिकतम नंबर या आउटपुट को दर्शाता है। डबल पैरेंथेसिस बैश में गणितीय मूल्यांकन की अनुमति देते हैं, और हम यहां उनका भारी उपयोग करेंगे।

आइए मान लें कि हमारे पिछले उदाहरण को stdin के माध्यम से c3 प्राप्त हुआ। फिर, ro=3 और o=3 उपरोक्त स्विच केस स्टेटमेंट से जिसने c को इसके समकक्ष पूर्णांक में बदल दिया, इसे हमारे सूत्र में डालकर अंतिम इंडेक्स 'i' की गणना करें।

i=$(((ro*10)+o)) # BODMAS नियम का पालन करें, अंतिम इंडेक्स की गणना करने के लिए। 
is_free_field $i $(shuf -i 0-5 -n 1) # एक कस्टम फंक्शन कॉल करें जो जांचता है कि क्या अंतिम इंडेक्स मान खाली/फ्री सेल/फील्ड की ओर इंगित करता है।

इस गणित को समझने के लिए कि अंतिम इंडेक्स '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
}

बैश स्क्रिप्टिंग में महारत: अपना खुद का टर्मिनल माइनस्वीपर गेम बनाएं

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

बैश स्क्रिप्टिंग में महारत: अपना खुद का टर्मिनल माइनस्वीपर गेम बनाएं

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

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

m=$(shuf -e a b c d e f g X -n 1) # शफल में एक अतिरिक्त कैरेक्टर X जोड़ें, जब m=X, तो GAMEOVER
if [[ "$m" != "X" ]]; then # X हमारा विस्फोटक माइन (GAME-OVER) ट्रिगर होगा
for limit in ${!m}; do # !m m के मान के मान का प्रतिनिधित्व करता है
field=$(shuf -i 0-5 -n 1) # फिर से एक रैंडम नंबर प्राप्त करें और
index=$((i+limit)) # m के मान को हमारे इंडेक्स में जोड़ें और एक नया इंडेक्स तब तक गणना करें जब तक m अपने अंतिम तत्व तक नहीं पहुंच जाता।
is_free_field $index $field
done

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

बैश स्क्रिप्टिंग में महारत: अपना खुद का टर्मिनल माइनस्वीपर गेम बनाएं

उपलब्ध और निकाले गए माइन्स की गिनती रखें

प्रोग्राम को माइनफील्ड में उपलब्ध सेल को ट्रैक करने की आवश्यकता है; अन्यथा, यह सभी सेल प्रकट होने के बाद भी खिलाड़ी से इनपुट मांगता रहता है। इसे लागू करने के लिए, मैं 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 # ठीक इसका मतलब है कि आपने सभी माइन निकाल ली हैं।
printf '\n\n\t%s: %s %d\n\n' "You Win" "you scored" "$score"
exit 0
fi

गेमओवर के लिए लॉजिक बनाएं

गेमओवर स्थिति के लिए, हम टर्मिनल के बीच में कुछ चतुर लॉजिक का उपयोग करके प्रिंट करते हैं जिसे मैं पाठक पर छोड़ देता हूं कि यह कैसे काम करता है।

if [[ "$m" = "X" ]]; then
g=0 # पैरामीटर एक्सपेंशन में उपयोग करने के लिए
room[$i]=X # इंडेक्स को ओवरराइड करें और X प्रिंट करें
for j in {42..49}; do # माइनफील्ड के बीच में,
out="gameover"
k=${out:$g:1} # प्रत्येक सेल में एक वर्णमाला प्रिंट करें
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 में एडवांस्ड सिलेक्टर्स

    CSS में एडवांस्ड सिलेक्टर्स में एडजेसेंट सिबलिंग सिलेक्टर, एट्रिब्यूट सिलेक्टर, डायरेक्ट चाइल्ड सिलेक्टर, nth-of-type सिलेक्टर आदि शामिल हैं। इसमें जनरल सिबलिंग सिलेक्टर भी शामिल है, एक उदाहरण नीचे दिखाया गया है:h1 ~ h3डायरेक्ट चाइल्ड सिलेक्टर का उदाहरण -div > spanCSS में एडवांस्ड सिलेक्टर्स दिखा

  1. बैश स्क्रिप्टिंग में महारत: अपना खुद का टर्मिनल माइनस्वीपर गेम बनाएं बैश स्क्रिप्टिंग में महारत: अपना खुद का टर्मिनल माइनस्वीपर गेम बनाएं

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

  1. - Bash सशर्त अभिव्यक्तियों में मास्टर करें: -e, -eq, -z, !=, [ और [[ के साथ 6 आवश्यक उदाहरण

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