Давайте выберем несколько чисел, которые на первый взгляд кажутся простыми, и проверим их, как показано в листинге 12.8.
Листинг 12.8.Опробование сценария isprime с несколькими числами
$ isprime 77
No, 77 is not a prime
$ isprime 771
No, 771 is not a prime
$ isprime 701
Yes, 701 is a prime
Если вам любопытно, раскомментируйте команду echo в цикле while, чтобы увидеть, как выполняются вычисления, и получить представление, насколько быстро или медленно сценарий находит делитель, делящий число нацело, без остатка. В листинге 12.9 показано, что в этом случае получается при попытке проверить число 77.
Листинг 12.9.Запуск сценария с раскомментированной отладочной строкой
$ isprime 77
··for counter 2, remainder = 1
··for counter 3, remainder = 2
··for counter 4, remainder = 1
··for counter 5, remainder = 2
··for counter 6, remainder = 5
··for counter 7, remainder = 0
No, 77 is not a prime
Усовершенствование сценария
Сценарий реализует не самый эффективный алгоритм проверки числа, который работает тем медленнее, чем больше число. Например, взгляните на условие в цикле while. Сценарий раз за разом продолжает вычислять выражение $(expr $number / 2), тогда как его можно было вычислить только один раз и использовать вычисленное значение во всех последующих итерациях, сэкономив время на запуске подоболочки и вызове команды expr для вычисления значения, которое не изменяется ни на йоту до самой последней итерации.
Существуют также другие, не такие примитивные способы проверки простых чисел, включая замечательный алгоритм с интересным названием «Решето Эратосфена», более современный алгоритм «Решето Сундарама» или более сложный — «Решето Аткина». Поищите их описания в Интернете и проверьте с их помощью номер своего телефона (без дефисов!).
Это удобный сценарий для всех, кто любит играть в настольные игры, особенно ролевые, такие как Dungeons & Dragons .
В таких играх обычно бросаются кости, это может быть и один двадцатигранник, и шесть шестигранников, но в любом случае процесс основан на вероятностях. Игральные кости — по сути, простейший генератор случайных чисел, независимо от того, сколько таких генераторов задействовано в игре: один, два ( Monopoly или Trouble ) или больше.
Все эти случаи, как оказывается, легко смоделировать, что и делает сценарий в листинге 12.10, позволяющий указать количество и тип костей и затем «бросающий» их и возвращающий сумму.
Листинг 12.10.Сценарий rolldice
#!/bin/bash
# rolldice — анализирует количество и тип костей и имитирует их броски.
#·· Примеры: d6 = один шестигранник
#············2d12 = два двенадцатигранника у каждого
#············d4 3d8 2d20 = один четырехгранник, три восьмигранника
#··························и два двадцатигранника.
rolldie()
{
··dice=$1
··dicecount=1
··sum=0
··# Первый шаг: представить аргумент в формате MdN.
·· if [-z "$(echo $dice | grep 'd')"]; then
····quantity=1
····sides=$dice
··else
····quantity=$(echo $dice |
cut −f— f1)
····if [-z "$quantity"]; then # Пользователь указал dN, а не просто N.
······quantity=1
····fi
····sides=$(echo $dice | cut −dd −f2)
··fi
··echo ""; echo "rolling $quantity $sides-sided die"
··# Бросить кубик…
··while [$dicecount −le $quantity]; do
···· roll=$((($RANDOM % $sides) + 1))
····sum=$(($sum + $roll))
····echo " roll #$dicecount = $roll"
····dicecount=$(($dicecount + 1))
··done
··echo "I rolled $dice and it added up to $sum"
}
while [$# −gt 0]; do
··rolldie $1
··sumtotal=$(($sumtotal + $sum))
··shift
done
echo ""
echo "In total, all of those dice add up to $sumtotal"
echo ""
exit 0
Сценарий вращается вокруг простой строки кода, которая вызывает генератор случайных чисел оболочки bash, используя говорящую ссылку $RANDOM
. Это ключевая строка в сценарии, всё остальное лишь внешнее оформление.
Другой интересный фрагмент — где выполняется анализ описания костей
, потому что сценарий поддерживает все три формы: 3d8, d6 и 20. Это стандартная игровая нотация: количество костей + d + количество граней. Например, 2d6 означает: две кости с шестью гранями у каждой. Проверьте себя — сумеете ли вы сами разобраться, как обрабатываются все формы.
Читать дальше