can you tell me what  this code  does:
 import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class NeuralDotGUI extends JPanel {

private NeuralDot neuralDot;
private int cellWidth;
private int cellHeight;

public NeuralDotGUI(NeuralDot neuralDot, int cellWidth, int cellHeight) {
this.neuralDot = neuralDot;
this.cellWidth = cellWidth;
this.cellHeight = cellHeight;
}

public void paintComponent(Graphics g) {
super.paintComponent(g);

// Draw grid cells
for (int i = 0; i < NeuralDot.GRID_SIZE; i++) {
for (int j = 0; j < NeuralDot.GRID_SIZE; j++) {
int x = i * cellWidth;
int y = j * cellHeight;
if (neuralDot.grid[i][j]) {
g.setColor(Color.GREEN);
} else {
g.setColor(Color.WHITE);
}
g.fillRect(x, y, cellWidth, cellHeight);
}
}

// Draw dot
g.setColor(Color.RED);
g.fillOval(neuralDot.x * cellWidth, neuralDot.y * cellHeight, cellWidth, cellHeight);
}

public static void main(String[] args) throws InterruptedException {
NeuralDot dot = new NeuralDot();
NeuralDotGUI gui = new NeuralDotGUI(dot, 10, 10);

JFrame frame = new JFrame();
frame.setTitle(“Neural Dot”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(gui);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

while (true) {
gui.repaint();
dot.run();
Thread.sleep(250);
}
}
}


next file : import java.util.Random;
public class NeuralNetwork {

private int numInputs;
private int numHidden;
private int numOutputs;
private double[][] inputHiddenWeights;
private double[][] hiddenOutputWeights;
private double[] hiddenBiases;
private double[] outputBiases;
private double learningRate;

public NeuralNetwork(int numInputs, int numHidden, int numOutputs, double learningRate) {
this.numInputs = numInputs;
this.numHidden = numHidden;
this.numOutputs = numOutputs;
this.learningRate = learningRate;

// Initialize weights and biases with random values between -1 and 1
inputHiddenWeights = new double[numInputs][numHidden];
hiddenOutputWeights = new double[numHidden][numOutputs];
hiddenBiases = new double[numHidden];
outputBiases = new double[numOutputs];
Random random = new Random();
for (int i = 0; i < numInputs; i++) {
for (int j = 0; j < numHidden; j++) {
inputHiddenWeights[i][j] = random.nextDouble() * 2 - 1;
}
}
for (int i = 0; i < numHidden; i++) {
for (int j = 0; j < numOutputs; j++) {
hiddenOutputWeights[i][j] = random.nextDouble() * 2 - 1;
}
hiddenBiases[i] = random.nextDouble() * 2 - 1;
}
for (int i = 0; i < numOutputs; i++) {
outputBiases[i] = random.nextDouble() * 2 - 1;
}
}

public double[] feedForward(double[] inputs) {
// Compute hidden layer activations
double[] hiddenLayer = new double[numHidden];
for (int i = 0; i < numHidden; i++) {
double activation = 0;
for (int j = 0; j < numInputs; j++) {
activation += inputs[j] * inputHiddenWeights[j][i];
}
hiddenLayer[i] = sigmoid(activation + hiddenBiases[i]);
}

// Compute output layer activations
double[] outputs = new double[numOutputs];
for (int i = 0; i < numOutputs; i++) {
double activation = 0;
for (int j = 0; j < numHidden; j++) {
activation += hiddenLayer[j] * hiddenOutputWeights[j][i];
}
outputs[i] = sigmoid(activation + outputBiases[i]);
}

return outputs;
}




public void train(double[] inputs, double[] targetOutputs, double reward) {
// Compute feedforward outputs and backpropagate errors
double[] hiddenLayer = new double[numHidden];
for (int i = 0; i < numHidden; i++) {
double activation = 0;
for (int j = 0; j < numInputs; j++) {
activation += inputs[j] * inputHiddenWeights[j][i];
}
hiddenLayer[i] = sigmoid(activation + hiddenBiases[i]);
}
double[] outputs = feedForward(inputs);
double[] outputErrors = new double[numOutputs];
for (int i = 0; i < numOutputs; i++) {
outputErrors[i] = (targetOutputs[i] - outputs[i]) * sigmoidDerivative(outputs[i]);
}
double[] hiddenErrors = new double[numHidden];
for (int i = 0; i < numHidden; i++) {
double error = 0;
for (int j = 0; j < numOutputs; j++) {
error += outputErrors[j] * hiddenOutputWeights[i][j];
}
hiddenErrors[i] = error * sigmoidDerivative(hiddenLayer[i]);
}
// Update weights and biases using errors and learning rate
for (int i = 0; i < numInputs; i++) {
for (int j = 0; j < numHidden; j++) {
inputHiddenWeights[i][j] += learningRate * inputs[i] * hiddenErrors[j];
}
}
for (int i = 0; i < numHidden; i++) {
for (int j = 0; j < numOutputs; j++) {
hiddenOutputWeights[i][j] += learningRate * hiddenLayer[i] * outputErrors[j];
}
hiddenBiases[i] += learningRate * hiddenErrors[i];
}
for (int i = 0; i < numOutputs; i++) {
outputBiases[i] += learningRate * outputErrors[i] * reward;
}
}


private double sigmoid(double x) {
return 1 / (1 + Math.exp(-x));
}

private double sigmoidDerivative(double x) {
return x * (1 - x);
}
}


next file : import java.util.Arrays;
import java.util.Random;

public class NeuralDot {

private static final int VISION_RANGE = 5;
public static final int GRID_SIZE = 100;
private static final int NUM_INPUTS = (2VISION_RANGE + 1) * (2VISION_RANGE + 1) + 2;
private static final int NUM_HIDDEN = 16;
private static final int NUM_OUTPUTS = 3;
private static final double LEARNING_RATE = 0.1;
private static final int NUM_EPISODES = 10000;

public int x;
public int y;
public boolean[][] grid;
private Random random;
private NeuralNetwork neuralNetwork;

public NeuralDot() {
x = GRID_SIZE / 2;
y = GRID_SIZE / 2;
grid = new boolean[GRID_SIZE][GRID_SIZE];
random = new Random();
neuralNetwork = new NeuralNetwork(NUM_INPUTS, NUM_HIDDEN, NUM_OUTPUTS, LEARNING_RATE);
}

public void run() {
for (int episode = 0; episode < NUM_EPISODES; episode++) {
// Reset the grid and place a food dot randomly
resetGrid();
placeFoodDot();

// Initialize variables for tracking dot movement and reward
int lastX = x;
int lastY = y;
int timeWithoutFood = 0;
double reward;

// Play the episode until the dot eats the food dot
while (!grid[x][y]) {
// Get the nearest food dot
int[] foodDot = getNearestFoodDot();

// Compute the inputs to the neural network
double[] inputs = new double[NUM_INPUTS];
int index = 0;
for (int i = x - VISION_RANGE; i <= x + VISION_RANGE; i++) {
for (int j = y - VISION_RANGE; j <= y + VISION_RANGE; j++) {
if (i < 0 || i >= GRID_SIZE || j < 0 || j >= GRID_SIZE) {
inputs[index++] = 0;
} else if (i == x && j == y) {
inputs[index++] = 1;
} else {
inputs[index++] = grid[i][j] ? -1 : 0;
}
}
}
inputs[index++] = foodDot[0] - x;
inputs[index++] = foodDot[1] - y;

// Compute the outputs of the neural network
double[] outputs = neuralNetwork.feedForward(inputs);

// Choose the action with the highest probability
double maxProbability = Double.NEGATIVE_INFINITY;
int action = 0;
for (int i = 0; i < NUM_OUTPUTS; i++) {
if (outputs[i] > maxProbability) {
maxProbability = outputs[i];
action = i;
}
}

// Take the chosen action
switch (action) {
case 0:
moveLeft();
break;
case 1:
moveRight();
break;
case 2:
moveForward();
break;
}

// Compute the reward signal
if (grid[x][y]) {
reward = 10;
timeWithoutFood = 0;
} else {
reward = -0.1;
if (x == lastX && y == lastY) {
timeWithoutFood++;
reward -= 0.01 * timeWithoutFood;
} else {
timeWithoutFood = 0;
}
}

// Train the neural network on the input-output pair
double[] targetOutputs = new double[NUM_OUTPUTS];
targetOutputs[action] = 1;
neuralNetwork.train(inputs, targetOutputs, reward);

// Update last movement variables
lastX = x;
lastY = y;
}
}
}

private void resetGrid() {
for (int i = 0; i < GRID_SIZE; i++) {
Arrays.fill(grid[i], false);
}
}

private void placeFoodDot() {
int foodX = random.nextInt(GRID_SIZE);
int foodY = random.nextInt(GRID_SIZE);
grid[foodX][foodY] = true;
}

private int[] getNearestFoodDot() {
int nearestX = -1;
int nearestY = -1;
double nearestDistance = Double.POSITIVE_INFINITY;
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
if (grid[i][j]) {
double distance = Math.sqrt((i - x)(i - x) + (j - y)(j - y));
if (distance < nearestDistance) {
nearestX = i;
nearestY = j;
nearestDistance = distance;
}
}
}
}
return new int[] {nearestX, nearestY};
}

private void moveLeft() {
int newX = x - 1;
if (newX < 0) {
newX = 0;
}

grid[x][y] = false;
x = newX;
grid[x][y] = true;
}

private void moveRight() {
int newX = x + 1;
if (newX >= GRID_SIZE) {
newX = GRID_SIZE - 1;
}

grid[x][y] = false;
x = newX;
grid[x][y] = true;
}

private void moveForward() {
int newY = y + 1;
if (newY >= GRID_SIZE) {
newY = GRID_SIZE - 1;
}

grid[x][y] = false;
y = newY;
grid[x][y] = true;
}

public static void main(String[] args) {
NeuralDot dot = new NeuralDot();
dot.run();
}

}