0

这是我的问题:我正在研究玩家分组(它将玩家分组)。我是通过一个 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 个玩家!)。

4

6 回答 6

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-th 元素存在,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列表中的另一半(在这种情况下,您根本不需要做任何fors),或者每次随机选择一名玩家。例如,像这样:

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)

简单地说:对象,就像a一样,默认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 声明被认为有害”以进一步阅读该主题。

于 2013-05-10T15:28:52.503 回答
2

对于循环,您的条件是i < players.Count() / 2 + 1. 这就是说,由于您在循环的每次迭代中删除了 2 个玩家,因此您更改了条件的值。

假设您从 7 名玩家开始。

  1. 迭代 1:i = 0,条件 = 4,总共处理 2 个玩家,剩余 5 个玩家
  2. 迭代 2:i = 1,条件 = 3,总共处理 4 个玩家,剩余 3 个玩家
  3. 迭代 3:i = 2,条件 = 2,条件不满足

最后,您有 2 个组和 3 个剩余玩家,但由于您这样做"Remained: " + players[0],您只显示剩余玩家中的 1 个。

于 2013-05-10T15:21:13.417 回答
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;
于 2013-05-10T15:52:55.050 回答
0

如果我理解正确,您似乎正在尝试生成成对的玩家。我不太了解您在循环中选择随机元素或退出条件的方法。

您面临的一个问题是,当您在 Grouping 函数中运行循环时,您正在删除元素,从而更改 player.count() 的值和元素的位置

IE。如果数组中有 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)
 }
于 2013-05-10T15:33:07.800 回答
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
        }
    }
于 2013-05-10T15:25:14.517 回答
0

真的谢谢大家!我纠正了我的代码错误。我的 Grouping() 方法:

    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]);
        }
    }
于 2013-05-10T15:36:07.213 回答