I need to use arrays/lists for my assignment and thought of using one for my highscore list for my game in windows form.
Right now I'm using a regular int for my Score and I'm wondering how I can get this into an array for a highscore list on my highscore.cs
Current code for score in game.cs
int Score = 0;
Scorelabel.Text ="score:" + score;
if (Picturebox.Left < -180)
{
Picturebox.Left = 800;
Score++;*
Things I've tried:
namespace Game
{
public partial class Highscore : Form
{
public Highscore()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
int[] Highscore = new int[10];
for (int Score = 0; Score < 10; Score++)
{
textBox1.Text = new System.Windows.Forms.TextBox();
}
}
}
I tried to make the initial score int an array. I would end up getting the error:"Operator ++ cannot be applied to operand of type 'int[]'
Also tried to get my int into an array but would get the error that I can't convert ints to arrays.
What I want
I want my scores from the game.cs to show in a listbox on my highscore.cs that shows the top 10 scores descending from highest to lowest.
Let's imagine you've got 20 players and each one got some score.
As you decided to create an array of ints to store all scores, so do I:
int[] scores = new int[20];
For example, I fill that array with random unique scores from 10 to 100. You fill in your way:
int[] scores = new int[20];
Random rnd = new Random();
for (int i = 0; i < scores.Length; i++)
{
int score = 0;
// This loop used to generate new random int until it wouldn't be unique (wouldn't exist in array)
while (score == 0 || scores.Contains(score))
score = rnd.Next(10, 100);
scores[i] = score;
lblAllScores.Text += "Player #" + (i + 1) + " score: " + scores[i] + "\n";
}
I append each score and Player # (as number of iteration + 1) to some Label on Form to show all players and their scores. Something like this:
Now you (and I) want take top 10 scores (obviously in descending order, from highest to lowest). Here the keywords are Take and Descending order. In C# through System.Linq namespace provided such pretty extension methods like Take and OrderByDescending. And seems they can give us desired result if we use it properly.
I (and you) creating a new array of ints to store only Top 10 Scores. Then a take initial array scores and use OrderByDescending method to sort values in it from highest to lowest. (x => x) provided as selector to determine key by which method should order values - in our case by value itself. And then I use Take(10) method to take first 10 scored from that sorted array - this is our Top 10 Scores:
int[] top10Scores = scores.OrderByDescending(x => x).Take(10).ToArray();
And all I need to do - put this into Form, which I can do by simple iteration on top10Scores array with for loop. But I (and probably you) want to know what Player has that score. Upper we use (index of array + 1) as Player Number. And we know that scores are unique for each Player. Than now we can take the score value from top10Scores array and try to find its index in source scores array with Array.FindIndex method:
for (int i = 0; i < top10Scores.Length; i++)
{
int playerNumber = Array.FindIndex(scores, score => score == top10Scores[i]) + 1;
lblTop10Scores.Text += "Player #" + playerNumber + " score: " + top10Scores[i] + "\n";
}
And at our Form we have this:
Complete code:
private void ScorePlayers()
{
int[] scores = new int[20];
Random rnd = new Random();
for (int i = 0; i < scores.Length; i++)
{
int score = 0;
while (score == 0 || scores.Contains(score))
score = rnd.Next(10, 100);
scores[i] = score;
lblAllScores.Text += "Player #" + (i + 1) + " score: " + scores[i] + "\n";
}
int[] top10Scores = scores.OrderByDescending(x => x).Take(10).ToArray();
for (int i = 0; i < top10Scores.Length; i++)
{
int playerNumber = Array.FindIndex(scores, score => score == top10Scores[i]) + 1;
lblTop10Scores.Text += "Player #" + playerNumber + " score: " + top10Scores[i] + "\n";
}
}
Please note, that this is only a sketch and example to demonstrate how to use OrderByDescending and Take extension methods to get first 10 elements of sorted from highest to lowest value collection. In real application you probably will have at least simple Dictionary<string, int>, where would be stored player name (as string) and his score (as int). Or, more likely, it would be a model class called Player with Name and Score properties and each Player would be stored in some List<Player>:
public class Player
{
public string Name { get; set; }
public int Score { get; set; }
}
Hope you can find your solution and this example would be helpful for you.
Instead of removing the first occurrence of a duplicated value, as my code currently does, how can I get it to delete the second occurrence instead?
namespace deletenumber
{
class Program
{
public static void Main(String[] args)
{
Random r = new Random();
int[] a = new int[10];
for (int i = 0; i < 10; i++)
a[i] = r.Next(1, 100);
for (int i = 0; i < 10; i++)
Console.WriteLine(" a [" + i + "] = " + a[i]);
Console.WriteLine();
Console.ReadLine();
Console.WriteLine("What number do you want to delete?");
int item = Convert.ToInt32(Console.ReadLine());
Console.WriteLine();
int index = Array.IndexOf(a, item);
a = a.Where((b, c) => c != index).ToArray();
Console.WriteLine(String.Join(", ", a));
Console.ReadLine();
}
}
}
I'm not sure why exactly you might want to delete only the second occurrence because there should be no matter which one of the duplicates is removed, correct?
Anyway, there are several ways of achieving what you want.
I will not directly write a solution here, but will propose the methods you can use in order to achieve what you want:
Array.LastIndexOf
Use the same IndexOf method again to find the second occurrence, by starting the search from the previous occurrence (myArray.IndexOf("string", last_indexof_index);)
Generally, consider using a HashSet<T> (official docs here) if you want to have a collection of unique elements.
You can also convert your existing collection to HashSet<int>:
int[] a = new int[10];
var set = new HashSet<int>(a);
You could convert your array to a List and then just remove the index before casting it back to an array:
var list = new List<int>(a);
list.RemoveAt(index);
a = list.ToArray();
I have a comma delimited text file that contains 20 digits separated by commas. These numbers represent earned points and possible points for ten different assignments. We're to use these to calculate a final score for the course.
Normally, I'd iterate through the numbers, creating two sums, divide and be done with it. However, our assignment dictates that we load the list of numbers into two arrays.
so this:
10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85
becomes this:
int[10] earned = {10,20,30,40,45,50,20,45,85};
int[10] possible = {10,20,35,50,50,50,20,90,85};
Right now, I'm using
for (x=0;x<10;x++)
{
earned[x] = scores[x*2]
poss [x] = scores[(x*2)+1]
}
which gives me the results I want, but seems excessively clunky.
Is there a better way?
The following should split each alternating item the list into the other two lists.
int[20] scores = {10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85};
int[10] earned;
int[10] possible;
int a = 0;
for(int x=0; x<10; x++)
{
earned[x] = scores[a++];
possible[x] = scores[a++];
}
You can use LINQ here:
var arrays = csv.Split(',')
.Select((v, index) => new {Value = int.Parse(v), Index = index})
.GroupBy(g => g.Index % 2,
g => g.Value,
(key, values) => values.ToArray())
.ToList();
and then
var earned = arrays[0];
var possible = arrays[1];
Get rid of the "magic" multiplications and illegible array index computations.
var earned = new List<int>();
var possible = new List<int>();
for (x=0; x<scores.Length; x += 2)
{
earned.Add(scores[x + 0]);
possible.Add(scores[x + 1]);
}
This has very little that would need a text comment. This is the gold standard for self-documenting code.
I initially thought the question was a C question because of all the incomprehensible indexing. It looked like pointer magic. It was too clever.
In my codebases I usually have an AsChunked extension available that splits a list into chunks of the given size.
var earned = new List<int>();
var possible = new List<int>();
foreach (var pair in scores.AsChunked(2)) {
earned.Add(pair[0]);
possible.Add(pair[1]);
}
Now the meaning of the code is apparent. The magic is gone.
Even shorter:
var pairs = scores.AsChunked(2);
var earned = pairs.Select(x => x[0]).ToArray();
var possible = pairs.Select(x => x[1]).ToArray();
I suppose you could do it like this:
int[] earned = new int[10];
int[] possible = new int[10];
int resultIndex = 0;
for (int i = 0; i < scores.Count; i = i + 2)
{
earned[resultIndex] = scores[i];
possible[resultIndex] = scores[i + 1];
resultIndex++;
}
You would have to be sure that an equal number of values are stored in scores.
I would leave your code as is. You are technically expressing very directly what your intent is, every 2nd element goes into each array.
The only way to improve that solution is to comment why you are multiplying. But I would expect someone to quickly recognize the trick, or easily reproduce what it is doing. Here is an excessive example of how to comment it. I wouldn't recommend using this directly.
for (x=0;x<10;x++)
{
//scores contains the elements inline one after the other
earned[x] = scores[x*2] //Get the even elements into earned
poss [x] = scores[(x*2)+1] //And the odd into poss
}
However if you really don't like the multiplication, you can track the scores index separately.
int i = 0;
for (int x = 0; x < 10; x++)
{
earned[x] = scores[i++];
poss [x] = scores[i++];
}
But I would probably prefer your version since it does not depend on the order of the operations.
var res = grades.Select((x, i) => new {x,i}).ToLookup(y=>y.i%2, y=>y.x)
int[] earned = res[0].ToArray();
int[] possible = res[1].ToArray();
This will group all grades into two buckets based on index, then you can just do ToArray if you need result in array form.
here is an example of my comment so you do not need to change the code regardless of the list size:
ArrayList Test = new ArrayList { "10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85" };
int[] earned = new int[Test.Count / 2];
int[] Score = new int[Test.Count / 2];
int Counter = 1; // start at one so earned is the first array entered in to
foreach (string TestRow in Test)
{
if (Counter % 2 != 0) // is the counter even
{
int nextNumber = 0;
for (int i = 0; i < Score.Length; i++) // this gets the posistion for the next array entry
{
if (String.IsNullOrEmpty(Convert.ToString(Score[i])))
{
nextNumber = i;
break;
}
}
Score[nextNumber] = Convert.ToInt32(TestRow);
}
else
{
int nextNumber = 0;
for (int i = 0; i < earned.Length; i++) // this gets the posistion for the next array entry
{
if (String.IsNullOrEmpty(Convert.ToString(earned[i])))
{
nextNumber = i;
break;
}
}
earned[nextNumber] = Convert.ToInt32(TestRow);
}
Counter++
}
public void GnomeSort<T>(IList<T> list, IComparer<T> comparer)
{
sortTimer = new Stopwatch();
sortTimer.Start();
bool stillGoing = true;
while (stillGoing)
{
stillGoing = false;
for (int i = 1; i < list.Count; )
{
T x = list[i - 1];
T y = list[i];
if (comparer.Compare(x, y) <= 0)
i++;
else
{
list[i - 1] = y;
list[i] = x;
i--;
if (i == 0)
i = 1;
stillGoing = true;
}
}
}
sortTimer.Stop();
richTextBox1.Text += "Gnome Sorting completed, total time taken " + sortTimer.Elapsed + "\n";
}
If I run this twice, using the same unsorted randomly generated array here:
randomArray = randomizedArray
(Convert.ToInt32(textBox1.Text), Convert.ToInt32(textBox2.Text));
randomArrayGnome = randomArray;
randomArrayBubble = randomArray;
randomArrayInsertion = randomArray;
GnomeSort(randomArray);
BubbleSort(randomArrayBubble);
But it outputs something close to this:
Gnome Sorting completed, total time taken 00:00:02.5419864
Bubble Sorting completed, total time taken 00:00:00.0003556
but if I switch the call order, the times are drastically different, instead Bubble Sorting may take 6 seconds. What is happening here? How come it isn't sorting them correctly?
Your problem is with your initialisation of the arrays. As shown here:
randomArray = randomizedArray
(Convert.ToInt32(textBox1.Text), Convert.ToInt32(textBox2.Text));
randomArrayGnome = randomArray;
randomArrayBubble = randomArray;
randomArrayInsertion = randomArray;
The above code creates four variables that all reference the same array. So what happens is that the first sort algorithm sorts the array, subsequent ones will encounter an array that is already sorted so will execute very fast.
As simple solution is to use a Linq - ToList to clone the array:
randomArray = randomizedArray
(Convert.ToInt32(textBox1.Text), Convert.ToInt32(textBox2.Text));
randomArrayGnome = randomArray.ToList();
randomArray & randomArrayGnome both holds the reference to randomizedArray.
When you call
GnomeSort(randomArray);
BubbleSort(randomArrayBubble);
the reference array is already sorted, BubbleSort is working on a already sorted array!
You can use Array.Clone() so that four different reference are created!
I'm very new to C# (And Stack Overflow, forgive me for any poor etiquette here), and I'm writing the game Mastermind in a console application. I'm trying to show a list of the user's guesses at the end of the game, and I know that using Console.WriteLine(); will just give me 30-odd lines off numbers which don't tell the user anything.
How can I alter my code so that the program displays 4 numbers in a group, at a time? For example:
1234
1234
1234
//Store numbers in a history list
ArrayList guesses = new ArrayList(); //This is the ArrayList
Console.WriteLine("Please enter your first guess.");
guess1 = Convert.ToInt32(Console.ReadLine());
guesses.Add(guess1);
foreach (int i in guesses)
{
Console.Write(i);
}
I assume that each element of your byte array is a single digit (0-9). If that assumption is invalid -- please let me know, I'll modify the code :)
Action<IEnumerable<int>> dump = null;
dump = items =>
{
if(items.Any())
{
var head = String.Join("", items.Take(4));
Console.WriteLine(head);
var tail = items.Skip(4);
dump(tail);
}
};
dump(guesses);
It looks like you're most of the way there, you have a console write that writes them all out without linebreaks. Next add an integer count and set it to zero. Increment it by one in the foreach loop. count % 4 == 0 will then be true for all counts that are a multiple of four. This means you can stick an if block there with a write-line to give you your groups of four.
List<int> endResult = new List<int>();
StringBuilder tempSb = new StringBuilder();
for(int i=0; i < groups.Count; i++)
{
if(i % 4 == 0) {
endResult.Add(int.Parse(sb.ToString()));
tempSb.Clear(); // remove what was already added
}
tempSb.Append(group[i]);
}
// check to make sure there aren't any stragglers left in
// the StringBuilder. Would happen if the count of groups is not a multiple of 4
if(groups.Count % 4 != 0) {
groups.Add(int.Parse(sb.ToString()));
}
This will give you a list of 4 digit ints and make sure you don't lose any if your the number of ints in your groups list is not a multiple of 4. Please note that I am continuing based on what you provided, so groups is the ArrayList of ints.
This is some thing I quickly put together:
Update:
ArrayList guesses = new ArrayList(); //This is the ArrayList
// Four or more
guesses.Add(1); guesses.Add(2);
guesses.Add(3);guesses.Add(4);
guesses.Add(5); guesses.Add(6); guesses.Add(7);guesses.Add(8); guesses.Add(9);
//Uncomment-Me for less than four inputs
//guesses.Add(1); guesses.Add(2);
int position = 0;
if (guesses.Count < 4)
{
for (int y = 0; y < guesses.Count; y++)
{
Console.Out.Write(guesses[y]);
}
}
else
{
for (int i = 1; i <= guesses.Count; i++)
{
if (i%4 == 0)
{
Console.Out.WriteLine(string.Format("{0}{1}{2}{3}", guesses[i - 4], guesses[i - 3],
guesses[i - 2], guesses[i - 1]));
position = i;
}
else
{
if (i == guesses.Count)
{
for (int j = position; j < i; j++)
{
Console.Out.Write(guesses[j]);
}
}
}
}
}