1

私はマルチプレイヤーゲームをコーディングしています。このゲームでは、各プレイヤーはグループ内のすべてのプレイヤーと1回だけプレイする必要があります。つまり、ジョー、メアリー、ピーターの3人のプレーヤーがいる場合、これらはジョーとメアリー、ジョーとピーター、メアリーとピーターの組み合わせになります。

ラウンド数を計算するコードは非常に簡単でした。ラウンド数はnに等しいので!/ r!*(n-r)!ここで、nはプレーヤーの数に等しく、rは2に等しくなります(ゲームは各ラウンドで2人のプレーヤーでプレイされているため)。

 public int factorial(int n)
 {
      if (n == 0)
          return 1;
      return n * factorial(n - 1);
 }

 public int calcNoOfRounds()
 {
      return factorial(noOfPlayers) / (factorial(2) * factorial(noOfPlayers -2));
 }

ただし、実際のプレーヤーの組み合わせを返す効率的な方法を作成することに固執しています。次のコードを試しました。動作しますが、手作業が多すぎて改善したいことがあります。このコードでは、p1とp2、p2とp3、p3とp4 ... p(n-1)とp(n)をペアリングしています。次に、3番目のプレーヤーから始めて、それらのプレーヤーを、前のプレーヤーを除く上記のすべてのプレーヤーと照合します。つまり、p3対p1、p4対p1、p4対p2、p5対p1、p5対p2、p5対p3などです。 。もっと良い方法でできると思いますか?

 public void calcPlayerCombinations()
 {
     List<string> playerNames = new List<string>();

     for (int i = 0; i < noOfPlayers; i++)
     {
          playerNames.Add(players[i].PlayerName);
     }

     for (int i = 0; i < noOfPlayers - 1; i++)
     {
          playerCombinations.Add(playerNames[i] + " " + playerNames[i + 1]);
     }

     for (int j = 3; j <= noOfPlayers; j++)
     {
          int counter = 1;

          do
          {
             playerCombinations.Add(playerNames[j -1] + " " + playerNames[counter -1]);
             counter++;

          } while (counter != (j - 1));
     }
 }

ゲームが実際にプレイされている場合、同じプレーヤーが6つの連続したゲームをどのようにプレイするのか、この方法は好きではありません。はい、ラウンドの組み合わせをランダムに選ぶことができましたが、それでも、将来の参照のためのより良い方法を知りたいです。

助けてくれてありがとう!

4

2 に答える 2

2

なぜあなたは各プレイヤーを(ペアリングの「最初の」として)彼らよりも遅い(「2番目の」として)各プレイヤーとペアリングしないのですか?例えば:

public static IEnumerable<string> PairPlayers(List<string> players)
{
    for (int i = 0; i < players.Count - 1; i++)
    {
        for (int j = i + 1; j < players.Count; j++)
        {
            yield return players[i] + " " + players[j];
        }
    }
}

(もちろん、必要に応じて、これも熱心に行うことができます。)

ただし、要件を誤って解釈した可能性があります。

于 2013-01-06T10:01:05.210 に答える
1

この例は、プレーヤーのリストをキューとして使用する方法を示しています。プレイヤーがプレイしたとき、彼らは後ろに置かれ、再び選ばれる可能性が最も低くなります。また、Jon Skeetがやったことを熱心に(なしでyield)行う方法も示しています。

using System;
using System.Collections.Generic;
using System.Linq;

namespace SOPlayersOrder
{
    class Program
    {
        /// <summary>
        /// Represents a match up between two players.
        /// It is tempting to use strings for everything, but don't do it,
        /// you'll only end up having to split those strings and you will
        /// not benefit from type safety.
        /// </summary>
        public class MatchUp
        {
            public string Player1 { get; set; }
            public string Player2 { get; set; }

            public override string ToString()
            {
                return string.Format("{0} vs {1}", Player1, Player2);
            }
        }

        public static IEnumerable<MatchUp> PairPlayers(List<string> players)
        {
            var results = new List<MatchUp>();
            for (int i = 0; i < players.Count - 1; i++)
            {
                for (int j = i + 1; j < players.Count; j++)
                {
                    var matchup = new MatchUp { Player1 = players[i], Player2 = players[j] };
                    //yield return matchup; //this is how Jon Skeet suggested, I am showing you "eager" evaluation
                    results.Add(matchup);
                }
            }
            return results;
        }

        public static IEnumerable<MatchUp> OrganiseGames(IEnumerable<string> players, IEnumerable<MatchUp> games)
        {
            var results = new List<MatchUp>();
            //a list that we will treat as a queue - most recently played at the back of the queue
            var playerStack = new List<string>(players);
            //a list that we can modify
            var gamesList = new List<MatchUp>(games);
            while (gamesList.Count > 0)
            {
                //find a game for the top player on the stack
                var player1 = playerStack.First();
                var player2 = playerStack.Skip(1).First();
                //the players are in the order of least recently played first
                MatchUp matchUp = FindFirstAvailableGame(playerStack, gamesList);
                //drop the players that just played to the back of the list
                playerStack.Remove(matchUp.Player1);
                playerStack.Remove(matchUp.Player2);
                playerStack.Add(matchUp.Player1);
                playerStack.Add(matchUp.Player2);
                //remove that pairing
                gamesList.Remove(matchUp);
                //yield return matchUp; //optional way of doing this
                results.Add(matchUp);
            }
            return results;
        }

        private static MatchUp FindFirstAvailableGame(List<string> players, List<MatchUp> gamesList)
        {            
            for (int i = 0; i < players.Count - 1; i++)
            {
                for (int j = i + 1; j < players.Count; j++)
                {
                    var game = gamesList.FirstOrDefault(g => g.Player1 == players[i] && g.Player2 == players[j] ||
                                                             g.Player2 == players[i] && g.Player1 == players[j]);
                    if (game != null) return game;
                }
            }
            throw new Exception("Didn't find a game");
        }

        static void Main(string[] args)
        {
            var players = new List<string>(new []{"A","B","C","D","E"});
            var allGames = new List<MatchUp>(PairPlayers(players));

            Console.WriteLine("Unorganised");

            foreach (var game in allGames)
            {
                Console.WriteLine(game);
            }

            Console.WriteLine("Organised");

            foreach (var game in OrganiseGames(players, allGames))
            {
                Console.WriteLine(game);
            }

            Console.ReadLine();
        }
    }
}
于 2013-01-06T12:31:20.940 に答える