mtg-genetic-deckbuilding

Generating and improving Magic: The Gathering decks using a genetic algorithm
git clone https://kevincorvisier.fr/git/mtg-genetic-deckbuilding.git
Log | Files | Refs | LICENSE

commit 5884d1deef322fbe8fd5a2bfa92a0d158550942b
parent 4a658a4301b15aa52171df3888cec8923307aeea
Author: Kevin Corvisier <git@kevincorvisier.fr>
Date:   Mon, 16 Dec 2024 14:14:44 +0900

Add population-stats.csv file containing the strongest, median and worst
fitness result per generation
Diffstat:
Rlaunchers/genetic-deckbuilding - Package.launch -> launchers/Package_genetic-deckbuilding.launch | 0
Rlaunchers/genetic-deckbuilding - Run.launch -> launchers/Run_genetic-deckbuilding.launch | 0
Msrc/main/java/fr/kevincorvisier/mtg/gdb/ai/GeneticAlgorithm.java | 5+++++
Asrc/main/java/fr/kevincorvisier/mtg/gdb/events/EvaluationDoneEvent.java | 17+++++++++++++++++
Asrc/main/java/fr/kevincorvisier/mtg/gdb/io/PopulationStatsCsvWriter.java | 47+++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main/packaged-resources/cfg/application.properties | 2+-
6 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/launchers/genetic-deckbuilding - Package.launch b/launchers/Package_genetic-deckbuilding.launch diff --git a/launchers/genetic-deckbuilding - Run.launch b/launchers/Run_genetic-deckbuilding.launch diff --git a/src/main/java/fr/kevincorvisier/mtg/gdb/ai/GeneticAlgorithm.java b/src/main/java/fr/kevincorvisier/mtg/gdb/ai/GeneticAlgorithm.java @@ -7,11 +7,13 @@ import java.util.Random; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import fr.kevincorvisier.mtg.gdb.Reloadable; import fr.kevincorvisier.mtg.gdb.evaluation.Evaluation; import fr.kevincorvisier.mtg.gdb.evaluation.stop.EvaluationStopCondition; +import fr.kevincorvisier.mtg.gdb.events.EvaluationDoneEvent; import fr.kevincorvisier.mtg.gdb.operators.crossover.Crossover; import fr.kevincorvisier.mtg.gdb.population.Individual; import fr.kevincorvisier.mtg.gdb.population.NextGenerationService; @@ -35,6 +37,8 @@ public class GeneticAlgorithm implements Reloadable private final PopulationFactory populationFactory; private final NextGenerationService nextGenerationService; + private final ApplicationEventPublisher publisher; + private Population population = null; protected int generationCount = 0; @@ -113,6 +117,7 @@ public class GeneticAlgorithm implements Reloadable population.onFitnessUpdated(); writeOutput(); + publisher.publishEvent(new EvaluationDoneEvent(generationCount, population)); final long bestFingerprint = population.get(0).getFingerprint(); if (bestFingerprint != previousBestFingerprint) diff --git a/src/main/java/fr/kevincorvisier/mtg/gdb/events/EvaluationDoneEvent.java b/src/main/java/fr/kevincorvisier/mtg/gdb/events/EvaluationDoneEvent.java @@ -0,0 +1,17 @@ +package fr.kevincorvisier.mtg.gdb.events; + +import javax.validation.constraints.NotNull; + +import fr.kevincorvisier.mtg.gdb.population.Population; +import lombok.Data; +import lombok.NonNull; + +@Data +public class EvaluationDoneEvent +{ + private final int generationCount; + + @NonNull + @NotNull + private final Population population; +} diff --git a/src/main/java/fr/kevincorvisier/mtg/gdb/io/PopulationStatsCsvWriter.java b/src/main/java/fr/kevincorvisier/mtg/gdb/io/PopulationStatsCsvWriter.java @@ -0,0 +1,47 @@ +package fr.kevincorvisier.mtg.gdb.io; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import fr.kevincorvisier.mtg.gdb.events.EvaluationDoneEvent; +import fr.kevincorvisier.mtg.gdb.population.Population; + +@Component +public class PopulationStatsCsvWriter +{ + private final File file; + + public PopulationStatsCsvWriter(@Value("${output.directory}") final File outputDirectory) throws IOException + { + outputDirectory.mkdirs(); + file = new File(outputDirectory, "population-stats.csv"); + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) + { + writer.append("Generation,Strongest,Median,Worst\n"); + } + } + + @EventListener + public void onEvaluationDone(final EvaluationDoneEvent event) throws IOException + { + final Population population = event.getPopulation(); + final double strongest = population.get(0).getFitness(); + final double median = population.get(population.getSize() / 2).getFitness(); + final double worst = population.get(population.getSize() - 1).getFitness(); + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file, true))) + { + writer.append(Integer.toString(event.getGenerationCount())).append(',') // + .append(Double.toString(strongest)).append(',') // + .append(Double.toString(median)).append(',') // + .append(Double.toString(worst)).append('\n'); + } + } +} diff --git a/src/main/packaged-resources/cfg/application.properties b/src/main/packaged-resources/cfg/application.properties @@ -1,4 +1,4 @@ -output.directory=/home/kebi/Documents/mtg/output +output.directory=output max.generations=1000 max.no-improvement-count=20