This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have been instructed to write a program that collects a bowling score (integer) and a name from the user, separated by a space, and sorts each of them into an array using the Split method. The output has to be formatted to find the average score and output it to the console, as well as sort the scores (and names) in order of lowest to highest.
I have been able to do everything except find a way to sort the names with their corresponding scores.
Here is what I have so far. To clarify, I need help writing a sorting algorithm for my array of names.
using System;
class Program
{
//class variables
const int MAX = 10;
static void Main()
{
//declare array
int[] score = new int[MAX];
string[] name = new string[MAX];
//program prologue
Console.WriteLine("****************Bowling Project****************");
Console.WriteLine("Please enter a name and a score for each player. For example 'John 145'.\nHit enter when you are done.");
//for loop to get input
for (int i=0; i<MAX; i++)
{
Console.Write("Enter a name and a score for player #{0}: ", (i + 1));
string input = Console.ReadLine();
if (input == "")
{
break; // if nothing is entered, it will break the loop
}
//split the user data into 2 arrays (integer and string)
string[] separateInput = input.Split();
name[i] = separateInput[0];
score[i] = int.Parse(separateInput[1]);
}
Console.WriteLine("\n****************Input Complete****************");
//calculate the average score and send to the console
CalculateScores(score);
Console.WriteLine("The scores for the game are:");
//sort the scores
BubbleSort(score);
Console.ReadLine();
}//End Main()
//CalculateScores Method
//Calculates the average score of an array of integers
//Takes an array of integers as parameters
//Returns void
//Outputs the average to the console
static void CalculateScores(int[] score)
{
int sum = 0;
int average = 0;
for (int i = 0; i < score.Length; i++)
{
sum += score[i];
average = sum / score.Length;
}
Console.WriteLine("The average score was {0}", average);
}//End calculateScores
//Swap method
//Takes 2 integers as parameters
//Switches the value of 2 integers (a and b)
static void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
//BubbleSort method
//Sorts an array of integers
//Takes an array of integers as a parameter
//Returns void
//Outputs to the console
static void BubbleSort(int[] score)
{
for (int j = 0; j < score.Length -1; j++)
{
for (int i = 0; i < score.Length - 1; i++)
{
if (score[i] > score[i + 1])
{
Swap(ref score[i], ref score[i + 1]);
}
}
}
foreach (int a in score)
Console.WriteLine("{0}", a);
Console.ReadLine();
}
}//End class Program
Assuming that names[] corresponds 1 to 1 with score[]:
Just take your BubbleSort method, and pass both names[] and score[] into it
Then, you whenever you do an operation on score[] do it on names[] too.
something like this
static void BubbleSort(int[] score, string[] names)
{
for (int j = 0; j < score.Length -1; j++)
{
for (int i = 0; i < score.Length - 1; i++)
{
if (score[i] > score[i + 1])
{
Swap(ref score[i], ref score[i + 1]);
Swap(ref names[i], ref names[i + 1]);
}
}
}
foreach (int a in score)
Console.WriteLine("{0}", a);
Console.ReadLine();
}
you might have to make a swap method for strings
static void Swap(ref string a, ref string b)
{
string temp = a;
a = b;
b = temp;
}
you should make a separate class that will store a player with its score array.
then make an array of players that you can sort based upon their name
EDIT: I've updated my answer to be an implemented player class that builds upon your original code. If this is for a university project this may get seen by plagiarism checkers so I'd be wary to use it.
public class Player
{
public Player(){}
public Player(string name, int score)
{
m_name = name;
m_score = score;
}
public Player(Player p)
{
m_name = p.Name;
m_score = p.Score;
}
public string Name
{
get{return m_name;}
}
public int Score
{
get{return m_score;}
}
private string m_name
private int m_score
}
Player[] players = new Player[MAX];
static void BubbleSort(Player[] players)
{
for (int j = 0; j < players.Length -1; j++)
{
for (int i = 0; i < players.Length - 1; i++)
{
if (players[i].Score > players[i + 1].Score)
{
Swap(ref players[i], ref players[i + 1]);
}
}
}
foreach (Player a in players)
Console.WriteLine("{0}", a.Score);
Console.ReadLine();
}
static void Swap(ref Player a, ref Player b)
{
Player temp = a;
a = b;
b = temp;
}
Instead of using two collections of loosely associated values, use a single collection of a class:
public class BowlingScore {
public string Name { get; private set; }
public int Score { get; private set; }
public BowlingScore(string name, int score) {
Name = name;
Score = score;
}
}
Use a list rather than an array for the collection:
List<BowlingScore> scores = new List<BowlingScore>();
In your loop you can create instances of the class and add to the list:
BowlingScore item = new BowlingScore(separateInput[0], int.Parse(separateInput[1]);
scores.Add(item);
By using a list instead of an array, it will only contain the items that you actually add. Your current code would need another variable to keep track of how many items in the array was actually used, so that you don't include the ones left empty at the end.
Now, as you have the name and score as a single unit, you can sort the list using the same approach as you used for sorting an array, only you compare a property of the objects. As you swap the whole objects, the name will follow the score when you sort on scores, and vice versa.
The items in the list can be accessed using index just like an array, only the length of the list is in the Count property instead of Length.
No need to create two arrays because you are losing the semantic meaning between the player's name and its score. But also no need to create a new class for that. You can re-use built-in classes/structs like Tuple<...> or KeyValuePair<...>. For ordering, you can use linq-extension methods.
static void Main(string[] args)
{
// just some sample players
const string player1 = "David 100";
const string player2 = "Jennifer 1430";
const string player3 = "Eve 234";
// the string-array with information about players
var players = new[] { player1, player2, player3 };
// initialize the array: a tuple is the name of the player and the score
var scores = new List<Tuple<string, int>>(players.Length);
foreach (string player in players)
{
// split by whitespace
string[] info = player.Split(' ');
// be failure tolerant: split must result in at least 2 entries and second one must be integer
int score;
if (info.Length <= 2 && int.TryParse(info[1], out score))
scores.Add(new Tuple<string, int>(info[0], score));
}
// print average score
Console.WriteLine("Average score for {0} players is: {1}{2}", scores.Count, scores.Select(t => t.Item2).Average(), Environment.NewLine);
// print score of each single player (ordered from highest to lowest score)
foreach (Tuple<string, int> score in scores.OrderByDescending(t=>t.Item2))
Console.WriteLine("Player '{0}' => score: {1}", score.Item1, score.Item2);
Console.WriteLine();
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
Related
This question already has answers here:
Random number generator with no duplicates
(12 answers)
Closed 2 years ago.
We are making our first 2D mobile game in Unity and we need some help. We coded on Java but is also our first time coding C#.
We are making a card game and we want to give to every player a random number, but (here's the important and difficult part for us) we want each random number not to repeat.
For example if we have 5 players and we want to assign a random number from 5 to 10, if number 6 is assigned to player 1 then number 6 cant be assigned to other player.
Here's where we are:
//Player class only have string name and int trabajo
public static void assignRandom(Player jug)
{
int randomnum;
bool aleatorio;
do
{
randomnum= Random.Range(1, 5);
aleatorio = comprobarAleatorio(randomnum);
}
while (aleatorio);
jug.setTrabajo(randomnum);
}
public static bool comprobarAleatorio(int numaleatorio)
{
bool exists = false;
int longitud = jugadoresList.Count;
for (int i = 0; i < 5; i++)
{
if (jugadoresList[i].getTrabajo().Equals(numaleatorio))
{
exists = true;
}
}
}
Then with the int we make a switch and show on screen what type of player you are. But clearly we are doing something wrong because the numbers repeat itselfs, even with 0 (we dont know how).
We appreciate every help. Thank you very much! (and sorry for our english)
One solution is you can generate a list that contains valid numbers and then shuffle them.
Code to shuffle a list from here:
// A Function to generate a
// random permutation of arr[]
static void randomize(int []arr, int n)
{
// Creating a object
// for Random class
Random r = new Random();
// Start from the last element and
// swap one by one. We don't need to
// run for the first element
// that's why i > 0
for (int i = n - 1; i > 0; i--)
{
// Pick a random index
// from 0 to i
int j = r.Next(0, i+1);
// Swap arr[i] with the
// element at random index
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// Prints the random array
for (int i = 0; i < n; i++)
Console.Write(arr[i] + " ");
}
Check the code below :
public static void assignRandom(Player jug) //Player class only have string name and int trabajo
{
int randomnum;
private Random random = new Random(); //Declared an instance of Random
ArrayList randomNumsList = new ArrayList(); //Create arraylist to add random nums
bool aleatorio;
do
{
randomnum= random.next(1, 5); //Changed Random.ranged to random.next();
randomNumsList.add(randomnum); //add the random num to list
aleatorio = comprobarAleatorio(randomnum);
}
while (aleatorio);
if (!randomNumsList.Contains(randomnum) { //Only call setTrabajo if the randomNumsList don't have currently generated randomnum
jug.setTrabajo(randomnum);
}
}
public static bool comprobarAleatorio(int numaleatorio)
{
bool exists = false;
int longitud = jugadoresList.Count;
for (int i = 0; i < 5; i++)
{
if (jugadoresList[i].getTrabajo().Equals(numaleatorio))
{
exists = true;
}
}
return exists;
}
}
Tell me if it helps or if it does not help.
I am trying to create a bowling program that when you enter in your name followed by your score, it will take the average, lowest, and highest scores of the players and print them. However for some reason I cannot get the lowest score to print, as when I hit enter twice, it will use the blank value instead of the lowest entered value and name. How can I fix this so that it will display the lowest score?
{
class Program
{
static void Main(string[] args)
{
const int SIZE = 10;
int i;
// create an array with 10 elements
string[] scoreInfo = new string[SIZE];
string[] names = new string[SIZE];
int[] scores = new int[SIZE];
for (i = 0; i < SIZE; i++)
{
// Prompt the user
Console.Write("Enter your first name and score on one line");
Console.WriteLine(" separated by a space.");
// Read one line of data from the file and save it in inputStr
string inputStr = Console.ReadLine( );
// if statement to break when the user enters a zero
if (inputStr == String.Empty)
{
break;
}
// The Split method creates an array of two strings
scoreInfo = inputStr.Split();
// Parse each element of the array into the correct data type
names[i] = scoreInfo[0];
scores[i] = int.Parse(scoreInfo[1]);
}
Console.WriteLine("The avarage score is {0}", AverageScore(scores, i));
Console.WriteLine("{0} scored the lowest at {1}", names[LowScore(scores, i--)], scores[LowScore(scores, i--)]);
Console.WriteLine("{0} scored the highest at {1}", names[HighScore(scores)], scores[HighScore(scores)]);
Console.ReadLine();
Console.ReadLine();
}
static int LowScore(int[] scores, int j)
{
int min = scores.Min();
return Array.IndexOf(scores, min);
}
static int HighScore(int[] scores)
{
int max = scores.Max();
return Array.IndexOf(scores, max);
}
static double AverageScore(int[] numbers, int j)
{
double average = 0;
for (int i = 0; i < j--; i++)
{
int product = 1;
product = numbers[i] * product;
average = product / j;
}
return average;
}
}
}
Use a different data structure and make less work for yourself.
Start with a dictionary that maps names to scores so that you don't have to mess around with indexes.
Then, LINQ is your friend, as you've already noticed. You don't need to create functions for things that already exist (like min/max/average).
eg.
Dictionary<string, int> ranking = new Dictionary<string, int>();
ranking.Add("adam", 20);
ranking.Add("bill", 10);
ranking.Add("carl", 30);
double avg = ranking.Average(kvp => (double)kvp.Value);
var sorted = ranking.OrderBy(kvp => kvp.Value);
var min = sorted.First();
var max = sorted.Last();
Console.WriteLine("Average: {0}", avg);
Console.WriteLine("Lowest: {0} with {1}", min.Key, min.Value);
Console.WriteLine("Highest: {0} with {1}", max.Key, max.Value);
Modify your Average function like this:-
static double AverageScore(int[] numbers, int j)
{
double sum = 0;
for (int i = 0; i < j; i++)
{
sum += numbers[i];
}
return (double)sum / j;
}
I am not sure why you were taking product of items for finding average of scores.
And Your Min function like this:-
static int LowScore(int[] scores, int j)
{
int min = scores.Where((v, i) => i < j).Min();
return Array.IndexOf(scores, min);
}
Here, you are passing the complete array of integer, so if only 3 players entered values, rest of the values will be initialized to default, i.e. 0 for int, Thus you were getting 0 as Min value.
Also, You need to change the method invocation like this:-
Console.WriteLine("{0} scored the lowest at {1}", names[LowScore(scores, i)], scores[LowScore(scores, i)]);
I've created a Dice program which rolls a dice dependant on how many times the user wishes to roll. The problem I'm having is being able to calculate how many times each number appears.
Example. Roll Twice - Number is 5.
Number is 4.
I want to be able to count that a 4 and a 5 has being rolled and display it back to the user.
My Code so far
using System;
namespace Dice
{
class Dice
{
private Random randy;
int total;
public static void Main()
{
Dice myDice = new Dice();
myDice.randy = new Random();
Console.Clear();
myDice.manyThrow();
myDice.throwDice();
Console.ReadKey();
}
//*******************************************************
public void throwDice()
{
double count = 0;
while(count != total)
{
count++;
Console.WriteLine("Throw No " + count + " is " + oneThrow());
}
}
//*******************************************************
public int oneThrow()
{
return randy.Next(6) + 1; // pick a number from 1 to 6 and return this
}
public int manyThrow()
{
Console.Write("How many times do you want to roll\t");
total = Convert.ToInt32(Console.ReadLine());
return total;
}
public void countEm()
{
// This is where I intend to place the code
}
}
}
I've being trying to solve this for hours.
Add an array to count roll results:
using System;
namespace Dice
{
class Dice
{
private Random randy;
int total;
int [] rolls = new int[7];
public static void Main()
{
Dice myDice = new Dice();
myDice.randy = new Random();
Console.Clear();
myDice.manyThrow();
myDice.throwDice();
myDice.countEm();
Console.ReadKey();
}
//*******************************************************
public void throwDice()
{
double count = 0;
while (count != total)
{
count++;
Console.WriteLine("Throw No " + count + " is " + oneThrow());
}
}
//*******************************************************
public int oneThrow()
{
var result = randy.Next(6) + 1; // pick a number from 1 to 6 and return this
this.rolls[result]++;
return result;
}
public int manyThrow()
{
Console.Write("How many times do you want to roll\t");
total = Convert.ToInt32(Console.ReadLine());
return total;
}
public void countEm()
{
for (int i = 1; i<7; i++)
{
Console.WriteLine("{0} rolled {1} times", i, rolls[i]);
}
}
}
}
Try this:
static int[] counts = new int[6];
And in oneThrow():
int result = randy.Next(6);
counts[result]++;
return result + 1;
Then in countEm():
for (int i = 0; i < counts.Length; i++)
{
Console.WriteLine("{0}: {1}", i + 1, counts[i]);
}
Keep an array of the possible outcomes count.
class Dice
{
private Random randy;
private int total;
private static const int NUM_SIDES = 6;
private int[] counts;
public Dice()
{
randy = new Random();
counts = new int[ NUM_SIDES ];
}
public static void Main()
{
Dice myDice = new Dice();
Console.Clear();
int throws = myDice.manyThrow(); // need to save the number of throws
myDice.throwDice( throws );
countEm();
Console.ReadKey();
}
public void throwDice( int throws )
{
double count = 0;
while(count != throws)
{
count++;
int result = oneThrow();
counts[ result - 1 ]++; // NOTE: result-1 because arrays are 0-based.
Console.WriteLine("Throw No " + count + " is " + oneThrow());
}
}
// ...
public void countEm()
{
for( int i = 0; i < counts.Count; ++i )
Console.WriteLine( (i+1) + " thrown " + counts[i] + " times." );
}
If you just want to keep track of the count of each number rolled, then you add to your class an array of integers to store the count of each number rolled. The number of the dice roll could be the index into the array.
If you need to keep track of the order of the numbers rolled. Your class could could use a linked list or other ordered list to keep track of the numbers.
This sort of sounds like a homework assignment, so I'll leave the implementation details to the reader :)
Modify the countEM like this:
public void countEm(int numberOfThrows)
{
List<int> Throws = new List<int>(); //Create list, where value of throws will be stored.
for(int i = 0; i < numberOfThrows) //Loop as many times as are given by parameter.
{
Throws.Add(OneThrow()); //Add return value of throw to the list.
}
//Show values in Throws list.
foreach(var diceValue in Throws)
{
Console.WriteLine(string.Format("Value of throw: {0}", diceValue ));
}
}
coutEM should be called with the number of times you want to throw like:
countEM(5);
Above represents 5 throws. The result for example could be filled with:
1, 4, 6, 3, 4
class Program
{
public static void Main()
{
double[,, ] stats = new double[3, 2, 10];
string[] players = new string[3];
int x, y, z;
players[0] = "Tom Brady";
players[1] = "Drew Brees";
players[2] = "Peyton Manning";
for (x = 0; x < 3; ++x)
{
Console.WriteLine("Enter stats for {0}", players[x]);
for (y = 0; y < 2; ++y)
{
Console.WriteLine("Game {0}", y + 1);
stats[x, y, z] = ***inputstats(stats[x, y, z])***;
}
}
}
public static double[] inputstats(double[] methodstats)
{
methodstats = new double[10];
Console.WriteLine("Enter pass attempts: ");
methodstats[0] = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter completions: ");
methodstats[1] = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter completion percentage: ");
methodstats[2] = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter total yards: ");
methodstats[3] = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter touchdowns: ");
methodstats[4] = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter interceptions: ");
methodstats[5] = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter rushing yards: ");
methodstats[6] = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter rushing touchdowns: ");
methodstats[7] = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter fumbles: ");
methodstats[8] = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Enter QB rating: ");
methodstats[9] = Convert.ToDouble(Console.ReadLine());
return methodstats;
}
}
Here is my code I have so far. Keep in mind that I am VERY beginner. I am trying to create a console that will ask for user input for 3 different players over 2 games. Once I get all the data input by the user, I will go on to add the ability for the user to be prompted to display either the game 1 statline, game 2 statline, or the average of the two games.
Right now I'm stuck on just getting the input. I am getting an error where I have bold and italics on the line that the best overload method match has some invalid arguments. What am I messing up here? I'm pretty sure it is in z, but I'm not quite sure how to input it into the third dimension of the array for the 10 stats. Halp!
You have 2 mismatches on that line:
stats[x, y, z] = inputstats(stats[x, y, z]);
double[] inputstats(double[] methodstats)
{
}
The expression stats[x, y, z] is a single double, not an array. So when you fix the argument error you will get one for the assignment of the return value.
This line would compile:
stats[x, y, z] = Math.Sin(stats[x, y, z]);
because the function is declared as double Sin(double a)
Your input method collects an array of doubles, that is not possible with your current array form. You would have to use a jagged array (array-of-array-of-array:
double[][][] stats = ...
// extra code to create the arrays
inputstats(stats[x][y]);
void inputstats(double[] methodstats)
{
}
But you might as well bite the bullet and write a proper class for your data:
class PlayerStats
{
public double PassAttempts { get; set; }
public double Completions { get; set; }
// etc ...
}
A simpler solution would be:
public static void Main()
{
double[][][] stats = new double[3][2][10];
string[] players = new string[3];
players[0] = "Tom Brady";
players[1] = "Drew Brees";
players[2] = "Peyton Manning";
for (int player = 0; player < 3; ++player)
{
Console.WriteLine("Enter stats for {0}", players[ player ]);
for (int game = 0; game < 2; ++game)
{
Console.WriteLine("Game {0}", game + 1);
stats[player][game] = inputstats();
}
}
public static double[] inputstats()
{
//same code
}
A few notes. I used an array of an array of an array instead of a multidimensional array so that an array can be assigned to stats[][] (More Info Here). Also, you should use more descriptive iterator variables (player and game here) and locally scope them. That is declare them in the for loop declaration. Generally, the more local the scope of a variable, the better.
edit:
According to Kevin DiTraglia you can assign an array to [,]. But anyway [][][] is apparently faster and more natural for me coming from Java and C/C++
This relates to another code I posted earlier but since this is a different question I decided to make a new post. I'm currently stuck with this code, I'm a c# beginner so this look complicated to me. I've been working on this code that is supposed to get an array from the user, calculate its average then display the results inside show(). I got this working to show the average of the array but now I need to actually display the array each value individually i.e. The 1st value you entered was : 12
The 2nd value you enteres was : 32
Thank guys!
private static int Array()
{
string inValue;
int[] score = new int[10];
int total = 0;
for (int i = 0; i < score.Length; i++)
{
Console.Write("Enter Value {0}: ", i + 1);
inValue = Console.ReadLine();
score[i] = Convert.ToInt32(inValue);
}
for (int i = 0; i < score.Length; i++)
{
total += score[i];
}
return total;
}
Change your GetValues() function to actually return the array of integers, then use the return value in your other functions.
i.e. change GetValues() to:
private static int[] GetValues()
{
string inValue;
int[] score = new int[5];
int total = 0;
for (int i = 0; i < score.Length; i++)
{
Console.Write("Enter Value {0}: ", i + 1);
inValue = Console.ReadLine();
score[i] = Convert.ToInt32(inValue);
}
return score;
}
EDIT: Here is how to use the GetValues() function above in a function to print out all the values. You should be able to work out the rest from here:
private static void PrintArray(int[] scoreArray)
{
for (int i = 0; i < scoreArray.Length; i++)
{
Console.WriteLine("Value #{0}: {1}", i + 1, scoreArray[i]);
}
}
Note how the scoreArray is passed in, as well as how each value is accessed, using scoreArray[i] (where i is a number from 0 to 4 inclusive).
Move int[] score out of GetValues and declare it at the class level making it static:
static int[] score = new int[5];
My next recommendation is that you don't do inside your functions more than what they claim to do from their name; for example, GetValues() should only get the values from user; not calculate totals (as you are doing) because it's misleading; it forces you to look at the implementation to know exactly what it does. Similarly for Show(); if the purpose is to show values entered by user, then call it ShowValues(); If the purpose is to show values entered by user as well as calculate the average, then name it something along the lines of ShowValuesAndAverage()
Here's a complete implementation of your program with my recommendations:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace testscores
{
class Program
{
static int[] score = new int[5];
//Get Values
private static void GetValues()
{
string inValue;
for (int i = 0; i < score.Length; i++)
{
Console.Write("Enter Value {0}: ", i + 1);
inValue = Console.ReadLine();
score[i] = Convert.ToInt32(inValue);
}
}
//FIND AVERAGE
private static double FindAverage()
{
double total = 0.0;
for (int i = 0; i < score.Length; i++)
{
total += score[i];
}
double average = total / 5.0;
return average;
}
//Show
static void ShowValuesAndAverage()
{
Console.WriteLine("The values are:");
for (int i = 0; i < score.Length; i++)
{
Console.WriteLine(string.Format("The {0} value you entered was {1}", i + 1, score[i]));
}
Console.WriteLine("The average is: {0}", FindAverage());
}
//Main
static void Main()
{
GetValues();
ShowValuesAndAverage();
Console.ReadKey();
}
}
}
Make one function for GetValues() and return the array. Then pass the array into a AddValues() function, and into Show().
Either that or read up on how to use pointers, but that might be overcomplicating things a little.