Horse Racing Console App. Simulation - C# - c#

I have a project which involves simulating a horse race and reporting who comes first, second and third. I have gone all of the way up to making a random number for each measure of distance and whichever horse has the highest total number wins. I am having trouble putting the first, second and third place down right. I have the total in an array and I'm not quite sure where to go with it now.
Console.Write ("Type 'Begin' to start the race. ");
string startRace = Console.ReadLine ();
if (startRace == "Begin")
{
Console.Clear ();
Console.WriteLine ("You may now begin the race.");
Console.Clear ();
int[] tot = new int[numberOfHorses];
for (int i = 0; i < numberOfHorses; i++)
{
Console.Write (string.Format("{0, 10}: ", horseName[i]));
int total = 0;
for (int n = 1; n <= furlongs; n++)
{
int randomNum = rnd.Next (0, 10);
Console.Write (" " + randomNum + " ");
total = total + randomNum;
}
tot[i] = total;
Console.Write (" | " + total);
Console.WriteLine (" ");
} //This is where I start to get unsure of myself.
int firstPlace = Int32.MinValue
for (int place = 0; place < numberOfHorses; place++)
{
if (tot[place] > firstPlace)
{
firstPlace = tot[place];
}
}
}
'numberOfHorses' is how many horses the user has decided to race and 'horseName' is what the user has named each horse. Thanks. :)

You need a sorting function. Instead of:
int firstPlace = Int32.MinValue
for (int place = 0; place < numberOfHorses; place++)
{
if (tot[place] > firstPlace)
{
firstPlace = tot[place];
}
}
try this:
int[] horseIndexes = new int[numberOfHorses];
for (int place = 0; place < numberOfHorses; place++)
{
horseIndexes[place] = place ;
}
// this is the sorting function here
// (a,b) => tot[b] - tot[a]
// it will sort in descending order
Array.Sort(horseIndexes, (a,b) => tot[b] - tot[a]);
for (int place = 0; place < horseIndexes.Length && place < 3; place++)
{
Console.WriteLine("place: " + (place+1));
Console.WriteLine("horse: " + horseName[horseIndexes[place]);
Console.WriteLine("total: " + tot[horseIndexes[place]);
}
There are better ways of doing this using LINQ expressions, but hopefully this example is the most understandable.

Emerald King should already know how to find the highest number in a list. Take the top number out (set it to 0) then repeat the process to find second, and again to find third.

Related

C# Display loop iteration on single line in console

So im using a for loop to loop through all rows in an excel spreadsheet and i can display the current row number very easily by just using the "i" definition, however it prints on multiple lines since each iteraton displays with a Console.WriteLine() command.
What i would like is for it to only show it once, and have it display an updated iteration on one single line. Here is my current code:
void DeleteCells(string filePath)
{
int currRowNumber = 0;
// create excel-instance:
Application excel = new Application();
// open the concrete file:
Workbook excelWorkbook = excel.Workbooks.Open(#filePath);
// select worksheet. NOT zero-based!!:
_Worksheet excelWorkbookWorksheet = excelWorkbook.ActiveSheet;
if(isclosing)
{
closeProgram(excel, excelWorkbook);
}
int numRows = excelWorkbookWorksheet.UsedRange.Rows.Count;
Console.WriteLine("Number of rows: " + numRows);
Console.Write("Checking Row #: " + currRowNumber);
int numRowsDeleted = 0;
int nullCounter = 0;
//for (int j = 1; j <=)
for (int i = 1; i < numRows + 4; i++)
{
//We want to skip every row that is null and continue looping until we have more than 3 rows in a row that are null, then break
if (i > 1)
{
i -= 1;
}
//Create Worksheet Range
Microsoft.Office.Interop.Excel.Range range = (Microsoft.Office.Interop.Excel.Range)excelWorkbookWorksheet.Cells[i, 2];
string cellValue = Convert.ToString(range.Value);
if (nullCounter == 5)
{
Console.WriteLine("Null row detected...breaking");
Console.WriteLine("Number of rows deleted: " + numRowsDeleted);
break;
}
if (cellValue != null)
{
if (cellValue.Contains("MESSAGE NOT CONFIGURED"))
{
//Console.WriteLine("Deleting Row: " + Convert.ToString(cellValue));
((Range)excelWorkbookWorksheet.Rows[i]).Delete(XlDeleteShiftDirection.xlShiftUp);
numRowsDeleted++;
//Console.WriteLine("Number of rows deleted: " + numRowsDeleted);
nullCounter = 0;
i--;
currRowNumber++;
}
else
{
currRowNumber++;
nullCounter = 0;
}
}
else
{
nullCounter++;
//Console.WriteLine("NullCounter: " + nullCounter);
}
i++;
}
Console.WriteLine("Fixes Finished! Please check your excel file for correctness");
closeProgram(excel, excelWorkbook);
}
Sample output:
Row Number: 1
Row Number: 2
Row Number: 3
Row Number: 4
Row Number: 5
etc..
I want it to display only one line and continuously update the row number. How would i go about doing this? Any help is appreciated. Thanks.
UPDATE:
So i have the following loop:
for (int i = 1; i < numRows + 2; i++) //numRows was +4, now +2
{
Console.Clear();
Console.WriteLine("Number of rows: " + numRows);
Console.Write("Checking Row #: " + currRowNumber);
//We want to skip every row that is null and continue looping until we have more than 3 rows in a row that are null, then break
if (i > 1)
{
i -= 1;
}
//Create Worksheet Range
Microsoft.Office.Interop.Excel.Range range = (Microsoft.Office.Interop.Excel.Range)excelWorkbookWorksheet.Cells[i, 2];
string cellValue = Convert.ToString(range.Value);
if (nullCounter == 3) //was 5
{
Console.WriteLine("\nNull row detected...breaking");
Console.WriteLine("Number of rows deleted: " + numRowsDeleted);
break;
}
if (cellValue != null)
{
if (cellValue.Contains(searchText))
{
//Console.WriteLine("Deleting Row: " + Convert.ToString(cellValue));
((Range)excelWorkbookWorksheet.Rows[i]).Delete(XlDeleteShiftDirection.xlShiftUp);
numRowsDeleted++;
//Console.WriteLine("Number of rows deleted: " + numRowsDeleted);
nullCounter = 0;
i--;
currRowNumber++;
rowsPerSecond = i;
}
else
{
currRowNumber++;
nullCounter = 0;
}
}
else
{
nullCounter++;
//Console.WriteLine("NullCounter: " + nullCounter);
}
i++;
}
I want to calculate how many rows im looping through per second, then calculate from that number how long it will take to complete the entire loop, based on how many rows there are.
Again, any help is appreciated, thanks!
On each loop circle use the Clear() method before print output:
Console.Clear();
You could do this:
const int ConsoleWidth = 80;
for(int i = 0; i < 10; i++)
{
// pull cursor to the start of the line, delete it with spaces
// then pull it back again
for(int j = 0; j < ConsoleWidth; j++) Console.Write("\b");
for(int j = 0; j < ConsoleWidth; j++) Console.Write(" ");
for(int j = 0; j < ConsoleWidth; j++) Console.Write("\b");
Console.Write("Row Number: {0}", i);
}
If you do
Console.Write("Row Number: {0}", i);
It will keep appending in front of previous text.
If you do
Console.Clear();
Any message that you intend to write before this text will dissapear.
If you know the exact position of the text, you can try to modify the text in console at that position as:
// First time write
Console.WriteLine("Row Number: {0}", i);
// x,y coordinates in the method for later iterations
Console.SetCursorPosition(11, 0);
Console.Write(i);
If the amount of text in the row will never decrease (e.g. because the number only ever gets bigger) you can do this by using Console.Write() and prefixing the text with \r:
for (int i = 0; i < 100000; ++i)
Console.Write($"\rRow Number: {i}");
Console.WriteLine();
If the text decreases in length because the number gets smaller, you can use a formatting string to output the number left-justified with extra spaces which will overwrite the extra digits:
for (int i = 100000; i >= 0; --i)
Console.Write($"\rRow Number: {i, -6}");
Console.WriteLine();
Doing it this way has the advantage that you keep any previous text in the console and only update the single line. This also makes it a lot quicker compared to clearing the entire display every iteration.
try to use Console.SetCursorPosition before Console.Write
You can do as the previous answers suggested, here is another way.
int line = Console.CursorTop;
int len = new String("Row Number: ").length;
Console.WriteLine("Row Number: ");
for(your loop)
{
Console.WriteLine(i);
//Print whatever else you want!
Console.SetCursorPosition(len,line);
}
Advantage of this approach is that the position is remembered and you can come back to the same position after displaying any other information to the user, This is useful when updating a single character in a screen full of text!
To answer the next question, use
Stopwatch s = new Stopwatch();
long millis =0,avg;
for(int i=0;i<loopLength;i++)
{
s.Start();
//Do work
s.Stop();
millis += s.ElapsedMilliseconds;
avg = millis/(i+1);
Console.WriteLine("Time remaining :" + (TimeSpan.FromMilliseconds(avg*(loopLength - (i+1))).Seconds);
}

Counting times values occured in Array

I am having a hard time with a program I need to write. The requirements are that the user enters in the size of the Array. Then they enter the elements of the array after this the program needs to display the values entered then how many times each value occurs. While everything seems to work except its not display the "occurs" part properly. Lets say "1 1 2 3 4" is entered (Array size being 5) It prints
1 occurs 1 time.
1 occurs 1 time.
2 occurs 1 time.
3 occurs 1 time.
4 occurs 2 times.
this isn't right because 1 occured 2 times and 4 is only 1 time. Please Help...
static void Main(string[] args)
{
int[] arr = new int[30];
int size,
count=0,
count1=0,
count2=0;
Console.Write("Enter Size of the Array: ");
size = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter the elements of an Array: ");
for (int i=0; i < size; i++)
{
arr[i] = Convert.ToInt32(Console.ReadLine());
}
Console.Write("Values Entered: \n");
for (int i = 0; i < size; i++)
{
Console.WriteLine(arr[i]);
if (arr[i] <= 10)
count++;
else
count1++;
}
for(int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
if (arr[i] == arr[j])
count2++;
else
count2 = 1;
}
Console.WriteLine(arr[i] + " Occurs " + count2 + " Times.");
}
Console.WriteLine("The number of valid entries are: " + count + "\nThe number of invalid entries are: " + count1);
Console.ReadKey();
}
if you can use Linq, this is easy job:
After
Console.Write("Values Entered: \n");
add
var grouped = arr.GroupBy(x => x);
foreach (var group in grouped)
{
Console.WriteLine("number {0} occurs {1} times", group.Key, group.Count());
}
EDIT
Since OP isn't allowed to use Linq, here's array-only solution. Much more code than that dictionary approach, but with arrays only.
Console.Write("Values Entered: \n");
//an array to hold numbers that are already processed/counted. Inital length is as same as original array's
int[] doneNumbers = new int[arr.Length];
//counter for processed numbers
int doneCount = 0;
//first loop
foreach (var element in arr)
{
//flag to skip already processed number
bool skip = false;
//check if current number is already in "done" array
foreach (int i in doneNumbers)
{
//it is!
if (i == element)
{
//set skip flag
skip = true;
break;
}
}
//this number is already processed, exit loop to go to next one
if (skip)
continue;
//it hasn't been processed yes, so go through another loop to count occurrences
int occursCounter = 0;
foreach (var element2 in arr)
{
if (element2 == element)
occursCounter++;
}
//number is processed, add it to "done" list and increase "done" counter
doneNumbers[doneCount] = element;
doneCount++;
Console.WriteLine("number {0} occurs {1} times", element, occursCounter);
}
You can simply use dictionary:
static void Main(string[] args)
{
var dic = new Dictionary<int, int>();
Console.Write("Enter Size of the Array: ");
int size = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter the elements of an Array: ");
for (int i = 0; i < size; i++)
{
int val = Convert.ToInt32(Console.ReadLine());
int current;
if (dic.TryGetValue(i, out current))
{
dic[val] = current + 1;
}
else
{
dic.Add(val, 1);
}
}
foreach (int key in dic.Keys)
{
Console.WriteLine(key + " Occurs " + dic[key] + " Times.");
}
Console.Read();
}
The problem is that you're resetting count2 to 1 any time you find a mismatch.
What you should do instead is set count2 to 0 in the outer loop (so it basically resets once for each item), and then let the inner loop count all the instances of that number:
// For each item 'i' in the array, count how many other items 'j' are the same
for (int i = 0; i < size; i++)
{
count2 = 0; // processing a new item, so reset count2 to 0
for (int j = 0; j < size; j++)
{
if (arr[i] == arr[j]) count2++;
}
Console.WriteLine(arr[i] + " occurs " + count2 + " times.");
}

Find sum of elements of an array

What calculations do I need to find the total?
else if (a =2) {
TotalCredit = new int[15];
Console.WriteLine("please enter the credits");
int i = 0;
for (i = 0; i < 15; i++) {
int Credit = Convert.ToInt32(Console.ReadLine());
Total + Credit;
}
Console.WriteLine(Total);
}
You need to declare the variable Total ahead it use and it should be before loop to keep its scope available after loop. More than that your sum operation should be corrected using += operator
Correct it as follows:
int Total=0;
for (i = 0; i < 15; i++)
{
int Credit = Convert.ToInt32(Console.ReadLine());
Total += Credit;
}
Console.WriteLine(Total);
Try this.
else if (a ==2)
{
int[] TotalCredit = new int[15];
Console.WriteLine("please enter the credits");
int i = 0;
int Total = 0;
for (i = 0; i < 15; i++)
{
int Credit = Convert.ToInt32(Console.ReadLine());
Total += Credit;
}
Console.WriteLine(Total);
}
I've added this line int Total = 0; to declare a variable Total with the value 0, to store the total there.
Then I've changed a line in the for to be Total += Credit; which is the same as Total = Total + Credit; so every new value will be added and store into the variable Total.
This is a C# I guess, as convention https://msdn.microsoft.com/en-us/library/ff926074.aspx you'd better declare the variables to be lowercase.
As you have declared an array of ints I'm going to assume you want to keep the actual values the user has entered and not just the total. Make sure you add System.Linq in your using clauses.
else if (a==2)
{
var totalCredit = new int[15];
Console.WriteLine("please enter the credits");
for (int i = 0; i < 15; i++)
totalCredit[i] = Convert.ToInt32(Console.ReadLine());
var total = totalCredit.Sum();
Console.WriteLine (total);
}
A good idea would be to validate input gracefully, and minimize duplication of the magic constant 15—even better would be to assign it a meaningful name (the same goes for the a variable). Also, if you intend to store each input into the array for later usage outside of the else if block, you'll need to declare it outside of said block. However, if you do not need the individual credit values, the array is unnecessary.
const int numberOfCredits = 15;
int[] credits = new int[numberOfCredits];
...
else if (a == 2)
{
int total = 0;
int count = 0;
while (count < numberOfCredits)
{
Console.WriteLine("Enter credit #" + (count + 1).ToString() + ":");
int input;
if (int.TryParse(Console.ReadLine(), out input))
{
credits[count] = input;
total += input;
count += 1;
}
}
Console.WriteLine(total);
}

Trying to find the average amount of attempt it takes for Tom to roll a six on: 10 repetitions

It takes the total number of rolls and divides them by 10. For example, if it took 56 rolls so my average is 5.6.
Random numGen = new Random ();
int numOfAttempt = 0;
int Attempt = 0;
int avrBefore = 0;
int avrAfter = 0;
for (int i = 1; i <= 10; i++)
do {
Attempt = numGen.Next (1, 7);
Console.WriteLine (Attempt);
numOfAttempt++;
avrBefore = numOfAttempt;
avrAfter = avrBefore / 10;
} while (Attempt != 6);
Console.WriteLine ("He tried " + numOfAttempt + " times to roll a six.");
Console.WriteLine ("The average number of times it took to get a six was " + avrAfter);
Console.ReadKey ();
maybe you need to reset the vars inside the for loop, before the while:
for (int i = 1; i <= 10; i++){
int numOfAttempt = 0;
int Attempt = 0;
int avrBefore = 0;
int avrAfter = 0;
do {//your code
You are diving by ten at the wrong time.
You are dividing by ten even when you haven't done ten iterations.
This code below instead shows the correct average at each iteration.
void Main()
{
Random numGen = new Random ();
int totalAttempts = 0;
for (int i = 1; i <= 10; i++)
{
int attempts = 0;
int attempt = 0;
do {
attempt = numGen.Next (1, 7);
attempts++;
} while (attempt != 6);
totalAttempts+=attempts;
Console.WriteLine ("He tried " + attempts + " times to roll a six.");
Console.WriteLine ("The average number of times it took to get a six was " + (double)totalAttempts / i);
}
}
So you want to know how many times it took to get a six. This is quite simple. You just have to save how many times you rolled the dices and how many times you got a six.
Random numGen = new Random ();
int attempt = 0;
int numOfAttempt = 0;
int numberOfSixes = 0;
int i;
for (i = 0; i < 10; i++) {
do {
attempt = numGen.Next (1, 7);
Console.WriteLine (Attempt);
numOfAttempt++;
} while (Attempt != 6);
numberOfSixes++;
}
Console.WriteLine ("He tried " + numOfAttempt + " times to roll a six.");
Console.WriteLine ("The average number of times it took to get a six was " + (numberOfAttempt/numberOfSixes));
Console.ReadKey ();
I hope you understand my approach.
I would appreciate it if you could elaborate your thought process behind avrBefore,avrAfter and divide by 10. I didn't get that.
You can shorten down the code a lot and get it correct:
Random numGen = new Random();
int numOfAttempt = 0;
for (int i = 0; i < 10; i++)
{
int attempt = 0;
while (attempt != 6)
{
attempt = numGen.Next(1, 7);
Console.WriteLine (attempt );
numOfAttempt++;
}
}
Console.WriteLine("He tried " + numOfAttempt + " times to roll a six.");
Console.WriteLine("The average number of times it took to get a six was " + numOfAttempt / 10.0);
Console.ReadKey();

Stuck on how to make my scoring system work

So I am making a guess the word game in a windows form program in C#, and one of the requirements are that I must include a scoring system. (start out with 100 points, each time a wrong letter is guessed 10 points are subtracted from the total 100 and if you guess right it adds 10 to the total 100.) I have everything else working except for the points. I could really use some help as to how to fix this problem. Mind taking a look?`
public void CheckLetter(string word)
{
lblWord.Text = "";
corLetter += word[0];
score = score;
int amountToUpdate = 0;
score = score + amountToUpdate;
for (int i = 0; i < mysteryWord.Length; i++)
{
count = 0;
for (int j = 0; j < corLetter.Length; j++)
{
if (corLetter[j]== mysteryWord[i])
{
lblWord.Text += corLetter[j].ToString().ToUpper();
count++;
}
}
if (count == 0)
{
lblWord.Text += "_ ";
}
}
bool letterInWord = false;
for (int i = 0; i < word.Length; i++)
{
if (rtbGuess.Text == mysteryWord[i].ToString())
{
letterInWord = true;
}
}
score = score + amountToUpdate;
lblPoints.Text = (score).ToString();
if (!letterInWord)
{
lblPoints.Text = (score = score - 10).ToString();
}
}`
What exactly isn't working about the score? I just wrote some code up real quick, and had the score working fine. I see lots of things in your code I don't understand though, like:
score = score;
int amountToUpdate = 0;
score = score + amountToUpdate;
at the beginning, and:
score = score + amountToUpdate;
lblPoints.Text = (score).ToString();
at the end. Some of your variable names help, like rtbGuess tell me the guesses are typed into a rich text box.
Anyway, your code checks if the letter is incorrect, but not if it IS correct:
if (!letterInWord)
{
lblScore.Text = (int.Parse(lblScore.Text) - 10).ToString();
}
else
{
lblScore.Text = (int.Parse(lblScore.Text) + 10).ToString();
}

Categories