We have a task to create a random hand of cards (5 cards). Where the cards can not be the same. We have yet not learnd how to use arrays so it would be nice if anyone could help us to get started without using arrays.
This is how we have started, but we can not figure out how to not get the same card twice.
static void Cards()
{
var rnd = new Random();
var suit, rank, count = 0;
while (count < 5)
{
rank = rnd.Next(13) + 1;
suit = rnd.Next(4) + 1;
if (suit == 1)
{
Console.WriteLine("Spader " + rank);
}
else if (suit == 2)
{
Console.WriteLine("Hjärter " + rank);
}
else if (suit == 3)
{
Console.WriteLine("Ruter " + rank);
}
else
{
Console.WriteLine("Klöver " + rank);
}
count++;
}
}
Thanks!
This is the sort of problem that arrays can deal with, so it would be easier to learn how to use them. Without them you need to store your 5 cards in variables (string card1, string card2, etc) then on each iteration check to see if the card matches any of these and discard it if it does, else save it. But then you have a whole bunch of conditional code to see which variable to store it in...
Much easier to just have an array
string[] cards = new string[5];
then you can just loop over the array looking for a match (something like this)
for(int idx=0; idx<5; idx++){
if(cards[idx]==thecardyouhavejustcreatedwithrandomcode){
break; //bail out of the for on a match
}
cards[iAntalKort]=thecardyouhavejustcreatedwithrandomcode;
}
Related
I'm sitting here with a school project I can't seem to figure out; I am to create a console application that let's the user enter a number of salesmen for a hypothetical company. The information about the salesmen includes their name, district and number of sold items. The salesmen are then to be sorted into different levels according to the number of sold items. Finally, the salesmen are to be printed to the console. The printing should be done one level at the time, if for instance two salesmen reached level one and one reached level 2, the console should look something like:
John Johnsson, someDistrict, 33 items sold
Mary Mara, someOtherDistrict, 40 items sold
2 salesmen reached level 1
Judy Juggernut, anotherDistrict, 67 items sold
1 salesmen reached level 2
And it's the printing part in question that gives me trouble. When the user enters information a new object of a salesman-class is created and stored in an array of salesmen. The number of items sold for each salesman is then checked and each salesman is assigned a level. The array is then sorted using bubblesort, to have the salesman with the least amount of sales on salesmanArray[0] and so on.
Everything works fine until its time to print the results to the console. I tried to write a method for it:
public static void sortering(Salesman[] salesmenArray)
{
Salesman[] level1 = new Salesman[salesmenArray.Length];
Salesman[] level2 = new Salesman[salesmenArray.Length];
Salesman[] level3 = new Salesman[salesmenArray.Length];
Salesman[] level4 = new Salesman[salesmenArray.Length];
for (int i = 0; i < salesmenArray.Length - 1; i++)
{
if (salesmenArray[i].level == 1)
{
level1[i] = salesmenArray[i];
} else if (salesmenArray[i].level == 2)
{
level2[i] = salesmenArray[i];
} else if (salesmenArray[i].level == 3)
{
level3[i] = salesmenArray[i];
} else if (salesmenArray[i].level == 4)
{
level4[i] = salesmenArray[i];
}
}
if (level1.Length != 0)
{
for (int i = 0; i < level1.Length - 1; i++)
{
Console.WriteLine("Name: " + level1[i].name);
Console.WriteLine("District: " + level1[i].district);
Console.WriteLine("Items sold: " + level1[i].itemsSold);
}
Console.WriteLine("" + (level1.Length - 1) + " sellers have reached level 1");
}
//Same thing for level 2, 3 and 4
}
What I'm trying to do is 4 new arrays for the different levels. I then loop through the array with all the salesmen and place the salesmen into the arrays in accordance to the number of sold items. I then check if the level-arrays are empty. If they aren't, I loop through them printing out the name, district and items sold for each salesman. Finally also printing out how many sellers there are in each level. When running the program, I get an error on the line
Console.WriteLine("Name: " + level1[i].name);
Saying "System.NullReferenceException has been thrown "Object reference not set to an instance if an object".
I would assume that means level1[i].name isn't referencing to an object but I don't really know how to go from there... Any advice or pointers would be greatly appriciated!
You are getting a System.NullReferenceException because you are initializing the level arrays with the same length as the salesmen array, but you are only adding salesmen to the level arrays based on their level.
So there will be not initialized null elements in the level arrays, and when you try to access the name property of a null element, you get the exception because you try to read property of absent element.
To fix this, you may use List<Salesman> instead of Salesman[]. List<T> is a generic dynamic array and you can iterate over its items in the same way:
public static void sortering(Salesman[] salesmenArray)
{
var level1 = new List<Salesman>();
var level2 = new List<Salesman>();
var level3 = new List<Salesman>();
var level4 = new List<Salesman>();
for (int i = 0; i < salesmenArray.Length; i++)
{
if (salesmenArray[i].level == 1)
{
level1.Add(salesmenArray[i]);
}
else if (salesmenArray[i].level == 2)
{
level2.Add(salesmenArray[i]);
}
else if (salesmenArray[i].level == 3)
{
level3.Add(salesmenArray[i]);
}
else if (salesmenArray[i].level == 4)
{
level4.Add(salesmenArray[i]);
}
}
if (level1Count > 0)
{
for (int i = 0; i < level1.Count; i++)
{
Console.WriteLine("Name: " + level1[i].name);
Console.WriteLine("District: " + level1[i].district);
Console.WriteLine("Items sold: " + level1[i].itemsSold);
}
Console.WriteLine("" + level1Count + " sellers have reached level 1");
}
//Same thing for level 2, 3 and 4
}
Here is some other improvments then you can do with your code. For example if Salesman.level may contains only values form the list [1, 2, 3, 4] you can store levels in the List of List<Salesman> or in the array of List<Salesman> and add items in the easier way. Also string interpolation is an easier, faster, and more readable string concatenation syntax.
// here we creates a new array of lists and initialize it with 4 empty lists of Salesman
var levels = new List<Salesman>[]
{
new List<Salesman>(),
new List<Salesman>(),
new List<Salesman>(),
new List<Salesman>()
};
foreach(var salesmen in salesmenArray)
{
// (salesmen.level - 1)-th list stores salesmen with that level
levels[salesmen.level - 1].Add(salesmen);
}
// you can iterate salesmen of all levels with nested loops
for(int level = 0; level < levels.Lenth; level++)
{
foreach(var salesman in levels[level])
{
Console.WriteLine($"Name: {salesman.name}");
Console.WriteLine($"District: {salesman.district}");
Console.WriteLine($"Items sold: {salesman.itemsSold}");
}
// Count property gets the number of elements contained in the List<T> so you don't need to decrement this value for display the number of salesmen with this level
Console.WriteLine($"{levels[level].Count} sellers have reached level {level + 1}");
}
Finally there is an interesting mechanism to manipulate collections in .NET called LINQ. You can use LINQ syntax to select, filter, group and aggregate data. LINQ is readable efficiency and powerful tool. Here's a sample of your code rewritten with LINQ:
foreach(var group in salesmenArray
.GroupBy(salesman => salesman.level)
.OrderBy(groups => groups.Key))
{
foreach(var salesman in group)
{
Console.WriteLine($"Name: {salesman.name}");
Console.WriteLine($"District: {salesman.district}");
Console.WriteLine($"Items sold: {salesman.itemsSold}");
}
Console.WriteLine($"{group.Count()} sellers have reached level {group.Key}");
}
Where is the bubble sort? Sort the array first, then loop through the array with counters to count each level and print the output from the same loop.
// bubble sort
for (int i = 0; i < salesmenArray.Length; i++)
for (int j = 0; j < salesmenArray.Length - 1; j++)
if(salesmenArray[j].itemsSold > salesmenArray[j+1].itemsSold)
{
//swap positions
//...
}
int counter = 0;
int lastLevel = 1; //if 1 is the min level
for (int i = 0; i < salesmenArray.Length; i++)
{
if(salesmenArray[j].level != lastLevel)
{
//print summary
//...
counter = 0; //reset counter
}
// print detail lines
Console.WriteLine("Name: " + level1[i].name);
Console.WriteLine("District: " + level1[i].district);
Console.WriteLine("Items sold: " + level1[i].itemsSold);
counter++;
}
//print final summary for last level
//...
The ... are lines for you to fill.
Vadim's answer details why your code is failing. He proposed a way to solve the problem via Lists. I would also follow that road.
On the other hand, your approach was valid, but not very efficient and has a few traps for yourself (as Vadim mentioned, you are creating 4 level arrays with the same size of the total of salesmen, then you assign them to each level via i, leaving some null gaps). If you want your approach to work, in the printing for-loop, before getting level1[i].name, check that level1[i] is not null.
If you are using an IDE, I would recommend you to put a breakpoint inside the for-loop and see the contents of level1.
Good luck learning!
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have been working on on this problem for awhile I have two arrays in parallel that are the same length. I have nested foreach loops to compare the arrays so I can tell what number is greater. One number is randomly generated and the other is gathered from user input. The problem I'm having is the number that is randomly generated is being compared to each user input before moving to the next randomly generated number. This is my code:
Random r = new Random();
int length = 10;
int[] ranNum = new int[length];
int[] userNum = new int[length];
for (int i = 0; i < length; i++)
{
ranNum[i] = r.Next(1, 100);
}
for (int i = 0; i < length; i++)
{
Console.WriteLine("Enter a number between 1 and 100");
userNum[i] = Convert.ToInt32(Console.ReadLine());
}
foreach(int rn in ranNum)
{
foreach(int ui in userNum)
{
if (rn < ui)
{
Console.WriteLine(rn + " is less than " + ui);
}
else if (rn > ui)
{
Console.WriteLine(rn + " is greater than " + ui);
}
else
{
Console.WriteLine(rn + " is equal to " + ui);
}
}
}
I'm sure I'm missing something obvious any help would be appreciated Thank you in advance
Nested foreach loops are exactly like nested for loops in that they loop through each of the outer values with all of the inner values. If you're just trying to compare the values one-to-one, you'll need to iterate through both arrays at the same time. You can do this by grabbing their iterators and using a while loop; You can use LINQ and Zip both arrays; Or, you can use another for loop, like you used to generate your arrays, and use a common index to iterate through both loops:
for (int i = 0; i < length; i++) {
var rn = ranNum[i];
var ui = userNum[i];
if (rn < ui) {
Console.WriteLine(rn + " is less than " + ui);
} else if (rn > ui) {
Console.WriteLine(rn + " is greater than " + ui);
} else {
Console.WriteLine(rn + " is equal to " + ui);
}
}
Depending on what you're doing with these values, you might consider consolidating these loops, but this is how you would iterate through both at the same time.
There are TWO nested foreach loops here, which will create every possible combination of values. If you want to just match by index you can use a single for loop, or you can use the IEnumerable.Zip() function:
var results = ranNum.Zip(userNum, (rn, ui) => {
if (rn < ui) return $"{rn} is less than {ui}";
if (rn > ui) return $"{rn} is greater than {ui}";
return $"{rn} is equal to {ui}";
});
foreach (var result in results)
{
Console.WriteLine(result);
}
Im new to programming and Im currently attempting to make a dice program, where the user can input how many throws they would like to do and then a list will display how many throws it took to get a specific number, in this case that number is 6 (later on I'd like to make it for all numbers 1-6) How should I go about doing this?
Im currently trying to use an if-statement to recognize when a specific number is rolled, currently I want the program to recognize the number 6, but im a bit unsure how to display the amount of rolls it took to get that number, in a list, and also keeping the loop going until all rolls have been executed.
private void Btnkast_Click(object sender, EventArgs e)
{
bool throws;
int numberofthrows = 0;
int dice;
Random dicethrow = new Random();
throws = int.TryParse(rtbantal.Text, out numberofthrows);
int[] list = new int[numberofthrows];
for (int i = 0; i <= numberofthrows; i++)
{
dice = dicethrow.Next(1, 7);
if (dice == 6)
{...}
}
}
Also, the only reason I use tryparse is to prevent crashes when having to handle with string-values.
I have written this for you using a C# Console Application, but I'm sure you will be able to edit it to fit your requirements for Windows Forms.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
Random rnd = new Random(); // create Random object
Console.WriteLine("Enter a number between 1 and 6: "); // prompt user to enter a number between 1 and 6
int chosenNumberInt;
var chosenNumber = int.TryParse(Console.ReadLine(), out chosenNumberInt); // check to see if user actually entered a number. If so, put that number into the chosenNumberInt variable
Console.WriteLine("How many rolls would you like?"); // prompt user to enter how many rolls they would like to have
int chosenRollsInt;
var chosenRolls = int.TryParse(Console.ReadLine(), out chosenRollsInt);
Console.WriteLine(); // to create space
Console.WriteLine(); // to create space
Console.WriteLine("Chosen Number = " + chosenNumberInt + " --- Chosen Rolls = " + chosenRollsInt); // show user what they entered
Console.WriteLine("------------");
int count = 0;
int numberRolled = 0;
var lstRolls = new List<int>(); // create list object
for(int i = 1; i <= chosenRollsInt; i++)
{
count++;
int dice = rnd.Next(1, 7);
numberRolled = dice;
lstRolls.Add(numberRolled); // add each roll to the list
Console.WriteLine("Roll " + i + " = " + numberRolled); // show each roll
}
var attempts = lstRolls.Count; // how many rolls did you do
var firstIndexOfChosenNumber = lstRolls.FindIndex(x => x == chosenNumberInt) + 1; // have to add 1 because finding the index is 0-based
Console.WriteLine("-------------");
if(firstIndexOfChosenNumber == 0)
Console.WriteLine("The chosen number was " + chosenNumberInt + " and that number was NEVER rolled with " + chosenRollsInt + " rolls.");
else
Console.WriteLine("The chosen number was " + chosenNumberInt + " and the number of rolls it took to hit that number was " + firstIndexOfChosenNumber);
}
}
Something that I didn't add would be the validation to ensure that the user does indeed enter a number between 1 and 6, but you can do that I'm sure.
I have created a DotNetFiddle that proves this code does work and even shows you each roll.
Let me know if this helps or if you need any more assistance.
UPDATE
Based on your comment on my original post, I have edited my code to allow the user to enter the number they want, along with how many rolls. Then, once all of the rolls have been completed, I find the index of the first occurrence of the number they selected in the beginning.
Let me know if this is what you want.
Read the comments I added in the code
private void Btnkast_Click(object sender, EventArgs e)
{
bool throws;
int numberofthrows = 0;
int dice;
Random dicethrow = new Random();
throws = int.TryParse(rtbantal.Text, out numberofthrows);
List<int> list = new List<int>(); //I changed this to a list
for (int i = 0; i < numberofthrows; i++)
{
dice = dicethrow.Next(1, 7);
list.Add(dice); //add every roll to the array to check later the values if you want
if (dice == 6)
{
//Print that you found 6 at the roll number list.Count
Console.WriteLine("Found 6 at roll number: " + list.Count);
break; //probably break the loop so you won't continue doing useless computation
}
}
}
Index out of bounds when create new thread with parameters? - Continue to my previous topic , now i got a new problem with my my Bakery Algorithm code !
Here's my code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace BakeryAlgorithm
{
class Program
{
static int threads = 10;
static string x = "";
static int count = 0;
static int[] ticket = new int[threads];
static bool[] entering = new bool[threads];
public static void doLock(int pid)
{
for (int i = 0; i < threads; i++)
{
ticket[i] = 0;
entering[i] = false;
}
entering[pid] = true;
int max = 0;
for (int i = 0; i < threads; i++)
{
if (ticket[i] > ticket[max]) { max = i; }
}
ticket[pid] = 1+max;
entering[pid] = false;
for (int i = 0; i < threads; ++i)
{
if (i != pid)
{
while (entering[i])
{
Thread.Yield();
}
while (ticket[i] != 0 && (ticket[pid] > ticket[i] ||
(ticket[pid] == ticket[i] && pid > i)))
{
Thread.Yield();
}
}
}
if (x == "C" || x == "c")
Console.WriteLine("[System] PID " + pid.ToString() + " get into critical section");
}
public static void unlock(int pid)
{
ticket[pid] = 0;
count++;
Console.WriteLine("[Thread] PID " + pid.ToString() + " complete.");
}
public static void arrayInit()
{
for (int i = 0; i < threads; i++)
{
ticket[i] = 0;
entering[i] = false;
}
}
public static void simThread(int i)
{
doLock(i);
if (x == "C" || x=="c")
Console.WriteLine("[Thread] PID " + i.ToString() + " begin to process...");
//Do some thing ????
Random rnd = new Random((int)DateTime.Now.Ticks & 0x0000FFFF);
int a = rnd.Next(1,99);
int b = rnd.Next(1,99);
int c = rnd.Next(1,4);
int d = 0;
string o="";
if (c == 1)
{
d = a + b;
o="+";
}
else if (c == 2)
{
d = a * b;
o="*";
}
else if (c == 3)
{
d = a / b;
o="/";
}
else
{
d = a - b;
o="-";
}
if (x == "C" || x == "c")
Console.WriteLine("Math Result : " + a.ToString() + o + b.ToString() + "=" + d.ToString());
unlock(i);
}
[STAThread]
static void Main(string[] args)
{
arrayInit();
string choice="C";
while (choice == "C" || x == "c")
{
Console.WriteLine("Process log (C=Yes,K=No) : ");
x = Console.ReadLine();
if (x == "")
x = "C";
Console.Clear();
Console.WriteLine("----------------------------------");
Console.WriteLine("Bakery Algorithm C#");
Console.WriteLine("Number of threads : " + threads.ToString());
Console.WriteLine("Process Log...");
Console.WriteLine("----------------------------------");
Thread[] threadArray = new Thread[threads];
for (int i = 0; i < 10; i++)
{
int copy = i;
threadArray[i] = new Thread(() => simThread(copy));
if (x == "C" || x == "c")
Console.WriteLine("[System] PID " + i.ToString() + " created");
threadArray[i].Start();
}
Console.ReadLine();
Console.WriteLine("----------------------------------");
Console.WriteLine("Complete processed " + count.ToString() + " threads !");
count = 0;
Console.WriteLine("----------------------------------");
Console.WriteLine("You want to restart (Yes=C or No=K)");
choice = Console.ReadLine();
if (choice == "")
choice = "C";
}
}
}
}
The result are here :
2*2=4
2*2=4 << duplicated
3*2=6
4*2=8
4*6=24
4*2=8 << duplicated
.... and continue with duplicate values ( random position ) !
Hope somebody here can help !
There's many things wrong with your code, but the most important part is that you didn't read the requirements that make Lamport's bakery work:
Lamport's bakery algorithm assumes a sequential consistency memory model.
You will be hard-pressed to find a modern computer that has sequential consistency.
So even if your implementation was correct with respect to those constraints, it would still be wrong on pretty much any computer that runs .NET. To make this work on a modern CPU and in .NET, you'll need to insert memory barriers to prevent instruction reordering and introduce cache refreshing to make sure each CPU core sees the same values... and by then you're probably better off using different synchronization primitives altogether.
Now, fixing these kinds of algorithms tends to be rather hard - multi-threading is hard on its own, doing lock-less multi-threading just pushes this to absurd territory. So let me just address some points:
1) You can't just use new Random() and expect statistically random numbers from that. Random has an internal state that's by default initialized to the current OS tick - that means that creating 10 Randoms in a row and then doing Next on each of those is pretty likely to produce exactly the same "random" numbers.
One way of handling that gracefully would be to have a thread-local field:
ThreadLocal<Random> rnd
= new ThreadLocal<Random>(() => new Random(Guid.NewGuid().GetHashCode()));
Each of your threads can then safely do rnd.Value.Next(...) and get reliable numbers without locking.
However, since the whole point of this excercise is to allow shared access to mutable state, a solution more in line with the task would be to use a single shared Random field instead (created only once, before starting the threads). Since the Bakery algorithm is supposed to make sure you can safely use shared stuff in the critical section, this should be safe, if implemented correctly :)
2) To actually make the Bakery part work, you need to enforce the only proper instruction ordering.
This is hard. Seriously.
I'm not actually sure how to do this safely.
The best way to start is to insert an explicit memory barrier before and after each read and write of shared state. Then you can go one by one and remove those that aren't necessary. Of course, you should only need this in the doLock and unlock methods - the rest of simThread should be single-threaded.
For a short sample:
Thread.MemoryBarrier();
entering[pid] = true;
Thread.MemoryBarrier();
int max = 0;
for (int i = 0; i < threads; i++)
{
if (ticket[i] > ticket[max]) { max = i; }
}
Thread.MemoryBarrier();
ticket[pid] = 1+max;
Thread.MemoryBarrier();
entering[pid] = false;
Thread.MemoryBarrier();
So, which one of those is it safe to remove? I have no idea. I'd have to use a lot of mental power to make sure this is safe. Heck, I'm not sure if it's safe as is - do I need to rewrite the for cycle too? Are ticket[i] and ticket[max] going to be fresh enough for the algorithm to work? I know some are definitely needed, but I'm not sure which can safely be left out.
I'm pretty sure this will be slower than using a simple lock, though. For any production code, steer clear away from code like this - "smart" code usually gets you in trouble, even if everyone in your team understands it well. It's kind of hard finding those kinds of experts, and most of those wouldn't touch lock-less code like that with a meter-long stick :)
You must create a different random number for each thread (more details)
so try this code in your main method:
for (int i = 0; i < 10; i++)
{
int temp = i;
threadArray[i] = new Thread(() => simThread(temp));
Console.WriteLine("[He Thong] PID " + i.ToString() + " duoc khoi tao");
threadArray[i].Start();
Thread.Sleep(20);
}
and the following code in you threads:
Random rand = new Random((int) DateTime.Now.Ticks & 0x0000FFFF);
now you can ensure you produce different random number for each thread.
Try:
Random rnd = new Random(Environment.TickCount / (i + 1));
This will give different seeds to each RNG.
I am attempting to code a mini-game. I am new to C#. The first thing I want to do is have a string array that holds names of enemies.
string[] Opponents = new string[]
{
"enemy1", "enemy2", "enemy3", "enemy4", "enemy5", "enemy6", "enemy7", "enemy8", "enemy9", "enemy10", "enemy11", "enemy12", "enemy13", "enemy14", "enemy15", "enemy16", "enemy17", "enemy18", "enemy19", "enemy20", "enemy21", "enemy22", "enemy23", "enemy24", "enemy25", "enemy26", "enemy27", "enemy28", "enemy29", "enemy30", "enemy31", "enemy32", "enemy33", "enemy34", "enemy35", "enemy36", "enemy37"
};
I want to take this string and use the values to make waves of 5 enemies. Each time a wave is displayed, I would like to have 3 enemies removed and the next wave include 2 new enemies, placing them at the beginning of the wave. If the wave only has 3 enemies left, the next wave will have a new set of 5 (or whatever is left in he array) I would like it to look like this:
Wave 1: enemy1, enemy2, enemy3, enemy4, enemy5
Wave 2: enemy6, enemy7, enemy4, enemy5
Wave 3: enemy8, enemy9, enemy5
Wave 4: enemy10, enemy11, enemy12, enemy13, enemy14
etc...
This should be possible with any length of the array as the number of enemies later on will change.
I know I need to use a loop to do so, but I am having trouble...
This is what I have started with:
class Program
{
static void Main()
{
Game game = new Game();
game.Waves();
Console.ReadKey();
}
class Game
{
public void Waves()
{
string[] Opponents = new string[]
{
"enemy1", "enemy2", "enemy3", "enemy4", "enemy5", "enemy6", "enemy7", "enemy8", "enemy9", "enemy10", "enemy11", "enemy12", "enemy13", "enemy14", "enemy15", "enemy16", "enemy17", "enemy18", "enemy19", "enemy20", "enemy21", "enemy22", "enemy23", "enemy24", "enemy25", "enemy26", "enemy27", "enemy28", "enemy29", "enemy30", "enemy31", "enemy32", "enemy33", "enemy34", "enemy35", "enemy36", "enemy37"
};
string[] activeWave = new string[5];
Array.Copy(Opponents, 0, activeWave, 0, 5);
Console.WriteLine("Current wave of opponents: " + activeWave[0] + ", " + activeWave[1] + ", " + activeWave[2] + ", " + activeWave[3] + ", " + activeWave[4]);
}
}
}
Any help would be appreciated. Am I even on the right path?
I've drafted up a solution using queues. I'm not really that good at C#, so I'm sure there's a couple of syntax errors and typos, but I hope this gets you on the right track.
class Program{
string [] Opponents = ...;
int currentPlace = 0;
int curWaveNum = 0;
int newWaveSize = 5;
int newEnemiesPerWave = 2;
int enemiesRemovedPerWave = 3;
// Creates a queue, or a "FIFO" (First In, First Out) data structure.
Queue myQ = newQueue();
void addWave(){
// Remove enemies until you've gotten to enemiesRemovedPerWave, or until the
// wave is empty
for(int i = 0 ; i < enemiesRemovedPerWave ; i++){
if(myQ.count == 0){
break;
}
myQ.Dequeue();
}
// Set toAdd to be newWaveSize if the queue is empty, or newEnemiesPerWave if
// it's not empty
int toAdd = (myQ.count == 0 ? newWaveSize : newEnemiesPerWave);
// Add the enemies to the queue, from the Opponents array
for(int i = 0 ; i < toAdd ; i++){
// If there's only one enemy left in the Opponents array, only attempt
// to add one enemy to myQ
if(currentPlace + i >= Opponents.count){
break;
}
else{
// Actually add to the queue
myQ.enqueue(Opponents[currentPlace + i]);
}
}
// Update currentPlace. Note that you could have the above for loop be:
// for( ; currentPlace < currentPlace + toAdd ; currentPlace++)
// but I think how I wrote it is easier to understand
currentPlace += toAdd;
}
void printWave(){
Console.write("Wave %d: ", waveNum);
// Print everything but the last one
for(int i = 0 ; i < myQ.count - 1 ; i++){
Console.write(myQ[i] + ", ");
}
Console.write(myQ[myQ.count - 1] + "\n");
}
public void play(){
while(currentPlace < Opponents.count){
addWave();
printWave();
curWaveNum++;
}
}
}
The key to this is a data structure called a Queue. Think of it as an actual queue (line) at a store--the first people to get in line are served first. This is in contrast to a "LIFO" data structure, known as a Stack. A Stack behaves like, well, a stack of pancakes. When you make pancakes, you typically put the newest cooked ones on top, meaning the first pancake to bee taken will be the last one that was made, hence "LIFO," or "Last In, First Out."
You can read more about the functions defined for queues here!
Edit: Added printWave and play