从我的角度来看,你必须考虑这样一个事实,即当玩家有一个或多个 A 时,他或她在任何给定时间都有两个可能的得分。试图计算最接近 21 的单个值是对持有 21 点 A 的错误抽象。
作为一名球员,我不希望程序告诉我,当我有 ace 和 5 时,我有 16,因为我可能不会用 16 击球,但如果我有 ace 和 5,我绝对会击球. 从概念上讲,我真的有 6 个或16 个。
我认为手的价值应该可以表示为一两个值。显然,在没有 ace 的情况下,将只有一个值。同样,当 ace-as-11 意味着一手破牌时,这手牌只有一个值,因为该 ace必须计为 1。您也可以说任何 ace + 10 组合只有一个值,因为那是即时的二十一点。
这是一个部分实现——为这只猫剥皮的许多方法之一。我这样写是为了让你以某种方式思考;鉴于只有 A 可以有多个值,并且给定的手牌最多可以有两个可能的值,但是,这可以更简洁地完成。
public interface Hand
{
IEnumerable<int> PossibleValues { get; set; }
}
public interface Card
{
CardValues PossibleValues { get; set; }
}
public interface CardValues
{
int Value1 { get; }
int Value2 { get; }
}
public class BlackjackHand : Hand
{
IList<Card> cards;
public IEnumerable<int> PossibleValues
{
IList<int> possible_values = new List<int>();
int initial_hand_value = cards.Sum(c => c.Value1);
if(initial_hand_value <= 21)
{
possible_values.Add(initial_hand_value);
yield return initial_hand_value;
}
foreach(Card card in cards.Where(c => c.Value2 > 0))
{
IList<int> new_possible_values = new List<int>();
foreach(int value in possible_values)
{
var alternate_value = value + card.Value2;
if(alternate_value <= 21)
{
new_possible_values.Add(alternate_value);
yield return alternate_value;
}
}
possible_values.AddRange(new_possible_values);
}
yield break;
}
}