It is currently 23 May 2024, 12:26
   
Text Size

What card was discarded?

Post MTG Forge Related Programming Questions Here

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

What card was discarded?

Postby Rob Cashwalker » 27 Jul 2009, 02:45

I'm working on a spDrawCards routine. There are very few pure draw card spells. The bulk of them come with conditions... like lose n life, or discard n cards... So I'm intending that nearly all combinations can be supported.

There's one syntax I've run into so far that's not as easy as I had thought - "discard 2 cards unless you discard an artifact".

This is what I've got down so far:
Code: Select all
    if (shouldSpDrawCards(card) != -1)
    {
       int n = shouldSpDrawCards(card);
       String parse = card.getKeyword().get(n).toString();
        card.removeIntrinsicKeyword(parse);
       
        String k[] = parse.split(":");
        final int NumCards[] = {-1};
        final String NumCardsType[] = {"none"};
        final boolean NumCardsTypeYouCtrl[] = {false};
        final boolean NumCardsTypeInPlay[] = {false};
        final boolean NumCardsTypeInYourYard[] = {false};
        final boolean NumCardsTypeInAllYards[] = {false};
        final boolean NumCardsDomain[] = {false};
        if (k[1].length() == 1)
           NumCards[0] = Integer.parseInt(k[1]);
        else
        {
           if (k[1].startsWith("NumCardsType"))
           {
              String kk[] = k[1].split("/");
              NumCardsType[0] = kk[1];
              NumCardsTypeYouCtrl[0] = kk[2].equals("YouCtrl");
              NumCardsTypeInPlay[0] = kk[2].equals("InPlay");
              NumCardsTypeInYourYard[0] = kk[2].equals("InYourYard");
              NumCardsTypeInAllYards[0] = kk[2].equals("InAllYards");
           }
           NumCardsDomain[0] = k[1].equals("Domain");
        }
       
        final int NumDiscard[] = {0};
        final boolean UnlessDiscardLand[] = {false};
        final boolean UnlessDiscardArtifact[] = {false};
        final boolean AtRandom[] = {false};
       
        final int NumLife[] = {0};
       
        final int NumToLibrary[] = {0};
        final boolean ToLibraryTop[] = {false};
        final boolean ToLibraryTopBottom[] = {false};
        final boolean ToLibraryBottom[] = {false};
       
        final int NumOppDraw[] = {0};
       
        if (k.length > 2)
        {
           if (k[2].contains("Discard"))
           {
              String kk[] = k[2].split("/");
              NumDiscard[0] = Integer.parseInt(kk[1]);
              if (kk.length > 2)
              {
                 UnlessDiscardLand[0] = kk[2].equals("UnlessDiscardLand");
                 UnlessDiscardArtifact[0] = kk[2].equals("UnlessDiscardArtifact");
                 AtRandom[0] = kk[2].equals("AtRandom");
              }
           }

           if (k[2].contains("Life"))
           {
              String kk[] = k[2].split("/");
              NumLife[0] = Integer.parseInt(kk[1]);
           }

           if (k[2].contains("NumToLibrary"))
           {
              String kk[] = k[2].split("/");
              NumToLibrary[0] = Integer.parseInt(kk[1]);
              if (kk.length > 2)
              {
                 ToLibraryTop[0] = kk[2].equals("Top");
                 ToLibraryTopBottom[0] = kk[2].equals("TopBottom");
                 ToLibraryBottom[0] = kk[2].equals("Bottom");
              }
           }
           
           if (k[2].contains("NumOppDraw"))
           {
              String kk[] = k[2].split("/");
              NumOppDraw[0] = Integer.parseInt(kk[1]);
           }
           
           final SpellAbility spell = new Spell(card)
           {
              public int getNumCards()
              {
                 int n = 0;
                String cardController = card.getController();
                PlayerZone myPlay = AllZone.getZone(Constant.Zone.Play, cardController);
                PlayerZone opPlay = AllZone.getZone(Constant.Zone.Play, AllZone.GameAction.getOpponent(cardController));
                
                PlayerZone myYard = AllZone.getZone(Constant.Zone.Graveyard, cardController);
                PlayerZone opYard = AllZone.getZone(Constant.Zone.Graveyard, AllZone.GameAction.getOpponent(cardController));
                
                CardList AllCards = new CardList();
                 
                 if (! NumCardsType[0].equals("none"))
                 {
                    
                    if (NumCardsTypeInYourYard[0] == false)
                       AllCards.addAll(myYard.getCards());

                    if (NumCardsTypeInAllYards[0] == false)
                    {
                       AllCards.addAll(myYard.getCards());
                       AllCards.addAll(opYard.getCards());
                    }
                    
                    if (NumCardsTypeYouCtrl[0] == true)
                       AllCards.addAll(myPlay.getCards());
                       
                    if (NumCardsTypeInPlay[0] == true)
                    {
                       AllCards.addAll(myPlay.getCards());
                       AllCards.addAll(opPlay.getCards());
                    }
                    
                    AllCards = AllCards.filter(new CardListFilter()
                    {
                       public boolean addCard(Card c)
                       {
                          if (c.getType().contains(NumCardsType[0]))
                             return true;
                          
                          return false;
                       }
                    });
                    
                    n = AllCards.size();
                 }
                 if (NumCardsDomain[0] == true)
                 {
                    AllCards.addAll(myPlay.getCards()); 
                    String basic[] = {"Forest", "Plains", "Mountain", "Island", "Swamp"};

                    for(int i = 0; i < basic.length; i++)
                    {
                       if (! AllCards.getType(basic[i]).isEmpty())
                          n++;
                    }
                 }
                 
                 return n;
              }
              public void resolve()
              {
                 if (NumCards[0] == -1)
                    NumCards[0] = getNumCards();
                 
                 for (int i=0; i<NumCards[0]; i++)
                    AllZone.GameAction.drawCard(card.getController());
                 
                 if (NumDiscard[0] > 0)
                 {
                    for (int i=0; i < NumDiscard[0]; i++)
                       if(card.getController().equals("Human"))
                          AllZone.InputControl.setInput(CardFactoryUtil.input_discard());
                       else
                          AllZone.GameAction.discardRandom("Computer");
                 }
              }
           };
        }
    }
The discard part is at the bottom, for reference:
Code: Select all
                 if (NumDiscard[0] > 0)
                 {
                    for (int i=0; i < NumDiscard[0]; i++)
                       if(card.getController().equals("Human"))
                          AllZone.InputControl.setInput(CardFactoryUtil.input_discard());
                       else
                          AllZone.GameAction.discardRandom("Computer");
                 }
We could break out of the for loop if there was an easy way to know which card was discarded. I don't think there's any existing card that does something like this....
So short of writing another form of input_discard, does anyone have some ideas?
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: What card was discarded?

Postby DennisBergkamp » 27 Jul 2009, 11:49

Yeah I don't think so either... probably easiest (and useful) to just write some sort of input_discardXUnlessDiscardType(int x, String type).
They do get pretty tedious to write though after awhile :(
User avatar
DennisBergkamp
AI Programmer
 
Posts: 2602
Joined: 09 Sep 2008, 15:46
Has thanked: 0 time
Been thanked: 0 time

Re: What card was discarded?

Postby Rob Cashwalker » 27 Jul 2009, 11:52

DennisBergkamp wrote:Yeah I don't think so either... probably easiest (and useful) to just write some sort of input_discardXUnlessDiscardType(int x, String type).
They do get pretty tedious to write though after awhile :(
Yeah, especially since I'd have to also write an intelligent computer discard routine.
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: What card was discarded?

Postby Marek14 » 28 Jul 2009, 06:56

Also, it IS legal to discard an artifact AND another card (or even two artifact cards).
Marek14
Tester
 
Posts: 2763
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 297 times

Re: What card was discarded?

Postby Rob Cashwalker » 28 Jul 2009, 11:22

[quote="Marek14"]Also, it IS legal to discard an artifact Ahh... true. That would make it tough because if an artifact is selected first, then the OK button needs to still be available, AND still permit you to select another card.
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: What card was discarded?

Postby zerker2000 » 28 Jul 2009, 12:32

Rob Cashwalker wrote:That would make it tough because if an artifact is selected first, then the OK button needs to still be available, AND still permit you to select another card.
How? Outline in semi-pseudo-code:
Code: Select all
Inputxtype(x, CardFilter type,Message){
dicarded=0;
canexit=false;
ShowMessage
{
  showMessage(Message);
  if(canexit) EnableOnlyOkButton();
  else DisableAllButtons();
}
onOk{stop();}
selectCard(card)
{
  if(card.getzone==hand)
  {
   discard(card);
   discarded++;
   if(type.addCard(card))
   {
     EnableOnlyOkButton();
     canexit=true;
   }
   if(discarded==x) onOK();
   else if(discarded>x){
     Exception tantrum = new Exception("Discarded " + discarded + " of " + x +" cards?")
     throw(tantrum);
   }
  }
}
Actually, the above could probably work as a first version after a spelling&grammar check(e.g. function names and type declarations).
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: What card was discarded?

Postby Marek14 » 29 Jul 2009, 06:31

Rob Cashwalker wrote:Ahh... true. That would make it tough because if an artifact is selected first, then the OK button needs to still be available, AND still permit you to select another card.
My solution would be:

If you have an artifact card in your hand, and at least two cards in total, you're asked if you want to discard an artifact, or to discard two cards. Based on your choice, you then perform the discard.

If you don't have an artifact, the mode "discard two" is selected automatically. If you have one card in your hand (artifact or not), it's discarded automatically, the same if you have exactly two cards and none is artifact. If you have empty hand, no choice is offered and nothing happens.

I think it might be easier for AI to grasp, like (I don't know the details): "Find the least valuable artifact, and sum of two least valuable cards, then discard the lowest value."
Marek14
Tester
 
Posts: 2763
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 297 times

Re: What card was discarded?

Postby Rob Cashwalker » 29 Jul 2009, 11:53

I think I'm going to ignore this portion of the mechanic for a while. I'm not sure how the Input methods work. I've looked at the input_Discard method in CardFactoryUtil, and I haven't a clue how to modify it in order to deal with this. Zerker, when you get back, and school quiets down, you can add the functionality in.

I've now moved onto putting cards from your hand back to the library. This one seems like an easier hack from input_Discard.
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: What card was discarded?

Postby zerker2000 » 30 Jul 2009, 14:54

I Am currently on a computer on which I have put eclipse and am currently importing 7-29 source, but I shall be leaving tommorow at three: right now, I shall try to merge my old code into the latest release, post the results, and then probably get xtype discards working(when/if I get MPool/Abilities working). By the way, are there m/any cards that use a form of "discard <X> unless discard <type>" that isn't "2 or artifact"?
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: What card was discarded?

Postby Rob Cashwalker » 30 Jul 2009, 15:58

At the moment, as best I can tell, there are two spells. One is 2 or artifact and the other is 2 or land. But you never know when there will be another or when we can reuse the overall logic.
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: What card was discarded?

Postby mtgrares » 31 Jul 2009, 17:08

I'm probably the best one to answer this question. Below is the code for "discard 2 cards or an artifact card". Technically you can discard 2 artifact cards but that is a very rare case so I'm going to ignore it (for better or worse).

Note that I haven't compiled this code and there might be a few small errors. I just wrote this on the fly 2 minutes ago.

Code: Select all
//discard 2 cards or an artifact card
//note: you cannot discard 2 artifact cards which the rules allow
public static Input input_discard2orArtifact(final SpellAbility spell)
{
   //this must be final since it is used by an anonymous class (a class that isn't named)
   final int nDiscard = 2;

   Input target = new Input()
   {
      private static final long serialVersionUID = 2355676549786944050L;

      int n = 0;
      public void showMessage()
      {
         AllZone.Display.showMessage("Discard 2 cards unless you discard an artifact");
         //user cannot click on OK or Cancel buttons
         ButtonUtil.disableAll();

         //is your hand empty?
         if(AllZone.Human_Hand.getCards().length == 0)
            stop();
      }
      public void selectCard(Card card, PlayerZone zone)
      {
         if(zone.is(Constant.Zone.Hand))
         {
            AllZone.GameAction.discard(card);
            n++;
            
            if(card.isArtifact() || n == nDiscard)
              stop();
            
            //show message again to the user in case it might have changed
            //(but it won't in this case)
            //this also checks to see if the player's hand is empty
            showMessage();
         }//if

      }//selectCard()
   };//Input
   return target;
}//input_discard2orArtifact()
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: What card was discarded?

Postby Rob Cashwalker » 31 Jul 2009, 18:13

Thanks Rares. I'm still puzzled by how the Input methods operate... but I guess that's one area where your GUI design rocks - there's very little code necessary to make custom actions like this.
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: What card was discarded?

Postby mtgrares » 31 Jul 2009, 18:24

I know that Input is confusing. This is one of the earliest problems that I struggled to solve. How can a mouse click represent choosing a target with an infinite number of restrictions OR going to the next phase OR any number of other things.

I'm very happy that most of my code is readable and grokked (understood).
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: What card was discarded?

Postby mtgrares » 31 Jul 2009, 18:46

And you could write an "intelligent" method for the computer to use like GameAction.discard2OrArtifact() or GameAction.AI_discard(String parseString).
mtgrares
DEVELOPER
 
Posts: 1352
Joined: 08 Sep 2008, 22:10
Has thanked: 3 times
Been thanked: 12 times

Re: What card was discarded?

Postby Rob Cashwalker » 01 Aug 2009, 03:08

Yes, I've been considering an intelligent discard routine... besides just the 2 or artifact kind. Like discard land if the AI has at least 4 or 5 lands in play, discard the smallest vanilla creature, or the most expensive spell if early in the game....
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 31 guests


Who is online

In total there are 31 users online :: 0 registered, 0 hidden and 31 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: No registered users and 31 guests

Login Form