From 0d4088ff7ac8abb43e50eb12c141d3f80e91a745 Mon Sep 17 00:00:00 2001 From: austinio7116 Date: Thu, 26 Apr 2018 22:56:26 +0100 Subject: [PATCH] Added abstract GA code (cherry picked from commit c534c14) --- .../PlanarConquestGeneratorGATest.java | 59 ++++++++++ .../PlanarConquestGeneratorTest.java | 110 +++++++++++++++++- .../CardThemedConquestDeckBuilder.java | 84 +++++++++++++ .../forge/util/AbstractGeneticAlgorithm.java | 84 +++++++++++++ 4 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 forge-gui-desktop/src/test/java/forge/planarconquestgenerate/PlanarConquestGeneratorGATest.java create mode 100644 forge-gui/src/main/java/forge/limited/CardThemedConquestDeckBuilder.java create mode 100644 forge-gui/src/main/java/forge/util/AbstractGeneticAlgorithm.java diff --git a/forge-gui-desktop/src/test/java/forge/planarconquestgenerate/PlanarConquestGeneratorGATest.java b/forge-gui-desktop/src/test/java/forge/planarconquestgenerate/PlanarConquestGeneratorGATest.java new file mode 100644 index 00000000000..1644415615d --- /dev/null +++ b/forge-gui-desktop/src/test/java/forge/planarconquestgenerate/PlanarConquestGeneratorGATest.java @@ -0,0 +1,59 @@ +package forge.planarconquestgenerate; + + +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import forge.GuiBase; +import forge.GuiDesktop; +import forge.StaticData; +import forge.card.CardRulesPredicates; +import forge.deck.CardRelationMatrixGenerator; +import forge.deck.Deck; +import forge.deck.DeckFormat; +import forge.deck.io.DeckStorage; +import forge.game.GameFormat; +import forge.game.GameRules; +import forge.game.GameType; +import forge.item.PaperCard; +import forge.limited.CardRanker; +import forge.model.FModel; +import forge.properties.ForgeConstants; +import forge.properties.ForgePreferences; +import org.testng.annotations.Test; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Test +public class PlanarConquestGeneratorGATest { + + + @Test + public void test(){ + + GuiBase.setInterface(new GuiDesktop()); + FModel.initialize(null, new Function() { + @Override + public Void apply(ForgePreferences preferences) { + preferences.setPref(ForgePreferences.FPref.LOAD_CARD_SCRIPTS_LAZILY, false); + return null; + } + }); + + + PlanarConquestGeneraterGA ga = new PlanarConquestGeneraterGA(); + ga.initializeCards(40); + ga.run(); + List winners = ga.listFinalPopulation(); + + DeckStorage storage = new DeckStorage(new File(ForgeConstants.DECK_CONSTRUCTED_DIR), ForgeConstants.DECK_BASE_DIR); + + for(Deck deck:winners){ + storage.save(deck); + } + } +} diff --git a/forge-gui-desktop/src/test/java/forge/planarconquestgenerate/PlanarConquestGeneratorTest.java b/forge-gui-desktop/src/test/java/forge/planarconquestgenerate/PlanarConquestGeneratorTest.java index f9e77cfa03b..38d53b3b94f 100644 --- a/forge-gui-desktop/src/test/java/forge/planarconquestgenerate/PlanarConquestGeneratorTest.java +++ b/forge-gui-desktop/src/test/java/forge/planarconquestgenerate/PlanarConquestGeneratorTest.java @@ -109,6 +109,114 @@ public class PlanarConquestGeneratorTest { } } + @Test + public void generateBestDecksGA() { + + GuiBase.setInterface(new GuiDesktop()); + FModel.initialize(null, new Function() { + @Override + public Void apply(ForgePreferences preferences) { + preferences.setPref(ForgePreferences.FPref.LOAD_CARD_SCRIPTS_LAZILY, false); + return null; + } + }); + int cardsToUse=40; + GameFormat format = FModel.getFormats().getStandard(); + GameRules rules = new GameRules(GameType.Constructed); + standardMap = CardRelationMatrixGenerator.cardPools.get(format.getName()); + List cardNames = new ArrayList<>(standardMap.keySet()); + List cards = new ArrayList<>(); + for(String cardName:cardNames){ + cards.add(StaticData.instance().getCommonCards().getUniqueByName(cardName)); + } + List rankedList = CardRanker.rankCardsInDeck(cards); + List sets = new ArrayList<>(); + sets.add("XLN"); + sets.add("RIX"); + DeckStorage storage = new DeckStorage(new File(ForgeConstants.DECK_CONSTRUCTED_DIR), ForgeConstants.DECK_BASE_DIR); + GameFormat planarConquestFormat = new GameFormat("conquest",sets,null); + DeckFormat deckFormat = DeckFormat.PlanarConquest; + + Iterable filtered= Iterables.filter(rankedList, Predicates.and( + Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, PaperCard.FN_GET_RULES), + Predicates.compose(CardRulesPredicates.Presets.IS_NON_LAND, PaperCard.FN_GET_RULES), + planarConquestFormat.getFilterPrinted())); + + List filteredList = Lists.newArrayList(filtered); + + DeckGroup deckGroup = new DeckGroup("SimulatedTournament"); + List players = new ArrayList<>(); + int numPlayers=0; + for(PaperCard card: filteredList.subList(0,cardsToUse)){ + System.out.println(card.getName()); + + + for( int i=0; i<4;i++){ + Deck genDeck = DeckgenUtil.buildPlanarConquestDeck(card, planarConquestFormat, deckFormat); + Deck d = new Deck(genDeck,genDeck.getName()+"_"+i+"_"+0); + deckGroup.addAiDeck(d); + players.add(new TournamentPlayer(GamePlayerUtil.createAiPlayer(d.getName(), 0), numPlayers)); + numPlayers++; + } + } + + TournamentSwiss tourney = null; + for (int m=1;m<10;++m) { + + //get best decks in population + tourney = new TournamentSwiss(players, 2); + tourney = runTournament(tourney, rules, numPlayers, deckGroup); + players = new ArrayList<>(); + DeckGroup newDeckGroup = new DeckGroup("SimulatedTournament"+m); + numPlayers=0; + int winnerCount = new Float(tourney.getAllPlayers().size()* .5f).intValue(); + for (int k = 0; k < winnerCount; k++) { + String deckName = tourney.getAllPlayers().get(k).getPlayer().getName(); + for (Deck winningDeck : deckGroup.getAiDecks()) { + if (winningDeck.getName().equals(deckName)) { + newDeckGroup.addAiDeck(winningDeck); + players.add(new TournamentPlayer(GamePlayerUtil.createAiPlayer(winningDeck.getName(), 0), numPlayers)); + numPlayers++; + break; + } + } + } + deckGroup = newDeckGroup; + + //add random decks + for(PaperCard card: filteredList.subList(0,cardsToUse)){ + System.out.println(card.getName()); + for( int i=0; i<2;i++){ + Deck genDeck = DeckgenUtil.buildPlanarConquestDeck(card, planarConquestFormat, deckFormat); + Deck d = new Deck(genDeck,genDeck.getName()+"_"+i+"_"+m); + deckGroup.addAiDeck(d); + players.add(new TournamentPlayer(GamePlayerUtil.createAiPlayer(d.getName(), 0), numPlayers)); + numPlayers++; + } + } + } + + tourney = new TournamentSwiss(players, 2); + tourney = runTournament(tourney, rules, numPlayers, deckGroup); + + int winnerCount = new Float(tourney.getAllPlayers().size()* 0.25f).intValue(); + for (int k = 0; k < winnerCount; k++) { + String deckName = tourney.getAllPlayers().get(k).getPlayer().getName(); + Deck winningDeck; + for(Deck deck:deckGroup.getAiDecks()){ + if(deck.getName().equals(deckName)){ + winningDeck=deck; + storage.save(winningDeck); + System.out.println(winningDeck.getName()); + System.out.println(winningDeck.getAllCardsInASinglePool().toString()); + break; + } + } + } + + + } + @Test public void generatePlanarConquestCommanderDecks() { @@ -155,7 +263,7 @@ public class PlanarConquestGeneratorTest { DeckGroup deckGroup = new DeckGroup("SimulatedTournament"); List players = new ArrayList<>(); int numPlayers=0; - for( int i=0; i<2;i++){ + for( int i=0; i<16;i++){ Deck genDeck = DeckgenUtil.buildPlanarConquestCommanderDeck(card, planarConquestFormat, deckFormat); Deck d = new Deck(genDeck,genDeck.getName()+"_"+i); deckGroup.addAiDeck(d); diff --git a/forge-gui/src/main/java/forge/limited/CardThemedConquestDeckBuilder.java b/forge-gui/src/main/java/forge/limited/CardThemedConquestDeckBuilder.java new file mode 100644 index 00000000000..b618dd63c6b --- /dev/null +++ b/forge-gui/src/main/java/forge/limited/CardThemedConquestDeckBuilder.java @@ -0,0 +1,84 @@ +package forge.limited; + +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import forge.card.CardRulesPredicates; +import forge.card.ColorSet; +import forge.deck.DeckFormat; +import forge.deck.generation.DeckGenPool; +import forge.game.GameFormat; +import forge.item.PaperCard; +import forge.model.FModel; + +import java.util.List; + +/** + * Created by maustin on 28/02/2018. + */ +public class CardThemedConquestDeckBuilder extends CardThemedDeckBuilder { + + public CardThemedConquestDeckBuilder(PaperCard commanderCard0, final List dList, GameFormat gameFormat, boolean isForAI, DeckFormat format) { + super(new DeckGenPool( + Iterables.filter(FModel.getMagicDb().getCommonCards().getUniqueCards(), + gameFormat.getFilterPrinted()) + ), format); + this.availableList = dList; + keyCard = commanderCard0; + secondKeyCard = null; + // remove Unplayables + if(isForAI) { + final Iterable playables = Iterables.filter(availableList, + Predicates.compose(CardRulesPredicates.IS_KEPT_IN_AI_DECKS, PaperCard.FN_GET_RULES)); + this.aiPlayables = Lists.newArrayList(playables); + }else{ + this.aiPlayables = Lists.newArrayList(availableList); + } + this.availableList.removeAll(aiPlayables); + targetSize=format.getMainRange().getMinimum(); + colors = keyCard.getRules().getColorIdentity(); + colors = ColorSet.fromMask(colors.getColor() | keyCard.getRules().getColorIdentity().getColor()); + if(secondKeyCard!=null) { + colors = ColorSet.fromMask(colors.getColor() | secondKeyCard.getRules().getColorIdentity().getColor()); + targetSize--; + } + numSpellsNeeded = ((Double)Math.floor(targetSize*(getCreaturePercentage()+getSpellPercentage()))).intValue(); + numCreaturesToStart = ((Double)Math.ceil(targetSize*(getCreaturePercentage()))).intValue(); + landsNeeded = ((Double)Math.ceil(targetSize*(getLandPercentage()))).intValue();; + if (logColorsToConsole) { + System.out.println(keyCard.getName()); + System.out.println("Pre Colors: " + colors.toEnumSet().toString()); + } + findBasicLandSets(); + } + + @Override + protected void addKeyCards(){ + //do nothing as keycards are commander/partner and are added by the DeckGenUtils + } + + @Override + protected void addLandKeyCards(){ + //do nothing as keycards are commander/partner and are added by the DeckGenUtils + } + + @Override + protected void addThirdColorCards(int num) { + //do nothing as we cannot add extra colours beyond commanders + } + + @Override + protected void updateColors(){ + //do nothing as we cannot deviate from commander colours + } + /** + * Generate a descriptive name. + * + * @return name + */ + @Override + protected String generateName() { + return keyCard.getName() +" based commander deck"; + } + +} diff --git a/forge-gui/src/main/java/forge/util/AbstractGeneticAlgorithm.java b/forge-gui/src/main/java/forge/util/AbstractGeneticAlgorithm.java new file mode 100644 index 00000000000..e00f3241a37 --- /dev/null +++ b/forge-gui/src/main/java/forge/util/AbstractGeneticAlgorithm.java @@ -0,0 +1,84 @@ +package forge.util; + +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import forge.StaticData; +import forge.card.CardRulesPredicates; +import forge.deck.CardRelationMatrixGenerator; +import forge.deck.DeckFormat; +import forge.deck.io.DeckStorage; +import forge.game.GameFormat; +import forge.game.GameRules; +import forge.game.GameType; +import forge.item.PaperCard; +import forge.limited.CardRanker; +import forge.model.FModel; +import forge.properties.ForgeConstants; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractGeneticAlgorithm { + + protected List population; + private int targetPopulationSize; + private float pruneRatio = 0.5f; + public int generationCount = 0; + + public void initializePopulation(List population){ + this.population = population; + targetPopulationSize = population.size(); + } + + protected abstract void evaluateFitness(); + + public void pruneWeakest(){ + population = population.subList(0, new Float(population.size()*pruneRatio).intValue()); + } + + protected void generateChildren(){ + while(population.size() listFinalPopulation(){ + pruneWeakest(); + return population; + } + + protected abstract boolean shouldContinue(); + + + + + +}