motkot
@motkot
Программирование C#.

Как исправить нейросеть для пошаговой стратегии?

Буду благодарен если поможете. Здраствуйте, Никогда не писал нейросети. И решил сделать нейросеть для пошаговой стратегии. Посмотрел, почитал. Нашел вот эту штуку

Решил использовать.

Написал вот это:

Код
private void SetBrain(NeuralNetwork brain) // Создаю нейросеть
    {
        Brain = brain;
    }

    private void Awake()
    {
        SetBrain(new NeuralNetwork(new int[] { 5, 5, 5, 1 })); // Задаю значения

        var load = GridAction.PlayerTurn.LoadNeuralNetwork(this); // Загружаю сохраненную нейросеть

        if (!load) // Если нету сохраненной, тогда создать новую.
        {
            SetBrain(new NeuralNetwork(new int[] { 5, 5, 5, 1 }));
        }
    }

public IEnumerator UseNeuralNetwork()
    {
        if(IsAI)
        {
            yield return new WaitForSeconds(1);

            CalculateAttackVariant(CurrentCell);
            CalculateMoveVariant(CurrentCell);

            float[] inputs = new float[5];

            inputs[0] = MoveVariants.Count; // Количество возможных ходов.
            inputs[1] = AttackVariants.Count; // Количество возможных ходов для атаки.
            inputs[2] = Health; // Здоровье персонажа.
            inputs[3] = Damage; // Урон персонажа.
            inputs[4] = GridAction.PlayerTurn.CalculateMinimalDistance(GridAction.PlayerTurn.PlayerUnits, transform.position); // Дистанция до ближайшего персонажа
            Brain.fitness = Fitness; // Передаю текущую полезность в нейросеть

            var output = Brain.FeedForward(inputs); // Результат нейросети

            if (MoveVariants.Count == 0 && AttackVariants.Count != 0) // Если нету ходов, но есть ходы для атаки, то атаковать.
            {
                output[0] = -1;
            }

            if (MoveVariants.Count == 0 && AttackVariants.Count == 0) // Если вообще нету ходов, то пропустить
            {
                yield break;
            }

            if (AttackVariants.Count == 0 && output[0] < 0) // Если нету ходов для атаки, а вывод был меньше нуля, тогда переводить на положительное и говорить что это не правильно
            {
                Fitness -= 1;

                output[0] = 1;
            }

            if (output[0] > 0) // Если вывод больше нуля, то ходить
            {
                inputs[0] = MoveVariants.Count; // такие же параметры
                inputs[1] = AttackVariants.Count;
                inputs[2] = Health;
                inputs[3] = Damage;
                inputs[4] = GridAction.PlayerTurn.CalculateMinimalDistance(GridAction.PlayerTurn.PlayerUnits, transform.position);
                Brain.fitness = Fitness;

                output = Brain.FeedForward(inputs); // результат

                float MinimalValue = 1f / MoveVariants.Count; // делим количество вариантов хода на 1 и потом прибавляем это к переменной CurrentValue, чтобы понять куда нужно пойти ( сам до этого додумался и надеюсь это нормально )
                float CurrentValue = MinimalValue;
                int VariantIndex = 0;

                int i = MoveVariants.Count + AttackVariants.Count; // количество итераций

                while (i > 0)
                {
                    if (CurrentValue < CurrentValue + MinimalValue)
                    {
                        break;
                    }

                    CurrentValue += MinimalValue;

                    VariantIndex++;
                    i--;
                }

                // Логика ходьбы
                GridAction.SelectedCell = CurrentCell;

                GridAction.OnPlayerMove(ref CurrentCell.UnitInCell, MoveVariants[VariantIndex]);

                // Говорю что ходить - это не правильно чтобы нейросеть пыталась как можно быстрее закончить игру.
                Fitness -= 3;
            }
            else
            {
                inputs[0] = MoveVariants.Count;
                inputs[1] = AttackVariants.Count;
                inputs[2] = Health;
                inputs[3] = Damage;
                inputs[4] = GridAction.PlayerTurn.CalculateMinimalDistance(GridAction.PlayerTurn.PlayerUnits, transform.position);
                Brain.fitness = Fitness;

                output = Brain.FeedForward(inputs);

                // Тоже самое что и с ходьбой

                float MinimalValue = 1f / AttackVariants.Count;
                float CurrentValue = MinimalValue;
                int VariantIndex = 0;

                int i = MoveVariants.Count + AttackVariants.Count;

                while (i > 0)
                {
                    if (CurrentValue < CurrentValue + MinimalValue)
                    {
                        break;
                    }

                    CurrentValue += MinimalValue;

                    VariantIndex++;
                    i--;
                }

                // Логика атаки
                GridAction.SelectedCell = CurrentCell;

                GridAction.OnPlayerAttack(AttackVariants[VariantIndex], this);

                // Говорю что атака это хорошо
                Fitness += 60;
            }
        }
    }


Перезапуск сцены
public void Gameover()
    {
        if (PlayerUnits.Count == 0) // Добавление правильности при выйгрыше определенной команды
        {
            foreach (UnitBase unit in EnemyUnits)
            {
                unit.Fitness += 200;
                unit.Brain.fitness = unit.Fitness;
            }
        }
        else
        {
            foreach (UnitBase unit in PlayerUnits)
            {
                unit.Fitness += 200;
                unit.Brain.fitness = unit.Fitness;
            }
        }

        // Выбор лучшего юнита по количеству очкой правильности

        UnitBase highEnemy = null;

        float fitness = 0;

        foreach (UnitBase unit in EnemyUnits)
        {
            if (unit.Fitness > fitness)
            {
                highEnemy = unit;

                fitness = highEnemy.Fitness;
            }
        }

        foreach (UnitBase unit in PlayerUnits)
        {
            if (unit.Fitness > fitness)
            {
                highEnemy = unit;

                fitness = highEnemy.Fitness;
            }
        }


        // Сохранять текущую нейросеть

        highEnemy.Brain.Save($@"C:\Users\forgu\Desktop\Нейросеть\high.txt");

        // Перезапуск сцены

        SceneManager.LoadScene(0);
    }


-------------------------------------------------------------------------------------------------------------------------------------------------

У меня такие проблемы:

Нейросеть не идет к персонажу если он не рядом с ним, а ходит туда и обратно.

Мне кажется я даю ей не правильные входные данные. Что изменить.

У меня такие вопросы:

Правильно ли я обрабатываю результат?

Обучается ли вообще нейросеть? Работает ли Save?

Заранее спасибо!
  • Вопрос задан
  • 330 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы