Доска Гальтона на C++ Builder 6.0
Изобразить на экране доску Гальтона с движущимися по ней шариками. Одновременно по доске должно двигаться несколько шариков. Использовать датчик случайных чисел для выбора пути шарика при прохождении через препятствие. Подсчитать число шариков, попавших в каждое из отделений.
Так или «примерно так» звучат задачи из этой серии….
Доска Гальтона (как в материальном, так и в виртуальном виде) при высокой точности изготовления (а умельцев, слава богу, во все времена хватало) демонстрирует «НОРМАЛЬНОЕ РАСПРЕДЕЛЕНИЕ» во всей его красе. Мы не знаем, как будет вести себя любой отдельный шар, но мы знаем, как будет себя вести «большое множество шаров».
Если взять тысячу шаров, то лишь единичные из них отклонятся от своей первоначальной траектории настолько,
что попадут в боковые отсеки (полюса). Большая же часть ляжет в центральные карманы.
Если один колышек сбивал их вправо, следующий направлял влево и так далее. Это явление называется «нормальным распределением»
и широко используется в теории вероятностей.
Нормальное распределение – это такой же мощный закон, как, допустим, гравитационное притяжение. Даже наша жизнь очень напоминает доску Гальтона. Черная полоса в жизни, как правило, сменяется белой. Человека качает из стороны в сторону, но бьет не до смерти. Отдельные личности, конечно, становятся маргиналами-бомжами или, напротив, миллионерами. Но, сами знаете, большинство из нас, поободрав бока о житейские «препятствия», рано или поздно останавливаются в умеренной зоне (т.е. вдали от полюсов).
Ну, «теории» достаточно… Пора дробить поставленную задачу на части…
Раз на экране должны двигаться шары – значит не обойтись без мультипликации.
Каждый очередной кадр должен показать шары с их новыми координатами (чуть ниже предыдущего местоположения,
а правее или левее, как бог-случай даст).
Понятно, что воронка, упоры и стаканы, на всех кадрах – это МОНУМЕНТЫ.
Сколько в воронке шаров я показываю только числом. Сколько шаров в каждом стакане показывает элемент класса CGauge. А вот все движущиеся шары нужно прорисовывать конкретно, где каждый из шаров, должен стереть свое предыдущее изображение и нарисовать новое... Так сколько же их будет? Какого размера массив создавать (под движущиеся шары)?
Безусловно, количество, одновременно движущихся шаров, зависит от количества стаканов (число которых, пусть задается пользователем). На единицу меньшим, чем количество стаканов, будет количество упоров в самом нижнем ряду. Да и количество рядов упоров будет таким же (на единицу меньшим, чем количество стаканов). Количество движущихся шаров целесообразно сделать меньше или равным количеству стаканов, допуская, что одновременно будет показываться шар над самым верхним упором или шар ниже последнего ряда упоров. Большее число одновременно движущихся шаров будет мешать зрительному восприятию траектории движения каждого отдельного шара.
const int ballcount=20; //максимальный размер массива движущихся шаров
Данные движущегося шара я храню (и изменяю) в трех массивах:
int h[ballcount], x[ballcount], znak[ballcount];//координаты рисования шарика и знак движения
Перебор всех движущихся шаров производится в процедуре-обработчике события таймера, формируя очередной кадр:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{ bool boolstop=true; //флаг останова, отключается во втором цикле, который крутится до конца (без break;)
//событие выпадения нового шара
if( inew==0 && n>0)
{
for(int i=0;i<ballcount;i++) if(h[i]==0) { x[i]=x0-d/2; h[i]=h0-1; break;}
Label1->Caption= --n; inew=cnew;
}
inew--;
//событие движение шара
for(int i=0;i<ballcount;i++)
if(h[i]>0)
{
DrawStepBall(x[i], h[i], znak[i]); // один шаг (стереть и снова нарисовать)
boolstop=false;
}
//событие окончания (все шары в стаканах)
if(boolstop)
{
Timer1->Enabled=false;
ShowMessage("Воронка опустела...!");
}
}
где inew – переменная модуля, а cnew константа, которые совместно обеспечивают равномерность событий выпадения следующего шара из воронки.
Таким образом, процедура DrawStepBall(x[i], h[i], znak[i]) для каждого шара выполняет один очередной шаг, изменяя его координаты (все параметры по ссылке).
При этом h[i] постоянно увеличивается, т.к. шар движется вниз, а горизонтальная координата x[i] зависит от значения znak[i] .
В момент касания шаром упора знак смещения генерируется случайным образом... И шар пойдет влево или вправо по воле случая в независимости от того, в какую сторону он двигался до этого.
Конечно, остаются еще некоторые вопросы (рабочие моменты), но Вы либо решите их самостоятельно,
либо узнаете после тестирования ехе-шника, когда закажите код целиком (на любом, нужном Вам, языке программирования).
скачать exe-файл для тестирования
для Windows 10 скачать exe-файл для тестирования
Другие примеры на тему «Математические методы компьютерной 2D 3D графики»
Другие примеры на тему «Компьютерные игры (учебные, простенькие)»
Другие примеры на языках «C»,«C++»,«C#»
Поделиться в соц сетях: