Page 1 of 1

Computer is thinking

PostPosted: 23 Sep 2009, 21:25
by silly freak
I got the "Computer is thinking" bug for the first time. In the console, there appears an Exception:
Code: Select all
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
   at java.util.ArrayList.RangeCheck(ArrayList.java:547)
   at java.util.ArrayList.get(ArrayList.java:322)
   at CardList.getCard(CardList.java:72)
   at CardList.get(CardList.java:73)
   at CardFactory$808.canPlayAI(CardFactory.java:25135)
   at ComputerAI_General.getMain2(ComputerAI_General.java:217)
   at ComputerAI_General.playCards(ComputerAI_General.java:48)
   at ComputerAI_General.main2(ComputerAI_General.java:43)
   at ComputerAI_Input.think(ComputerAI_Input.java:45)

   at ComputerAI_Input.showMessage(ComputerAI_Input.java:25)

   at GuiInput.setInput(GuiInput.java:27)
   at GuiInput.update(GuiInput.java:21)
   at java.util.Observable.notifyObservers(Observable.java:142)
   at java.util.Observable.notifyObservers(Observable.java:98)
   at MyObservable.updateObservers(MyObservable.java:12)
   at Phase.nextPhase(Phase.java:109)
   at GuiDisplay3$25.actionPerformed(GuiDisplay3.java:772)
   at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
   at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
   at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
   at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
   at javax.swing.plaf.basic.BasicButtonListener$Actions.actionPerformed(BasicButtonListener.java:287)
   at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1636)
   at javax.swing.JComponent.processKeyBinding(JComponent.java:2849)
   at javax.swing.JComponent.processKeyBindings(JComponent.java:2884)
   at javax.swing.JComponent.processKeyEvent(JComponent.java:2812)
   at java.awt.Component.processEvent(Component.java:5993)
   at java.awt.Container.processEvent(Container.java:2041)
   at java.awt.Component.dispatchEventImpl(Component.java:4583)
   at java.awt.Container.dispatchEventImpl(Container.java:2099)
   at java.awt.Component.dispatchEvent(Component.java:4413)
   at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1848)
   at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:704)
   at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:969)
   at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:841)
   at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:668)
   at java.awt.Component.dispatchEventImpl(Component.java:4455)
   at java.awt.Container.dispatchEventImpl(Container.java:2099)
   at java.awt.Window.dispatchEventImpl(Window.java:2475)
   at java.awt.Component.dispatchEvent(Component.java:4413)
   at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
   at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
   at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
   at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
   at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
   at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
   at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
I think the cause is that swing catches the exception, which means the program continues. the highlighted line is where the buttons are disabled, but the buttons are not re-enabled as a result of the exceptional program flow.

the real problem is bugs in the card code. these cause the exceptions in the first place.
In my case, the computer wanted to activate a Lifespark Spellbomb (you can tell from the line in CardFactory):
Code: Select all
public boolean canPlayAI() {
    CardList land = new CardList(AllZone.Computer_Play.getCards());
    land = land.getType("Land");
    CardList basic = land.getType("Basic");
    if(basic.size() < 3) return false;
    Card[] basic_1 = basic.toArray();
    for(Card var:basic_1)
        if(var.isTapped()) basic.remove(var);
    basic.shuffle();
    if(basic.get(0) != null) {
        setTargetCard(basic.get(0));
        return true;
    }
    return false;
}//canPlayAI()
the if-condition throws an exception when all basic lands are tapped (--> list is empty)

fixed (& optimized; needs iterable card list) code:
Code: Select all
public boolean canPlayAI() {
    CardList land = new CardList(AllZone.Computer_Play.getCards());
    land = land.getType("Land").getType("Basic");
    for(Card var:land)
        if(var.isTapped()) land.remove(var);
    if(land.size() == 0 || land.get(0) == null) return false;
    basic.shuffle();
    setTargetCard(land.get(0));
    return true;
}//canPlayAI()
this is only an individual card fix; for the computer is thinking bug, a try/catch around calling card code should do the trick; i'll try to figure it out tomorrow

Re: Computer is thinking

PostPosted: 23 Sep 2009, 22:05
by DennisBergkamp
I've already fixed this bug in my local version, albeit a bit less elegant:

Code: Select all
public boolean canPlayAI()
        {
         CardList land = new CardList(AllZone.Computer_Play.getCards());
         land = land.getType("Land");
         CardList basic = land.getType("Basic");
         if (basic.size() < 3) return false;
         Card[] basic_1 = basic.toArray();
         for(Card var : basic_1)
            if (var.isTapped()) basic.remove(var);
          basic.shuffle();
          if (basic.size() == 0)
             return false;
          if (basic.get(0) != null) {
             setTargetCard(basic.get(0));
             return true;
          }
          return false;
        }//canPlayAI()
I've tested that, and it works. I mean, at least it doesn't cause the crash... however, it turns the land into a 3/3 until EOT, but then it still doesn't attack with it :roll:

I should really release the next version soon I guess, there are quite a few bug fixes I've done since. It would be a shame if other people do the same bug fix all over again.
But since it has a lot of the new cards, I think I'll hold off until Wizards releases their next version (Oct 2nd I think).

Re: Computer is thinking

PostPosted: 24 Sep 2009, 09:39
by silly freak
yes, that's a good idea. as I said, this is an individual card fix. to ultimately stop the computer is thinking bug, I guess you have to add a try/catch in the AI code.

Re: Computer is thinking

PostPosted: 24 Sep 2009, 22:31
by DennisBergkamp
Yes, there's still quite a few "Computer is thinking..." bugs around. I don't think I've ever seen one that's related to an infinite loop, they're all either null pointer or array index out of bound exceptions.
I'll replace my code with your fix, since it's shorter and uses the iterable CardList :)

Re: Computer is thinking

PostPosted: 25 Sep 2009, 17:41
by silly freak
ok, i have a small patch for the problem, in ComputerAI_General:
Code: Select all
/**
 * Returns the spellAbilities from the card list that the computer is able to play
 */
private SpellAbility[] getPlayable(CardList l) {
    ArrayList<SpellAbility> spellAbility = new ArrayList<SpellAbility>();
    for(Card c:l)
        for(SpellAbility sa:c.getSpellAbility())
            //This try/catch should fix the "computer is thinking" bug
            try {
                if(sa.canPlayAI() && ComputerUtil.canPayCost(sa)) spellAbility.add(sa);
            } catch(Exception ex) {
                showError(ex, "There is an error in the card code for %s:%n", c.getName(), ex.getMessage());
            }
    return spellAbility.toArray(new SpellAbility[spellAbility.size()]);
}
This new Method implements the last path of the getMain1() and getMain2() method (that was clearly duplicated). The real change is the try-catch around the if that calls canPlayAI()

Re: Computer is thinking

PostPosted: 25 Sep 2009, 18:24
by DennisBergkamp
Cool, this should definitely help with finding those buggy cards , thanks :)