I'm creating a bingo game where i have "Player" class with different variables in it. I want to ask the user how many players does he/she wants and depending of the input create as many instantiations as desired but i don't know how to do it. Here is my code:
int players = int.Parse(Console.ReadLine());
for(int i = 0; i <= players; i++)
{
Player player +1 = new Player((int[5, 3]), "Player " + i);
}
The expected result is to be able to instantiate a class as many times as a variable says.
Edit: This is the Player class:
public class Player
{
private int[,] playerTicket;
private int ticketId;
private string name;
public int[,] PlayerTicket
{
get { return playerTicket; }
set { playerTicket = value; }
}
public int TicketId
{
get { return ticketId; }
set { ticketId = value; }
}
public string Name
{
get { return Name; }
set { Name = value; }
}
public Player(int[,] playerTicket, int ticketId, string name)
{
this.playerTicket = PlayerTicket;
this.ticketId = TicketId;
this.name = Name;
}
}
int numberOfPlayers = Int32.Parse(Console.ReadLine());
//List which will contain each Player object
//Why use a list? A List is container which holds a reference to each
//Player object which is created in the loop,
//Reference to the List object
//https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netframework-4.7.2
List<Player> players = new List<Player>();
for(int i = 0; i <= numberOfPlayers; i++)
{
//Just instantiate a new Player object, make sure to pass in an integer for the second parameter of your constructor
Player player = new Player(new int[5, 3], i, "Player " + i);
//Add the Player to the List
players.Add(player);
}
Edit your Player class:
Either add a constructor which accepts the two parameters or make sure to pass in an integer for the second parameter of your constructor:
//You should be setting your class fields to the ones passed into the constructor
public Player(int[,] playerTicket, int ticketId, string name)
{
this.playerTicket = playerTicket;
this.ticketId = ticketId;
this.name = name;
}
I think you should use List and .Add(T) method. e.g.:
int players = int.Parse(Console.ReadLine());
List<Player> activePlayers = new List<Player>();
for(int i = 0; i <= players; i++)
{
activePlayers.Add(new Player((int[5, 3]), "Player " + i));
}
Related
I am currently making an application which tracks information on players and monsters for a tabletop game.
Currently I've got classes for "Monsters". This class contains information such as its name, maxHP, speed, attacks etc. I've managed to make a Database which contains the default values for each type of monster. What I currently need to do is make it possible to change things such as name (Monster > Monster 1, Monster 2 etc), change its HP, and some other things.
I understand that I need to make a copy of such, but I am uncertain on how to do this.
What I currently tried is the following:
public class DatabaseService
{
public List<Player> Players { get; set; }
public List<Monster> AllMonsters { get; set; }
public List<Monster> ActiveMonsters = new List<Monster>();
public bool RollForHP = false;
//Main Database Service
public DatabaseService()
{
Players = GetPlayers();
AllMonsters = GetAllMonsters();
}
public void DoStuff()
{
AddMonsterByName("Goblin", 2);
AddMonsterByName("Adult White Dragon", 1);
AddMonsterByName("Duergar", 4);
foreach (Monster monster in ActiveMonsters) { Console.WriteLine(monster.Name); }
}
//Converts the .json list with all players to Classes, which are then stored in the list "Players" if the "IsInParty" is true
private List<Player> GetPlayers()
{
var path = #"C:\Users\MyName\source\repos\DndAdvancedInitiativeTracker\Logic\Database\Players.json";
var json = File.ReadAllText(path);
var players = JsonConvert.DeserializeObject<List<Player>>(json);
List<Player> inPartyPlayers = new List<Player>();
foreach (var player in players)
{
if (player.IsInParty == true) { inPartyPlayers.Add(player); }
}
return inPartyPlayers;
}
//Converts the .json list with all monsters to Classes, which are then stored in the list "AllMonsters"
private List<Monster> GetAllMonsters()
{
var path = #"C:\Users\MyName\source\repos\DndAdvancedInitiativeTracker\Logic\Database\Monsters.json";
var json = File.ReadAllText(path);
var monsters = JsonConvert.DeserializeObject<List<Monster>>(json);
return monsters;
}
//Adds a given monster to the "ActiveMonsters" list
public void AddMonsterByName(string monsterName, int amountOfMonsters)
{
for (int i = 0; i < amountOfMonsters; i++)
{
List<Monster> DatabaseCopy = AllMonsters.Clone();
DatabaseCopy = AllMonsters;
Monster monster = DatabaseCopy.Find(x => x.Name == monsterName);
Console.WriteLine(monster.Name);
var number = CheckIfNameExistsInList(monsterName);
monster.Name = monsterName + " " + (number + i).ToString();
ActiveMonsters.Add(monster);
}
}
private int CheckIfNameExistsInList(string monsterName)
{
var counter = 1;
foreach (var monster in ActiveMonsters)
{
if (monster.Name.Contains(monsterName))
{
counter += 1;
}
}
return counter;
}
}
In the "DoStuff" Method, I try to add 2 goblins, then a dragon, then a goblin again. The first goblin is named to "Goblin 1" correctly, but the second loop fails, because the AllMonsters' name for goblins is now "Goblin 1" because of the reference type, therefore, the second "Goblin" search in AllMonsters is never found, and returns null.
I'm not sure why you're copying your database (and doing so for every iteration of a for loop which is quite wasteful), but your current check code CheckIfNameExistsInList will always return 1 even if there are no matches in the list.
You can simplify your AddMonstersByName (and use a simple check for previous monster entries) as follows:
public void AddMonstersByName(string name, uint number = 1)
{
var count = AllMonsters.Count(x => x.Name.Contains(name));
for (var i = 1; i <= number; i++)
{
var num = count + i;
AllMonsters.Add(new Monster(){Name= name+num.ToString()});
}
}
This was tested in a simple Console App:
var dataService = new DataService();
dataService.AddMonstersByName("Goblin", 2);
dataService.AddMonstersByName("Dragon", 2);
dataService.AddMonstersByName("Goblin", 2);
foreach (var monster in dataService.AllMonsters)
{
Console.WriteLine($"{monster.Name}");
}
where
public class DataService
{
public List<Monster> AllMonsters = new List<Monster>();
public void AddMonstersByName(string name, uint number = 1)
{
var count = AllMonsters.Count(x => x.Name.Contains(name));
for (var i = 1; i <= number; i++)
{
var num = count + i;
AllMonsters.Add(new Monster(){Name= name+num.ToString()});
}
}
}
public class Monster
{
public string Name { get; set; }
}
I am able to sort an array using a single datatype such as string, but how can I sort other arrays with different datatypes and follow the ascending order that same string datatype?
As you can see I have one Array.Sort method near the bottom of my code with the playerName and playerPosition arrays being sorted. I'd like to add the int[] arrays atBats and hits. Then I need to add the batting average also which is a float value.
using System;
using static System.Console;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//My Baseball application named BatStat
namespace BatStat
{
class Program
{
static void Main()
{
//My declared variables that hold the user input in memory
string teamName;
string[] playerName = new string[3];
string[] playerPosition = new string[3];
int[] atBats = new int[3];
int[] hits = new int[3];
//Begin program by requesting user to enter team name value
WriteLine("Welcome to Bat Stat, enter team name");
teamName = Console.ReadLine();
//Traverse all arrays and accumalate values from user input
for (int i = 0; i < playerName.Length; i++)
{
WriteLine("Enter players name");
playerName[i] = ReadLine();
WriteLine("Enter Players Position");
playerPosition[i] = ReadLine();
WriteLine("Enter Players at bats");
atBats[i] = Convert.ToInt32(ReadLine());
WriteLine("Enter Players hits");
hits[i] = Convert.ToInt32(ReadLine());
}
//Display top row menu for Bat Stat table
WriteLine("{0, -10}{1, -10}{2, -5}{3, -5}{4, -5}{5, -5}", "Team", "Player", "Pos", "AB", "H", "BA");
//for loop to traverse the arrays and display user input data in tabular format
for (int x = 0; x < playerName.Length; ++x)
{
Array.Sort(playerName, playerPosition);
float playerBA = (float)hits[x] / atBats[x];
WriteLine("{0, -10}{1, -10}{2, -5}{3, -5}{4, -5}{5, -4}", teamName, playerName[x], playerPosition[x], atBats[x].ToString("d"), hits[x].ToString("d"), playerBA.ToString("F3"));
}
//Display the team batting average at bottom in a single row
float teamBA = (float)hits.Sum() / atBats.Sum();
WriteLine("The batting average for the {0} is {1}", teamName, teamBA.ToString("F3"));
}
}
}
Since you're coding in C#, an Object-Oriented language, you should consider using objects.
You could declare your own class for the Player, holding the information you enter each time.
Then, when you sort by the player name and position, all the fields are sorted because you are sorting all players between them as a whole, not a specific field.
You could define your class as:
public class Player
{
public string Name { get; set; }
public string Position { get; set; }
public int AtBats { get; set; }
public int Hits { get; set; }
}
You can get rid of the multiple arrays, and use:
Player[] players = new Player[3];
And in your loop, you can create the players like this:
for (int i = 0; i < players.Length; i++)
{
var player = new Player();
WriteLine("Enter players name");
player.Name = ReadLine();
WriteLine("Enter Players Position");
player.Position = ReadLine();
WriteLine("Enter Players at bats");
player.AtBats = Convert.ToInt32(ReadLine());
WriteLine("Enter Players hits");
player.Hits = Convert.ToInt32(ReadLine());
players[i] = player;
}
Hope that clears things up a bit and gets you started.
As for the comparison itself, you have multiple ways to do that.
If you want to use Array instead of List, the most straightforward way would be to have Player implement the IComparable interface. That way each Player object will know how to compare itself with another player.
If I understand correctly, you want to sort them first by Name, and then by Position? Then you can modify the Player class to be:
public class Player : IComparable
{
public string Name { get; set; }
public string Position { get; set; }
public int AtBats { get; set; }
public int Hits { get; set; }
public int CompareTo(object obj)
{
if (obj == null) return 1;
var otherPlayer = obj as Player;
int result = this.Name.CompareTo(otherPlayer.Name);
if (result == 0)
{
result = this.Position.CompareTo(otherPlayer.Position);
}
return result;
}
}
Then, to sort the players will be a simple call: Array.Sort(players); and the second loop of your program becomes:
//for loop to traverse the arrays and display user input data in tabular format
Array.Sort(players);
for (int x = 0; x < players.Length; x++)
{
var player = players[i];
float playerBA = (float)player.Hits / player.AtBats;
WriteLine("{0, -10}{1, -10}{2, -5}{3, -5}{4, -5}{5, -4}", teamName, player.Name, player.Position, player.AtBats, player.Hits, playerBA.ToString("F3"));
}
Just a note: you were sorting the array 3 times, but you only needed it once. Here that you have 3 elements it doesn't make a difference, but if you had much more elements it would cost you.
You also don't need the .ToString("d"), as it's the default for an integer, and the conversion .ToString() is happening automatically when you call WriteLine.
I'm currently learning C# and have assigned myself to make a program to help me understand OOP which essentially takes in values and assigns them to variables. The program takes in information about football players; the name, last name, position, and shirt number.
I'm trying to use getters and setters to ensure that a shirt number can only be used once. So i've set a list up that stores all the shirt numbers that are being used. The problem i'm having is: the list keeps getting reset and I have no idea why. After one value has been added, by the time the next one gets added, the list is empty again. This makes my if statement in the setter not work as the list does not contain any values.
Im sure this is a rookie error and should be shouting at me, but Im new to this language and am not really sure on all the ins and outs of it.
I haven't really tried much, and I cant find anything online as this seems to be a specific error that im having. I don't know enough about the language to properly troubleshoot this, and what I do know about the language tells me this should work.
namespace RandomObject
{
class Program
{
static void Main(string[] args)
{
Player player1 = new Player("Lucas", "Torreira", "Defensive Midfielder", 11);
Player player2 = new Player("Alexandre", "Lacazette", "Striker", 9);
Player player3 = new Player("Pierre-Emerick", "Aubameyang", "Striker", 14);
Player player4 = new Player();
Console.Write("Please enter new players first name: ");
player4.Name = Console.ReadLine();
Console.Write("Please enter new players last name: ");
player4.LastName = Console.ReadLine();
Console.Write("Please enter new players position: ");
player4.Position = Console.ReadLine();
Console.Write("Please enter new players shirt number: ");
player4.ShirtNo = Convert.ToInt32(Console.ReadLine());
player1.PrintPlayerInfo();
player2.PrintPlayerInfo();
player3.PrintPlayerInfo();
player4.PrintPlayerInfo();
Console.ReadKey();
}
}
}
class Player
{
private List<int> shirtNumbers = new List<int>();
private int _shirtNo;
public void PrintPlayerInfo() //<access modifier> <return type> <method name>(parameters)
{
Console.WriteLine("Player: {0} {1}", Name, LastName);
Console.WriteLine("Position: {0}", Position);
Console.WriteLine("Shirt No.: {0}\n", _shirtNo);
}
public Player()
{
Name = string.Empty;
LastName = string.Empty;
Position = string.Empty;
_shirtNo = 0;
}
public Player(string name, string lastName, string position, int shirtNo)
{
Name = name;
LastName = lastName;
Position = position;
_shirtNo = shirtNo;
AddToList(_shirtNo);
}
private void AddToList(int newNumber)
{
shirtNumbers.Add(newNumber);
Console.WriteLine(shirtNumbers[0]);
}
public string Name { get; set; }
public string LastName { get; set; }
public string Position { get; set; }
public int ShirtNo
{
get { return _shirtNo; }
set
{
if (shirtNumbers.Contains(value) == false)
{
_shirtNo = value;
}
else
{
_shirtNo = 0;
}
}
}
}
}
In my main method I declare 3 instances of the class, with shirt numbers 11, 9, and 14. So when it comes to inputting one into the console using readlines and such, if I were to enter 14, the shirt number should be set to 0. However if I enter 10, it should be set to 10.
The Player class now does two things: it holds information about one player, and it contains a list of shirt numbers for all players. One of those two doesn't belong there.
The private List<int> shirtNumbers = new List<int>(); is an instance variable, meaning each player has its own list of shirt numbers. So if you assign a shirt to player X, the list in player Y's instance has no notion of this, enabling you to assign shirt N to both player X and Y.
Sure, you could fix this by declaring the list to be static, but that's just bad design; the Player class needs to know about one player, not all of them.
So instead keep this shirt number check outside your player class. Declare the shirt list before the player list, and modify your code accordingly.
You should have a static list of numbers. Otherwise every player has its own list of valid numbers.
class Player
{
private static List<int> shirtNumbers = new List<int>();
private int _shirtNo;
}
This way you have a single list that all your player share.
You are using the AddToList method on your constructor to add the shirtlist number which is correctly but when you are defining ShirtNo setter you are not adding to the list
Fix :
public int ShirtNo
{
get { return _shirtNo; }
set
{
if (shirtNumbers.Contains(value) == false)
{
_shirtNo = value;
AddToList(value)
}
else
{
_shirtNo = 0;
}
}
}
i copied your code to debug in my local machine. Few changes that needs to be done to your
1.The shirtNumbers list has to be declared static , if not for every instance of player class will have List (private static List shirtNumbers = new List();)
You are assigning values to the variable directly and not to the property in both the constructors.(getter setter is called property in C#).Hence the if condition inside setter wont be called.
class Player
{
private static List<int> shirtNumbers = new List<int>();
private int _shirtNo;
public void PrintPlayerInfo()
{
Console.WriteLine("Player: {0} {1}", Name, LastName);
Console.WriteLine("Position: {0}", Position);
Console.WriteLine("Shirt No.: {0}\n", _shirtNo);
}
public Player()
{
Name = string.Empty;
LastName = string.Empty;
Position = string.Empty;
ShirtNo = 0;
}
public Player(string name, string lastName, string position, int shirtNo)
{
Name = name;
LastName = lastName;
Position = position;
ShirtNo = shirtNo;
AddToList(_shirtNo);
}
private void AddToList(int newNumber)
{
shirtNumbers.Add(newNumber);
Console.WriteLine(shirtNumbers[0]);
}
public string Name { get; set; }
public string LastName { get; set; }
public string Position { get; set; }
public int ShirtNo
{
get { return _shirtNo; }
set
{
if (shirtNumbers.Contains(value) == false)
{
_shirtNo = value;
}
else
{
_shirtNo = 0;
}
}
}
}
Private Player[] players = new Player[2];
private int currentPlayerIndex = 0;
public Game(Form1 form)
{
for (int i = 0; i < players.Length; i++) {
players[i] = (string)"Player"; }
I keep getting an error saying it cannont convert string to Player type...
Below is the player class, which also sets the property for Name...
class Player
{
private string name = "";
public Player(string name)
{
name = "Player";
}
public string Name {
get { return name; }
set { name = value; }
}
players is an array of Player objects:
private Player[] players = new Player[2];
You're trying to put a string in the array.
players[i] = (string)"Player";
That does not work, you can only put an instance of Player in the array
players[i] = new Player("Player1");
Because your code doesn't provide for an implicit cast from string to Player. You need something like this:
public static implicit operator Player(string str)
{
return new Player(str);
}
Of course then you will need a Player constructor that takes a string argument.
Edit: Changed explicit to implicit. An implicit operator will cause the code to compile.
I can't sort my list entirely. It's int based sorting and I used CompareTo() form IComparable, custom Comparer delegate, and anonymous delegate. None of this work for me.
here is the code:
[TestMethod]
public void SortingPlayersFirst()
{
//arrange
Player player = new Player("neosb");
Player player2 = new Player("simone");
Player player3 = new Player("Alice");
player.Score = 5;
player2.Score = 2;
player3.Score = 10;
Players players = new Players();
players.Add(player);
players.Add(player2);
players.Add(player3);
//I have tried this one
players.Sort(Player.ComparePlayersByScore);
//and this one
players.Sort()
// and this one
IComparer<Player> comp = Comparer<Player>.Create(
(p1, p2) => p1.Score.CompareTo(p2.Score));
players.Sort(comp);
//this one fails the test
Assert.AreEqual(player3, players[0], "Highest score is not first");
//however this one passes the test
Assert.AreNotEqual(player2, players[2], "Lowest score is not last");
}
public class Players : List<Player>
{
}
public class Player : IComparable<Player>, IEquatable<Player>
{
public string Name { get; set; }
public int Score { get; set; }
public Player(string name)
{
Name = name;
Score = 0;
}
public int CompareTo(Player other)
{
return Score.CompareTo(other.Score);
}
public static int ComparePlayersByScore(Player player1, Player player2)
{
if (player1.Score > player2.Score)
return 1;
else if (player1.Score < player2.Score)
return -1;
else
return 0;
}
}
what do I have to do to sort this list and pass the unit test and why it's partly sorted.
You're sorting it in ascending order, rather than descending... but your test requires that the highest scoring player is first. This should work:
// Use the overload taking a Comparer<Player> delegate for simplicity
players.Sort((p1, p2) => p2.Score.CompareTo(p1.Score));
Note the reversal of the use of p1 and p2 in the lambda expression - that's how you reverse the comparison.