【问题标题】:Java card game "War" gets Out of bounds exceptionJava 纸牌游戏“战争”出现越界异常
【发布时间】:2019-11-08 01:32:47
【问题描述】:

我正在使用数组列表创建纸牌游戏“战争”的 java 版本。

这些是所有文件,主要基于 Paul Deiel 的“Java How to Program, Early Objects” https://github.com/eldar101/EldarRep/tree/master/Game_Of_War/src

游戏会询问两名玩家的姓名,然后将一副牌分成两副 26 张牌。 我已经添加了 JPanel 消息来通知牌组的大小以及每回合谁获胜。 它正常通过转弯,甚至达到数百个转弯,但由于某种原因永远不会结束并发出:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 14 out of bounds for length 14
    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
    at java.base/java.util.Objects.checkIndex(Objects.java:373)
    at java.base/java.util.ArrayList.get(ArrayList.java:425)
    at DeckOfCards.getCard(DeckOfCards.java:69)
    at Game.gamePlay(Game.java:51)
    at Game.<init>(Game.java:31)
    at main.main(main.java:5)

谁能告诉我为什么我在很多回合后随机出界?我不知道我错过了什么,因为游戏正常进行,只是没有结束并出​​现异常。

如果您想快速浏览一下,这是游戏本身的代码:

import java.util.Scanner;
import javax.swing.JOptionPane;


public class Game {
    String p1, p2;
    int p1DeckSize = 0, p2DeckSize = 0;
    DeckOfCards deck, deckP1, deckP2;

    public Game() {

        Scanner input = new Scanner(System.in);
        deck = new DeckOfCards(); // crate a new deck
        deck.shuffle(); // Shuffle the deck
        deckP1 = new DeckOfCards();
        deckP1.clearDeck();
        deckP2 = new DeckOfCards();
        deckP2.clearDeck();
        for (int i = 0; i < 26; i++) {
            deckP1.addICard(i,deck.getCard(i));
        }
        for (int i = 0; i < 26; i++) {
            deckP2.addICard(i,deck.getCard(i+26));
        }
        deck.clearDeck();
        JOptionPane.showMessageDialog(null, "Welcome to a game of \"War\"!");
        this.p1 = JOptionPane.showInputDialog(null, "Please enter player 1's name:");
        this.p2 = JOptionPane.showInputDialog(null, "Please enter player 2's name:");
        JOptionPane.showMessageDialog(null, this.p1 + " is player 1 \n" + this.p2 + " is player 2");

        gamePlay();
    }

    public void gamePlay() {
        int turn = 1, i = 0;
        //int indexP1 = 0, indexP2 = 0;
        while (deckP1.deckSize() != 0 && deckP2.deckSize() != 0) {
            JOptionPane.showMessageDialog(null, "Turn number " + turn++);
            JOptionPane.showMessageDialog(null, p1 + " has " + deckP1.getCard(i).toString() + "\n" + p2 + " has " + deckP2.getCard(i).toString());
            if (deckP1.getCard(i).cardValue() > deckP2.getCard(i).cardValue()) {
                JOptionPane.showMessageDialog(null, p1 + " wins this turn!");
                turnWin(deckP1, deckP2, i);
                JOptionPane.showMessageDialog(null, p1 + " : " +deckP1.deckSize() +" " + p2+ " : " +deckP2.deckSize()  );
            } else if (deckP1.getCard(i).cardValue() < deckP2.getCard(i).cardValue()) {
                JOptionPane.showMessageDialog(null, p2 + " wins this turn!");
                turnWin(deckP2, deckP1, i);
                JOptionPane.showMessageDialog(null, p1 + " : " +deckP1.deckSize() +" " + p2+ " : " +deckP2.deckSize()  );
            } else {
                JOptionPane.showMessageDialog(null, "The cards are equal! time for war!");
                JOptionPane.showMessageDialog(null, p1 + " : " +deckP1.deckSize() +" " + p2+ " : " +deckP2.deckSize()  );
                JOptionPane.showMessageDialog(null, p1 + "'s third card is " + deckP1.getCard(i+3) + "\n" + p2  + "'s third card is " + deckP2.getCard(i+3));
                warStage(deckP1, deckP2, i);
                i++;
                JOptionPane.showMessageDialog(null, p1 + " : " +deckP1.deckSize() +" " + p2+ " : " +deckP2.deckSize()  );

            }
            if (deckP1.deckSize() == 0)
                JOptionPane.showMessageDialog(null, p1 + " Lost the game!" + p2 + " is the winner!");
            else if (deckP2.deckSize() == 0)
                JOptionPane.showMessageDialog(null, p2 + " Lost the game!" + p1 + " is the winner!");
        }
    }


    public void turnWin(DeckOfCards d1, DeckOfCards d2, int i) {
        Card temp1 = new Card(d1.getCard(i).face, d1.getCard(i).suit);
        Card temp2 = new Card(d2.getCard(i).face, d2.getCard(i).suit);
        d1.removeICard(i);
        d2.removeICard(i);
        d1.addCard(temp1);
        d1.addCard(temp2);
    }  //end method turnWin

    public void warStage(DeckOfCards d1, DeckOfCards d2, int i) {
        Card temp1 = new Card(d1.getCard(i + 3).face, d1.getCard(i + 3).suit);
        Card temp2 = new Card(d2.getCard(i + 3).face, d2.getCard(i + 3).suit);
        if (temp1.cardValue() > temp2.cardValue())
        {
            for (int j = 0; j < 3; j++){
                turnWin(d1, d2,i+1);}

        } else if (temp1.cardValue() < temp2.cardValue()) {
            for (int j = 0; j < 3; j++){
                turnWin(d2, d1, i+1);}
        }
        else
        {
            warStage(d1,d2,i+3);
        }
    }  //end method warStage
}

感谢您的帮助。

【问题讨论】:

    标签: java arraylist indexoutofboundsexception


    【解决方案1】:

    很可能在您的gameplay() 方法中,您的控件转到warStage() 方法,如果我没记错的话,您从“甲板”中删除“卡片”,而这个DeckOfCards 由某种列表支持您只需从列表中删除一个条目。然后增加计数器变量i

    另一方面,套牌的大小正在减少,这是游戏逻辑。但是当控件返回顶部时,DeckOfCards 可能有Card 但不在您指定的索引i 中。

    首先简单地执行单独的牌组大小检查,然后继续执行逻辑。意思是,在gameplay()方法中,将最后两个方法分别作为前两个条件,然后将第一个条件作为第三个条件,使其成为else if
    所以:
    if deckP1.deckSize() check
    else if deckP2.deckSize() check
    else if deckP1.getCard(i).cardValue() &gt; deckP2.getCard(i).cardValue()
    等等

    【讨论】:

      【解决方案2】:

      查看有问题的行:

      JOptionPane.showMessageDialog(null, p1 + "'s third card is " + deckP1.getCard(i+3) + "\n" + p2  + "'s third card is " + deckP2.getCard(i+3));
      

      你正在游戏中达到以下目标:

      玩家 X:只有 3 张牌 玩家 Y:有 3 张牌

      两个玩家都玩 5:

      • 玩家 X 可以下 3 张牌
      • 玩家 Y 可以下 2 张牌

      当您尝试获取(x+3)该卡不存在时,您会看到您看到的异常。如果没有谷歌搜索,我不知道这应该如何结束,因为我从未真正经历过:

      • 战争阶段是否只有 2 张牌?
      • 玩家 Y 不会因为无法支付赌注而自动输掉吗?

      您可能应该考虑做一些事情:

      1) 对面和花色选项使用枚举,通过执行以下操作可能会更安全一些:

      for all Suits
          for all Faces
              deck.add(new Card(suit,face));
      

      2) 开始使用数组列表,如堆栈或队列。本质上你应该只做

      Deck.deal()

      它总是占据最上面的牌(不管你怎么看顶部/底部)。在 99% 的纸牌游戏(我能想到的)中,您只会从顶部发牌,因此能够在不丢弃顶部 3 张牌的情况下访问第三张牌是没有意义的。现在一些 RPG 类型的游戏允许您搜索套牌等,但这是另一套规则。

      3) 创建一个

      public class Player {
          private Deck active;
          private Deck discard;
      }
      

      这意味着您可以从您的活动套牌中进行 deal() 并添加到您的弃牌套牌中。例如你会有(类似的):

      p1Card = p1.deal();
      p2Card = p2.deal();
      
      if (p1Card > p2Card) 
         p2.getDiscard().addAll(p1Card, p2Card);
      

      这也意味着您可以检查 p1Card 是否为 null 或 DeckEmptyException 并执行以下操作:

      p1.shuffleDiscard();
      

      这将洗牌并将所有卡片从丢弃到激活。我认为这是打仗的正确方式,而不是仅仅将获胜的牌添加到当前牌组的底部。

      【讨论】:

        猜你喜欢
        • 2021-03-05
        • 2023-04-04
        • 2021-12-15
        • 1970-01-01
        • 1970-01-01
        • 2012-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多