Надоели скучные и однообразные программы? Давайте немного пофантазируем и напишем программу, которая будет моделировать движение пьяного человека, и представим все это графически.
Суть программы будет заключаться в следующем:
Будем моделировать движение пьяного человека (он пьян до того, что не знает что делает, но лежать ему не хочется). В начальный момент времени задается положение человека в некотором дворе с непроницаемыми стенками и одним выходом. Кроме того даются 5 вероятностей - остаться на месте и перемещаться в 4 стороны. Если появляется попытка переместиться через стенку, то «пьяньчуга» остается на месте. Сумма вероятностей строго равно 1. Если «пьяньчуга» нашел выход или попал в один из люков, то моделирование заканчивается и выводится соответствующее сообщение.
И так, в Visual Studio в C# создайте форму, и объекты как показано на рисунке «Рисунок 1.1». Соответственно, к каждому объекту подписано его имя.
После создания формы и всех ее объектов приступим к написанию кода программы.
Для начала я перечислю, какие библиотеки и глобальные переменные необходимы для работы программы.
Библиотеки:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D;
Глобальные переменные:
Point[,] coord = new Point[11, 11]; Point[] coord_courses; coord_points[] mass_points; Point PointUser = new Point(); Point PointUser_For_searche = new Point(); int shag = 5; Graphics Line; Rectangle EllipseDraw = new Rectangle(); Rectangle EllipseDraw2 = new Rectangle(); GraphicsPath GraphicsPathEllipse;
Для того чтобы запоминать сколько раз «пьяньчуга» попадал в ту или иную точку, мы будем использовать структуру «coord_points», которая включает в себя координаты точки x и y и количество попаданий «Count». Структуру объявляем глобально.
public struct coord_points { int x; int y; int Count; public coord_points(int X, int Y, int count) { x = X; y = Y; Count = count; } public int X { get { return x; } set { x = value; } } public int Y { get { return y; } set { y = value; } } public int count { get { return Count; } set { Count = value; } } };
Теперь напишем код для кнопки «Нарисовать местность».
pictureBox.Refresh(); //Обновить область для рисования listBox1.Items.Clear(); // Очищаем ListBox с координатами isleovanie.Text = ""; // Очищаем значение исследования Line = Graphics.FromHwnd(pictureBox.Handle); // Создаем объект для рисования на pictureBox count_iter.Text = 0.ToString();//Обнуляем поле «Кол-во итераций» distance.Text = 0.ToString();//Обнуляем поле «Расстояние (пиксеметры)» count_courses.Text = 0.ToString();//Обнуляем поле «Общее кол-во шагов» count_down.Text = 0.ToString();//Обнуляем поле количество шагов «Вниз» count_up.Text = 0.ToString();//Обнуляем поле количество шагов «Вверх» count_l.Text = 0.ToString();//Обнуляем поле количество шагов «Влево» count_r.Text = 0.ToString();//Обнуляем поле количество шагов «Вправо» System.Drawing.Pen red = new Pen(Color.Red, 1); SolidBrush EllipseBrush = new SolidBrush(Color.Black); Graphics Ellipse = Graphics.FromHwnd(pictureBox.Handle); Graphics Ellipse2 = Graphics.FromHwnd(pictureBox.Handle); GraphicsPathEllipse = new GraphicsPath(); Random rnd = new Random(); int max_h = pictureBox.Height / 2 + pictureBox.Height / 4; int max_w = pictureBox.Width / 2 + pictureBox.Width / 4; int temp = 0; Point start1 = new Point(10, 10); Point start2 = new Point(10, 10); Point end1 = new Point(10, pictureBox.Height - 50); Point end2 = new Point(pictureBox.Width - 10, 10); Point end3 = new Point(pictureBox.Width - 10, pictureBox.Height - 50); //Координаты помещения coord[0, 0].X = end2.X - rnd.Next(pictureBox.Width / 3, pictureBox.Width / 2); coord[0, 0].Y = start1.Y; coord[0, 1].X = end2.X - rnd.Next(5, pictureBox.Width / 3); coord[0, 1].Y = end2.Y; //Слева линия coord[1, 0].X = start1.X; coord[1, 0].Y = start1.Y; coord[1, 1].X = end1.X; coord[1, 1].Y = end1.Y; //Верхняя coord[2, 0].X = start1.X; coord[2, 0].Y = start1.Y; coord[2, 1].X = coord[0, 0].X; coord[2, 1].Y = end2.Y; //Верхняя 2 coord[6, 0].X = coord[0, 1].X; coord[6, 0].Y = start1.Y; coord[6, 1].X = end2.X; coord[6, 1].Y = end2.Y; //Правая coord[3, 0].X = end2.X; coord[3, 0].Y = end2.Y; coord[3, 1].X = end3.X; coord[3, 1].Y = end3.Y; //Нижняя coord[4, 0].X = end1.X; coord[4, 0].Y = end1.Y; coord[4, 1].X = end3.X - pictureBox.Width / 2 - pictureBox.Width / 3 - rnd.Next(0, 30); coord[4, 1].Y = end3.Y; //Нижняя coord[7, 0].X = end3.X - pictureBox.Width / 4 - pictureBox.Width / 2 - rnd.Next(0, 50); coord[7, 0].Y = end1.Y; coord[7, 1].X = end3.X; coord[7, 1].Y = end3.Y; //Нижняя 2 coord[8, 0].X = coord[4, 1].X; coord[8, 0].Y = end3.Y; coord[8, 1].X = coord[4, 1].X; coord[8, 1].Y = end3.Y + 40; //Нижняя 2 coord[9, 0].X = coord[7, 0].X; coord[9, 0].Y = end3.Y; coord[9, 1].X = coord[7, 0].X; coord[9, 1].Y = coord[8, 1].Y; //Нижняя 3 coord[10, 0].X = coord[8, 1].X; coord[10, 0].Y = coord[8, 1].Y; coord[10, 1].X = coord[9, 1].X; coord[10, 1].Y = coord[9, 1].Y; //Координаты для эллипса coord[5, 0].X = rnd.Next(50, max_w); coord[5, 0].Y = rnd.Next(50, max_h); coord[5, 1].X = rnd.Next(50, max_w); coord[5, 1].Y = rnd.Next(50, max_h); for (; ; ) { if (coord[5, 1].X == 0 || coord[5, 1].Y == 0) { temp = rnd.Next(50, max_w); if (temp != coord[5, 0].X) coord[5, 1].X = temp; temp = rnd.Next(50, max_w); if (temp != coord[5, 0].Y) coord[5, 1].Y = temp; } else break; } ////////////////// EllipseDraw = new Rectangle(coord[5, 0].X, coord[5, 0].Y, 10, 10); EllipseDraw2 = new Rectangle(coord[5, 1].X, coord[5, 1].Y, 10, 10); Line.DrawLine(red, start1.X, start1.Y, end1.X, end1.Y); //Левая Line.DrawLine(red, coord[2, 0].X, coord[2, 0].Y, coord[2, 1].X, coord[2, 1].Y); //Верхняя Line.DrawLine(red, coord[6, 0].X, coord[6, 0].Y, coord[6, 1].X, coord[6, 1].Y); //Верхняя Line.DrawLine(red, end2, end3); //Правая Line.DrawLine(red, coord[4, 0].X, coord[4, 0].Y, coord[4, 1].X, coord[4, 1].Y); //Нижняя прямая Line.DrawLine(red, coord[7, 0].X, coord[7, 0].Y, coord[7, 1].X, coord[7, 1].Y); //Нижняя прямая Line.DrawLine(red, coord[8, 0].X, coord[8, 0].Y, coord[8, 1].X, coord[8, 1].Y); //Нижняя 2 слева Line.DrawLine(red, coord[9, 0].X, coord[9, 0].Y, coord[9, 1].X, coord[9, 1].Y); //Нижняя 2 справа Line.DrawLine(red, coord[10, 0].X, coord[10, 0].Y, coord[10, 1].X, coord[10, 1].Y); //Нижняя 3 прямая int el_x1 = rnd.Next(50, max_w); int el_y1 = rnd.Next(50, max_h); GraphicsPathEllipse.AddEllipse(new Rectangle(el_x1, el_y1, 10, 10));//Рисуем первый люк Ellipse.FillEllipse(EllipseBrush, new Rectangle(el_x1, el_y1, 10, 10)); //Рисуем случайно все остальные люки (kolvolukov.Text – кол-во люков) for (int i = 2; i < = Convert.ToInt32(kolvolukov.Text); i++) { int el_x2 = rnd.Next(50, max_w); int el_y2 = rnd.Next(50, max_h); for (; ; ) { if (el_x2 == 0 || el_y2 == 0) { temp = rnd.Next(50, max_w); if (temp != el_x1) el_x2 = temp; temp = rnd.Next(50, max_w); if (temp != el_y1) el_y2 = temp; } else break; } el_x1 = el_x2; el_y1 = el_y2; GraphicsPathEllipse.AddEllipse(new Rectangle(el_x2, el_y2, 10, 10)); Ellipse.FillEllipse(EllipseBrush, new Rectangle(el_x2, el_y2, 10, 10)); } searching.Enabled = true; //Активируем кнопку «Провести исследование»
Напишем метод «MessageShow», который будет выводить сообщение на экран при завершении моделирования. void MessageShow(int type) { if(type == 1) MessageBox.Show("Моделирование закончено!"); else MessageBox.Show("Пьянчуга попал в люк"); } Теперь напишем объект «check», который осуществляет ряд проверок движения «пьяньчуги». Если «пьяньчуга» нашел выход или попал в один из люков, выводится соответствующее сообщение и моделирование прекращается.
int check(int type) { //Конец пути пьянчуги if (PointUser.X >= coord[0, 0].X && PointUser.X < = coord[0, 1].X && PointUser.Y { if(type == 1) MessageShow(1); return -1; } //Пьянчуга попал в люк if (GraphicsPathEllipse.IsVisible(PointUser)) { if(type == 1) MessageShow(2); return -1; } //Слева линия if (PointUser.X = coord[1, 0].Y && PointUser.Y < = coord[1, 1].Y) { PointUser.X += shag; } //Верхняя if(PointUser.X >= coord[2, 0].X && PointUser.X < = coord[2, 1].X && PointUser.Y = coord[6, 0].X && PointUser.X < = coord[6, 1].X && PointUser.Y = coord[3, 0].X && PointUser.Y >= coord[3, 0].Y && PointUser.Y < = coord[3, 1].Y) { PointUser.X -= shag; } //Нижняя if ((PointUser.X >= coord[4, 0].X && PointUser.X < = coord[4, 1].X) && PointUser.Y >= coord[4, 1].Y) { PointUser.Y -= shag; } if ((PointUser.X >= coord[7, 0].X && PointUser.X < = coord[7, 1].X) && PointUser.Y >= coord[7, 1].Y) { PointUser.Y -= shag; } if (PointUser.X < = coord[8, 0].X && PointUser.Y >= coord[8, 0].Y && PointUser.Y < = coord[8, 1].Y) { PointUser.X += shag; } if ((PointUser.X >= coord[10, 0].X && PointUser.X < = coord[10, 1].X) && PointUser.Y >= coord[10, 1].Y) { PointUser.Y -= shag; } if (PointUser.X >= coord[9, 0].X && PointUser.Y >= coord[9, 0].Y && PointUser.Y < = coord[9, 1].Y)//Нижняя 2 справа { PointUser.X -= shag; } return 0; }
Следующие объекты и методы необходимы для проверки правильного указания коэффициентов вероятности перемещения и количества люков.
bool check_ver() { double sum = Convert.ToDouble(go_up.Text) + Convert.ToDouble(go_down.Text) + Convert.ToDouble(go_right.Text) + Convert.ToDouble(go_left.Text); if (sum > 1 || sum < 1) MessageBox.Show("Сумма коэффициентов направленности превышает допустимое значение равное 1."); else if (Convert.ToInt32(kolvolukov.Text) < 1 || Convert.ToInt32(kolvolukov.Text) > 50) MessageBox.Show("Количество люков не может быть меньше 1 или больше 50."); else return true; return false; } //Запускается, когда происходит изменение Вероятности перемещения «Вверх» private void go_up_TextChanged(object sender, EventArgs e) { check_ver(); } //Запускается, когда происходит изменение Вероятности перемещения «Вниз» private void go_down_TextChanged(object sender, EventArgs e) { check_ver(); } //Запускается, когда происходит изменение Вероятности перемещения «Вправо» private void go_right_TextChanged(object sender, EventArgs e) { check_ver(); } //Запускается, когда происходит изменение Вероятности перемещения «Влево» private void go_left_TextChanged(object sender, EventArgs e) { check_ver(); } //Запускается, когда происходит изменение поля Количество люков private void kolvolukov_TextChanged(object sender, EventArgs e) { check_ver(); }
Напишем методы, которые изменяют шаг движения. Если на объект выводятся «точки», шаг составляет 5, если цифры – 15. Создано для удобства вывода на экран.
private void pic_point_CheckedChanged(object sender, EventArgs e) { shag = 5; } private void pic_char_CheckedChanged(object sender, EventArgs e) { shag = 15; } //Объект «isPoint» возвращает положение координаты точки, если она есть в массиве mass_points int isPoint(Point mass_nums, coord_points[] mass_points) { for (int i = 0; i < mass_points.Count(); i++) { if (mass_points[i].X == mass_nums.X && mass_points[i].Y == mass_nums.Y) return i; } return -1; } //Метод «setCount» увеличивает счетчик попадания человека в точку на 1 void setCount(coord_points[] mass_points, int index) { mass_points[index].count = mass_points[index].count + 1; } // Метод «listBox1_MouseDoubleClick» вызывается при двойном клике на объект «listBox1», где хранятся координаты перемещения «пьяньчуги». Метод выделяет красным цветом точку по указанной координате. private void listBox1_MouseDoubleClick(object sender, MouseEventArgs e) { System.Drawing.Pen red = new Pen(Color.Red, 2); Graphics Ellipse = Graphics.FromHwnd(pictureBox.Handle); Ellipse.DrawEllipse(red, new Rectangle(mass_points[listBox1.Items.IndexOf(listBox1.Text)].X, mass_points[listBox1.Items.IndexOf(listBox1.Text)].Y, 2, 2)); }
Наконец, метод «pictureBox_MouseDown», который осуществляет моделирование движения пьяного человека.
private void pictureBox_MouseDown(object sender, MouseEventArgs e) { if (check_ver() == true)//Если все проверки прошли { PointUser.X = e.X; //Получаем X-координату точки PointUser.Y = e.Y; //Получаем Y-координату точки PointUser_For_searche.X = e.X; PointUser_For_searche.Y = e.Y; Line = Graphics.FromHwnd(pictureBox.Handle); System.Drawing.Graphics graph = Graphics.FromHwnd(pictureBox.Handle); System.Drawing.Pen WhiteSmoke = new Pen(Color.WhiteSmoke, 1); System.Drawing.Pen Black = new Pen(Color.Black, 2); EllipseDraw = new Rectangle(PointUser.X, PointUser.Y, 2, 2); Graphics Ellipse = Graphics.FromHwnd(pictureBox.Handle); Ellipse.DrawEllipse(Black, EllipseDraw); Random rnd = new Random(); int count = 0, countiter = 0, c_left = 0, c_right = 0, c_up = 0, c_down = 0; double hod, left, right, up, down; coord_courses = new Point[Convert.ToInt32(count_steps.Text)]; List mass_nums = new List(); for (int i = 1; i < = Convert.ToInt32(count_steps.Text); i++) { if (rnd.Next(1, 5) != 1)//Если вероятность не «стоять на месте» { coord_courses[count] = PointUser; mass_nums.Add(PointUser); hod = rnd.NextDouble(); up = Convert.ToDouble(go_up.Text); down = Convert.ToDouble(go_down.Text); right = up + down; left = up + down + Convert.ToDouble(go_right.Text); //Если вероятность «идти влево» if (hod > left && hod < left + Convert.ToDouble(go_left.Text)) { PointUser.X -= shag; if (check(1) == -1) break; else { if (pic_point.Checked) Ellipse.DrawEllipse(Black, new Rectangle(PointUser.X, PointUser.Y, 2, 2)); } c_left++; } else if (hod > 0 && hod < up) //Если вероятность «идти вверх» { PointUser.Y -= shag; if (check(1) == -1) break; else { if (pic_point.Checked) Ellipse.DrawEllipse(Black, new Rectangle(PointUser.X, PointUser.Y, 2, 2)); } c_up++; } else if (hod > right && hod < right + Convert.ToDouble(go_right.Text)) //вправо { PointUser.X += shag; if (check(1) == -1) break; else { if (pic_point.Checked) Ellipse.DrawEllipse(Black, new Rectangle(PointUser.X, PointUser.Y, 2, 2)); } c_right++; } else if (hod > up && hod < up + down) //вниз { PointUser.Y += shag; if (check(1) == -1) break; else { if (pic_point.Checked) Ellipse.DrawEllipse(Black, new Rectangle(PointUser.X, PointUser.Y, 2, 2)); } c_down++; } } countiter++; } count = c_down + c_left + c_right + c_up; count_iter.Text = countiter.ToString(); distance.Text = (count).ToString(); count_courses.Text = count.ToString(); count_down.Text = c_down.ToString(); count_up.Text = c_up.ToString(); count_l.Text = c_left.ToString(); count_r.Text = c_right.ToString(); up = Convert.ToDouble(go_up.Text); down = Convert.ToDouble(go_down.Text); right = Convert.ToDouble(go_right.Text); left = Convert.ToDouble(go_left.Text); if (up > down && up > right && up > left) isleovanie.Text = "При к.н. (Вверх) пьянчуга прошел " + Math.Round(((double)c_up / (double)count) * 100) + "% пути"; else if (down > up && down > right && down > right) isleovanie.Text = "При к.н. (Вниз) пьянчуга прошел " + Math.Round(((double)c_down / (double)count) * 100) + "% пути"; else if (right > up && right > left && right > down) isleovanie.Text = "При к.н. (Вправо) пьянчуга прошел " + Math.Round(((double)c_right / (double)count) * 100) + "% пути"; else if (left > up && left > right && left > down) isleovanie.Text = "При к.н. (Влево) пьянчуга прошел " + Math.Round(((double)c_left / (double)count) * 100) + "% пути"; mass_points = new coord_points[mass_nums.Count]; Point[] coord_courses2 = new Point[mass_nums.Count]; int index = 0, j = 0; for (int i = 0; i < mass_nums.Count; i++) if ((index = isPoint(mass_nums[i], mass_points)) > -1) { setCount(mass_points, index); } else { mass_points[j].X = mass_nums[i].X; mass_points[j].Y = mass_nums[i].Y; mass_points[j].count = 1; j++; } for (int i = j - 1; i >= 0; i--) { if (!pic_point.Checked) { if (i + 1 == j) graph.DrawString(mass_points[i].count.ToString(), new Font("Times New Roman", 8), new SolidBrush(Color.Red), mass_points[i].X - 3, mass_points[i].Y - 8); else graph.DrawString(mass_points[i].count.ToString(), new Font("Times New Roman", 8), new SolidBrush(Color.Black), mass_points[i].X - 3, mass_points[i].Y - 8); } listBox1.Items.Add("X:" + mass_points[i].X + "; Y:" + mass_points[i].Y + "; Кол-во:" + mass_points[i].count); } } }
Напишем последний метод «searching_Click», чтобы завершить написание программы. Здесь выполняется исследование.
private void searching_Click(object sender, EventArgs e) { Random rnd = new Random(); int count = 0, countiter = 0, c_left = 0, c_right = 0, c_up = 0, c_down = 0; double hod, left, right, up, down; for (int sch = 1; sch < = 10; sch++) { PointUser = PointUser_For_searche; for (int i = 1; i left && hod < left + Convert.ToDouble(go_left.Text)) //влево { PointUser.X -= shag; if (check(2) == -1) break; c_left++; } else if (hod > 0 && hod < up) //вверх { PointUser.Y -= shag; if (check(2) == -1) break; c_up++; } else if (hod > right && hod < right + Convert.ToDouble(go_right.Text)) //вправо { PointUser.X += shag; if (check(2) == -1) break; c_right++; } else if (hod > up && hod < up + down) //вниз { PointUser.Y += shag; if (check(2) == -1) break; c_down++; } } countiter++; } } count = c_down + c_left + c_right + c_up; count_iter.Text = countiter.ToString(); distance.Text = (count).ToString(); count_courses.Text = count.ToString(); count_down.Text = c_down.ToString(); count_up.Text = c_up.ToString(); count_l.Text = c_left.ToString(); count_r.Text = c_right.ToString(); up = Convert.ToDouble(go_up.Text); down = Convert.ToDouble(go_down.Text); right = Convert.ToDouble(go_right.Text); left = Convert.ToDouble(go_left.Text); if (up > down && up > right && up > left) { isleovanie.Text = "При к.н. (Вверх) пьянчуга прошел " + Math.Round(((double)c_up / (double)count) * 100) + "% пути"; label10.Text = "Среднее значение: " + Math.Round((double)c_up / (double)count, 2).ToString(); } else if (down > up && down > right && down > right) { isleovanie.Text = "При к.н. (Вниз) пьянчуга прошел " + Math.Round(((double)c_down / (double)count) * 100) + "% пути"; label10.Text = "Среднее значение: " + Math.Round((double)c_down / (double)count, 2).ToString(); } else if (right > up && right > left && right > down) { isleovanie.Text = "При к.н. (Вправо) пьянчуга прошел " + Math.Round(((double)c_right / (double)count) * 100) + "% пути"; label10.Text = "Среднее значение: " + Math.Round((double)c_right / (double)count, 2).ToString(); } else if (left > up && left > right && left > down) { isleovanie.Text = "При к.н. (Влево) пьянчуга прошел " + Math.Round(((double)c_left / (double)count) * 100) + "% пути"; label10.Text = "Среднее значение: " + Math.Round((double)c_left / (double)count, 2).ToString(); } }
После написание кода программы проверим ее работу:
-
Указать вероятности перемещения
-
Указать количество люков и тактов
-
Выбрать метод представления пути перемещения («Точки» или «Цифры»)
-
Кликнуть по кнопке «Нарисовать местность»
-
Кликнуть мышкой по области рисования «pictureBox»
-
Посмеяться над «пьяньчугой»
-
Кликнуть по кнопке «Провести исследование»
Примеры работы программы:
«Пьяньчуга» попал в люк:
«Пьяньчуга» нашел выход:
Данную статью Вы можете скачать в формате doc
Скачать Пьяньчуга - Моделирование движения пьяного человека на C#
Автор: Евтеев Евгений Александрович
Email: [email protected]