Skip to content

Commit

Permalink
Implementation for Neural Net menu.
Browse files Browse the repository at this point in the history
* Save best neural net.
* Load best neural net (e.g. from some earlier execution).
* Override all neural nets using the current best neural net.
  • Loading branch information
Thommynator committed Dec 19, 2018
1 parent b2ab7e0 commit a11ae50
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 20 deletions.
63 changes: 56 additions & 7 deletions src/main/java/thommynator/App.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
package thommynator;

import lombok.extern.slf4j.Slf4j;
import thommynator.game.GameCanvas;
import thommynator.game.Population;
import thommynator.game.Racetrack;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicInteger;

public class App extends JFrame {
import static thommynator.game.MenuContent.NEURALNET_LOAD;
import static thommynator.game.MenuContent.NEURALNET_OVERRIDE_BEST;
import static thommynator.game.MenuContent.NEURALNET_SAVE;
import static thommynator.game.MenuContent.RACE_START;
import static thommynator.game.MenuContent.RACE_STOP;

@Slf4j
public class App extends JFrame implements ActionListener {

public static final int MAP_WIDTH = 800;
public static final int MAP_HEIGHT = 600;
public static final AtomicInteger CAR_ID_FACTORY = new AtomicInteger(0);
public static final Racetrack RACETRACK = new Racetrack();
public static final Population POPULATION = new Population(200);
public static final int INITIAL_X = 30;
public static final int INITIAL_Y = 30;
public static final AtomicInteger CAR_ID_FACTORY = new AtomicInteger(0);


public App() {
Expand All @@ -33,20 +44,38 @@ private void initUI() {

// add a menu at the top
JMenuBar menuBar = new JMenuBar();
JMenuItem menuItem = null;
JMenu raceMenu = new JMenu("Race");
raceMenu.add(new JMenuItem("Start"));
raceMenu.add(new JMenuItem("Stop"));
menuItem = new JMenuItem(RACE_START.getMsg());
menuItem.addActionListener(this);
raceMenu.add(menuItem);

menuItem = new JMenuItem(RACE_STOP.getMsg());
menuItem.addActionListener(this);
raceMenu.add(menuItem);
menuBar.add(raceMenu);


JMenu neuralNetMenu = new JMenu("Neural Net");
neuralNetMenu.add(new JMenuItem("Save best..."));
neuralNetMenu.add(new JMenuItem("Load best..."));
menuItem = new JMenuItem(NEURALNET_SAVE.getMsg());
menuItem.addActionListener(this);
neuralNetMenu.add(menuItem);

menuItem = new JMenuItem(NEURALNET_LOAD.getMsg());
menuItem.addActionListener(this);
neuralNetMenu.add(menuItem);

menuItem = new JMenuItem(NEURALNET_OVERRIDE_BEST.getMsg());
menuItem.addActionListener(this);
neuralNetMenu.add(menuItem);

menuBar.add(neuralNetMenu);
setJMenuBar(menuBar);

// add the content panel
JPanel contentPanel = new JPanel();
contentPanel.setLayout(null);
contentPanel.add(new GameCanvas(new Population(200)));
contentPanel.add(new GameCanvas(POPULATION));
contentPanel.add(new Racetrack());

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Expand All @@ -58,4 +87,24 @@ private void initUI() {
// close window
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

@Override
public void actionPerformed(ActionEvent e) {

String actionCommand = e.getActionCommand();
if (actionCommand.equals(NEURALNET_SAVE.getMsg())) {
POPULATION.getBestCar().getNeuralNet().save();
log.info("Saved best Neural Net.");
}

if (actionCommand.equals(NEURALNET_LOAD.getMsg())) {
POPULATION.overrideAllWithJson();
log.info("Loaded best Neural Net.");
}

if (actionCommand.equals(NEURALNET_OVERRIDE_BEST.getMsg())) {
POPULATION.overrideAllWithBest();
log.info("Use the best neural net for all.");
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/thommynator/game/Car.java
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,4 @@ private boolean isInsideCanvas(double x, double y) {
&& y > buffer
&& y < (App.MAP_HEIGHT - buffer);
}
}
}
2 changes: 0 additions & 2 deletions src/main/java/thommynator/game/GameCanvas.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,11 @@ public void run() {

long now = System.currentTimeMillis();
if (now - epochStartTime > MAX_EPOCH_TIME) {
population.getBestCar().getNeuralNet().save();
population.nextGeneration();
epochStartTime = now;
}

if (!population.isAlive()) {
population.getBestCar().getNeuralNet().save();
population.nextGeneration();
epochStartTime = now;
}
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/thommynator/game/MenuContent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package thommynator.game;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
public enum MenuContent {

RACE_START("Start"),
RACE_STOP("Stop"),
NEURALNET_SAVE("Save best..."),
NEURALNET_LOAD("Load..."),
NEURALNET_OVERRIDE_BEST("Override all...");

@Getter
private final String msg;
}
20 changes: 10 additions & 10 deletions src/main/java/thommynator/game/Population.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class Population {
private ArrayList<Car> cars;

public Population(int amountOfCars) {
log.debug("Create a new population with {} cars.", amountOfCars);
log.debug("Create a new POPULATION with {} cars.", amountOfCars);
this.amountOfCars = amountOfCars;

cars = new ArrayList<>();
Expand All @@ -28,14 +28,14 @@ public Population(int amountOfCars) {
}

/**
* Generate a new population of cars from the current one.
* Generate a new POPULATION of cars from the current one.
* Cars with a high {@link Car#fitness} have a better chance to survive.
*/
public void nextGeneration() {
log.debug("Creating new generation...");
ArrayList<Car> children = new ArrayList<>();

// make sure, that the best car is for sure in the new population
// make sure, that the best car is for sure in the new POPULATION
Car bestCar = this.getBestCar();

Car child = this.generateChild(bestCar);
Expand All @@ -58,7 +58,7 @@ public void nextGeneration() {
}

/**
* Finds the best car of this population and returns it.
* Finds the best car of this POPULATION and returns it.
* The best car is the one with the highest {@link Car#fitness}.
*
* @return the {@link Car} with the hightest fitness.
Expand All @@ -85,7 +85,7 @@ public Car getBestCar() {

/**
* Checks if the populations is alive or dead.
* A population is dead, if all if its cars are dead. As long as one single car is alive, the whole populations
* A POPULATION is dead, if all if its cars are dead. As long as one single car is alive, the whole populations
* is alive.
*
* @return true if alive, otherwise false.
Expand All @@ -111,14 +111,14 @@ private Car mutateChild(Car child) {
}

/**
* Calls for all cars in the population the update method {@link Car#updateState()}.
* Calls for all cars in the POPULATION the update method {@link Car#updateState()}.
*/
public void update() {
cars.parallelStream().forEach(Car::updateState);
}

/**
* Loads the {@link NeuralNet} of the best car and uses it for the whole population.
* Loads the {@link NeuralNet} of the best car and uses it for the whole POPULATION.
* Every {@link Car} will have the same {@link NeuralNet} after this.
*/
public void overrideAllWithBest() {
Expand All @@ -127,19 +127,19 @@ public void overrideAllWithBest() {
}

/**
* Loads a {@link NeuralNet} from a json file and uses it for the whole population.
* Loads a {@link NeuralNet} from a json file and uses it for the whole POPULATION.
* Every {@link Car} will have the same {@link NeuralNet} after this.
*/
public void overrideAllWithJson() {
this.overrideAllWithJson("neural-net.json");
}

protected void overrideAllWithJson(String fileName) {
public void overrideAllWithJson(String fileName) {
NeuralNet neuralNet = NeuralNet.load(fileName);
this.overrideAllNeuralNets(neuralNet);
}

private void overrideAllNeuralNets(NeuralNet neuralNet) {
public void overrideAllNeuralNets(NeuralNet neuralNet) {
cars.parallelStream().forEach(car -> car.setNeuralNet(new NeuralNet(neuralNet)));
}

Expand Down

0 comments on commit a11ae50

Please sign in to comment.