좋아, 내가 개발하고있는 카드 게임은 Scopa와 비슷하다. 누군가 알고 있다면. 데크에는 각각 10 장씩 4 개의 다른 수트로 나뉘어 진 40 장의 카드가 들어 있습니다 (에이스 => 값 1, 두 => 값 2, 세 = ..., 네, 다섯, 여섯, 일곱 번째, 여왕, 여왕, 10). 2 명의 플레이어가 있습니다 (실제로 AI와 인간 플레이어). 그들은 4 장의 카드를 가지고 있습니다.카드 게임 - 부분 집합 합계 - 다음 알고리즘을 최적화 할 수 있습니까?
테이블에는 4 개의 무료 카드가 있으며, 플레이어는 다음 규칙을 준수해야합니다. 1) 코트 카드 (노크, 퀸 및 킹)는 동일한 코트 카드 만 사용할 수 있습니다 (예 : 여왕 나는 테이블에서 여왕 만 데려 갈 수있다). 2) 숫자 카드 (에이스에서 일곱 번째까지)는 합계로 동일한 숫자 카드 또는 더 작은 숫자 카드를 사용할 수 있습니다 (예를 들어, 내가 7을 가졌 으면 7을 취할 수 있거나 {에이스, 6을} 또는 {3, 4} 또는 {에이스, 3 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);
}
}
}
는이 알고리즘이 어떻게 든 개선 될 수 있다고 생각하십니까? 디버깅하기 쉽고 유지 보수가 쉽도록이 코드를 줄이려고합니다 ... 누군가가 중복 된 조합을 피하기위한 좀 더 우아한 해결책을 가지고 있다면 정말 감사 할 것입니다. (나는 {하트 하트, 스페이드 하트 2 개}와 {스페이드 2 개, 하트 에이스 2 개} 중 하나만 얻고 싶지 않습니다.
미리 감사드립니다.
Card 클래스에서 Equals 및 GetHashCode를 재정의하고 가능한 경우 목록 대신 집합을 사용해야합니다. –
이미 GetHashCode, Equals 및 == /! = 연산자를 재정의했습니다. 집합이란 무엇입니까? –