此代码随机抽取52张卡片,并在每次点击时将4张文件放入4盒文本中。我对它的工作原理有了一般的了解,但我需要帮助清除一些混乱或理解它是如何工作的。我对那些我不太确定的人发表了大胆的评论。
namespace Cards
{
enum Value { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace}
}
namespace Cards
{
enum Suit { Clubs, Diamonds, Hearts, Spades }
}
namespace Cards
{
class PlayingCard
{
private readonly Suit suit;
private readonly Value value;
public PlayingCard(Suit s, Value v)
{
this.suit = s;
this.value = v;
}
public override string ToString()
{
string result = string.Format("{0} of {1}", this.value, this.suit);
return result;
}
public Suit CardSuit() // **Not sure why this is here. Maybe for future use?**
{
return this.suit;
}
public Value CardValue() // **Same as above**
{
return this.value;
}
}
}
namespace Cards
{
using System;
using System.Collections;
class Pack // **Data Access Layer?**
{
public const int NumSuits = 4;
public const int CardsPerSuit = 13;
private PlayingCard[,] cardPack;
private Random randomCardSelector = new Random();
public Pack() //**Storing all elements**
{
this.cardPack = new PlayingCard[NumSuits, CardsPerSuit]; //
for (Suit suit = Suit.Clubs; suit <= Suit.Spades; suit++) //
{
for (Value value = Value.Two; value <= Value.Ace; value++)
{
this.cardPack[(int)suit, (int)value] = new PlayingCard(suit, value);
}
}
}
public PlayingCard DealCardFromPack() // **Purpose: To dealing unique cards**
{
Suit suit = (Suit)randomCardSelector.Next(NumSuits); // **picks random 0-3 from Suit**
while (this.IsSuitEmpty(suit)) // **Purpose: Checks if empty but don't know how it works**
{
suit = (Suit)randomCardSelector.Next(NumSuits);
}
Value value = (Value)randomCardSelector.Next(CardsPerSuit);
while (this.IsCardAlreadyDealt(suit, value)) // ?
{
value = (Value)randomCardSelector.Next(CardsPerSuit);
}
PlayingCard card = this.cardPack[(int)suit, (int)value];
this.cardPack[(int)suit, (int)value] = null; // **sets the current element to null so it isn't reused.**
return card;
}
private bool IsSuitEmpty(Suit suit) // **checks if empty**
{
bool result = true;
for (Value value = Value.Two; value <= Value.Ace; value++) //**Checks Null or not**
{
if(!IsCardAlreadyDealt(suit, value))
{
result = false;
break;
}
}
return result;
}
private bool IsCardAlreadyDealt(Suit suit, Value value) //**returns current element null?**
{
return (this.cardPack[(int)suit, (int)value] == null);
}
}
}
namespace Cards
{
using System;
using System.Collections;
class Hand // **Business layer?**
{
public const int HandSize = 13;
private PlayingCard[] cards = new PlayingCard[HandSize]; // **single array? Thought it had to be 2 because of 2 parameters?**
private int playingCardCount = 0;
public void AddCardToHand(PlayingCard cardDealt)//**Confusion when class used as variable**
{
if (this.playingCardCount >= HandSize)
{
throw new ArgumentException("Too many cards");
}
this.cards[this.playingCardCount] = cardDealt; //**Confused...cardDealt value going in card[]? How does that work..**
this.playingCardCount++;//**incrementing, how is this helpful**
}
public override string ToString() //to show all 13 cards in hand
{
string result = "";
foreach (PlayingCard card in this.cards)
{
result += card.ToString() + "\n";
}
return result;
}
}
}
namespace Cards
{
public partial class Game : Window
{
public const int NumHands = 4;
private Pack pack = null;
private Hand[] hands = {new Hand(), new Hand(), new Hand(), new Hand()}; //**Creates 4 different list all single array?**
public Game()
{
InitializeComponent();
}
private void dealClick(object sender, RoutedEventArgs e)
{
try
{
pack = new Pack();
for (int handNum = 0; handNum < NumHands; handNum++) //
{
hands[handNum] = new Hand();
for (int numCards = 0; numCards < Hand.HandSize; numCards++)
{
PlayingCard cardDealt = pack.DealCardFromPack(); //**Deals 13 random cards into each array. Don't understand how it worked though.**
hands[handNum].AddCardToHand(cardDealt);
}
}
north.Text = hands[0].ToString();
south.Text = hands[1].ToString();
east.Text = hands[2].ToString();
west.Text = hands[3].ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}
答案 0 :(得分:2)
部分答案:
卡,包和手不是数据访问层的一部分。它们是应用程序的模型(对象/实体/域模型)。
如果你有代码将这些代码保存/加载到Db或文件,那么该代码就是DAL。
private readonly Suit suit; // **readonly to protect from changing value?**
private readonly Value value;
是的,只读,因为一旦卡存在,它永远不会改变。这会破坏游戏的逻辑(和诚实)。将这个概念融入模型是一个好主意。
public PlayingCard(Suit s, Value v) //**Returning value of every card**
这不会返回任何内容,它是PlayingCard类的构造函数。
public Suit CardSuit() // **Not sure why this is here. Maybe for future use?**
不,不是'未来使用'。这是课堂中非常重要的一部分,让其他代码找出它是哪一张卡片。请注意,只读字段suit
是私有的。
答案 1 :(得分:2)
<强>游戏牌强>:
class PlayingCard // **Data Access Layer?**
这看起来像商业模式,与数据访问无关。事实上,我根本没有看到代码中使用的任何数据持久性(如数据库),因此该应用程序没有数据访问层。
private readonly Suit suit; // **readonly to protect from changing value?**
正确。这使得价值不可变&#34;因为一旦构造了对象就无法改变它。请注意,此值在类(&仅中)中设置。构造函数。因此,要有一个不同的suit
,需要构建一个不同的类实例(不同的对象,就像它一样)。
public PlayingCard(Suit s, Value v) //**Returning value of every card**
不是真的。这是该类的构造函数。每次创建类的新实例(例如,var card = new PlayingCard(someSuit, someValue)
)时,此方法都会执行以构造该实例。
public Suit CardSuit() // **Not sure why this is here. Maybe for future use?**
这是获取该卡的当前Suit
值的方法。所以使用卡片的东西可以看出它适合它。请注意,它返回的值为private
,因此无法从课外读取。 (我不同意这个实现,更喜欢属性而不是方法,但完全是另一个主题。)
<强>包强>:
class Pack // **Data Access Layer?**
不,和以前一样。这些都是模特。我稍后会谈到这一点。
public Pack() //**Storing all elements**
构造函数,与以前一样。
public PlayingCard DealCardFromPack() // **Purpose: To dealing unique cards**
是。这是对Pack
对象的逻辑方法。可以合理地期望Pack
可用于处理PlayingCard
。也就是说,可以从Pack
中提取它们。这就是这个方法的用途。
Suit suit = (Suit)randomCardSelector.Next(NumSuits); // **picks random 0-3 from Suit**
是的,从给定的已知Suit
枚举中选择一个随机Suit
。
while (this.IsSuitEmpty(suit)) // **Purpose: Checks if empty but don't know how it works**
嗯,一包没有无数的牌。每次删除一个,它都会从持有卡片的班级(Pack
)中删除。因此,它不再适用于不再拥有卡片的套装。因此,这会在尝试处理之前检查是否仍有卡片留下。
this.cardPack[(int)suit, (int)value] = null; // **sets the current element to null so it isn't reused.**
是的,这与上一部分有关。发卡时,它已被删除。所以这个&#34;删除&#34;来自Pack
。
private bool IsSuitEmpty(Suit suit) // **checks if empty**
这是类中的一种辅助方法。处理卡片的方法需要检查套装是否为空,因此编写此方法进行检查。 (而不是将所有代码都放在一个大方法中,这将是糟糕的设计。)
private bool IsCardAlreadyDealt(Suit suit, Value value) //**returns current element null?**
这是另一种辅助方法。交易卡时,人们无法处理已经处理过的卡。所以这会检查。所以基本上,使用这些方法的更大方法是:&#34;在随机看西装时,我需要一套仍然有卡片的西装。在随意查看该套装中的牌时,我需要一张仍然在牌组中的牌。现在从卡组中取出该卡。&#34;
<强>手强>:
class Hand // **Business layer?**
有点儿。有点。这是另一种模式。我会在一秒钟内完成。
private PlayingCard[] cards = new PlayingCard[HandSize]; // **single array? Thought it had to be 2 because of 2 parameters?**
2个参数是什么?它是一系列卡片。每个Hand
基本上都是一组卡片。这会存储对这些卡的引用。
public void AddCardToHand(PlayingCard cardDealt)//**Confusion when class used as variable**
我不确定你在评论中提出的问题。这种方法的目的是在手上添加一张牌。因此,对卡的引用将传递给该方法,并且该方法将其添加到当前手中。
this.cards[this.playingCardCount] = cardDealt; //**Confused...cardDealt value going in card[]? How does that work..**
在这种情况下,cardDealt
是要添加到Hand
的卡片。它与&#34;处理&#34;无关。上一课的概念。它只是变量的名称。这条线正在做的是将该卡添加到Hand
。
this.playingCardCount++;//**incrementing, how is this helpful**
现在一手牌更大。因此,如果您将第三张牌添加到手牌中,则会将其添加为this.cards[2]
。在此之后添加另一张牌需要进入this.cards[3]
,否则它将取代现有的牌,这并不是所需的效果。
public override string ToString() //to show all 13 cards in hand
正确,这种方法只是打印出目前Hand
中的内容。
<强>结论强>:
好的,既然我们已经完成了这个练习(并且可以随意要求澄清),那就让我们谈谈一下&#34;模型&#34;&#34;是。它是一种商业层,因为它是一个商业对象。&#34;也就是说,它是一个封装商业概念的对象。
在本申请案例中,有三个具体概念代表&#34;业务&#34;把牌交给一只手。这些是:
每个模型都有责任在内部维护其业务逻辑。这是通过其内部变量,属性,方法等来完成的。像DealCardFromDeck
这样的事实是关于业务如何工作的现实概念,这些概念被编码到模型中。其他模型并不关心该模型如何实现该业务逻辑,他们只知道可以从一个卡片处理一张卡片。 (这是该模型与其他模型的外部可见界面的一部分。)
业务逻辑(业务层,如果你愿意的话,虽然这段代码没有真正拥有&#34;层&#34;本身)可以看出模型如何相互作用。最简单的是,我上面三个模型的列表基本上描述了它们如何相互作用。代码只是该逻辑的一种实现。
答案 2 :(得分:0)
问题:// 数据访问层?
答案:不可以。这是一个模拟单张卡的课程
问题:// 业务层?
答案:不可以。这是一个为卡片集合建模的课程。
答案 3 :(得分:0)
代码是自我解释的。我想你需要深入了解如何编程,例如:
答案 4 :(得分:0)
大多数东西都是基本的C#,一个体面的程序员应该马上认出来。处理随机卡的算法存在缺陷。这是大纲:
选择随机套装。
如果已经处理了该套装的所有牌,请转到步骤1.
选择随机排名。
如果已经处理了所选套装和等级的卡片,请转到步骤3.
从卡座中取出选定的卡片。
处理它。
这个例子最好地说明了这个有缺陷的原因。下面的牌留在牌组中(2C = 2个俱乐部):
2C 2S 3S 4S
在现实生活中,交易2个球杆的几率是1/4。使用这个算法,它是1/2,因为它有同等的机会选择交易俱乐部,因为它做了一个铲子。可以把它想象成将甲板分成4堆并随机选择一堆来处理。每一堆代表一套西装。这不是这样做的方法。
我允许你瞧不起这段代码的作者。哦,找到一本更好的书。
答案 5 :(得分:-1)
public Suit CardSuit() // **Not sure why this is here. Maybe for future use?**
{
return this.suit;
}
public Value CardValue() // **Same as above**
{
return this.value;
}
这些方法通常被称为“getters”。调用时,这些方法返回类的内部状态(变量)。程序员通常会将它们添加到呼叫中,即使没有立即使用它们。
老实说,我认为一本关于C#的入门书比Stack Overflow更能为你服务。