Skip to content

Commit

Permalink
pawn
Browse files Browse the repository at this point in the history
  • Loading branch information
lukzarczynski committed Oct 29, 2017
1 parent 2279068 commit 1275d9f
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 81 deletions.
3 changes: 3 additions & 0 deletions src/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: com.lukzar.Main

4 changes: 1 addition & 3 deletions src/com/lukzar/Main.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.lukzar;

import com.lukzar.config.Configuration;
import com.lukzar.config.Templates;
import com.lukzar.model.Piece;
import com.lukzar.services.Evolution;
Expand All @@ -23,13 +22,12 @@ public static void main(String[] args) throws IOException {
final Evolution evolution = new Evolution();
evolution.initialize();
System.out.println("Initial population size: " + evolution.getPopulation().size());
evolution.getPopulation().sort(Evolution.FITNESS_COMPARATOR);
writeToFile(evolution.getPopulation(), "out/population_0");

for (int i = 1; i <= 10; i++) {
evolution.evolvePopulation();
System.out.println("Population " + i + " size: " + evolution.getPopulation().size());
System.out.println(evolution.getPopulation().stream().filter(Piece::isAsymmetric).count());
// System.out.println(evolution.getPopulation().stream().filter(Piece::isAsymmetric).count());
writeToFile(evolution.getPopulation(), String.format("out/population_%s", i));

}
Expand Down
2 changes: 1 addition & 1 deletion src/com/lukzar/fitness/FitnessAttribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public enum FitnessAttribute {
BOX_LENGTH("Box Length: %.3f"),
BASE_WIDTH("Base width Length: %.3f"),
AREA("Area: %.3f ( 100%%, %s of total area )", Configuration.Piece.WIDTH * Configuration.Piece.HEIGHT),
UP_HALF_AREA("Upper Half Area: %.3f ( %s )", AREA),
TOP_HALF_AREA("Upper Half Area: %.3f ( %s )", AREA),
BOTTOM_HALF_AREA("Lower Half Area: %.3f ( %s )", AREA),
MID_Y_AREA("Middle Half over Y Area: %.3f ( %s )", AREA),
MID_X_AREA("Middle Half over X Area: %.3f ( %s )", AREA),
Expand Down
84 changes: 45 additions & 39 deletions src/com/lukzar/fitness/FitnessUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,12 @@
import com.lukzar.utils.RayCasting;
import com.lukzar.utils.Timer;

import java.util.ArrayList;
import java.util.Collection;
import java.util.DoubleSummaryStatistics;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;

import static com.lukzar.fitness.FitnessAttribute.ARC_LENGTH;
import static com.lukzar.fitness.FitnessAttribute.AREA;
import static com.lukzar.fitness.FitnessAttribute.AVERAGE_DEGREE;
import static com.lukzar.fitness.FitnessAttribute.BASE_WIDTH;
import static com.lukzar.fitness.FitnessAttribute.BOTTOM_HALF_AREA;
import static com.lukzar.fitness.FitnessAttribute.BOX_LENGTH;
import static com.lukzar.fitness.FitnessAttribute.CENTROID;
import static com.lukzar.fitness.FitnessAttribute.DOUBLE_ARC_LENGTH;
import static com.lukzar.fitness.FitnessAttribute.HEIGHT;
import static com.lukzar.fitness.FitnessAttribute.LINE_LENGTH;
import static com.lukzar.fitness.FitnessAttribute.MID_X_AREA;
import static com.lukzar.fitness.FitnessAttribute.MID_Y_AREA;
import static com.lukzar.fitness.FitnessAttribute.MIN_DEGREE;
import static com.lukzar.fitness.FitnessAttribute.SHAPE_LENGTH;
import static com.lukzar.fitness.FitnessAttribute.SYMMETRIC;
import static com.lukzar.fitness.FitnessAttribute.TRIANGLE_BASE_AREA;
import static com.lukzar.fitness.FitnessAttribute.TRIANGLE_PIECE_AREA;
import static com.lukzar.fitness.FitnessAttribute.UP_HALF_AREA;
import static com.lukzar.fitness.FitnessAttribute.WIDTH;
import static com.lukzar.fitness.FitnessAttribute.*;
import static com.lukzar.utils.PolygonUtils.distance;

/**
Expand Down Expand Up @@ -76,20 +52,50 @@ public static double calculateFitness(Piece svg) {

final Map<FitnessAttribute, Object> attributes = getAttributes(svg);


double doubleArcLength = (Double) attributes.get(DOUBLE_ARC_LENGTH);
double arcLength = (Double) attributes.get(ARC_LENGTH);
double lineLength = (Double) attributes.get(LINE_LENGTH);
double boxLength = (Double) attributes.get(BOX_LENGTH);
double area = (Double) attributes.get(AREA);
double topArea = (Double) attributes.get(TOP_HALF_AREA);
double bottomArea = (Double) attributes.get(BOTTOM_HALF_AREA);
double middleArea = (Double) attributes.get(MID_Y_AREA);
double MinDegree = (Double) attributes.get(MIN_DEGREE);
double height = (Double) attributes.get(HEIGHT);
double width = (Double) attributes.get(WIDTH);
boolean symmetric = (Boolean) attributes.get(SYMMETRIC);
double averageDegree = (Double) attributes.get(AVERAGE_DEGREE);
double minDegree = (Double) attributes.get(MIN_DEGREE);

double topRatio = topArea / area;
double bottomRatio = bottomArea / area;
double midRatio = middleArea / area;
double perimeter = doubleArcLength + arcLength + lineLength;
double perimeterRatio = perimeter / boxLength;
double narrowness = height / width;
double lineRatio = lineLength / perimeter;
double doubleArcRatio = doubleArcLength / perimeter;
double arcRatio = arcLength / perimeter;
double areaRatio = area / (width * height);


// fitness
double result = 0.0;
// result += normalize((height / width));
// result += normalize(1 - (lengthOfLines / boxLength));
// result += normalize(lengthOfArcs / boxLength);
// result += normalize(lengthOfDoubleArcs / boxLength);
// result += normalize(areaLowerHalf / (areaUpperHalf + 0.001));
// result += areaUpperHalf / area;
// result += 1.5 - (areaLowerHalf / area);
// result += 0.5 * (area / (200 * 200));
// result += normalize(areaMiddle / area);
// result += normalize(1 - (areaLowerHalf / area));
// result += normalize(1 - (lengthOfLines / boxLength));
// result += normalize(lengthOfArcs / boxLength);

result += 0.54 * arcRatio;
// result += -0.54 * area;
result += -0.063 * areaRatio;
result += -0.054 * averageDegree;
result += 0.119 * bottomRatio;
result += 0.0 * doubleArcRatio;
// result += -0.110 * height;
result += -0.054 * lineRatio;
result += 0.110 * midRatio;
result += -0.009 * minDegree;
result += -0.110 * narrowness;
result += -0.119 * perimeter;
result += -0.145 * perimeterRatio;

return result;
}
Expand Down Expand Up @@ -157,7 +163,7 @@ public static LinkedHashMap<FitnessAttribute, Object> getAttributes(Piece piece)
result.put(BOX_LENGTH, boxLength);
result.put(BASE_WIDTH, baseWidth);
result.put(AREA, area);
result.put(UP_HALF_AREA, upperHalfArea);
result.put(TOP_HALF_AREA, upperHalfArea);
result.put(BOTTOM_HALF_AREA, lowerHalfArea);
result.put(MID_Y_AREA, middleHalfArea);
result.put(MID_X_AREA, middleXHalfArea);
Expand Down
14 changes: 13 additions & 1 deletion src/com/lukzar/model/Piece.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class Piece {

private boolean asymmetric;

private double fitness = 0.0;

public Piece(Point start) {
this.start = start;
}
Expand All @@ -42,12 +44,14 @@ public Piece(Piece piece) {
public String toSvg() {
updateStartPoints();

List<String> attributesDescription = FitnessUtil.getAttributesDescription(this);
attributesDescription.add(0, "Fitness: " + FitnessUtil.calculateFitness(this));
String format = String.format(Templates.getImageTemplate(),
this.start.toSvg(),
getAllParts().stream()
.map(Part::toSvg)
.collect(Collectors.joining("\n")),
FitnessUtil.getAttributesDescription(this).stream()
attributesDescription.stream()
.map(s -> "<li>" + s + "</li>")
.collect(Collectors.joining("\n"))
);
Expand Down Expand Up @@ -96,6 +100,14 @@ public LinkedList<Part> getAllParts() {
return result;
}

public double getFitness() {
return fitness;
}

public void setFitness(double fitness) {
this.fitness = fitness;
}

public boolean intersectsWithAny(Part p) {
return intersectsWithAny(p, parts.size());
}
Expand Down
75 changes: 38 additions & 37 deletions src/com/lukzar/services/Evolution.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,25 @@
import com.lukzar.model.elements.Part;
import com.lukzar.utils.RandomUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.*;

/**
* Created by lukasz on 16.07.17.
*/
public class Evolution {

public static final double changePoints = 0.7;
public static final double changeParts = 0.3;
public static final double assymetric = 1.0 - changePoints - changeParts;
private static final double change_starting_point = 0.2;

public static final Comparator<Piece> FITNESS_COMPARATOR = (a, b) -> {
double d1 = FitnessUtil.calculateFitness(b);
double d2 = FitnessUtil.calculateFitness(a);
return Double.compare(d1, d2);
};
private static final double change_point = 0.6;
private static final double change_part = 0.4;
// change to assymetric = 1.0 - change_point - change_part;

private static final int crossover_size = 20;
private static final int maximum_population_size = 100;
private static final int initial_population_size = 10;


private static final Comparator<Piece> FITNESS_COMPARATOR = (a, b) -> Double.compare(b.getFitness(), a.getFitness());

private List<Piece> population = new ArrayList<>();

Expand All @@ -39,27 +37,21 @@ public List<Piece> getPopulation() {
return population;
}

// public void initialize() {
// while (population.size() < Configuration.Evolution.INITIAL_SIZE) {
// try {
// population.add(PieceGenerator.generate());
// } catch (IntersectsException ignored) {
// }
// }
// }
public void initialize() {
while (population.size() < 10) {
while (population.size() < initial_population_size) {
Piece triangle = new Piece(Point.of(200, 200));
triangle.add(new Line(Point.of(100, 0)));
population.add(triangle);
}

population.forEach(p -> p.setFitness(FitnessUtil.calculateFitness(p)));
}

// Evolve a population
public void evolvePopulation() {
List<Piece> newPopulation = new ArrayList<>();

for (int i = 0; i < 5; i++) {
for (int i = 0; i < Math.min(crossover_size, population.size() / 2); i++) {
final List<Piece> crossover = crossover(tournamentSelection(), tournamentSelection());
crossover
.stream()
Expand All @@ -79,43 +71,52 @@ public void evolvePopulation() {
}
newPopulation.removeIf(p -> FitnessUtil.getMinDegree(p) < Configuration.Piece.MIN_DEGREE);
newPopulation.forEach(Piece::update);
newPopulation.forEach(p -> p.setFitness(FitnessUtil.calculateFitness(p)));

population.addAll(newPopulation);
population.sort(FITNESS_COMPARATOR);
// Collections.shuffle(population);
if (population.size() > 100) {
population.subList(100, population.size()).clear();
if (population.size() > maximum_population_size) {
population.subList(maximum_population_size, population.size()).clear();
}
}

private Piece mutate(Piece piece) {
final Piece result = new Piece(Point.of(
RandomUtils.ensureRange(RandomUtils.randomRange(
piece.getStart().getX() - Configuration.Evolution.MUTATION_OFFSET,
piece.getStart().getX() + Configuration.Evolution.MUTATION_OFFSET),
110,190),
Configuration.Piece.HEIGHT
), piece);
double random = Math.random();

Point startPoint;
if (random < change_starting_point) {
startPoint = Point.of(
RandomUtils.ensureRange(RandomUtils.randomRange(
piece.getStart().getX() - Configuration.Evolution.MUTATION_OFFSET,
piece.getStart().getX() + Configuration.Evolution.MUTATION_OFFSET),
110, 190),
Configuration.Piece.HEIGHT
);
} else {
startPoint = piece.getStart();
}

final Piece result = new Piece(startPoint, piece);

final Point minBound = Point.of(result.isAsymmetric() ? 0 : Configuration.Piece.WIDTH / 2.0, 0);
final Point maxBound = Point.of(Configuration.Piece.WIDTH, Configuration.Piece.HEIGHT);

double random = Math.random();

int partsSize = result.getParts().size();
int partToChange = RandomUtils.randomRange(0, partsSize - 1);
final Part part = result.getParts().get(partToChange);

final Part newPart;

if (random <= changePoints) {
if (random <= change_point) {
// change points


newPart = PointMutation.mutate(part, minBound, maxBound);
newPart.setStartPos(part.getStartPos());
result.getParts().set(partToChange, newPart);

} else if (random <= changePoints + changeParts) {
} else if (random <= change_point + change_part) {
// change part
List<Part> mutate = PartMutation.mutate(part);
result.getParts().remove(partToChange);
Expand Down

0 comments on commit 1275d9f

Please sign in to comment.