Пример Windows-приложения «Стрельба по мишени»

В рамках курсовой работы по информатике студентом 1 курса одного из вузов было получено следующее задание:

В одномерном массиве с четным количеством элементов (2N) находятся координаты N точек плоскости. Они располагаются в следующем порядке: x1, y1, x2, y2, x3, y3 и т.д. Определить минимальный радиус круга с центром в начале координат, которое содержит все точки. Язык Visual Basic (VB).

Студент, ранее занимавшийся со мной программированием, решил эту задачу в среде Visual Studio 2017 Community, используя пакет «Разработка классических приложений .Net» и язык Visual Basic. В заметке «Стрельба по мишени. Пример реализации на Visual Basic» я привожу его решение с небольшими комментариями.

Постановка задачи

Немного расширим и уточним постановку задачи. Пусть точка на плоскости — это отверстие от пули в мишени. Стрельба ведется на открытой местности и на ее результат влияет скорость и направление ветра. Кроме того, стрелок обладает навыками стрельбы, что проявляется в расположении пробоин в мишени (случайным образом) и в некотором круге, определяющим кучность стрельбы. Кроме того, добавим графическую иллюстрацию результатов стрельбы.

Решение

Создадим форму приложения, на котором разместим следующие визуальные элементы: 3 кнопки (button1,2,3), 2 простых списка (listBox1,2), окно рисования (pictureBox1 — белый квадрат), 5 текстовых полей (textBox1,…,5) и 7 надписей (label1,…,7).

Для задания параметров используем свойства, задаваемый с проверкой через элементы TextBox, для чего добавим в пространство имен проекта класс RIN, описанный в заметке Свойства. Пример «Ввод целого числа в заданном диапазоне». Модель стрельбы — пули равномерно распределены в круге, радиус которого определяется радиусом мишени и кучностью стрельбы, а центр круга смещается в направлении ветра в зависимости от его скорости. Элемент listBox2 используем для отображения характеристик стрельбы (радиус максимального круга, координаты наиболее удаленной от центра мишени пробоины, рекомендуемая поправка на ветер).

В классе Form1 зададим следующие поля:

Point [] p = new Point[1000]; // массив точек - не более 1000
int n_fakt; // фактическое число пробоин
int Rmin = 0; // Результат - минимальный радиус
Graphics graph1; // Графический контент - холст

Отдельные алгоритмы реализуем в методах:
public void shots(Point [] p, int N, int D, int W, int R, int K)   // стрельба и
private int MinRad(Point[] p, int n, out int t)   // Нахождение минимального радиуса и «номера» точки.

События Click  на кнопках будут обрабатываться соответствующими методами.

Для графической иллюстрации результатов стрельбы воспользуемся методами класса Graphics из библиотеки System.Drawing, в частности для поворота  оси Y метод ScaleTransform(1, -1), а для сдвига по осям X и Y — метод TranslateTransform(200, -200).

Текст файла Form1.cs (без класса RID):

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Стрельба_по_мишени
{ 
   public partial class Form1 : Form
   {
      Point [] p = new Point[1000]; // массив точек - не более 1000
      int n_fakt; // фактическое число пробоин
      int Rmin = 0; // Результат - минимальный радиус
      Graphics graph1; // Графический контент - холст

      // конструктор
      public Form1()
      {
         InitializeComponent();
         graph1 = this.pictureBox1.CreateGraphics();
      }

      // стрельба
      public void shots(Point [] p, int N, int D, int W, int R, int K)
      {
         Random ran = new Random();
         for (int i = 0; i < N; i ++)
         {
            double r = R * (11 - K) / 10 * ran.NextDouble();
            double fi = 2 * Math.PI * ran.NextDouble();
            p[i].X = Convert.ToInt32(W * Math.Cos(D * Math.PI / 180) + r * Math.Cos(fi));
            p[i].Y = Convert.ToInt32(W * Math.Sin(R * Math.PI / 180) + r * Math.Sin(fi));
         }
      }
      // Нахождение минимального радиуса и "номера" точки
      private int MinRad(Point[] p, int n, out int t)
      {
         double R = 0.0; // минимальный радиус
         double R1; // радиус точки (x,y)
         t = -1; // номер точки
         // Цикл по всем точкам, нахождение радиуса R
         for (int i = 0; i < n; i++)
         {
            R1 = Math.Sqrt(p[i].X * p[i].X + p[i].Y * p[i].Y);
            if (R1 > R)
            {
               R = R1;
               t = i;
            }
         }
         return Convert.ToInt32(R); // Минимальный радиус
      }

      // Запуск стрельбы по мишени и расчет минимального радиуса круга, содержащего все попадания 
      private void button1_Click(object sender, EventArgs e)
      {
         // Задание параметров:
         RIN n = new RIN( textBox1.Text, 1, 1000, 20, "число пуль");
         n_fakt = n.N;
         textBox1.Text = n.N.ToString();
         if (!n.n_bool)
            MessageBox.Show(n.info);
         RIN d = new RIN(textBox2.Text, 0, 360, 180, "направление ветра");
         if (!d.n_bool)
         {
            MessageBox.Show(d.info);
            textBox2.Text = d.N.ToString();
         }
         RIN w = new RIN(textBox3.Text, 0, 20, 20, "скорость ветра");
         if (!w.n_bool)
         {
            MessageBox.Show(w.info);
            textBox3.Text = w.N.ToString();
         }
         RIN r = new RIN(textBox4.Text, 100, 200, 200, "радиус мишени");
         if (!r.n_bool)
         {
            MessageBox.Show(r.info);
            textBox4.Text = r.N.ToString();
         }
         RIN k = new RIN(textBox5.Text, 1, 10, 3, "кучность стрельбы");
         if (!k.n_bool)
         {
            MessageBox.Show(k.info);
            textBox5.Text = k.N.ToString();
         }
      // Заполнение мишени случайными пробоинами
         shots(p, n.N, d.N, w.N, r.N, k.N);
      // Вывод массива точек (x,y) в ListBox1
         listBox1.Items.Clear();
         for (int i = 0; i < n.N; i++)
            listBox1.Items.Add(p[i].X.ToString() + " " + p[i].Y.ToString());
      // Нахождение минимального радиуса и "номера" точки k
         int t = -1;
         Rmin = MinRad(p, n.N, out t);
      // Вывод результата в ListBox2
         listBox2.Items.Clear();
         listBox2.Items.Add("Результат :");
         listBox2.Items.Add("Радиус максимального круга = " + Rmin.ToString());
     //  Для контроля:
         listBox2.Items.Add("Cамая удаленная точка № " + (t+1).ToString() + " x = " + p[t].X.ToString() + " y = " + p[t].Y.ToString());
         int grad = d.N;
         if (grad < 180)
            grad += 180;
         else
            grad -= 180;
         listBox2.Items.Add("Нужна поправка " + w.N + " на " + grad.ToString() + " градусов");
      }

// Графическая иллюстрация
private void button2_Click(object sender, EventArgs e)
{
// инструменты
Pen Pen1 = new Pen(Color.Green, 2); // Линии
Pen Pen2 = new Pen(Color.Red, 1); // Окружность
Pen Pen3 = new Pen(Color.Blue, 1); // Точки
Pen Pen4 = new Pen(Color.Black, 1); // Мишень
SolidBrush brush1 = new SolidBrush(Color.Black); // Текст меток на осях
Font font1 = new Font("Arial", 10); // Шрифт и размер меток
// Связывание холста с pictureBox
graph1 = this.pictureBox1.CreateGraphics();
// Отметки на координатных осях
Single X, Y;
for (X = -200; X <= 200; X += 50)
graph1.DrawString(X.ToString(), font1, brush1, X + 200, 200);
for (Y = -200; Y <= 200; Y += 50)
graph1.DrawString(Y.ToString(), font1, brush1, 200, 200 - Y); 
// Преобразование компьютерной системы координат в математическую
// Поворот оси Y
graph1.ScaleTransform(1, -1);
// Сдвиг по осям X и Y
graph1.TranslateTransform(200, -200);
// Рисование осей математической системы координат
// Ось X
graph1.DrawLine(Pen1, -200, 0, 200, 0);
// Ось Y
graph1.DrawLine(Pen1, 0, -200, 0, 200);
// Делаем засечки по осям координат
for (X = -200; X<=200; X+=50)
graph1.DrawLine(Pen1, X, -5, X, 5);
for (Y = -200; Y<=200; Y+=50)
graph1.DrawLine(Pen1, -5, Y, 5, Y); 
// концентрические круги: 10, 9, 8, ... , 1 (подсчет очков)
int rm = Convert.ToInt32(textBox4.Text);
double dr = rm/10;
double rz = 0;
for (int i=0; i<10; i++)
{
rz += dr;
int riz = (int) rz;
graph1.DrawEllipse(Pen4, -riz, - riz, 2*riz, 2*riz);
}
// Рисуем точки и окружность минимального радиуса
int n = n_fakt;
for (int i = 0; i < n; i++)
graph1.FillEllipse(new SolidBrush(Color.BlueViolet), p[i].X - 3, p[i].Y - 3, 6, 6);
graph1.DrawEllipse(Pen2, -Rmin, -Rmin, 2 * Rmin, 2 * Rmin);
}
// Очистка холста
private void button3_Click(object sender, EventArgs e)
{
graph1.Clear(Color.White);
}
}  // end class Form1
// Здесь должно быть описание класса RIN
}

Результат одной из стрельб:

Конец примера.

Примечание. Изучите последствия ошибок ввода параметров, например, задайте количество пуль 0, 2, 25,999,1002, 3.5, qwerty. Все ли ошибки ввода обрабатываютcя успешно?

 


NEW: Наш Чат, в котором вы можете обсудить любые вопросы, идеи, поделиться опытом или связаться с администраторами.


Помощь проекту:

Понравилась статья? Поделиться с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
1 Комментарий
Новые
Старые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

Суперкруто

1
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x
()
x