Визуализация работы лифта

У меня есть задача визуализировать и оптимизировать работы лифта ( оптимизацией еще не занимался) Код для работы лифта полностью готов, но неправильно работает. В одной строке производятся неправильные вычисления, и как их починить я не знаю.

namespace WindowsFormsApplication1
{

public partial class Form1 : Form
{
    public double time = -0.1;
    double time2 = 0;
    int lambda;//переменная для Пуассоновского потока
    double threshold;
    Random rand = new Random();
    int floor = 1 , target = 1;
    int wght, flrs;
    List<string> elevator = new List<string>();//список для пассажиров лифта
    List<string> pass =  new List<string>();//список потенциальных пассажиров появлющихся на этажах
    char name = 'A';

    public Form1()
    {
        InitializeComponent();

        flrs = (int)numericUpDown2.Value;
        wght = (int)numericUpDown1.Value;
        dataGridView1.RowCount = flrs;
        for (int i = 0; i < flrs; i++)
        {
            dataGridView1[0, i].Value = flrs - i;//рисование количества этажей(изначально)
            pass.Add(" ");
        }
        trackBar2.Value = 10;
    }

    void PosPrepare(int lambda)
    {
        threshold = Math.Exp(-lambda);// для Пуассоновского потока
    }


    int PosNext()// для Пуассоновского потока
    {
        int next = 0;
        for (double k = rand.NextDouble(); k > threshold; next++)
            k *= rand.NextDouble();
        return next;
    }


    void draw_passangers(int index)//отрисовка пассажиров на этажах
    {
        string s = "";
        foreach (char p in pass[index])
            s += " " + p;
        dataGridView1[2, flrs - 1 - index].Value = s;
    }

    void draw_elevator()// отрисовка лифта
    {
        string s = "[ ";
        foreach (string p in elevator)
            s += p;

        dataGridView1[1,flrs - floor].Value = s + "]";// ломается здесь
    }

    private void timer2_Tick(object sender, EventArgs e)// Пкссоновский поток для 1 этажа
    {
        time += timer2.Interval / 1000.0;
        if(pass.Count!=0)
        for (int j = 0; Math.Abs(time - time2) < 1e-10 || time > time2; j++)
        {
            if (j == 100) { trackBar2.Value++; return; }
            int next = PosNext();
            double delta = next * timer2.Interval / 1000;
            time2 = time + delta;
            int d = rand.Next(2, 10);
            pass[0] += name + Convert.ToString( d);//
            draw_passangers(0);
            if (name == 'Z') name = 'A'; else name++;

           timer2.Stop();
            Application.DoEvents();
          timer2.Start();
        }
    }

    private void timer3_Tick(object sender, EventArgs e)// Пуассоновский поток для отсальных этажей
    {
        time += timer3.Interval / 1000.0;

            for (int j = 0; Math.Abs(time - time2) < 1e-10 || time > time2; j++)
        {
            if (j == 100) { trackBar2.Value++; return; }
            int next = PosNext();
            double delta = next * timer3.Interval / 1000;
            time2 = time + delta;
            int fi = rand.Next(1, pass.Count);
            int d = (rand.Next(10) == 0) ? rand.Next(2, 10) : 1;
            //pass.Insert(fi, name + Convert.ToString(d));
            pass[fi] +=(name + Convert.ToString(d));
            draw_passangers(fi);
            if (name == 'Z') name = 'A'; else name++;
            timer3.Stop();
            Application.DoEvents();
            timer3.Start();
        }
    }



    private void trackBar1_Scroll(object sender, EventArgs e)// скорость лифта
    {
        timer1.Interval = trackBar1.Value;
    }

    private void Button2_Click(object sender, EventArgs e)
    {
        flrs = (int)numericUpDown2.Value;
        wght = (int)numericUpDown1.Value;
        dataGridView1.RowCount = flrs;
        pass.Clear();
        for (int i = 0; i < flrs; i++)
        {
            dataGridView1[0, i].Value = flrs - i;
            pass.Add(" ");
        }
    }

    private void Button1_Click(object sender, EventArgs e)
    {

        if (button1.Text == "Старт")
        {

            button1.Text = "Пауза";
            timer1.Start();
            timer2.Start();
            timer3.Start();
        }
        else
        {
            timer1.Stop();
            timer2.Stop();
            timer3.Stop();
            button1.Text = "Старт";

        }
    }

    private void trackBar2_ValueChanged_1(object sender, EventArgs e)// скорость спавна людей
    {
        lambda = trackBar2.Value;
        PosPrepare(lambda);
    }

    private void timer1_Tick(object sender, EventArgs e)//логика движения лифта
    {
            if (elevator.Count > 0)
                for (int i = 0; i < elevator.Count; i++)
                    if (elevator[i][0] - '0' == floor)
                    {
                        elevator.RemoveAt(i);
                        i--;
                    }

            dataGridView1[1, (int)numericUpDown2.Value - floor].Value = "";
        if (target > floor) floor++;
        //if (target > 0) ;
        else if (target < floor) floor--;
        else // достигнут целевой этаж
        {
            //if (elevator.Count > 0)
            //    elevator.RemoveAt(0);

            while (elevator.Count < wght && pass.Count() > flrs)/
            {
                elevator.Add(Convert.ToString(pass[floor - 1][0]));
                pass.RemoveAt(0);
                draw_passangers(floor - 1);
            }
            // elevator.Clear();
            if (elevator.Count > 0)// лоика движения лифта куда ехать на какаой этаж
            {
                int dmax = 0, t = 1;
                for (int i = 0; i < elevator.Count; i++)
                {

                    {
                        if (Math.Abs((int)(elevator[i][0] - '0') - floor) > dmax)//неправильные рассчеты тут
                        {
                            dmax = Math.Abs((elevator[i][0] - '0') - floor);
                            t = (elevator[i][0] - '0');
                        }
                    }
                }
                target = t;
            }
            else
            {
                for (int i = flrs; i > 0; i--)
                    if (pass.Count > 0)
                    {
                        target = i;
                        break;
                    }
            }
        }
            while (elevator.Count < wght && pass.Count > 0)// загрузка пассажиров
            {
            if (pass[floor] == null) break;
                elevator.Add(Convert.ToString(pass[floor - 1]));
                pass.RemoveAt(0);
                draw_passangers(floor - 1);
            }
        Application.DoEvents(); 
            draw_elevator();
        } 
    }        
}

Ответы (1 шт):

Автор решения: Bulson

Вот вам небольшой поэтапный пример.

Создайте в решении проект консольного приложения. И начните вот с этого.

class Elevator
{

}

class Program
{
    static void Main(string[] args)
    {
        //у нас есть лифт
        var elevator = new Elevator();
    }
}

Добавьте лифту положение этажа

class Elevator
{
    public int Level { get; private set; }

    public Elevator()
    {
        Level = 1;
    }
}

class Program
{
    static void Main(string[] args)
    {
        //у нас есть лифт
        var elevator = new Elevator();

        //изначально лифт на 1 этаже
        Console.WriteLine($"Лифт на этаже: {elevator.Level}");

        Console.WriteLine();
        Console.ReadLine();
    }
}

Теперь добавим лифту состояние

class Elevator
{
    public enum States
    {
        EmptyWaiting
    }
    public int Level { get; private set; }
    public States State { get; private set; }

    public Elevator()
    {
        Level = 1;
    }
}

class Program
{
    static void Main(string[] args)
    {
        //у нас есть лифт
        var elevator = new Elevator();

        //изначально лифт на 1 этаже
        Console.WriteLine($"Лифт на этаже: {elevator.Level}");
        //лифт пустой в ожидании
        Console.WriteLine($"Состояние лифта: {elevator.State}");

        Console.WriteLine();
        Console.ReadLine();
    }
}

Теперь лифту добавим команду на движение и новый тип состояния подъема

class Elevator
{
    public enum States
    {
        EmptyWaiting,
        EmptyClimbing
    }
    public int Level { get; private set; }
    public States State { get; private set; }

    public Elevator()
    {
        Level = 1;
    }

    public void GoTo(int level)
    {
        State = States.EmptyClimbing;
    }
}

class Program
{
    static void Main(string[] args)
    {
        //у нас есть лифт
        var elevator = new Elevator();

        //изначально лифт на 1 этаже
        Console.WriteLine($"Лифт на этаже: {elevator.Level}");
        //лифт пустой в ожидании
        Console.WriteLine($"Состояние лифта: {elevator.State}");
        Console.WriteLine(new string('-', 50));

        //поступил вызов с 6 этажа
        elevator.GoTo(6);
        //лифт поехал, он в движении наверх
        Console.WriteLine($"Состояние лифта: {elevator.State}");
        Console.WriteLine(new string('-', 50));

        Console.WriteLine();
        Console.ReadLine();
    }
}

Добавим лифту событие изменения его состояния

class Elevator
{
    public enum States
    {
        EmptyWaiting,
        EmptyClimbing,
        OpenDoorsWaiting
    }

    public event EventHandler<States> StateChanged;
    public int Level { get; private set; }
    public States State { get; private set; }

    public Elevator()
    {
        Level = 1;
    }

    public async Task GoTo(int level)
    {
        State = States.EmptyClimbing;
        StateChanged?.Invoke(this, this.State);

        for (int i = 1; i <= level; i++)
        {
            await Task.Delay(1000);
        }

        State = States.OpenDoorsWaiting;
        StateChanged?.Invoke(this, this.State);
    }
}

class Program
{
    static void Main(string[] args)
    {
        //у нас есть лифт
        var elevator = new Elevator();
        //подпишемся на изменение состояния лифта
        elevator.StateChanged +=
            (s, e) => Console.WriteLine($"Состояние лифта: {e}");

        //изначально лифт на 1 этаже
        Console.WriteLine($"Лифт на этаже: {elevator.Level}");
        //лифт пустой в ожидании
        Console.WriteLine($"Состояние лифта: {elevator.State}");
        Console.WriteLine(new string('-', 50));

        //поступил вызов с 6 этажа
        Console.WriteLine("Лифт поехал на 6 этаж");
        elevator.GoTo(6).GetAwaiter().GetResult();
        Console.WriteLine("Лифт приехал на 6 этаж и открыл двери");
        Console.WriteLine($"Лифт на этаже: {elevator.Level}");
        Console.WriteLine(new string('-', 50));

        Console.WriteLine();
        Console.ReadLine();
    }
}

Теперь будем считать этажи во время подъема и вызывать событие изменения этажа

class Elevator
{
    public enum States
    {
        EmptyWaiting,
        EmptyClimbing,
        OpenDoorsWaiting
    }

    public event EventHandler<States> StateChanged;
    public event EventHandler<int> LevelChanged;
    public int Level { get; private set; }
    public States State { get; private set; }

    public Elevator()
    {
        Level = 1;
    }

    public async Task GoTo(int level)
    {
        State = States.EmptyClimbing;
        StateChanged?.Invoke(this, this.State);

        for (int i = 1; i <= level; i++)
        {
            await Task.Delay(1000);
            Level = i;
            LevelChanged?.Invoke(this, this.Level);
        }

        State = States.OpenDoorsWaiting;
        StateChanged?.Invoke(this, this.State);
    }
}

class Program
{
    static void Main(string[] args)
    {
        //у нас есть лифт
        var elevator = new Elevator();
        //подпишемся на изменение состояния лифта
        elevator.StateChanged +=
            (s, e) => Console.WriteLine($"Состояние лифта: {e}");
        //подпишемся на изменение этажа у лифта
        elevator.LevelChanged +=
            (s, e) => Console.WriteLine($"Лифт на этаже: {e}");

        //изначально лифт на 1 этаже
        Console.WriteLine($"Лифт на этаже: {elevator.Level}");
        //лифт пустой в ожидании
        Console.WriteLine($"Состояние лифта: {elevator.State}");
        Console.WriteLine(new string('-', 50));

        //поступил вызов с 6 этажа
        Console.WriteLine("Лифт поехал на 6 этаж");
        elevator.GoTo(6).GetAwaiter().GetResult();
        Console.WriteLine("Лифт приехал на 6 этаж и открыл двери");
        Console.WriteLine($"Лифт на этаже: {elevator.Level}");
        Console.WriteLine(new string('-', 50));

        Console.WriteLine();
        Console.ReadLine();
    }
}

В конечном счете результ работы такой

пример работы консольного приложения

Теперь можно переходить к программе Windows Forms. Скопируйте в этот проект наш класс Лифта, добавьте коллекции картинок, напишите следующий код.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        this.Load += Form1_Load;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        _pictureBoxLevel.Image = _imageListLevels.Images[0];
        _pictureBoxState.Image = _imageListStates.Images[0];

        _buttonInvoke.Click += ButtonInvoke_Click;
    }

    private async void ButtonInvoke_Click(object sender, EventArgs e)
    {
        this.Form1_Load(this, EventArgs.Empty);
        await Task.Delay(500);

        var elevator = new Elevator();
        elevator.StateChanged += Elevator_StateChanged;
        elevator.LevelChanged += Elevator_LevelChanged;

        if (int.TryParse(_textBoxLevel.Text, out int level)
            && level > 1
            && level <= 9)
        {
            await elevator.GoTo(level);
        }
    }

    private void Elevator_LevelChanged(object sender, int e)
    {
        _pictureBoxLevel.Image = _imageListLevels.Images[--e];
    }

    private void Elevator_StateChanged(object sender, Elevator.States e)
    {
        switch (e)
        {
            case Elevator.States.EmptyWaiting:
                _pictureBoxState.Image = _imageListStates.Images[0];
                break;
            case Elevator.States.EmptyClimbing:
                _pictureBoxState.Image = _imageListStates.Images[1];
                break;
            case Elevator.States.OpenDoorsWaiting:
                _pictureBoxState.Image = _imageListStates.Images[2];
                break;
            default:
                break;
        }
    }
}

Получилось так

пример работы

Конечно этот пример еще очень далек от нужного результата, но я хотел вам показать сам принцип, как такое задание можно выполнить.

→ Ссылка