Загрузка данных
#!/usr/bin/env bash
# Показать анимацию загрузки.
# Второй аргумент — число шагов; один шаг длится 0.1 секунды.
loading() {
local message=$1
local steps=${2:-10}
local i
local frames=("|" "/" "-" "\\")
for ((i = 0; i < steps; i++)); do
printf '\r%s %s' "$message" "${frames[i % 4]}"
sleep 0.1
done
printf '\r%s Готово.\n' "$message"
}
# Создать и перемешать колоду из 52 карт.
new_deck() {
deck=()
for suit in "черви" "бубны" "трефы" "пики"; do
for rank in {1..13}; do
deck+=("$rank:$suit")
done
done
# Перемешивание колоды.
for ((i = ${#deck[@]} - 1; i > 0; i--)); do
j=$((RANDOM % (i + 1)))
temp=${deck[i]}
deck[i]=${deck[j]}
deck[j]=$temp
done
deck_position=0
}
# Взять следующую карту из колоды.
draw_card() {
local card=${deck[deck_position]}
((deck_position++))
local rank=${card%%:*}
local suit=${card#*:}
case "$rank" in
1)
CARD="Туз $suit"
CARD_VALUE=11
;;
11)
CARD="Валет $suit"
CARD_VALUE=10
;;
12)
CARD="Дама $suit"
CARD_VALUE=10
;;
13)
CARD="Король $suit"
CARD_VALUE=10
;;
*)
CARD="$rank $suit"
CARD_VALUE=$rank
;;
esac
}
# Подсчитать очки. Если нужно, считать туз за 1 вместо 11.
total() {
local sum=0
local aces=0
local value
for value in "$@"; do
sum=$((sum + value))
if (( value == 11 )); then
aces=$((aces + 1))
fi
done
while (( sum > 21 && aces > 0 )); do
sum=$((sum - 10))
aces=$((aces - 1))
done
printf '%s' "$sum"
}
# Показать карты.
show_hand() {
local title=$1
shift
printf '%s: ' "$title"
printf '%s; ' "$@"
printf '\n'
}
# Проверить блэкджек: две карты на сумму 21.
is_blackjack() {
local card_count=$1
shift
(( card_count == 2 )) && (( $(total "$@") == 21 ))
}
while true; do
echo
echo "=== Игра «21 очко» ==="
loading "Перемешиваем колоду" 12
new_deck
player_cards=()
player_values=()
dealer_cards=()
dealer_values=()
# Сначала карты получает игрок.
echo "Раздаём карты..."
for _ in 1 2; do
sleep 0.5
draw_card
player_cards+=("$CARD")
player_values+=("$CARD_VALUE")
done
# Затем карты получает дилер.
for _ in 1 2; do
sleep 0.5
draw_card
dealer_cards+=("$CARD")
dealer_values+=("$CARD_VALUE")
done
show_hand "Ваши карты" "${player_cards[@]}"
printf 'Ваши очки: %s\n' "$(total "${player_values[@]}")"
printf 'Открытая карта дилера: %s\n' "${dealer_cards[0]}"
echo "Вторая карта дилера пока скрыта."
player_total=$(total "${player_values[@]}")
player_blackjack=0
dealer_blackjack=0
if is_blackjack "${#player_cards[@]}" "${player_values[@]}"; then
player_blackjack=1
echo "У вас блэкджек!"
fi
if is_blackjack "${#dealer_cards[@]}" "${dealer_values[@]}"; then
dealer_blackjack=1
fi
# Проверить блэкджек сразу после раздачи.
if (( player_blackjack || dealer_blackjack )); then
loading "Открываем карты дилера" 8
show_hand "Карты дилера" "${dealer_cards[@]}"
printf 'Очки дилера: %s\n' "$(total "${dealer_values[@]}")"
if (( player_blackjack && dealer_blackjack )); then
echo "У обоих блэкджек — ничья."
elif (( player_blackjack )); then
echo "Вы выиграли: у вас блэкджек!"
else
echo "Дилер выиграл: у него блэкджек."
fi
else
# Сначала игрок решает, брать ли ещё карту.
while (( player_total < 21 )); do
read -r -p "Взять карту? (д/н): " answer
case "$answer" in
д|Д|да|Да|ДА|y|Y)
loading "Вы берёте карту" 6
draw_card
player_cards+=("$CARD")
player_values+=("$CARD_VALUE")
player_total=$(total "${player_values[@]}")
echo "Вам выпала карта: $CARD"
show_hand "Ваши карты" "${player_cards[@]}"
printf 'Ваши очки: %s\n' "$player_total"
;;
н|Н|нет|Нет|НЕТ|n|N)
echo "Вы остановились."
break
;;
*)
echo "Введите «д» (добрать) или «н» (остановиться)."
;;
esac
done
echo
if (( player_total <= 21 )); then
# Только после хода игрока открываются карты дилера.
loading "Теперь ход дилера" 10
show_hand "Карты дилера" "${dealer_cards[@]}"
dealer_total=$(total "${dealer_values[@]}")
printf 'Очки дилера: %s\n' "$dealer_total"
# Дилер добирает карты, пока у него меньше 17 очков.
while (( dealer_total < 17 )); do
loading "Дилер берёт карту" 7
draw_card
dealer_cards+=("$CARD")
dealer_values+=("$CARD_VALUE")
dealer_total=$(total "${dealer_values[@]}")
echo "Дилеру выпала карта: $CARD"
show_hand "Карты дилера" "${dealer_cards[@]}"
printf 'Очки дилера: %s\n' "$dealer_total"
done
else
dealer_total=$(total "${dealer_values[@]}")
echo "У вас перебор — дилер не добирает карты."
fi
echo
show_hand "Ваши карты" "${player_cards[@]}"
printf 'Ваши очки: %s\n' "$player_total"
show_hand "Карты дилера" "${dealer_cards[@]}"
printf 'Очки дилера: %s\n' "$dealer_total"
if (( player_total > 21 )); then
echo "Вы перебрали — дилер выиграл."
elif (( dealer_total > 21 )); then
echo "Дилер перебрал — вы выиграли!"
elif (( player_total > dealer_total )); then
echo "Вы выиграли!"
elif (( player_total < dealer_total )); then
echo "Дилер выиграл."
else
echo "Ничья."
fi
fi
echo
read -r -p "Сыграть ещё раз? (д/н): " again
case "$again" in
д|Д|да|Да|ДА|y|Y)
;;
*)
echo "Спасибо за игру!"
break
;;
esac
done