我有一张卡片(目标)列表,其中包含卡片游戏中卡片的所有可能目标。但是,我需要使用TargetCount卡的所有可能组合来创建minimax树。我应该如何在C#中解决这个问题?
我尝试使用网站周围的CartesianProduct扩展程序,但它似乎不起作用(当我尝试使用它时出现编译错误)。
我只是将目标存储在List<Card>
中,并且已经拥有所有可能的目标。现在,对于每种可能的X卡组合,我想在搜索树中添加一个包含每个X可能目标的List<Card>
,如下所示。我该怎么做呢?
List<GameDecision> Out = new List<GameDecision>();
foreach(Card SpellCard in PlayerSpellbook(Player))
{
List<Card> PossibleTargets = GetPossibleTargets(SpellCard);
foreach(all combinations of possible targets)
{
List<Card> Targets = new list of Card.TargetCount targets;
Out.Add(new GameDecision() { Type = GameDecisionType.PlayCard, TheCard = SpellCard, Targets = Targets });
}
}
答案 0 :(得分:1)
你的问题有点不清楚。
你说组合。组合只是每个可用选项的列表。例如,您有数组{ 1, 2, 3 }
,并且您希望组合长度为2,您将获得数组:
{ 1, 2 }
{ 1, 3 }
{ 2, 3 }
您可能意味着排列。排列是每个顺序中的每个组合。所以,从{ 1, 2, 3 }
之前的相同数组开始,长度为2的所有排列都是:
{ 1, 2 }
{ 1, 3 }
{ 2, 1 }
{ 2, 3 }
{ 3, 1 }
{ 3, 2 }
要获得所有排列而不管数组长度如何,首先需要找到组合并计算排列。
无论您选择哪种选项,这里都有一些有用的扩展方法。
using System;
using System.Collections.Generic;
using System.Linq;
public static class IEnumerableExtensions
{
// Can be used to get all combinations at a certain level
// Source: http://stackoverflow.com/questions/127704/algorithm-to-return-all-combinations-of-k-elements-from-n#1898744
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } :
elements.SelectMany((e, i) =>
elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] { e }).Concat(c)));
}
private static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource item)
{
if (source == null)
throw new ArgumentNullException("source");
yield return item;
foreach (var element in source)
yield return element;
}
// This one came from: http://stackoverflow.com/questions/774457/combination-generator-in-linq#12012418
public static IEnumerable<IEnumerable<TSource>> Permutations<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
throw new ArgumentNullException("source");
var list = source.ToList();
if (list.Count > 1)
return from s in list
from p in Permutations(list.Take(list.IndexOf(s)).Concat(list.Skip(list.IndexOf(s) + 1)))
select p.Prepend(s);
return new[] { list };
}
}
听起来你只想得到一个组合的所有排列(在你的情况下PossibleTargets
)。
foreach (var permutation in PossibleTargets.Permutations())
{
List<Card> Targets = new List<Card>(permutation);
Out.Add(new GameDecision() { Type = GameDecisionType.PlayCard, TheCard = SpellCard, Targets = Targets });
}
如果你确实意味着组合,那么你还需要提供要解决的结果数组的长度。您将其指定为X
,但您的代码中没有任何迹象表明X
可能是什么。为了使其正常工作,X必须小于Permutations.Count()
,否则您将始终获得由列表中的每个元素组成的1个组合。
var length = X;
foreach (var combination in PossibleTargets.Combinations(length))
{
List<Card> Targets = new List<Card>(combination);
Out.Add(new GameDecision() { Type = GameDecisionType.PlayCard, TheCard = SpellCard, Targets = Targets });
}
通常的做法是遍历每个可能的长度(从Combinations.Length到1)以获得任何长度的每种可能组合。
for (var length = PossibleTargets.Count(); length > 0; length--)
{
foreach (var combination in PossibleTargets.Combinations(length))
{
List<Card> Targets = new List<Card>(combination);
Out.Add(new GameDecision() { Type = GameDecisionType.PlayCard, TheCard = SpellCard, Targets = Targets });
}
}
此示例获取每个可能长度的每个排列(任意顺序的卡片组合)。
for (var length = PossibleTargets.Count(); length > 0; length--)
{
foreach (var combination in PossibleTargets.Combinations(length))
{
foreach (var permutation in combination.Permutations())
{
List<Card> Targets = new List<Card>(permutation);
Out.Add(new GameDecision() { Type = GameDecisionType.PlayCard, TheCard = SpellCard, Targets = Targets });
}
}
}