【问题标题】:Preventing IndexOutOfBoundsException on while loop [Java]在 while 循环中防止 IndexOutOfBoundsException [Java]
【发布时间】:2015-11-08 19:58:45
【问题描述】:

我正在制作一个纸牌游戏,它运行良好,但我无法在不遇到 IndexOutOfBoundsException 错误的情况下到达牌组底部。我有一个 1 到 52 之间的随机数字数组,我用它来选择从我拥有的卡片数组列表中调用的索引。由于卡片组是一个 ArrayList,我可以在每次循环后轻松移除每张卡片。但是我无法从随机数数组中删除数字,因此随着卡片列表变小,调用索引过高的机会就越大。想不出办法。我尝试使用 if 语句将随机数的值更改为小于 arrayList 的最大长度的值,但仍然出现错误。

public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println("Welcome to War! Press enter to begin."); //User prompt
    Scanner scanner = new Scanner(System.in); //Scanner init
    String[] suit = {" of Diamonds", " of Spades", " of Hearts", " of Clubs"};//Array for suits
    String[] faces = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};//Array for faces
    String[] deck = new String[52]; //Deck size setup
    boolean deckComplete = false;//Boolean for deck being finished
    int[] random = new int[52];//Array for all numbers between 0 and the number of cards in the deck multiplied by number of decks
    ArrayList<Integer> random1 = new ArrayList<Integer>();
    int playerOneTotal = 0;
    int playerTwoTotal = 0;



    for (int x = 0; x<random.length; x++) {
        random[x] = x;
    }//Content setup for random array

    Random rndNum = new Random();//Random init

    int i = 0;

        for (i = 0; i < deck.length; i++) {

            deck[i] = faces[i % 13] + suit[i % 4];
        }//Deck of cards setup



    ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(deck));//Changing Array with card contents into an ArrayList

    while (deckComplete == false) {         //While loop for dealing cards


        for (int j = deck.length; j >= 1; j--) {


           // System.out.println("Hit enter to be dealt a card!");    
            String readString = scanner.nextLine(); //Set variable "readString" to user input
            int randomNumber = rndNum.nextInt(j);
            int randomNumberTwo = rndNum.nextInt(j);


            if (readString.equals("")) {        //If user input equals "enter"...

                 if (randomNumber >= arrayList.size()) {
                    randomNumber = arrayList.size() - 1;
                }

                if (randomNumberTwo == arrayList.size()) {
                    randomNumberTwo = arrayList.size() - 1;
                }


                  int playerOne = random[randomNumber];
                  int playerTwo = random[randomNumberTwo];
                  int playerOneScore = 0;
                  int playerTwoScore = 0;


                  System.out.println("Player One Draws a: " + arrayList.get(random[randomNumber])); //Print out card
                  arrayList.remove(random[randomNumber]); //Remove card from deck
                  System.out.println("Player Two Draws a: " + arrayList.get(random[randomNumberTwo])); //Print out card
                  arrayList.remove(random[randomNumberTwo]); //Remove card from deck


                  playerOneTotal = playerOneTotal + playerOneScore;
                  playerTwoTotal = playerTwoTotal + playerTwoScore;

                  if (playerOneTotal > playerTwoTotal) {
                      System.out.println("Player One Wins this round! Current Score - Player One: " + playerOneTotal + " Player Two: " + playerTwoTotal);
                  }else if (playerOneTotal < playerTwoTotal) {
                      System.out.println("Player Two Wins this round! Current Score - Player One: " + playerOneTotal + " Player Two: " + playerTwoTotal);
                  }else if (playerOneTotal == playerTwoTotal) {

                  }


                   if (j == 1) {    //If program gets to last card...
                       deckComplete = true; //Set desk complete to true

                       System.out.println(arrayList.get(random[randomNumber])); //Print last card
                       arrayList.remove(random[randomNumber]); //Remove last card
                       System.out.println("You are out of cards!"); //Print "You are out of cards"
                       break; //Stop loop
                   }  
               }



       }

除了尝试(如下)之外,还有什么方法可以让我得到正确的结果吗?

if (randomNumber >= arrayList.size()) {
                    randomNumber = arrayList.size() - 1;
                }

                if (randomNumberTwo == arrayList.size()) {
                    randomNumberTwo = arrayList.size() - 1;
                }

编辑:这是确切的错误消息。

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 33, Size: 23 at java.util.ArrayList.rangeCheck(ArrayList.java:635) at java.util.ArrayList.get(ArrayList.java:411) at Game.main(Game.java:72)

【问题讨论】:

  • 请发布您得到的异常的完整堆栈跟踪。
  • @LittleSanti 对不起。已更新。
  • 也许将 nexInt 参数设置为j 的最小值并且列表大小就足够了?您可以使用 Math.min
  • @sergioFC 感谢您的回复。你能澄清一点吗?我不确定我是否理解。
  • 我错了,我想我没有遇到问题

标签: java arrays loops arraylist


【解决方案1】:

如果我没看错,你每回合都会从ArrayList 中随机选择一张牌。通过在游戏开始时将整个ArrayList 洗牌(类似于在现实生活中洗牌的方式),您可以使您的生活变得更轻松。然后您可以简单地删除列表的第一个(或最后一个)元素,而不必担心IndexOutOfBoundsException

要洗牌整副牌,请使用Collections.shuffle

Collections.shuffle(fileList, new Random());

从牌库中取出最上面的牌:

arrayList.remove(0);

【讨论】:

  • 我将尝试实现这一点,因为它看起来确实比我用来实现这一点的当前方法干净得多。我确实相信我仍然会遇到无法根据卡组中的元素数量向下增加随机数的问题。我的主要问题是,当牌组中只剩下 35 个元素时,我经常会调用索引 43 左右。
  • 我认为问题出在两个arrayList.remove 语句中。删除第一个元素后,列表会更短。当您删除第二个元素时,该第二个元素的索引可能不再有效。例如,列表长度为 36。随机数 1 为 13,随机数 2 为 35。删除索引 13 处的元素 => 列表长度为 35。删除索引 35 处的元素 => IndexOutOfBoundsException。要绕过这个,首先对两个随机数执行String card = arrayList.get(i),然后执行arrayList.remove(card)。这样可以确保您移除实际的卡片,而不考虑索引。
【解决方案2】:

您拥有deck,这是按顺序排列的 52 张卡片的完整列表。

您创建arrayList 作为它的副本,就像您所做的那样,只是将其重命名为stack(或cardStack),然后:

  • 使用Collections.shuffle() 随机播放stack
  • 使用remove(stack.size()-1)(或remove(0),但速度较慢)从stack 获取卡片。

更好的是,使用 ArrayDeque 而不是 ArrayList,因为它可以用作 LIFO(后进先出)堆栈。在您的情况下,您将使用stack.pop() 拿一张卡片。


跟进

为了让游戏正常运行,一张牌必须不仅仅是文字“黑桃 A”。你需要知道它是一个 A,它是一个 Spade,所以你需要一个类,例如命名为 Card,有两个字段:suitface。然后该类的toString() 方法将返回“黑桃A”。

还请注意,除非您想作弊,否则您永远不会使用索引访问 cardStack。洗牌后唯一允许的操作是pop(),取走栈顶的牌。

您的整个循环将如下所示:

// Build deck
...

// Create shuffled stack
Deque<Card> cardStack = new ArrayDeque<>(Arrays.asList(deck));
Collections.shuffle(cardStack, rndNum);

// Play game
while (! cardStack.isEmpty()) {
    Card player1card = cardStack.pop();
    Card player2card = cardStack.pop();

    // do you stuff here
}

【讨论】:

  • 我想我理解您所说的解决方案,但我想我仍然会遇到调用高于deck 中元素数量的索引的问题。有什么方法可以删除数字以及删除卡片,这样我就不会在 ArrayList 大小为 38 时调用索引 43?
  • 谢谢。我看到这种方法更好。我已经写出了如何按照我的方式编写程序,但我似乎无法弄清楚如何基于使用单独的卡片类来构建套牌。对不起,我仍然是这方面的初学者。你能提供一些指导吗?
猜你喜欢
  • 2012-11-06
  • 2022-01-22
  • 2015-11-17
  • 2014-04-24
  • 1970-01-01
  • 2012-10-18
  • 2019-02-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多