好吧,我正在開發的紙牌遊戲與Scopa非常相似,如果有人知道的話。 甲板上有40張卡片,分成4張不同的10張卡片(ace => value1,two => value2,three = ...,4,5,6,7,knave,queen,king => value 10)。 有2名玩家(實際上是一名AI和一名人類玩家),他們手中有4張牌。紙牌遊戲 - 子集合 - 可以優化以下算法嗎?
桌上有4張免費牌,玩家只能遵守以下規則: 1)法庭卡(kn,,王后和國王)只能使用相同的法庭卡(例如,如果我有一個女王,我只能從桌上拿一個女王)。 2)數字卡(從王牌到七)可以採用相同的數字卡或總和較小的數字卡(例如,如果我有一個七我可以拿七或{一個王牌,一個六}或{一個三,一四個}或{一個王牌,三個二})。
現在時機已到,找到這期間,卡它打開AI最終可以採取:
private List<List<Card>> CalculateAITake()
{
List<Int32> handValues = new List<Int32>();
List<List<Card>> takes = new List<List<Card>>();
/* here i take every hand card value, in a unique way
* in order to avoid processing two or more times the
* same value
*/
foreach (Card card in m_AIHand)
{
Int32 cardValue = (Int32)card.Rank;
if (!handValues.Contains(cardValue))
handValues.Add(cardValue);
}
/* for each hand card value now, I calculate the
* combinations of cards I can take from table
*/
foreach (Int32 handValue in handValues)
{
// it's a court card, let's use a direct and faster approach
if (handValue >= 8)
{
foreach (Card card in m_CardsOnTable)
{
if ((Int32)card.Rank == handValue)
{
List<Card> take = new List<Card>();
take.Add(card);
takes.Add(take);
}
}
}
else
// it's a numeric card, let's use recursion
CalculateAITakeRecursion(takes, (new List<Card>(m_CardsOnTable)), 0, (new List<Card>()), handValue, 0);
}
return takes;
}
private void CalculateAITakeRecursion(List<List<Card>> takes, List<Card> cardsExcluded, Int32 cardsExcludedIndex, List<Card> cardsIncluded, Int32 sumWanted, Int32 sumPartial)
{
for (Int32 i = cardsExcludedIndex; i < cardsExcluded.Count; ++i)
{
Card cardExcluded = cardsExcluded[i];
Int32 sumCurrent = sumPartial + (Int32)cardExcluded.Rank;
/* the current sum is lesser than the hand card value
* so I keep on recursing
*/
if (sumCurrent < sumWanted)
{
List<Card> cardsExcludedCopy = new List<Card>(cardsExcluded);
cardsExcludedCopy.Remove(cardExcluded);
List<Card> cardsIncludedCopy = new List<Card>(cardsIncluded);
cardsIncludedCopy.Add(cardExcluded);
CalculateAITakeRecursion(takes, cardsExcludedCopy, ++cardsExcludedIndex, cardsIncludedCopy, sumWanted, sumCurrent);
}
/* the current sum is equal to the hand card value
* we have a new valid combination!
*/
else if (sumCurrent == sumWanted)
{
cardsIncluded.Add(cardExcluded);
Boolean newTakeIsUnique = true;
Int32 newTakeCount = cardsIncluded.Count;
/* problem: sometimes in my results i can find both
* { ace of hearts, two of spades }
* { two of spades, ace of hearts }
* not good, I don't want it to happens because there
* is still a lot of work to do on those results!
* Contains() is not enought to guarantee unique results
* so I have to do this!
*/
foreach (List<Card> take in takes)
{
if (take.Count == newTakeCount)
{
Int32 matchesCount = 0;
foreach (Card card in take)
{
if (cardsIncluded.Contains(card))
matchesCount++;
}
if (newTakeCount == matchesCount)
{
newTakeIsUnique = false;
break;
}
}
}
if (newTakeIsUnique)
takes.Add(cardsIncluded);
}
}
}
你認爲該算法能夠以某種方式改進? 我試圖儘可能地縮短這段代碼,這樣它可以很容易調試和易於維護...另外,如果有人有一個更優雅的解決方案,以避免重複的組合,我真的,真的很感激它(我不想同時獲得{ace的心,兩個黑桃}和{兩個黑桃,一顆心} ......只有其中一個)。
很多,很多預先感謝!
你應該看看你的Card類中覆蓋Equals和GetHashCode,並可能使用Sets而不是列表。 – 2012-02-14 21:18:25
我已經覆蓋了GetHashCode,Equals和== /!=運算符。 什麼是集合? – 2012-02-14 21:37:16