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 c8b6e48de05ff68f918b3491dcd82c0236d9dc5b
parent 9401e2d6903cad98053dcc8d6ad266a593d0f0cc
Author: Kevin Corvisier <git@kevincorvisier.fr>
Date:   Wed,  8 Jan 2025 08:39:50 +0900

Separate name generation from crossover
Diffstat:
Msrc/main/java/fr/kevincorvisier/mtg/gdb/ai/GeneticAlgorithm.java | 7+++----
Msrc/main/java/fr/kevincorvisier/mtg/gdb/operators/crossover/Crossover.java | 2--
Msrc/main/java/fr/kevincorvisier/mtg/gdb/operators/crossover/UniformCrossover.java | 20++++----------------
Asrc/main/java/fr/kevincorvisier/mtg/gdb/population/IndividualNameGenerator.java | 21+++++++++++++++++++++
Msrc/main/java/fr/kevincorvisier/mtg/gdb/population/NextGenerationService.java | 8+++++++-
5 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/src/main/java/fr/kevincorvisier/mtg/gdb/ai/GeneticAlgorithm.java b/src/main/java/fr/kevincorvisier/mtg/gdb/ai/GeneticAlgorithm.java @@ -14,8 +14,8 @@ 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.IndividualNameGenerator; import fr.kevincorvisier.mtg.gdb.population.NextGenerationService; import fr.kevincorvisier.mtg.gdb.population.Population; import fr.kevincorvisier.mtg.gdb.population.PopulationFactory; @@ -29,8 +29,7 @@ public class GeneticAlgorithm implements Reloadable { protected final Random rnd = new Random(); - // Operators - private final Crossover crossover; + private final IndividualNameGenerator individualNameGenerator; private final CardPoolService cardPool; private final List<Evaluation> evaluators; private final EvaluationStopCondition evaluationStoppingCondition; @@ -128,7 +127,7 @@ public class GeneticAlgorithm implements Reloadable else noImprovementCount++; - crossover.setGenerationCount(++generationCount); + individualNameGenerator.setGenerationCount(++generationCount); } while (shouldContinue()); } diff --git a/src/main/java/fr/kevincorvisier/mtg/gdb/operators/crossover/Crossover.java b/src/main/java/fr/kevincorvisier/mtg/gdb/operators/crossover/Crossover.java @@ -7,6 +7,4 @@ import fr.kevincorvisier.mtg.gdb.population.Individual; public interface Crossover { Pair<Individual, Individual> crossover(final Individual parent1, final Individual parent2); - - void setGenerationCount(final int generationCount); } diff --git a/src/main/java/fr/kevincorvisier/mtg/gdb/operators/crossover/UniformCrossover.java b/src/main/java/fr/kevincorvisier/mtg/gdb/operators/crossover/UniformCrossover.java @@ -11,6 +11,7 @@ import forge.deck.Deck; import forge.deck.DeckSection; import forge.item.PaperCard; import fr.kevincorvisier.mtg.gdb.population.Individual; +import fr.kevincorvisier.mtg.gdb.population.IndividualNameGenerator; import lombok.RequiredArgsConstructor; @Service @@ -19,11 +20,9 @@ public class UniformCrossover implements Crossover { private static final DeckSection[] SECTIONS = { DeckSection.Main, DeckSection.Sideboard }; + private final IndividualNameGenerator individualNameGenerator; private final Random rnd = new Random(); - protected int generationCount = 0; - private int individualIncrementCounter = 0; - @Override public Pair<Individual, Individual> crossover(final Individual parent1, final Individual parent2) { @@ -50,18 +49,7 @@ public class UniformCrossover implements Crossover } } - return Pair.create(new Individual(uniqName(), first), new Individual(uniqName(), second)); - } - - private String uniqName() - { - return "g" + generationCount + "_" + individualIncrementCounter++; - } - - @Override - public void setGenerationCount(final int generationCount) - { - this.generationCount = generationCount; - this.individualIncrementCounter = 0; + return Pair.create(new Individual(individualNameGenerator.createName() + "_crossover", first), + new Individual(individualNameGenerator.createName() + "_crossover", second)); } } diff --git a/src/main/java/fr/kevincorvisier/mtg/gdb/population/IndividualNameGenerator.java b/src/main/java/fr/kevincorvisier/mtg/gdb/population/IndividualNameGenerator.java @@ -0,0 +1,21 @@ +package fr.kevincorvisier.mtg.gdb.population; + +import org.springframework.stereotype.Service; + +@Service +public class IndividualNameGenerator +{ + private int generationCount = 0; + private int individualIncrementCounter = 0; + + public String createName() + { + return "g" + generationCount + "_" + individualIncrementCounter++; + } + + public void setGenerationCount(final int generationCount) + { + this.generationCount = generationCount; + this.individualIncrementCounter = 0; + } +} diff --git a/src/main/java/fr/kevincorvisier/mtg/gdb/population/NextGenerationService.java b/src/main/java/fr/kevincorvisier/mtg/gdb/population/NextGenerationService.java @@ -50,6 +50,7 @@ public class NextGenerationService private final Selection selection = new HybridSelection(); private final RandomDeckGenerator deckGenerator; private final ValidationService validationService; + private final IndividualNameGenerator individualNameGenerator; private final Random rnd = new Random(); @@ -86,7 +87,7 @@ public class NextGenerationService while (next.getSize() < targetSize) { final Deck deck = deckGenerator.getRandomDeck(); - final Individual child = new Individual("g0_new_" + next.getSize(), deck); + final Individual child = new Individual(individualNameGenerator.createName() + "_new", deck); if (validate(child, next)) next.addIndividual(child); @@ -108,6 +109,11 @@ public class NextGenerationService { pair = crossover.crossover(pair.getFirst(), pair.getSecond()); } + else + { + pair = Pair.create(new Individual(individualNameGenerator.createName() + "_" + pair.getFirst().getName(), pair.getFirst().getDeck()), + new Individual(individualNameGenerator.createName() + "_" + pair.getSecond().getName(), pair.getSecond().getDeck())); + } // Mutation if (rnd.nextDouble() < mutationRate)