/*
* Neural Tanks is a game created by Eddie O'Hagan that leverages Neural Networking
* to use for AI. This was created in Unreal Engine 4 which is developed by Epic Games.
* (Copyright Epic Games, Inc. All Rights Reserved.)
*
* Smart Tanks was originally developed by Mat Buckland in 2002 as an example
* on how Neural Networking can be used to train a set of minesweepers
* to collect mines. I (Eddie O'Hagan) updated this project in 2024 to use more
* Object Oriented Programming and modern practices. To see the original tutorial;
* visit <see href="http://www.ai-junkie.com/ann/evolved/nnt1.html">Neural Networking Tutorial</see>
* and <see href="http://www.ai-junkie.com/ga/intro/gat1.html">Genetic Algorithm Tutorial</see>
*/
#pragma once
#include "NeuronLayer.h"
#include "Chromosome.h"
#include "NeuralNetwork.generated.h"

/// <summary>
/// <b>NeuralNetwork:</b> Contains a collection of Neuron Layers which work with each other
/// to calculate output values based on the provided input values. For Smart Tanks specifically,
/// the Neural Network calculates the best left and right track speeds to get the most amount of TankAmmunitions.
/// This is done over generations; where Neuron weights are adjusted based on each others fitness score.
/// </summary>
UCLASS(config = Game)
class UNeuralNetwork : public UObject
{
	GENERATED_BODY()

protected:
	/// <summary>
	/// The number of inputs the Neural Network takes in to calculate the outputs.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "General")
	int	myNumberOfInputs;

	/// <summary>
	/// The number of outputs the Neural Network generates.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "General")
	int	myNumberOfOutputs;

	/// <summary>
	/// The number of hidden layers (middle layers) in the Neural Network.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "General")
	int	myNumberOfHiddenLayers;

	/// <summary>
	/// The total number of Neurons in each hidden layer.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "General")
	int	myNumberOfNeuronsPerHiddenLayer;

	/// <summary>
	/// The total number of Neuron inputs in the entire Neural Network.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "General")
	int myTotalNumberOfNeuronInputs;
	
	/// <summary>
	/// The collection of neuron layers that make up the Neural Network.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "General")
	TArray<UNeuronLayer*> myNeuronLayers;

	/// <summary>
	/// The calculated output values from the Neural Network.
	/// </summary>
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "General")
	TArray<float> myOutputs;

public:
	/// <summary>
	/// Default Constructor. Initializes the Neural Network by creating the input, hidden layer(s), 
	/// and output layers. 
	/// </summary>
	UNeuralNetwork();

	/// <summary>
	/// This is the "Meat and Potatoes" of the Neural Network. This takes the provided input values
	/// (in the example of smart tanks: the x,y look at vector of the Tank and the x,y position
	/// of the closest TankAmmunition, so 4 inputs in total).
	/// </summary>
	/// <param name="inputValues">The collection of inputs for the Neural Network to process.</param>
	/// <returns>The calculated outputs from the Neural Network.</returns>
	TArray<float> CalculateOutput(TArray<float>& inputs);
	
	/// <summary>
	/// Returns the number of inputs values this Neural Network reads in.
	/// </summary>
	/// <returns>The number of inputs values this Neural Network reads in.</returns>
	int GetNumberOfInputs() const;

	/// <summary>
	/// Returns the number of output values this Neural Network generates. 
	/// </summary>
	/// <returns>The number of output values this Neural Network generates.</returns>
	int GetNumberOfOutputs() const;

	/// <summary>
	/// Returns the total number of layers in the Neural Network.
	/// </summary>
	/// <returns>The total number of layers in the neural network.</returns>
	int GetNumberOfLayers() const;

	/// <summary>
	/// Returns the total number of Neuron inputs in the entire Neural Network.
	/// </summary>
	/// <returns>The total number of Neuron inputs in the entire Neural Network</returns>
	int GetTotalNumberOfNeuronInputs() const;

	/// <summary>
	/// Assigns the provided weights to the Neuron Layers in the Neural Network.
	/// </summary>
	/// <param name="weights">The weights to assign to the neural network.</param>
	void SetWeights(const TArray<float>& weights);
};