Changing the player class every turn in a loop - c#

I need some kind of class or structure to hold data for 4 players in a simple game. How can I change the player class in every turn during the loop?
I mean something similar to this, where in every turn of a loop some instructions are chaning the data in the class of each player. Is there any effortless way to do this instead of creating many ifs?
internal class Program
{
private static void Main(string[] args)
{
Player player1 = new Player();
Player player2 = new Player();
Player player3 = new Player();
Player player4 = new Player();
int playerTurn = 1;
while(true)
{
//some instructions to change the data for example
//player(playerTurn).x = 1
}
}
}
class Player
{
public int x = 0;
public int y = 0;
}

Whenever you have numbered variables like this:
Player player1 = new Player();
Player player2 = new Player();
Player player3 = new Player();
Player player4 = new Player();
What you probably want is a collection. For example:
var players = new List<Player>
{
new Player(),
new Player(),
new Player(),
new Player()
};
Then you can loop over the list, change specific elements therein, etc.
In your specific case, it looks like you want to access the specific Player by an index:
//player(playerTurn).x = 1
You can do this with the list index:
players[playerTurn].x = 1;
Though if the list is ever sorted, that index is gone. In this case you might instead use a Dictionary<int, Player>. For example:
var players = new Dictionary<int, Player>
{
{ 1, new Player() },
{ 2, new Player() },
{ 3, new Player() },
{ 4, new Player() }
}
In this case each Player object is always and consistently uniquely identified by that integer value. And the usage is the same:
players[playerTurn].x = 1;
Alternatively, you might create a unique identifier on the Player itself. For example, suppose it has an ID property that you can set:
var players = new List<Player>
{
new Player { ID = 1 },
new Player { ID = 2 },
new Player { ID = 3 },
new Player { ID = 4 }
};
In this case you can still use the more generically versatile List<Player> structure, and query it to find the specific Player:
players.Single(p => p.ID == playerTurn).x = 1;
There are other collection types you can use. You could even take it a step further and create a custom PlayerList object which internally contains a collection, the current "turn", and other information about the list of players. But overall the point is that collection types are useful when you have a series of objects.

Related

recursive list processing seems to be changing the list at higher levels

I am trying to write a competition pairing algorithm to avoid playing the same player twice
so we have a list of players
we take the first player, then the first player they have not played
remove that from the list
send the remaining list to be processed again
if the last pair cant play, the recursion should unroll and the first player get matched against the next player they have not played, and away we go again .
What seems to be happening is that the original list (players) is changing size along with the truncated list that is sent out through the recursive call.
So when the reucrsion unwinds, the list players is down to 2 items rather than the expected 4 or 6. It is like the list is being passed by reference rather than by value.
any thoughts?
edit***
not so much the list being passed by reference, but the list (players) being changed each time the procedure is called, so we end up with the first iteration of the procedure (which should have a list of 6 players) using a list of 2 players when the recursion unwinds ***
Ive shoved the whole code in here (along with the test list set up code)
using System;
using System.Collections.Generic;
using System.Runtime.ConstrainedExecution;
namespace CPair
{
class Program
{
static void Main(string[] args)
{
//create players
List<int> alist = new List<int>() { 2 };
var a = new Player(1, "a", "wk", alist, 10);
List<int> blist = new List<int>() { 1 };
var b = new Player(2, "b", "wa", blist, 9);
List<int> clist = new List<int>() { };
var c = new Player(3, "c", "bc", clist, 8);
List<int> dlist = new List<int>() { };
var d = new Player(4, "d", "wk", dlist, 7);
List<int> elist = new List<int>() { };
var e = new Player(5, "e", "bc", elist, 5);
List<int> flist = new List<int>() { };
var f = new Player(6, "f", "ab", flist, 3);
List<Player> PlayList = new List<Player>();
PlayList.Add(a);
PlayList.Add(b);
PlayList.Add(c);
PlayList.Add(d);
PlayList.Add(e);
PlayList.Add(f);
PlayList.Sort((p, q) => p.Points.CompareTo(q.Points));
foreach (Player p in PlayList)
{
Console.WriteLine(p.PlayerName);
}
List<Player> paired = new List<Player>();
paired = pairing(PlayList);
foreach (Player r in paired)
{
Console.WriteLine(r.PlayerName);
}
}
static List<Player> pairing(List<Player> players)
{
List<Player> pairingList = new List<Player>();
int n = 1;
bool failed = true;
List<Player> returnedList = new List<Player>();
while ((failed) && n <= players.Count - 1)
{
if (PairIsGood(players[0], players[n], 0))
{
Player p1 = new Player();
p1 = players[0];
Player p2 = new Player();
p2 = players[n];
if (players.Count <= 2)
{
returnedList.Add(p1);
returnedList.Add(p2);
failed = false;
}
else
{
List<Player> nextPairs = new List<Player>();
nextPairs = players;
nextPairs.RemoveAt(0);
nextPairs.RemoveAt(n-1);
returnedList = pairing(nextPairs);
Console.WriteLine(players.Count.ToString());
Console.WriteLine(nextPairs.Count.ToString());
if (returnedList.Count == 0)
{
failed = true;
n++;
}
else
{
returnedList.Add(p1);
returnedList.Add(p2);
failed = false;
}
}
}
else
{
n++;
}
}
return returnedList;
}
static bool PairIsGood(Player p1, Player p2, int round)
{
bool good = true;
foreach (int op in p1.OpList)
{
if (op == p2.PlayerID)
{
good = false;
}
}
return good;
}
}
}
Here is your problem:
List<Player> nextPairs = new List<Player>();
nextPairs = players;
nextPairs.RemoveAt(0);
nextPairs.RemoveAt(n-1);
You create a new List<Player> and assign it to nextPairs
You then effectively throw that new list away, and instead assign nextPairs to players.
nextPairs and players are now both referencing the same list, and removing from nextPairs will remove from players too, since they're the same list.
Take a look at Array.Copy() if you want a true independent copy.
As an aside, I see you are doing the same redundant creation pattern here:
Player p1 = new Player();
p1 = players[0];
Player p2 = new Player();
p2 = players[n];
This should simply be
Player p1 = players[0];
Player p2 = players[n];
I suspect you need to read up a bit on objects and references and how they work.

Instantiate Class Within Method With Greater Scope

So I'm making a little ESL bomb game, but I want to make a more efficient set of code. As of now I have this:
public partial class Form2 : Form
{
string pinNumber;
Bomb bombA = new Bomb("A", 1, "A", 1, "A", "B", "C", "D", "Sentence");
int progress;
int wireChoice;
string ansChoice;
int timer = 600;
public Form2()
{
InitializeComponent();
timer1.Start();
Random _bombType = new Random();
int bombType = 1;
if (bombType == 1)
{
genBomb();
}
else
{
}
}
public void genBomb()
{
bombA.Pin = 6259;
bombA.Serial = "G6P4LN";
bombA.Wire = 2;
bombA.Code = "to rearrange";
bombA.Choice1 = "rearrange";
bombA.Choice2 = "to rearrange";
bombA.Choice3 = "rearranged";
bombA.Choice4 = "rearranging";
bombA.Question = "I purchased so many new outfits that I need ______ my closet.";
uiUpdate();
}
public void uiUpdate()
{
serialLbl.Text = bombA.Serial;
puzzleLbl.Text = bombA.Question;
ans1.Text = bombA.Choice1;
ans2.Text = bombA.Choice2;
ans3.Text = bombA.Choice3;
ans4.Text = bombA.Choice4;
timerLbl.Text = timer.ToString();
}
I have a separate public class file for the Bomb class with public variables. However, I have to instantiate bombA in the Form2 field and redefine its variable values in the method genBomb().
I want to create bombA within that method instead, but doing so causes other methods that refer to bombA.Variable to not function because they no longer exist in that context.
How can I accomplish this?
Scope is defined when the variable or member is declared, not necessarily when you create an object. You can declare the field without giving it a value:
Bomb bombA;
and initialize it in genBomb:
public void genBomb()
{
bombA = new Bomb("A", 1, "A", 1, "A", "B", "C", "D", "Sentence");
bombA.Pin = 6259;
....
Be aware that you need to check for a null value in uiUpdate since there's nothing preventing it from being called prior to genBomb.

C# - Making classes in a for loop

I have this class:
class player
{
public string name;
public int rating;
{
The number of these classes made is dependant on a user specified amount numberOfPlayers. So my first reaction was to create a for loop to do this. i.e:
for (int i = 0; i< numberOfPlayers; i++)
{
//create class here
}
However, I need to be able to access these classes individually when later using their individual data - almost like they've been put into an array. How would I go about making a number of classes of which can be accessed individually?
You use a List<T> variable where T is your class
List<Player> players = new List<Player>();
for (int i = 0; i< numberOfPlayers; i++)
{
Player p = new Player();
p.Name = GetName();
p.rating = GetRating();
players.Add(p);
}
Of course GetName and GetRating should be substituded by your code that retrieves these informations and add them to the single player.
Getting data out of a List<T> is in no way very different from reading from an array
if(players.Count > 0)
{
Player pAtIndex0 = players[0];
....
}
You can read more info at MSDN page on List class
List<Player> players = new List<Player>();
for (int i = 0; i< numberOfPlayers; i++)
{
Player p = new Player();
p.Name = "";
p.rating = "";
players.Add(p);
}
to access it individually you can use...
foreach(Player p in players )
{
}
You've got the right idea. Make a player class that can be re-used over and over, a loop in which to create these players and now we need to store them somewhere. This will probably divide opinion if you get more than one answer but I like dictionaries for this kind of thing as you can access values by unique keys.
// Your player class. I've added 'id' so we can identify them by this later.
class Player
{
public int id;
public string name;
public int rating;
}
// The dictionary. They work like this dictionary<key, value> where key is a unique identifier used to access the stored value.
// Useful since you wanted array type accessibility
// So in our case int represents the player ID, the value is the player themselves
Dictionary<int, Player> players = new Dictionary<int, Player>();
// Create your players
for (int i = 0; i < numberOfPlayers; i++)
{
Player p = new Player()
{
id = i + 1,
name = $"Player{i}",
rating = 5
};
// Add them to dictionary
players.Add(p.id, p);
}
// Now you can access them by the ID:
if (players.ContainsKey(1))
{
Console.WriteLine(players[1].name);
}
The dictionary key can be anything you like so long as it's unique. You could identify them by name if you like.

How to print the position of a gameObject in a list?

I have a list and text:
List<GameObject> EnteredPlayers = new List<GameObject>();
public Text finishText;
When the player enters the trigger, they will be added to the list:
if (col.gameObject.tag == "finish") {
EnteredPlayers.Add(player);
finishText.text = //player's position in list here
}
I would like to print the player's position in the list. For example, if their position is [0] then the text would say 1st place.
Any idea how I can do this?
// Add the player
EnteredPlayers.Add(player);
// Get the position
int position = EnteredPlayer.Count
// Create a dictionary with the position names
// Put this dictionary outside of your method managing the games
Dictionary<string, string> positionNames = new Dictionary<string, string>(){
{ "1", "First" },
{ "2", "Second" },
{ "3", "Third" }
};
// Assign the label text
finishText.Text = positionNames[position.ToString()];

Remove Duplicate values from a list while keeping track of the removed items' indexes

I have two lists. One is a string list of players and the other one is an int list that represents the number of mentions for each player. (for each element in the players list, there is one in the number of mentions list). There are duplicate players in the list of players, for example there are 3 players "player 1"s with 5,10,13 number of mentions in the NumofMentions list. I want to eliminate duplicate values but keep the sum of the number of mentions. For the aforementioned example, I want to have one "player1" with the number of mentions 28.
What is the easiest way to do this?
It sounds like your player name and values go hand in hand, perhaps they shouldn't belong in 2 separate lists but a list of class player. You haven't shown us any code so we have to work with our own interpretations of your problem, but here's how I would approach it...
public class Player
{
public string name { get; set; }
public int value { get; set; }
}
public void MyTest()
{
var myList = new List<Player>
{
new Player { name = "Player 1", value = 5 },
new Player { name = "Player 1", value = 10 },
new Player { name = "Player 1", value = 13 },
new Player { name = "Player 2", value = 3 },
new Player { name = "Player 2", value = 4 },
new Player { name = "Player 2", value = 6 }
};
var mySummedList = myList.GroupBy(x => x.name).Select(x => new Player { name = x.Key, value = x.Sum(y => y.value)});
foreach(var val in mySummedList)
{
Debug.WriteLine(String.Format("{0}: {1}", val.name, val.value));
}
}
//Output:
//Player 1: 28
//Player 2: 13
Don't use a List; use a Dictionary
var mentions = new Dictionary<string, int>();
mentions["PlayerName"] = 5;
var currentCount = mentions["PlayerName"];
mentions["PlayerName"] = currentCount + amountToAdd;
You can still get all the players from the Dictionary's Keys property
foreach(var player in mentions.Keys)
{
//do some work
}
Given you have four lists coming in, do the following for each list:
foreach(var playerCounter in googleQueryList)
{
if(mentions.ContainsKey(playerCounter.Name))
{
//Update the player here
var currentCount = mentions[player.Name];
mentions[player.Name] = currentCount + playerCounter.NumOfMentions;
}
else
{
//Add the player here
mentions[player.Name] = playerCounter.NumOfMentions;
}
}

Categories