Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Determain and assign a play order based on player initiative within a list in C#

Posted on 2009-06-28
5
209 Views
Last Modified: 2012-05-07
I have a list of players. Each player has two properties, Initiative (int) and TurnOrder (int). In C# (.Net 2.0 for this please) I would like to assign each player in the list a unique integer for their TurnOrder (1 through X) based on which player's have the highest initiative (numerically speaking). I would want to randomly break ties between players with the same initiative value, which could be between two or more players (each player with a matching initiative would "roll the dice" to see what the final order would be between them).

The idea would be once I have assigned each player in the list a unique TurnOrder, I could then simply sort the list by TurnOrder:

PlayerList.Sort(delegate(Player p1, Player p2) { return p1.Initiative.CompareTo(p2.Initiative); });
0
Comment
Question by:ScottBlinn
  • 2
  • 2
5 Comments
 
LVL 5

Expert Comment

by:rendaduiyan
ID: 24733961
How about this one:
1) sorting the players by Initiative, high to low
2) use a loop to give each player a TurnOrder value by:
    2-1) if n nad n+1 has same Initiative, find the one bigger than n;
      a) randomly assign TurnOrder for n, n+1, ...
    2-2) assigne a TurnOrder .
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24734159
Here is an implementation:
    public class Player
    {
        public int TurnOrder;
        public int Initiative;
        
        public Player(int Initiative) { this.Initiative = Initiative; }
    }
 
    public partial class Form1 : Form
    {
 
        private Random R = new Random();
        List<Player> PlayerList = new List<Player>();
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            PlayerList.Add(new Player(5));
            PlayerList.Add(new Player(2));
            PlayerList.Add(new Player(1));
            PlayerList.Add(new Player(7));
            PlayerList.Add(new Player(5));
            PlayerList.Add(new Player(5));
            PlayerList.Add(new Player(4));
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            PlayerList.Sort(SortByInitiative);
            for (int i = 0; i < PlayerList.Count; i++)
            {
                PlayerList[i].TurnOrder = i + 1;
            }
            PlayerList.Sort(delegate(Player p1, Player p2) { return p1.TurnOrder.CompareTo(p2.TurnOrder); });
 
            foreach (Player p in PlayerList)
                Console.WriteLine(p.TurnOrder.ToString() + " --> " + p.Initiative.ToString());
        }
 
        private int SortByInitiative(Player p1, Player p2)
        {
            if (p1.Initiative != p2.Initiative)
                return p2.Initiative.CompareTo(p1.Initiative);
            else
                return R.Next() >= .5 ? 1 : -1;
        }
 
    }

Open in new window

0
 

Author Comment

by:ScottBlinn
ID: 24738141
Thank you guys.

Idol Mind: I implemented your solution and it almost does the trick. It seems that because it only takes in two players to compare at once, you end up with the same pattern/order between all players with the same Initiative value (so all players with an Initiative of 5 show up in the same order/are assigned the same TurnOrder value within the final list). What would I need to do to assign a random order between the players with the same Initiative each time the code is run?
0
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 400 total points
ID: 24738425
Apologies ScottBlinn...I used the wrong Random method.

Use this SortByInitiative() instead:

        private int SortByInitiative(Player p1, Player p2)
        {
            if (p1 == p2)
                return 0; // <-- need this because the internal Sort method compares an object against itself (and should return zero)
            else
            {
                if (p1.Initiative != p2.Initiative)
                    return p2.Initiative.CompareTo(p1.Initiative);
                else
                    return R.NextDouble() >= .5 ? 1 : -1;
            }
        }

Here is a modified version (I added a "name" field to make sure):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
 
        private Random R = new Random();
        List<Player> PlayerList = new List<Player>();
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            PlayerList.Add(new Player(5, "a"));
            PlayerList.Add(new Player(2, "b"));
            PlayerList.Add(new Player(1, "c"));
            PlayerList.Add(new Player(7, "d"));
            PlayerList.Add(new Player(5, "e"));
            PlayerList.Add(new Player(5, "f"));
            PlayerList.Add(new Player(4, "g"));
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            PlayerList.Sort(SortByInitiative);
            for (int i = 0; i < PlayerList.Count; i++)
            {
                PlayerList[i].TurnOrder = i + 1;
            }
            PlayerList.Sort(delegate(Player p1, Player p2) { return p1.TurnOrder.CompareTo(p2.TurnOrder); });
 
            foreach (Player p in PlayerList)
                Console.WriteLine(p.TurnOrder.ToString() + " --> " + p.Initiative.ToString() + ", " + p.Name);
        }
 
        private int SortByInitiative(Player p1, Player p2)
        {
            if (p1 == p2)
                return 0;
            else
            {
                if (p1.Initiative != p2.Initiative)
                    return p2.Initiative.CompareTo(p1.Initiative);
                else
                    return R.NextDouble() >= .5 ? 1 : -1;
            }
        }
 
    }
 
    public class Player
    {
        public string Name;
        public int TurnOrder;
        public int Initiative;
 
        public Player(int Initiative, string name) { this.Initiative = Initiative; this.Name = name; }
    }
 
}

Open in new window

0
 

Author Closing Comment

by:ScottBlinn
ID: 31597788
This did the trick. Thank you Idle Mind.
0

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction Although it is an old technology, serial ports are still being used by many hardware manufacturers. If you develop applications in C#, Microsoft .NET framework has SerialPort class to communicate with the serial ports.  I needed to…
This article introduced a TextBox that supports transparent background.   Introduction TextBox is the most widely used control component in GUI design. Most GUI controls do not support transparent background and more or less do not have the…
Established in 1997, Technology Architects has become one of the most reputable technology solutions companies in the country. TA have been providing businesses with cost effective state-of-the-art solutions and unparalleled service that is designed…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question