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;
}
}
}