It is currently 12 Sep 2025, 19:38
   
Text Size

New 2 Color Deck Generator

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

New 2 Color Deck Generator

Postby Rob Cashwalker » 30 Sep 2010, 11:56

I just added a new random deck generator. It allows the user to specify the colors.

At the moment it doesn't handle dual lands, nor does it add any artifacts.

It attempts to promote a slight mana curve, and most cards should not be singleton.

Code: Select all

package forge;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import forge.error.ErrorViewer;

public class Generate2ColorDeck
{
   private String color1 = "";
   private String color2 = "";
   private Random r = null;
   private Map<String,String> ClrMap = null;
   private ArrayList<String> notColors = null;
   
   public Generate2ColorDeck(String Clr1, String Clr2)
   {            
      r = new Random();
      
      ClrMap = new HashMap<String,String>();
      ClrMap.put("White", "W");
      ClrMap.put("Blue", "U");
      ClrMap.put("Black", "B");
      ClrMap.put("Red", "R");
      ClrMap.put("Green", "G");
      
      notColors = new ArrayList<String>();
      notColors.add("White");
      notColors.add("Blue");
      notColors.add("Black");
      notColors.add("Red");
      notColors.add("Green");
      
      if (Clr1.equals("AI"))
      {
         // choose first color
         color1 = notColors.get(r.nextInt(5));
         
         // choose second color
         String c2 = notColors.get(r.nextInt(5));
         while (c2.equals(color1))
            c2 = notColors.get(r.nextInt(5));
         color2 = c2;
      }
      else
      {
         color1 = Clr1;
         color2 = Clr2;
      }
      
      notColors.remove(color1);
      notColors.remove(color2);
   }

   public CardList get2ColorDeck(int Size)
   {
      String tmpDeck = "";
      CardList tDeck = new CardList();
      
      Map<String, Integer> CardCounts = new HashMap<String, Integer>();
      
      int LandsPercentage = 42;
      int CreatPercentage = 34;
      int SpellPercentage = 24;
      
      // start with all cards
      CardList AllCards = AllZone.CardFactory.getAllCards();

      // remove cards that generated decks don't like
      AllCards = AllCards.filter(new CardListFilter(){
         public boolean addCard(Card c){
            return (!c.getSVar("RemAIDeck").equals("True"));
         }
      });
      
      // reduce to cards that match the colors
      CardList CL1 = AllCards.getColor(ClrMap.get(color1));
      CardList CL2 = AllCards.getColor(ClrMap.get(color2));
      
      // remove multicolor cards that don't match the colors
      CardListFilter clrF = new CardListFilter(){
         public boolean addCard(Card c){
            for (int i=0; i<notColors.size(); i++)
            {
               if (c.getManaCost().contains(ClrMap.get(notColors.get(i))))
                  return false;
            }
            return true;
         }
      };
      CL1 = CL1.filter(clrF);
      CL2 = CL2.filter(clrF);
      
      // build subsets based on type
      CardList Cr1 = CL1.getType("Creature");
      CardList Cr2 = CL2.getType("Creature");
      
      String ISE[] = {"Instant", "Sorcery", "Enchantment", "Planeswalker"};
      CardList Sp1 = CL1.getValidCards(ISE);
      CardList Sp2 = CL2.getValidCards(ISE);

      // final card pools
      CardList Cr12 = new CardList();
      CardList Sp12 = new CardList();
            
      // used for mana curve in the card pool
      final int MinCMC[] = {1}, MaxCMC[] = {2};
      CardListFilter cmcF = new CardListFilter(){
         public boolean addCard(Card c){
            int cCMC = c.getCMC();
            return (cCMC >= MinCMC[0]) && (cCMC <= MaxCMC[0]);               
         }
      };
      
      // select cards to build card pools using a mana curve
      for (int i=4; i>0; i--)
      {
         CardList Cr1CMC = Cr1.filter(cmcF);
         CardList Cr2CMC = Cr2.filter(cmcF);
         CardList Sp1CMC = Sp1.filter(cmcF);
         CardList Sp2CMC = Sp2.filter(cmcF);
         
         for (int j=0; j<i; j++)
         {
            Card c = Cr1CMC.get(r.nextInt(Cr1CMC.size()));
            Cr12.add(c);
            CardCounts.put(c.getName(), 0);
            
            c = Cr2CMC.get(r.nextInt(Cr2CMC.size()));
            Cr12.add(c);
            CardCounts.put(c.getName(), 0);
            
            c = Sp1CMC.get(r.nextInt(Sp1CMC.size()));
            Sp12.add(c);
            CardCounts.put(c.getName(), 0);
            
            c = Sp2CMC.get(r.nextInt(Sp2CMC.size()));
            Sp12.add(c);
            CardCounts.put(c.getName(), 0);
         }
         
         MinCMC[0] += 2; MaxCMC[0] +=2;
         // resulting mana curve of the card pool
         //16x 1 - 2
         //12x 3 - 4
         //8x 5 - 6
         //4x 7 - 8
         //=40x - card pool could support up to a 275 card deck (all 4-ofs plus basic lands)
      }
      
      // shuffle card pools
      Cr12.shuffle();
      Sp12.shuffle();

      // calculate card counts
      float p = (float) ((float)CreatPercentage * .01);
      int CreatCnt = (int)(p * (float)Size);
      tmpDeck += "Creature Count:" + CreatCnt + "\n";
      
      p = (float) ((float)SpellPercentage * .01);
      int SpellCnt = (int)(p * (float)Size);
      tmpDeck += "Spell Count:" + SpellCnt + "\n";
      
      // build deck from the card pools
      for (int i=0; i<CreatCnt; i++)
      {
         Card c = Cr12.get(r.nextInt(Cr12.size()));
         while (CardCounts.get(c.getName()) > 3)
            c = Cr12.get(r.nextInt(Cr12.size()));
         
         tDeck.add(AllZone.CardFactory.getCard(c.getName(), Constant.Player.Computer));
         int n = CardCounts.get(c.getName());
         CardCounts.put(c.getName(), n + 1);
         tmpDeck += c.getName() + " " + c.getManaCost() + "\n";
      }
      
      for (int i=0; i<SpellCnt; i++)
      {
         Card c = Sp12.get(r.nextInt(Sp12.size()));
         while (CardCounts.get(c.getName()) > 3)
            c = Sp12.get(r.nextInt(Sp12.size()));
         
         tDeck.add(AllZone.CardFactory.getCard(c.getName(), Constant.Player.Computer));
         int n = CardCounts.get(c.getName());
         CardCounts.put(c.getName(), n + 1);
         tmpDeck += c.getName() + " " + c.getManaCost() + "\n";
      }
      
      // Add basic lands
      // TODO: dual lands?
      int numBLands = 0;
      if (LandsPercentage > 0)
      {
         p = (float)((float)LandsPercentage * .01);
         numBLands = (int)(p * (float)Size);
      }
      else    // otherwise, just fill in the rest of the deck with basic lands
         numBLands = Size - tDeck.size();
      
      tmpDeck += "numBLands:" + numBLands + "\n";
      
      if (numBLands > 0)   // attempt to optimize basic land counts according to color representation
      {
         CCnt ClrCnts[] = {new CCnt("Plains", 0),
                       new CCnt("Island", 0),
                       new CCnt("Swamp", 0),
                       new CCnt("Mountain", 0),
                       new CCnt("Forest", 0)};
               
         // count each card color using mana costs
         // TODO: count hybrid mana differently?
         // TODO: count all color letters? ie: 2 W W counts as 2
         for (int i=0;i<tDeck.size(); i++)
         {
            Card c = tDeck.get(i);
            String mc = c.getManaCost();
            
            if (mc.contains("W"))
               ClrCnts[0].Count++;
            
            if (mc.contains("U"))
               ClrCnts[1].Count++;
            
            if (mc.contains("B"))
               ClrCnts[2].Count++;
            
            if (mc.contains("R"))
               ClrCnts[3].Count++;
   
            if (mc.contains("G"))
               ClrCnts[4].Count++;
         }
   
         // total of all ClrCnts
         int totalColor = 0;
         for (int i=0;i<5; i++)
         {
            totalColor += ClrCnts[i].Count;
            tmpDeck += ClrCnts[i].Color + ":" + ClrCnts[i].Count + "\n";
         }
         
         tmpDeck += "totalColor:" + totalColor + "\n";
         
         for (int i=0; i<5; i++)
         {
            if (ClrCnts[i].Count > 0)
            {   // calculate number of lands for each color
               p = (float)ClrCnts[i].Count / (float)totalColor;
               int nLand = (int)((float)numBLands * p);
               tmpDeck += "numLand-" + ClrCnts[i].Color + ":" + nLand + "\n";
               
               // just to prevent a null exception by the deck size fixing code
               CardCounts.put(ClrCnts[i].Color, nLand);
            
               for (int j=0; j<=nLand; j++)
                  tDeck.add(AllZone.CardFactory.getCard(ClrCnts[i].Color, Constant.Player.Computer));
            }
         }
      }
      tmpDeck += "DeckSize:" + tDeck.size() + "\n";
      
      // fix under-sized or over-sized decks, due to integer arithmetic
      if (tDeck.size() < Size)
      {
         int diff = Size - tDeck.size();
         
         for (int i=0; i<diff; i++)
         {
            Card c = tDeck.get(r.nextInt(tDeck.size()));
            
            while (CardCounts.get(c.getName()) >= 4)
               c = tDeck.get(r.nextInt(tDeck.size()));
            
            int n = CardCounts.get(c.getName());
            tDeck.add(AllZone.CardFactory.getCard(c.getName(), Constant.Player.Computer));
            CardCounts.put(c.getName(), n + 1);
            tmpDeck += "Added:" + c.getName() + "\n";
         }
      }
      else if (tDeck.size() > Size)
      {
         int diff = tDeck.size() - Size;
         
         for (int i=0; i<diff; i++)
         {
            Card c = tDeck.get(r.nextInt(tDeck.size()));
            
            while (c.getType().contains("Basic"))   // don't remove basic lands
               c = tDeck.get(r.nextInt(tDeck.size()));
            
            tDeck.remove(c);
            tmpDeck += "Removed:" + c.getName() + "\n";
         }
      }

      tmpDeck += "DeckSize:" + tDeck.size() + "\n";
      //ErrorViewer.showError(tmpDeck);
      
      return tDeck;
   }
   
   class CCnt
   {
      public String Color;
      public int Count;
      
      public CCnt(String clr, int cnt)
      {
         Color = clr;
         Count = cnt;
      }
   }
}
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: New 2 Color Deck Generator

Postby mtgrares » 30 Sep 2010, 17:19

A better random deck generator sounds great. Sometimes the current deck generator (which I wrote) is too random since it doesn't consider a mana curve at all. (I think the old deck generator did create decks with at least 12 creatures.)

Thanks of the update because I enjoy using and playing against generated decks. (I turn on the AI Land Stack option in order to make it more challenging.)
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: New 2 Color Deck Generator

Postby Rob Cashwalker » 04 Oct 2010, 03:37

Made some changes this weekend.

First off, I added support for dual lands in the 2-color generator.

Then I changed how both the them deck generator and the 2-color generator count mana colors for the ratio of lands. It now counts each mana symbol.

I also changed the NewGame screen. Instead of listing all the different deck generators, I left only one "Generate Deck". It then presents a list dialog with the different generators.

Finally, I added a property to enable/disable the display of the 2-color deck list. "showdeck/2color=true"
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: New 2 Color Deck Generator

Postby friarsol » 04 Oct 2010, 13:58

Rob Cashwalker wrote:Then I changed how both the them deck generator and the 2-color generator count mana colors for the ratio of lands. It now counts each mana symbol.
For Hybrid Mana do those count as half mana or full mana?
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: New 2 Color Deck Generator

Postby Rob Cashwalker » 04 Oct 2010, 16:13

Alas, I still haven't decided how those should count. For now, they count full.
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: New 2 Color Deck Generator

Postby friarsol » 04 Oct 2010, 18:22

Rob Cashwalker wrote:Alas, I still haven't decided how those should count. For now, they count full.
How about this?
2/R counts as a full.
R/G in a red/green deck count as a half each.
R/G in a red/black deck counts as a full.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: New 2 Color Deck Generator

Postby Rob Cashwalker » 04 Oct 2010, 18:55

R/G in a R-B THEME deck, I guess... but how to know that the deck is supposed to be R-B, when there's G in a mana cost..?
R/G in a R-B GENERATED deck, will never occur, because of the color-selection filter - it removes any card that has a mana symbol outside of the decks two chosen colors.

In the long run I don't think it makes a huge difference:

given the mana costs for a simple R/G deck:
R
1 R
R R
2 R
G
1 G
G G
2 G
R/G
1 R/G
R/G R/G
2 R/G

colors always count as full: 10R + 10G = 20total (50%R 50%G)
hybrids count as half: 7.5R + 7.5G = 15total (50%R 50%G)
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: New 2 Color Deck Generator

Postby Bog Wraith » 05 Oct 2010, 16:17

Since the 1002 release I find myself, when not questing, playing allot of the 2 colour generated deck mode. I really like it & it seems very well balanced.

Just saw that dual lands are now included. Is there a way to eventually get a smattering of Artifacts in the mix too? Maybe colour specific Arty's like Scepter of Fugue when playing Black as one of your colours as an example. Would Arty's with a specific mana colour cost make it easier for them to be included and for randomization of those picks as well?

In any event, I really like the balance I've seen with this so far Rob, thanks very much for all the work! 8)
'Twas in the bogs of Cannelbrae
My mate did meet an early grave
'Twas nothing left for us to save
In the peat-filled bogs of Cannelbrae.
User avatar
Bog Wraith
Global Mod 1 (Ret)
 
Posts: 1108
Joined: 28 May 2008, 22:40
Location: Shandalar
Has thanked: 425 times
Been thanked: 153 times

Re: New 2 Color Deck Generator

Postby Rob Cashwalker » 05 Oct 2010, 18:00

I think if artifacts came into the mix, then it would end up diluting the colored cards.... This generator tries to promote card multiples.
I was also trying to think of an easy way to eliminate on-color cards with off-color activations, and I couldn't think of a simple, universal way, since not all abilities provide the activation cost, and not all cards include them in the card text.... Plus, how to differentiate "W" as a mana cost and not as a character in the word "Whenever".
Definitely something to look at at some point.

I played a number of matches with both players using these 2 color decks, and the computer was doing a kick-ass job, much better win % than the original generator.

I'm going to add a color option to the color list - "Random".
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: New 2 Color Deck Generator

Postby Bog Wraith » 05 Oct 2010, 19:31

I get what you mean about artifacts & it's no big deal not to have them.

I too have noticed that the AI is performing at a higher level then before. I find the games closer and the AI making more logical choices with the cards in hand vs what is already played to the table. I also find that the deck compositions are well balanced and that the randomization of the cards in the decks in multiple replays are very fair and playable.

As I said earlier, I find myself playing this more & more & enjoying it immensely! 8)
'Twas in the bogs of Cannelbrae
My mate did meet an early grave
'Twas nothing left for us to save
In the peat-filled bogs of Cannelbrae.
User avatar
Bog Wraith
Global Mod 1 (Ret)
 
Posts: 1108
Joined: 28 May 2008, 22:40
Location: Shandalar
Has thanked: 425 times
Been thanked: 153 times

Re: New 2 Color Deck Generator

Postby zerker2000 » 05 Oct 2010, 21:44

Rob Cashwalker wrote:I was also trying to think of an easy way to eliminate on-color cards with off-color activations, and I couldn't think of a simple, universal way, since not all abilities provide the activation cost
Uh, they don't? Since when is getManaCost() depreciated?
O forest, hold thy wand'ring son
Though fears assail the door.
O foliage, cloak thy ravaged one
In vestments cut for war.


--Eladamri, the Seed of Freyalise
zerker2000
Programmer
 
Posts: 569
Joined: 09 May 2009, 21:40
Location: South Pasadena, CA
Has thanked: 0 time
Been thanked: 0 time

Re: New 2 Color Deck Generator

Postby Rob Cashwalker » 06 Oct 2010, 03:26

Heh... you know, I was so busy working at this from the card level, I didn't really think about the SpellAbility.getManaCost(). On the other hand, some abilities (and most future ones) use the Ability_Cost, maybe the mana portion is copied to the SpellAbility?
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Re: New 2 Color Deck Generator

Postby friarsol » 06 Oct 2010, 04:45

Ability_Cost sets the ManaCost during creation of an ability.
Code: Select all
    public Ability_Activated(Card sourceCard, Ability_Cost abCost, Target tgt) {
        super(SpellAbility.Ability, sourceCard);
        setManaCost(abCost.getMana());
        setPayCosts(abCost);
        if (tgt != null && tgt.doesTarget())
           setTarget(tgt);
    }
Even if it didn't we could have getManaCost() check if abCost was set, and return the ManaCost from there instead of the unintiated ManaCost.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: New 2 Color Deck Generator

Postby slapshot5 » 06 Oct 2010, 14:35

I am getting an exception generating a 5 color deck:

Code: Select all
An error has occured. You can copy/paste this message or save it to a file.
Please report this, plus what you tried to do, to:
    http://www.slightlymagic.net/forum/viewforum.php?f=26
If you don't want to register an account, you can mail it directly to
    mtgerror@yahoo.com


GenerateConstructedDeck() : generateDeck() error, deck size it not 60, deck size is 29


Version:
Forge -- official beta: $Date: 2010-09-14 07:34:27 -0500 (Tue, 14 Sep 2010) $, SVN revision: $Revision: 2039 $

OS: Windows XP Version: 5.1 Architecture: x86

Java Version: 1.6.0_21 Vendor: Sun Microsystems Inc.

Detailed error trace:
java.lang.RuntimeException: GenerateConstructedDeck() : generateDeck() error, deck size it not 60, deck size is 29
    at forge.GenerateConstructedMultiColorDeck.generate5ColorDeck(GenerateConstructedMultiColorDeck.java:96)
    at forge.Gui_NewGame.generateConstructed5ColorDeck(Gui_NewGame.java:659)
    at forge.Gui_NewGame.genDecks(Gui_NewGame.java:625)
    at forge.Gui_NewGame.startButton_actionPerformed(Gui_NewGame.java:554)
    at forge.Gui_NewGame$11.actionPerformed(Gui_NewGame.java:420)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)
I pick a constructed deck for human and generate Deck for AI, then choose 5-color -> OK -> exception.

-slapshot5
slapshot5
Programmer
 
Posts: 1391
Joined: 03 Jan 2010, 17:47
Location: Mac OS X
Has thanked: 25 times
Been thanked: 68 times

Re: New 2 Color Deck Generator

Postby Rob Cashwalker » 06 Oct 2010, 17:04

I'm getting that too, on my work pc that hasn't been updated in a couple weeks, since before my updates. I didn't make any changes to the 5 color generator.

I'm suspecting it might be due to the changes involving card color.
The Force will be with you, Always.
User avatar
Rob Cashwalker
Programmer
 
Posts: 2167
Joined: 09 Sep 2008, 15:09
Location: New York
Has thanked: 5 times
Been thanked: 40 times

Next

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 51 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 51 users online :: 0 registered, 0 hidden and 51 guests (based on users active over the past 10 minutes)
Most users ever online was 7967 on 09 Sep 2025, 23:08

Users browsing this forum: No registered users and 51 guests

Login Form