Bash-ты ойын жазу арқылы үйренеміз. 2048 ойыны
Bash скрипттары Linux жүйесінде көптеген жұмыстарды жеңілдетуі мүмкін. Бірақ bash программалық тіл болмағандықтан (жай командалық қабат) оның көптеген өзіне тән ерекшеліктері бар. Сондықтан, оны қолданудан алдын жақсылап үйренуге тура келеді. habrahabr сайтында bash-ты үйрену үшін өте көптеген ойындар жазылған (Шахмат, Quadronix, Xonix, Теңіз соғысы, Sokoban, керек десеңіз 3D шутер). Бірақ, менің байқағаным, ол жазылғандарды оқып шығу бір бөлек, ал өзіңе жазу бір бөлек. Өйткені шын жұмыста керек кезде бәрібір, жаңылысып отырасың. Сондықтан мен де үйрену үшін бір ойын жасауды шештім. Ең бастысы ол жай көшірме немесе аударма емес (қарап қоймау үшін :-)), жаңа ойын болуы керек. Сөйтіп, өзіме жақында пайда болған 2048 ойынын таңдап алдым. Өйткені, логикасы оңай және аз уақыттың ішінде жасауға болады.
Бұл қалай сонда деп отқандарға кішігірім демонстрация ;).
Алдымен bash-тың ерекшеліктерін қарастырып кетейік.
Айнымалылар
Bash-скрипттарында айнымалылар типтері деген түсінік жоқ. Айнымалыларды жариялау және мән беру келесі түрде анықталады:user@localhost$ my_var # айнымалыны жариялау
user@localhost$ my_var=5 # айнымалыға мән беру
теңдік символының екі жағында бос орын қалдыруға болмайды, яғни айнымалыға былай мәр беру «my_var = 5» дұрыс емес. Айнымалыны оқу үшін, оның алдына "$" символы қойылады:
user@localhost$ echo $my_var # немесе ${my_var}
5
user@localhost$ echo "My variable value $my_var" # екі тырнақшаның ішінде пайдалануға болады
My variable 5
Айнымалыларды «declare» bash конструкциясы (builtin) арқылы типтеуге болады, бұл жақсы практикалардың бірі болып саналады:
user@localhost$ declare -r MY_CONST=3 # айнымалыны тек оқуға жариялау
user@localhost$ MY_CONST=4
-bash: MY_CONST: readonly variable
Осы секілді, бұл конструкцияның келесі кілттері бар:
-i — сандық тип
-a — массив
-l — айнамалы мәні тек іші регистрде болады
-u — айнамалы мәні тек үлкен регистрде болады
Функциялар
Функция келесі түрде анықталады:
function my_func() {
:
}
Бірақ, аргументтерді жақша ішінде беруге болмайды, аргументтер командаға аргумен берген секілді берілед және функция ішінде $1, $2… айнымалыларында қол жетімді болады. Мысалы
function my_func() {
echo "$1, $2!"
}
my_func "hello" "world"
нәтижесінде консолда «Hello, world!» мәтіні шығарылады. Функция ішінде declare-нің толық аналогы local пайдаланылады. Келесі ерекшелік өте маңызды:
i=3
function f() {
echo $i
}
function g() {
local i=5
f
}
function h() {
local i=10
f
}
g
h
Нәтижесінде консольда 5 және 10 шығарылады.
Массивтер
my_arr=( 1 2 3 4 ) # массивті анықтау
${my_arr[0]} # массив элементін оқу
my_arr[2]=10 # массив элементінңің мәнін өзгерту
${#my_arr[*]} # массив элементтерінің саны
Bash-та екі өлшемді массив жоқ. Бірақ бір өлшемді массивті екі өлшемді ретінде пайдалануға болады. Мысалы:
my_arr=(
1 2 3
4 5 6
7 8 9
)
for (( i = 0; i < SIZE; i++ )); do
for (( j = 0; j < SIZE; j++ )); do
echo "${my_arr[i * 3 + j]}" # 3 баған саны
done
done
Бұл қысқаша шолу болатын, егер қызығушылық болса әр тақырыптың өзі үлкен мақала болады. 2048 ойынының ережесін википедиядан алдым. Алдымен ойынға керек функцияларды анықтаймыз. Ойынның циклі келесі қадамдардан тұрады:
1. Пайдаланушы басқан бағытқа қарай плиткаларды ығыстыру
2. Плитка мәні 2048-ге жеткенін тексеру
3. Экранға плиткалардың жаңа мәндерін шығару
4. 1-қадамға қайта оралу
Бұл циклді орындайтын басты функцияны анықтаймыз:
function main() {
stty -echo # echo өшіру үшін
newGame # жаңа ойын бастаймыз
while [[ true ]]; do
action # плиткаларды ығыстыру
if [[ $shifted = "true" ]]; then
placeRandomTile # егер плиткалар ығысқан болса, кездейсоқ плитка қосу
fi
display # экранға шығарамыз
if isYouWin; then # пайдаланушы жеңген жеңбегендігін тексереміз
askWantContinue
display
fi
done
}
Плитка мәндерін tiles массивінде сақтаймыз. newGame функциясы оның мәндерін тазалап отырады:
function newGame() {
score=0
shifted=false
tiles=(
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
)
placeRandomTile; placeRandomTile; # ойын басында екі кездейсоқ плитка қосылады
display
}
«action» функциясы пайдаланушының батырма басуын күтіп, плиткаларды керекті жақтарға ығыстырады:
function action() {
shifted=false
local -l key
read -n 1 key
case $key in
$KEY_UP ) shiftToTop ;;
$KEY_DOWN ) shiftToBottom ;;
$KEY_LEFT ) shiftToLeft ;;
$KEY_RIGHT ) shiftToRight ;;
esac
}
shiftToTop, shiftToBottom, shiftToLeft, shiftToRight функциялары, сәйкесінше плиткаларды жоғарыға, төменге, солға, оңға ығыстырады. Ал ең үздік нәтижені файлда сақтаймыз. Ол нәтижені жазатын және оқитын функциялар:
function writeBestScore() {
if [[ -w $BEST_SCORE_FILE ]]; then
if (( score > bestScore )); then
echo "$score" > $BEST_SCORE_FILE
fi
fi
}
function readBestScore() {
if [[ -r $BEST_SCORE_FILE ]]; then
bestScore=$(cat $BEST_SCORE_FILE)
else
bestScore=0
fi
}
Қорытынды
Жазу барысында өте көп шалындым деуге болады, әдемі debugger болмағандықтан, қателіктер не үшін болып жатқанын түсіну қиын. Әсіресе массивтерде шатысып кетесің, толық соңына дейін жақсылап үйрену үшін тағы бір қиындау ойын жазу керек сияқты. Кодым мықты, таза деп мақтана алмайм, бірақ ойынды жазу кішкентай болсын тәжірибе берді.Ойынды тағы толықтыруға болады, жасалмаған функционалдар:
1. Ойынның соңғы қалпын файлда сақтау
2. Соңғы жүрісті артқа қайтару
3. Пайдаланушының жеңілгендігін тексеру және оған хабарлау
4. Баған бойынша сандарды түзулеу
1 және 2-ші функционалды файлға жазу арқылы істеуге болады. Бірақ екі күн скриптті қарай беріп жалығып кеттім. Кодты келесі ресурстардан қарауға болады: pastebin және github. href=«asciinema.org/a/9614»>asciinema.org сайтындағы жазба.
Ойынды қосу үшін, келесі командаларды орындаңыз:
chmod +x game2048.bash
./game2048.bash
Ойыннан шығу үшін Ctrl+C батырмасын басыңыз.
P.S. Ойында бір үлкен қателік бар, көреміз кімнің бірінші байқайтынын :-)
P.P.S. Сайтта мақала жарияланбағанына көп болыпты, белсенді болайық, қазақша ресурстарды көтерейік достар )) kamyrov бауырымыз айтқандай "Қазақ айтишниктері АЛҒА!)"
UPDATE. Ең бастысын ұмытып кетіппін. Ойынның басқарылуы. Ойында плиткаларды ығыстыру үшін «w», «s», «a», «d» батырмаларын пайдаланыңыз. Олар, сәйкесінше «Жоғары», «Төмен», «Солға» және «Оңға» ығыстыру.
-
+2