我正在将一些旧的家庭作业从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 = 0
和result = 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中是微不足道的。
答案 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
,它也会返回不正确的值,否则,如果已发布,则会导致无限循环。