List.RemoveAt在第二次迭代时抛出异常

时间:2015-02-16 19:05:09

标签: c# list

我正在将一些旧的家庭作业从Java移植到C#,并且我一直试图从列表中删除一个元素的ArgumentOutOfRange异常。我在一个对象上调用一个方法,该方法又在包含该列表的类上调用静态方法。

我正在循环播放一系列Player对象,这些对象将DeckOfCards中的卡片复制到玩家手中并从DeckOfCards中移除该卡片。它适用于第一次迭代,第二次失败。

编辑:根据要求,以下是相关文件的完整代码。

Runner.cs

using System;

public class Runner
{

    public static void Main(String[] args){


       int choice = -1;

        while(choice != 3){
            Console.WriteLine("\nBlackjack!");
            Console.WriteLine("Press 1 to choose the timid strategy.");
            Console.WriteLine("Press 2 to choose the aggressive strategy.");
            Console.WriteLine("Press 3 to exit.");

            string input = Console.ReadLine();

            try
            {
                choice = Convert.ToInt32(input);
                if ((choice == 1) || (choice == 2))
                {
                    BlackJack game = new BlackJack(choice);
                    game.playRound();
                    /*Console.WriteLine(DeckOfCards.cardCount());
                    DeckOfCards.draw();
                    Console.WriteLine(DeckOfCards.cardCount());
                    DeckOfCards.draw();
                    Console.WriteLine(DeckOfCards.cardCount());
                    Console.WriteLine(DeckOfCards.topCard());*/
                }

                else if (choice == 3)
                {
                    Console.WriteLine("\nThanks for playing!");
                }

                else
                {
                    Console.WriteLine("\nPlease enter a number between 1 and 3");
                }
            }
            catch (OverflowException)
            {
                Console.WriteLine("\nPlease enter a number between 1 and 3");
            }
            catch (FormatException)
            {
                Console.WriteLine("\nPlease enter a number between 1 and 3");
            }

        }
    }
}

Blackjack.cs

using System;
using System.Collections;

public class BlackJack {

    private Player[] players;

    /*
     * Passes an integer value to player to determine which strategy the Player object will have.
     * Sets up the DeckOfCards and adds both Player objects to an array.
     * @require integer value 1 or 2
     * @ensure this.players[0] will have a non-null strategy object and both players added to an array 
    */   
    public BlackJack(int choice) {
        DeckOfCards.resetDeck();
        this.players = new Player[2];
        this.players[0] = new Player(choice, "Player"); //player
        this.players[1] = new Player("Dealer"); //dealer
    }

    /*
     * Plays the game, with each player hitting until the hand value specifed by his strategy is reached
     * or his hand value is greater than 21.
     * @require two non-null player objects
     * @ensure Players hit according to the specified strategies or until hand > 21
    */
    public void playRound() {
        for (int i = 0; i < this.players.Length; i++) { 
            this.players[i].takeTurn();
            this.players[i].showHand();
            //Console.WriteLine(DeckOfCards.cardCount());
            //DeckOfCards.showDeck();
        }

        //If the player's hand is greater than the dealer's hand and less than or equal to 21
        if(this.players[0].handValue() > this.players[1].handValue() && this.players[0].handValue() <= 21){
            Console.Write("Player wins!");
        }
        //If the player's hand is less than or equal to 21 and the dealer has busted
        else if((this.players[0].handValue() <= 21) && this.players[1].handValue() > 21){
             Console.Write("Player wins!");    
        }
        //Otherwise, the dealer has won.
        else{
             Console.Write("Better luck next time, pal.");
        }

    }

}

DeckOfCards.cs

using System;
using System.Collections.Generic;
using System.Linq;

public class DeckOfCards { 

    private static List<Card> deck = new List<Card>();

    private DeckOfCards(){}

    /*
     * Loads the deck with cards programmatically
     * @require
     * @ensure 52 unique cards in a shuffled deck ArrayList
    */
    public static void resetDeck(){
        //instead of having a 52 element array
        String[] suits = {"Hearts", "Clubs", "Spades", "Diamonds"};
        String[] faceValues = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "King", "Queen", "Ace"};
        int[] pointValues = {2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11};

        deck.Clear();

        /*
         * Generates card names and values by looping through two arrays
         * Creates a new Card object and adds it to the deck ArrayList
        */
        for(int i = 0; i < suits.Length; i++){
            for(int j = 0; j < faceValues.Length; j++){
                String cardName = faceValues[j] + " of " + suits[i];
                deck.Add(new Card(cardName, pointValues[j]));
            }
        }

        shuffle();

    }

    /*
     * Shuffles the deck
     * @require a non-empty deck ArrayList
     * @ensure cards in array appear in a different order
    */
    public static void shuffle()
    {
        var rnd = new Random(DateTime.Now.Millisecond);
        deck = deck.OrderBy(x => rnd.Next()).ToList();
    }

    /*
     * Returns the value of the top card and removes it from the deck ArrayList
     * @require deck size > 0
     * @ensure deck size - 1
    */
    public static Card draw() { 
        //This is giving me problems. I think it's happening becuse the draw() method, removes an element from the list, is called in a loop.
        //Apparently C# has problems with removing elements from lists in loops.
        Card result = deck[0];
        deck.RemoveAt(0);
        return result;
    }

//Methods from here till EOF for testing purposes only
    internal static void showDeck()
    {
        foreach(Card c in deck){
            Console.WriteLine(c.getName() + " has value " + c.getValue());
        }
    }

    internal static int cardCount()
    {
        int i = 0;
        foreach(Card c in deck){
            i = i + 1;
        }
        return i;
    }

    internal static Card topCard()
    {
        return deck[0];
    }

    internal static Card bottomCard()
    {
        return deck[51];
    }

}

Player.cs

using System;

public class Player {

    private Hand hand;
    private string name;
    private IStrategy myStrategy;

    /*
     * Constructor, sets up the Player object
     * @require integer value 1, 2, or 3, string name
     * @ensure Player with empty hand, specified name and selected strategy
    */
    public Player(int choice, string name){
        this.hand = new Hand();
        this.name = name;

        if(choice == 1){
            this.myStrategy = new TimidStrategy();
        }
        else if(choice == 2){
            this.myStrategy = new AggressiveStrategy();
        }
        else{
            this.myStrategy = new DealerStrategy();
        }
    }

    /*
     * Overloaded, sets up the Player object
     * @require string name
     * @ensure Player with specified name and dealer strategy
    */
    public Player(string name)
    {
        this.hand = new Hand();
        this.name = name;
        this.myStrategy = new DealerStrategy();
    }

    /*
     * Adds a card to the player's hand
     * @require deck > 0 cards
     * @ensure hand + 1 card, deck - 1 card
    */
    public void giveCard()
    {
        hand.addCard(DeckOfCards.draw());
    }

    /*
     * Adds card to the hand until the hand value reaches the limit specified in the stratgy or exceeds 21.
     * Checks for aces in a hand that exceeds 21 and changes them from 11 to 1 point if present.
     * @require non-null hand, deck >= 0 cards
     * @ensure cards added to hand until strategy limit is reached or 21 is exceeded
    */
    public void takeTurn()
    {
        int hitMe = 1;
        while (hitMe == 1)
        {
            giveCard();

            if (hand.getValue() > 21)
            {
                hand.changeAceValue();
            }

            hitMe = this.myStrategy.hitOrStand(hand.getValue());
        }
        /*
         * Note to self: This originally malfunctioned because the hitMe/myStrategy assignment needed to be last, not first.
         * The pieces of this method are all tested separately.
        */
    }

    /*
     * Prints the results of the round
     * @require non-null hand >= 0 cards
     * @ensure hand point value printed to screen
    */
    public void showHand(){
        Console.WriteLine();
        hand.showHand();
        if(hand.getValue() <= 21){
            Console.WriteLine(this.name + " stands at " + hand.getValue());
        }
        else if(hand.getValue() > 21){
           Console.WriteLine("Bust! " + this.name + " is over by: " + (hand.getValue() - 21));
        }
    }

    /*
        * Returns the player's name
        * @require string name != null
        * @ensure returns the player's name
       */
    public string getName()
    {
        return this.name;
    }


    //Methods from here till EOF for testing purposes only

    /*
     * Returns the hand's value.
     */
    internal int handValue()
    {
        return hand.getValue();
    }

    /*
     * Deals a card worth one point.
     * Used to test whether a player will stand at the value specified in his strategy.
     */
    internal void standTest()
    {
        int hitMe = 1;
        while (hitMe == 1)
        {
            hand.addCard(new Card("Worth One", 1));
            hitMe = this.myStrategy.hitOrStand(hand.getValue());
        }
    }

    internal int cardCount()
    {
        return this.hand.cardCount();
    }

}

这是经销商的策略,即崩溃的玩家。除了handValue部分之外,它与其他两个逐字相同。

using System;
public class DealerStrategy : IStrategy{
    /*
     * Determines whether the player will hit or stand based on the value of his hand.
     * @require integer value >= 0
     * @ensure positive integer result
    */
    public int hitOrStand(int handValue) {
        int result = 1;

        if(handValue >= 17){
            result = 1;
        }
        else if(handValue < 1){
            result = 1;
        }

        return result;
    }
}

上面的代码适用于循环的第一次迭代。它在第二次迭代时引发异常,Visual Studio告诉我Deck的Count = 0result = null

这是堆栈跟踪。

System.ArgumentOutOfRangeException was unhandled
  HResult=-2146233086
  Message=Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
  Source=mscorlib
  ParamName=index
  StackTrace:
       at System.ThrowHelper.ThrowArgumentOutOfRangeException()
       at System.Collections.Generic.List`1.get_Item(Int32 index)
       at DeckOfCards.draw()
       at Player.giveCard()
       at Player.takeTurn()
       at BlackJack.playRound()
       at Runner.Main(String[] args)
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

我做错了什么?这在Java中是微不足道的。

1 个答案:

答案 0 :(得分:0)

hitOrStand方法总是返回1:

public int hitOrStand(int handValue) {
    int result = 1;

    if(handValue >= 17){
        result = 1;
    }
    else if(handValue < 1){
        result = 1;
    }

    return result;
}

这意味着在takeTurn方法中,循环永远不会停止:

public void takeTurn()
{
    int hitMe = 1;
    while (hitMe == 1)
    {
        giveCard();

        if (hand.getValue() > 21)
        {
            hand.changeAceValue();
        }

        hitMe = this.myStrategy.hitOrStand(hand.getValue());
    }
    /*
     * Note to self: This originally malfunctioned because the hitMe/myStrategy assignment needed to be last, not first.
     * The pieces of this method are all tested separately.
    */
}

我怀疑其他策略之一正在用于hitOrStand,它也会返回不正确的值,否则,如果已发布,则会导致无限循环。