Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на языке Ruby.docx
Скачиваний:
18
Добавлен:
06.09.2019
Размер:
1.74 Mб
Скачать

18.2.1. Получение истинно случайных чисел из Web

Всякий, кто пытается сгенерировать случайное число, пользуясь детерминированными средствами, безусловно, живет во грехе.

Джон фон Нейман

В модуле Kernel есть функция rand, которая возвращает случайное число, но вот беда — число-то не является истинно случайным. Если вы математик, криптограф или еще какой-нибудь педант, то назовете эту функцию генератором псевдослучайных чисел, поскольку она пользуется алгебраическими методами для детерминированного порождения последовательности чисел. Стороннему наблюдателю эти числа представляются случайными и даже обладают необходимыми статистическими свойствами, но рано или поздно последовательность начнет повторяться. Мы можем даже намеренно (или случайно) повторить ее, задав ту же самую затравку.

Но природные процессы считаются истинно случайными. Поэтому при розыгрыше призов в лотерее счастливчики определяются лототроном, который хаотично выбрасывает шары. Другие источники случайности — радиоактивный распад или атмосферный шум.

Есть источники случайных чисел и в Web. Один из них — сайт www.random.org, который мы задействуем в следующем примере.

Программа в листинге 18.4 имитирует подбрасывание пяти обычных (шестигранных) костей. Конечно, игровые фанаты могли бы увеличить число граней до 10 или 20, но тогда стало бы сложно рисовать ASCII-картинки.

Листинг 18.4. Случайное бросание костей

require 'net/http'

HOST = "www.random.org"

RAND_URL = "/cgi-bin/randnum?col=5&"

def get_random_numbers(count=1, min=0, max=99)

 path = RAND_URL + "num=#{count}&min=#{min}&max=#{max}"

 connection = Net::HTTP.new(HOST)

 response, data = connection.get(path)

 if response.code == "200"

  data.split.collect { |num| num.to_i }

 else

  []

 end

end

DICE_LINES = [

 "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ ",

 "|     | |  *  | |  *  | | * * | | * * | | * * | ",

 "|  *  | |     | |  *  | |     | |  *  | | * * | ",

 "|     | |  *  | |  *  | | * * | | * * | | * * | ",

 "+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ "

DIE_WIDTH = DICE_LINES[0].length/6

def draw_dice(values)

 DICE_LINES.each do | line |

  for v in values

   print line[(v-1)*DIE_WIDTH, DIE_WIDTH]

   print " "

  end

  puts

 end

end

draw_dice(get_random_numbers(5, 1, 6))

Здесь мы воспользовались классом Net::НТТР для прямого взаимодействия с Web-сервером. Считайте, что эта программа — узкоспециализированный браузер. Мы формируем URL и пытаемся установить соединение; когда оно будет установлено, мы получаем ответ, возможно, содержащий некие данные. Если код ответа показывает, что ошибок не было, то можно разобрать полученные данные. Предполагается, что исключения будут обработаны вызывающей программой.

Посмотрим на вариацию этой идеи. Что если вы захотели бы применить случайные числа в каком-нибудь приложении? Поскольку обслуживающая программа на стороне сервера позволяет указать количество возвращаемых чисел, то было бы логично сохранить их в буфере. Учитывая, что при обращении к удаленному серверу задержки неизбежны, следует сразу заполнить буфер во избежание лишних запросов по сети.

В листинге 18.5 эта мысль реализована. Буфер заполняется отдельным потоком и совместно используется всеми экземплярами класса. Размер буфера и «нижняя отметка» (@slack) настраиваются; какие значения задать в реальной программе, зависит от величины задержки при обращении к серверу и от того, как часто приложение выбирает случайное число из буфера.