0

I am creating a little BlackJack application in C#. I am able to deal an intial hand to both the dealer and the player and then hit for the player. However once I do this, the dealer is supposed to draw a card from the deck when the dealer handvalue is less than 17.

This is the get a single card from the deck in the deck class:

public Card GetCard()
{
    int r0 = rndCard.Next(0, cardsInDeck_.Count - 1);
    cardsInDeck_.RemoveAt(r0);
    return cardsInDeck_[r0];
}

when I hit "stay" and the dealer activates I get this error on the last line

Index was out of range. Must be non-negative and less than the size of the collection

This is my "stay" method on the form

 private void buttonStay_Click(object sender, EventArgs e)        
 {          
    while (dealer.GetValue() < 17) 
    {
        dealer.CardsInDealerHand.Add(deck.GetCard());

    }

    dealerHandValue_ = dealer.GetValue();

    if (dealerHandValue_ > 21)
    {
        Win();

    }
    else
    {
        WinCondition();
    }
 }

I am new to programming in general but I think that something is wrong with either my deck or dealer.

I would appreciate any help on this.

Ondrej Janacek
  • 12,486
  • 14
  • 59
  • 93

4 Answers4

1

First thing that I notice: you're removing the card from the deck before you access it to return it, causing your indices to get out of whack. In some situations this may "work" in that it won't throw, but you won't get back the right card. In other situations you can end up overrunning your list's bounds.

Consider: You have 6 items in your "deck", and you pick the last one. Your current logic would be:

cardsInDeck_.RemoveAt(r0);  # Remove the item at index 5; now we have 5 items (0-based indexing)
return cardsInDeck_[r0]; # Try to get the item at index 5, but it's no longer there!

Even if you don't pick the last index, you're actually going to get the wrong card. For example, if you had:

{ A, J, 5, 10, 2 }

...in your deck, and you picked index 2, you should get the 5 back. Since you're removing the card first then accessing the list index, you'd actually get back the 10.

You'll need to get a reference to the card first, then remove it from the deck and return the reference:

public Card GetCard()
{
    int r0 = rndCard.Next(0, cardsInDeck_.Count - 1);
    var chosenCard = cardsInDeck_[r0];
    cardsInDeck_.RemoveAt(r0);
    return chosenCard;
}

It would probably be a good idea to check cardsInDeck_.Count for a zero value before trying to get another card as well, either in GetCard() or in the while loop, perhaps. If you're only dealing out two hands (one to the player, one to the dealer) then this is mathematically not a situation you'll hit, of course. Otherwise, with multiple players, you'd need to handle that situation somehow (e.g. you could add a second deck to the hand by repopulating cardsInDeck).

eldarerathis
  • 35,455
  • 10
  • 90
  • 93
  • I just tried this but I get the program crashing saying – user3230102 Feb 09 '14 at 08:19
  • minValue' cannot be greater than maxValue on the first line – user3230102 Feb 09 '14 at 08:20
  • @user3230102: That seems to imply that the deck was empty (e.g. `cardsInDeck_.Count - 1` must have been -1, which is less than 0), but I can't tell you why that would be given the code you've shown. Either way, the current logic in `GetCard()` is going to be buggy. It sounds like you have multiple errors going on. – eldarerathis Feb 09 '14 at 08:23
  • Does this mean that the list of cards in the deck is not populated? – user3230102 Feb 09 '14 at 08:24
  • @user3230102: Either it wasn't populated in the first place, or it was emptied and not repopulated. Again, I can't tell based on what's here at the moment. However, if the list was not getting populated at all to begin with, then I can't see how you would have gotten the error in your question, because an empty list will result in a call to `Random.Next(0, -1)`, giving you the error in your comment. It would have made it impossible to get the index error (on the first call, at least). – eldarerathis Feb 09 '14 at 08:29
  • As I said before this problem only occurs when the user hits "stay" , which means the dealer will loop through until it busts. Before then the getcard method works perfectly when the player calls it, I have also stepped through the program and it confirms then that the count of the list is zero. I think it has been depopulated at some point, Thank you anyways, your answer has been the best of the lot. – user3230102 Feb 09 '14 at 08:36
  • @user3230102: Well, a couple of possible culprits for that off the top of my head would be: 1) The list didn't get populated to begin with for some reason, so check whatever initializes it. 2) Something is not calculating correctly in the dealer's `GetValue()` method, and you're looping there too long and emptying the list inadvertently because `GetValue()` never reaches 18 to break you out of the loop. I would probably step through those two pieces of code to start, and see if it's either of those scenarios, then branch out into other pieces of the code if those look good. – eldarerathis Feb 09 '14 at 08:39
  • Will do, Thanks again, I knew something was wrong about the list count, but that hadn't occurred to me. I appreciate your answer and I will look into it. – user3230102 Feb 09 '14 at 08:46
0

r0 is being set to a value that is either negative or larger then the size of cardsInDeck_ by the function rndCard.Next

    int r0 = rndCard.Next(0, cardsInDeck_.Count - 1);
jeff_kile
  • 1,805
  • 16
  • 21
  • Do you know how I could fix this, visual studio says this line is the problem, but I thought the parameters for rndCard.Next will give a value between 0 and the size of the list of cards in the deck – user3230102 Feb 09 '14 at 08:08
  • Sorry I am not very familiar with C# or programming in general, do you mean the list of cards in the deck/ – user3230102 Feb 09 '14 at 08:21
  • Stack Overflow is not a debugging service. If I found the source of the error please mark the answer as correct. You need to look into debugging techniques and understand how functions on objects return values. – jeff_kile Feb 09 '14 at 08:25
0

Problem : You are trying to remove the items from the cardsInDeck_ without checking for its Count . if you keep on Removing items from the cardsInDeck_ at certain point it's Count becomes zero and no items can not be removed if the Count is Zero.

Solution : before removing items from cardsInDeck_ ,you need to check for its Count, you should remove items only if its Count is greater than zero.

Replace This:

cardsInDeck_.RemoveAt(r0);

With This:

if(cardsInDeck_.Count>0)
{
cardsInDeck_.RemoveAt(r0);
}
Sudhakar Tillapudi
  • 25,935
  • 5
  • 37
  • 67
0

The exception message: "Index was out of range. Must be non-negative and less than the size of the collection" is the problem here because if the deck is empty then

int r0 = rndCard.Next(0, cardsInDeck_.Count - 1); the second argument to Next is an exclusive upper bound. thus if Count is 0 then you are asking for an int >= 0 && < -1
if count is 1 you are asking for an int >= 0 && < 0

Also, I recommend that you follow standard C# naming conventions. Microsoft's recommendations are a good place to start

msdn C# style guide

Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84