Надоели скучные и однообразные программы? Давайте немного пофантазируем и напишем программу, которая будет моделировать движение пьяного человека, и представим все это графически.
Суть программы будет заключаться в следующем:
Будем моделировать движение пьяного человека (он пьян до того, что не знает что делает, но лежать ему не хочется). В начальный момент времени задается положение человека в некотором дворе с непроницаемыми стенками и одним выходом. Кроме того даются 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: u1009612_e2003@mail.ru


