Загрузка данных
#!/usr/bin/env bash
# Создать и перемешать колоду.
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
}
# Посчитать очки руки. Туз при необходимости превращается из 11 в 1.
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
new_deck
player_cards=()
player_values=()
dealer_cards=()
dealer_values=()
echo
echo "=== Игра «21 очко» ==="
# Сначала две карты получает игрок.
for _ in 1 2; do
draw_card
player_cards+=("$CARD")
player_values+=("$CARD_VALUE")
done
# Затем две карты получает дилер.
for _ in 1 2; do
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
echo
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)
draw_card
player_cards+=("$CARD")
player_values+=("$CARD_VALUE")
player_total=$(total "${player_values[@]}")
show_hand "Ваши карты" "${player_cards[@]}"
printf 'Ваши очки: %s\n' "$player_total"
;;
н|Н|нет|Нет|НЕТ|n|N)
break
;;
*)
echo "Введите «д» (добрать) или «н» (остановиться)."
;;
esac
done
echo
# Если игрок не перебрал, после его хода играет дилер.
if (( player_total <= 21 )); then
echo "Теперь ход дилера."
show_hand "Карты дилера" "${dealer_cards[@]}"
printf 'Очки дилера: %s\n' "$(total "${dealer_values[@]}")"
dealer_total=$(total "${dealer_values[@]}")
# Дилер добирает, пока у него меньше 17 очков.
while (( dealer_total < 17 )); do
draw_card
dealer_cards+=("$CARD")
dealer_values+=("$CARD_VALUE")
dealer_total=$(total "${dealer_values[@]}")
echo "Дилер берёт карту: $CARD"
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
read -r -p "Сыграть ещё раз? (д/н): " again
case "$again" in
д|Д|да|Да|ДА|y|Y)
;;
*)
echo "Спасибо за игру!"
break
;;
esac
done