这是我的问题: 我正在研究玩家石斑鱼(它将玩家分成小组)。我是通过一个for循环来做的,但它不会划分所有玩家:(。
以下是代码:
namespace Grouper
{
public partial class Form1 : Form
{
List<string> players=new List<string>();
public Form1()
{
InitializeComponent();
LoadPlayers();
}
private void But_rnd_Click(object sender, EventArgs e)
{
LoadPlayers();
bool isOdd = players.Count % 2 == 1;
List<string> results=new List<string>();
if(!isOdd) // Count of players is even
{
Grouping(ref results);
}
if(isOdd) // Count of players is odd
{
Grouping(ref results);
results.Add("Remained: " + players[0]);
ShowResults(ref results);
}
}
private void Grouping(ref List<string> results)
{
Random r=new Random();
for (int i = 0; i < players.Count() / 2 + 1; i++)
{
int randomPlr = r.Next(players.Count() / 2 + 1, players.Count());
results.Add(i + 1 + ".: " + players[i] + " + " + players[randomPlr]);
players.RemoveAt(i);
players.RemoveAt(randomPlr - 1);
}
}
private void ShowResults(ref List<string> results)
{
string write = "";
foreach (string result in results)
{
write += result + "\n";
}
MessageBox.Show(write);
}
private void LoadPlayers()
{
players.Clear();
players.Add("p1");
players.Add("p2");
players.Add("p3");
players.Add("p4");
players.Add("p5");
players.Add("p6");
players.Add("p7");
}
}
}
方法ShowResults()只显示2组和1名玩家,剩下2组和1名剩余= 5名玩家,但我有7名玩家!。
答案 0 :(得分:4)
您的代码中存在多个问题。
if
语句使用这实际上是奇数:
bool isOdd = players.Count % 2 == 1;
…
if(!isOdd)
{
…
}
if(isOdd) // Count of players is odd
{
…
}
使用if / else
,您的代码将更具可读性:
if (players.Count % 2 == 0)
{
…
}
else
{
…
}
此外,您可以完全省略此检查,进行分组,然后弄清楚如何处理其余部分(谁说每次最多会留下一个?如果您需要将它们分成三组之间怎么办?未来?):
Grouping(…);
if (players.Count > 0)
{
… process remaining players …
}
for
循环中的迭代次数正如其他人所指出的那样,你在这里“过分”:
for (int i = 0; i < players.Count() / 2 + 1; i++)
这将总是比你想要的多两次迭代。你应该改变它:
for (int i = 1; i < players.Count() / 2; i++)
这样它可以用于偶数或奇数,也适用于角落情况(仅限0或1个玩家)。或者,如果您在每次迭代时从列表中取出两名玩家,只需使用:
while (Players.count() > 1)
在以下代码中,您无法确定a)i
- 元素是否存在,b)随机索引与i
不匹配,这将有效地将同一个玩家放入基团:
int randomPlr = r.Next(players.Count() / 2 + 1, players.Count());
results.Add(i + 1 + ".: " + players[i] + " + " + players[randomPlr]);
players.RemoveAt(i);
players.RemoveAt(randomPlr - 1);
要么占一半,那么另一半占据players
列表(在这种情况下,你根本不需要做任何for
个),或每次随机挑选一名玩家。例如,像这样:
public string PickRandomPlayer(List<string> players)
{
int random = … generate random index …;
string player = players[random];
players.RemoveAt(random);
return player;
}
然后在for
看起来两次调用此方法,为每一半选择一个玩家。
ref
参数以下声明包含不必要的不需要的 ref
:
private void Grouping(ref List<string> results)
简单地说:默认情况下,对象,如List<string>
通过引用传递。这意味着,当您访问代码中的results
参数并对其进行修改(添加/删除项目)时,受影响的实例就是调用者提供的实例:
void Grouping(List<string> results) { … }
…
List<string> results = new … ;
…
Grouping(results);
…
… here results contains what Grouping put in
另一方面,当您指定ref
时,您可以将方法List<string>
的新实例传递出方法:
void Grouping(List<string> results)
{
results = new … ; // this instance will be returned out of the method!
}
…
List<string> results = new … ;
…
Grouping(ref results); // here, whatever is in results currently, is lost
…
goto
这只是糟糕。请参阅此SO question及其接受的答案。此外,谷歌对“GOTO声明被认为有害”以进一步阅读此主题。
答案 1 :(得分:2)
循环的条件是i < players.Count() / 2 + 1
。
这就是说,因为你在循环的每次迭代中删除了2个玩家,你就改变了条件的值。
假设你从7名球员开始。
最后,你有2个小组和3个剩余玩家,但是由于你"Remained: " + players[0]
,你只显示其余1个玩家。
答案 2 :(得分:0)
这不是很好,但应该有用(只需输入,所以调整语法):
private void But_rnd_Click(object sender, EventArgs e)
{
LoadPlayers();
List<string> results=new List<string>();
Grouping(ref results);
ShowResults(ref results);
}
private void Grouping(ref List<string> results)
{
Random r=new Random();
while (Players.count() > 1)
{
int p1 = r.next(players.count());
String p1s = players.get(p1);
players.removeat(p1);
int p2 = r.next(players.count());
String p2s = players.get(p2);
players.removeat(p2);
results.add(//whatever string you use to combine p1 + p2);
}
if (players.count() > 0)
{
// add remaining players
}
}
答案 3 :(得分:0)
如果我理解正确,看起来你正试图生成一对玩家。我真的不明白你在循环中选择随机元素或退出条件的方法。
您遇到的一个问题是,当您在分组函数中运行循环时,您将删除元素,从而更改players.count()的值以及元素的位置。
即。如果阵列中有5个玩家,则表示他们是“A”,“B”,“C”,“D”,“E”。 在循环的第一次迭代中,i = 0,count = 5。索引0处的元素是“A”,并且我们随机选择“D”作为对。我们删除这两个,列表变为“B”,“C”,“E”。 在下一次迭代中,i = 1,索引1处的元素是“C”(不是“B”)。
建议:尝试更简单的算法,例如以下(伪代码):
while (list.count() > 1)
{
randomElementIndex = random(1, list.count())
firstElem = list[0]; // the first one will always be different, since we remove the old first one
secondElem = list[randomElementIndex]
print output
list.remove(firstElem)
list.remove(secondElem)
}
答案 4 :(得分:0)
非常感谢所有人!我纠正了我的代码错误。我的分组()方法:
private void Grouping(ref List<string> results)
{
Random r=new Random();
int index = 0;
for (int i = players.Count /2; i > 0;i--)
{
index++;
back:
int rand1 = r.Next(players.Count);
int rand2 = r.Next(players.Count);
if (rand1 == rand2)
{
// Random numbers are same :(
goto back; // I know - it'll be slowly :(
}
results.Add(index + ".: " + players[rand1] + " - " + players[rand2]);
players.Remove(players[rand1]);
players.Remove(players[rand2]);
}
}
答案 5 :(得分:0)
我不确定你的意图,但看起来你正试图拿一个球员名单,并创建两支随机选择相同数量球员的球队。
其他人已经回复了为什么你的代码不起作用。我只是想建议一种不同的方式来做我认为你想做的事情。鉴于你的球员名单:
//create a new list of players mixing your original list in random order
var shuffled = players.OrderBy(item => rnd.Next()).ToList();
int n = shuffled.Count() / 2; // there will be n elements per team
bool isOdd=(shuffled.Count() % 2 == 1); // is the number of players odd?
// the first team will have the first n players in the "shuffled" list
var firstTeam = shuffled.Take(n).ToList();
// the second team will have the next n players in the "shuffled" list
var secondTeam= shuffled.Skip(n).Take(n).ToList();
// if the players were in odd number take the last one
// who wasn't chosen in any team
// (that was me in school, that's why I'm a developer now!! :) )
string didNotPlay=(isOdd)? shuffled.Last() : null;