C# Use timer to control program - c#

I am trying to create a console application similar to speedsum site. The speedsum is a website which is really useful and fun to test our own mathematical ability in 30s.
After giving few try-s I was just thought to create one small C# console application with same concept.
Following is my code which is working fine. But I could not display countdown ?!
My code:
static void Main(string[] args)
{
int testCount = 0;
Console.Write("\n Get.. Set... Go.... : This is a 30s test.. " +
"Once each problem is completed the time finished will be shown \n Good Luck.. :) \n \n");
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 1; i < 100000; i++)
{
if (watch.Elapsed.TotalSeconds >= 30)
break;
TimeSpan timeSpan = TimeSpan.FromSeconds(Convert.ToInt32(watch.Elapsed.TotalSeconds));
Console.Write($"\n {timeSpan.ToString("c")}" );
Random r = new Random();
int number1 = r.Next(10);
int number2 = r.Next(10);
int operation = r.Next(4);
var method = (operation > 2) ? '+' : '*';
int result = 0;
result = method == '+' ? (number1 + number2) : (number1 * number2);
Console.Write($" \n {number1} {method} {number2} = ");
var getAnswer = Convert.ToInt32(Console.ReadLine());
if (result == getAnswer)
{
testCount++;
continue;
}
else
break;
}
watch.Stop();
if(testCount >= 1 && testCount <=5)
Console.Write($"\n No Worries!! Try Hard ... \n you have solved {testCount} problems \n");
else if(testCount >=6 && testCount <=10)
Console.Write($"\n Good!! You can do well next time ... \n you have solved {testCount} problems \n");
else
Console.Write($"\n Awesome!! You are really a Genius ... \n you have solved {testCount} problems \n");
Console.Write("\n Thank you for playing with me... \n Enter a key to exit");
Console.Read();
}
I would like to get the countdown from 30s to 0s at,
Get.. Set... Go.... : This is a 30s test.. Once each problem is completed the time finished will be shown
Good Luck.. :)
<<Timer Should go here>> (30, 29... 0)
5 * 5 = 25 ...
This SO Question Showing how to get countdown into our program, But I am confused at how I can do both parallely countdown and giving problems.
Any suggestion would be helpful to me.

It looks like you want to use BackgroundWorker. Then, DoWork event will decrement amount of seconds left, while ProgressChanged event will report current progress. The advantage of this solution is that background worker is running async, so you will not block your main thread allowing the user to enter answer anytime they want.
private static int secondsLeft;
private static BackgroundWorker bgWorker;
static void Main(string[] args)
{
secondsLeft = 30;
bgWorker = new BackgroundWorker();
bgWorker.DoWork += bgWorker_DoWork;
bgWorker.ProgressChanged += bgWorker_ProgressChanged;
bgWorker.WorkerReportsProgress = true;
bgWorker.RunWorkerAsync();
Console.ReadLine();
}
private static void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (secondsLeft >= 0)
{
bgWorker.ReportProgress(secondsLeft);
Thread.Sleep(1000);
secondsLeft--;
}
}
private static void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Console.WriteLine($"Seconds left: {e.ProgressPercentage}");
}

Related

Keep changing text in same place C# console

I am creating a quiz with a timer. After asking for the number of questions they want to answer and the time for answering the questions, I would like to show a timer that keeps counting down on the same line. Below the timer I would like to show all the quiz questions.
However every time a question is asked, the timer appears on the new line.
I have already tried following this question, but it doesn't fix my problem. How can I update the current line in a C# Windows Console App?
public class GamePlay
{
private static int _secondPassed;
private static int _timeForAnswering;
private static bool _isTimerFinished;
private static void Timing()
{
Timer timer = new Timer(TimerCallback, null, 0, 1000);
Console.ReadKey();
}
private static void TimerCallback(Object o)
{
if (_secondPassed >= _timeForAnswering)
{
_isTimerFinished = true;
}
else
{
_isTimerFinished = false;
_secondPassed++;
Console.Write($"\rYou have {_timeForAnswering - _secondPassed} seconds left.");
}
}
public static async Task PlayGame(int numberOfQuestions, int timeForAnswering)
{
_timeForAnswering = timeForAnswering;
Random random = new Random();
await Task.Run(() => Timing());
for (int q = 1; q < numberOfQuestions + 1; q++)
{
if (_isTimerFinished)
{
Console.WriteLine();
Console.WriteLine("Game Over!");
break;
}
else
{
Console.WriteLine();
Console.WriteLine(/* Ask Question */);
// Get Answer
double usersAnswer = Console.ReadLine();
}
}
}
}
Console.SetCursorPosition is the way to go. With that you can modify any line in the Console.
https://learn.microsoft.com/de-de/dotnet/api/system.console.setcursorposition?view=net-6.0

How should I fix my runTime method to both subtract from my timeLeft variable/ return remaining time?

Sup, I am completely new to stackOverflow and I started to learn how to do C# during my class. For my final project, I'm doing a reaction game where you have to press the key t as fast as possible before the timer. However, one major issue came up. I tried using a timer method and had a variable inside of it called timeLeft. What I want to happen is that as soon as the user presses t, the time stops and it shows you the remaining time. However what I get instead is that no matter what, the computer doesn't take the key and tells you that you ran out of time. I didn't know where else to put this question in, but I felt like this is a good spot. The project is made in C# and with visual studio. My code is below, and if there is anything i should change or do for this project, let me know. Thank you!
static void Main(string[] args)
{
string starter;
ConsoleKeyInfo stopper;
Console.WriteLine("Welcome to REFLEX. Check how fast are those hands?");
Console.WriteLine("When you are ready to start, type start");
starter = Console.ReadLine();
if (starter.ToLower() == "start")
{
Console.WriteLine("Go");
Console.WriteLine("Press t to stop timer!");
stopper = Console.ReadKey();
Console.WriteLine(RunTimer(stopper));
}
else
{
Console.WriteLine("what are you doing? You have one more chance, otherwise restart");
Console.WriteLine("Welcome to REFLEX. Check how fast are those hands?");
Console.WriteLine("When you are ready to start, type start");
starter = Console.ReadLine();
if (starter.ToLower() == "start")
{
Console.WriteLine("Go");
Console.WriteLine("Press t to stop timer!");
stopper = Console.ReadKey();
Console.WriteLine(RunTimer(stopper));
}
else
{
Console.WriteLine("That's it, no more!");
}
}
}
static string RunTimer(ConsoleKeyInfo stopper)
{
int timeLeft;
for (timeLeft = 450000000; timeLeft > 0; timeLeft--)
{
while (stopper.Key != ConsoleKey.T)
{
do
{
stopper = Console.ReadKey();
Console.WriteLine(RunTimer(stopper));
}
while (timeLeft > 0);
}
}
if (timeLeft == 0)
{
return "Sorry, you ran out of time, try again!";
}
else
{
return "Congrats you won. You had " + timeLeft + " milseconds left";
}
}
The below should work for you, it will block until a key is pressed at Console.ReadKey, if you wanted to overcome this you would need to make it multithreaded but thats likely a problem for another day.
static string RunTimer()
{
int maxTime = 450000000;
ConsoleKeyInfo keyPressed;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
do
{
keyPressed = Console.ReadKey();
}
while (stopwatch.Elapsed.Milliseconds < maxTime && keyPressed.Key != ConsoleKey.T);
stopwatch.Stop();
if (stopwatch.Elapsed.Milliseconds < maxTime)
{
return "Sorry, you ran out of time, try again!";
}
else
{
int timeLeft = maxTime - stopwatch.Elapsed.Milliseconds;
return "Congrats you won. You had " + timeLeft + " milseconds left";
}
}
To Use it change this
if (starter.ToLower() == "start")
{
Console.WriteLine("Go");
Console.WriteLine("Press t to stop timer!");
stopper = Console.ReadKey();
Console.WriteLine(RunTimer(stopper));
}
to
if (starter.ToLower() == "start")
{
Console.WriteLine("Go");
Console.WriteLine("Press t to stop timer!");
Console.WriteLine(RunTimer());
}

On key down, abort a thread

I've just started learning C# and I'm trying to figure out threads.
So, I've made a two threads and I would like to stop one of them by pressing x.
So far when I press x it only shows on the console but it doesn't abort the thread.
I'm obviously doing something wronng so can someone please point out what I'm doing wrong? Thank you.
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
//Creating Threads
Thread t1 = new Thread(Method1)
{
Name = "Thread1"
};
Thread t4 = new Thread(Method4)
{
Name = "Thread4"
};
t1.Start();
t4.Start();
Console.WriteLine("Method4 has started. Press x to stop it. You have 5 SECONDS!!!");
var input = Console.ReadKey();
string input2 = input.Key.ToString();
Console.ReadKey();
if (input2 == "x")
{
t4.Abort();
Console.WriteLine("SUCCESS! You have stoped Thread4! Congrats.");
};
Console.Read();
}
static void Method1()
{
Console.WriteLine("Method1 Started using " + Thread.CurrentThread.Name);
for (int i = 1; i <= 5; i++)
{
Console.WriteLine("Method1: " + i);
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine("Method1 Ended using " + Thread.CurrentThread.Name);
}
static void Method4()
{
Console.WriteLine("Method4 Started using " + Thread.CurrentThread.Name);
for (int i = 1; i <= 5; i++)
{
Console.WriteLine("Method4: " + i);
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine("Method4 Ended using " + Thread.CurrentThread.Name);
}
It looks like you have a extra Console.ReadKey(); before if (input2 == "x"), that extra read causes the program to stop and wait before going inside your if statement waiting for a 2nd key to be pressed.
Also input.Key returns a enum, when you do the to string on it the enum will use a capital X because that is what it is set to. Either use input.KeyChar.ToString() to convert it to a string or use
var input = Console.ReadKey();
if (input.Key == ConsoleKey.X)
To compare against the enum instead of a string.
I also recommend you read the article "How to debug small programs", debugging is a skill you will need to learn to be able to write more complex programs. Stepping through the code with a debugger you would have seen input2 was equal to X so your if statement was
if ("X" == "x")
which is not true.

Is there a way to add a countdown to a .net console?

I am learning c# and I was trying to test my abilities by making a short game using the .net framework console. I want to make it so that if you don't type "(the thing the player needs to type)" within x amount of time, then they fail, and they go to the death screen.
I have tried looking up stuff like the System.Threading.CountdownEvent, Systen.Threading.Timer and System.Timers.Timer etc, but all the tutorials don't help.
tutorialfight:
if (fight == "Y")
{
Console.WriteLine("Goblin: 'You seem week, hit me first!'");
}
else if (fight == "N")
{
Console.WriteLine("This is the tutorial, you have no choice, Would you like to fight? (Y/N)");
fight = Console.ReadLine();
goto tutorialfight;
}
else
{
Console.WriteLine("Type Y for yes or N for no");
fight = Console.ReadLine();
goto tutorialfight;
}
int goblinhp = 5;
Console.WriteLine("Misery: 'Type what is says to do some damage. If you fail, you take some damage, and if you dont kill the enemy within the amount of time allowed, you die!'");
Console.WriteLine("Type 'x3hu' in 10 seconds to deal 1 damage");
string x3hu = Console.ReadLine();
if (x3hu != "x3hu")
{
Console.WriteLine("Your health went down 3 points!");
health = health - 3;
Console.WriteLine("Health: " + health);
Console.WriteLine("Misery: 'Dont worry, you've still got loads of health left!'");
}
else
{
goblinhp = goblinhp - 1;
Console.WriteLine("Goblin health: " + goblinhp);
Console.WriteLine("Misery: 'Great job!'");
}
It seems like you already have a grasp of what you need:
Some way of detecting Console input is available to read
Some way of setting a timeout for user input
You should be able to accomplish this by using the Console.KeyAvailable property and tracking the elapsed time of a Stopwatch.
The pseudo code would go something like this:
Console.WriteLine("You have 10 seconds to press attack (x)");
var timeout = 10;
StopWatch.Start();
while(Stopwatch.Elapsed.Seconds < timeout && !Console.KeyAvailable)
{
// wait
}
// process which event happened first
The conditions and looping logic could vary but this should be enough to get you headed in the right direction :)
KeyAvailable documentation
Stopwatch documentation
I made a simple solution based on Dawid Owens' answer.
class Program
{
static async Task Main(string[] args)
{
var timeout = 10;
var textToWrite = "Hello World!";
bool isTimeIsUp = false;
bool returnPressed = false;
StringBuilder enteredText = new StringBuilder();
Console.WriteLine($"You have {timeout} seconds to write: '{textToWrite}'");
Stopwatch stopwatch = Stopwatch.StartNew();
while (!returnPressed)
{
while (!isTimeIsUp && !Console.KeyAvailable)
{
isTimeIsUp = stopwatch.Elapsed.Seconds >= timeout;
}
if (isTimeIsUp) break;
var ch = Console.ReadKey();
returnPressed = ch.Key == ConsoleKey.Enter;
if (!returnPressed)
{
enteredText.Append(ch.KeyChar);
}
}
if (isTimeIsUp || enteredText.ToString() != textToWrite)
{
Console.WriteLine($"\nFailure!");
}
else
{
Console.WriteLine($"\nSuccess!");
}
}
}

How to make an efficient Console Updater

Currently i wanna display the following variable
Total Item
Total Execution
Finish Status
using System;
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
int TotalValue = 250; // Total Item Example
int TotalExecution = 0;
bool Finish_Status = false;
for (int i = 0; i < TotalValue; ++i)
{
//Do Work Here
System.Threading.Thread.Sleep(10); // Example Work
TotalExecution++;
if (TotalValue - TotalExecution == 0)
{
Finish_Status = true;
}
Console.Clear();
Console.Write("Progression Info\n Total Item : {0}\n Execution Total : {1}\n Remaining : {2}\n Finish_Status : {3}", TotalValue,TotalExecution, TotalValue - TotalExecution, Finish_Status); // Display Information To Console
}
Console.ReadLine();
}
}
}
The result is good,however i was wondering if theres a much more efficient way of doing this,preferably updating it without using Console.Clear();
You can use Console.SetCursorPosition to move the cursor around the console buffer for each write, rather than clearing the console each time.
For example:
using System;
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
int TotalValue = 250; // Total Item Example
int TotalExecution = 0;
bool Finish_Status = false;
Console.Write("Progression Info\n Total Item : \n Execution Total : \n Remaining : \n Finish_Status : ");
for (int i = 0; i < TotalValue; ++i)
{
//Do Work Here
System.Threading.Thread.Sleep(10); // Example Work
TotalExecution++;
if (TotalValue - TotalExecution == 0)
{
Finish_Status = true;
}
Console.SetCursorPosition(26, 1);
Console.Write(TotalValue);
Console.SetCursorPosition(31, 2);
Console.Write(TotalExecution);
Console.SetCursorPosition(25, 3);
Console.Write(TotalValue - TotalExecution);
Console.SetCursorPosition(29, 4);
Console.Write(Finish_Status);
}
Console.ReadLine();
}
}
}
Disclaimer: Obviously the above is quick 'n' dirty, and would benefit from substantial refinement, but you get the idea.
Welcome kepanin_lee
I think you are looking for something like this.
//Console.Clear()
Console.Write(vbCr & "Progression Info\n...
Just start with vbCr, by this way you force to start on the beginning of the same line, so you only overwrite the last line, without clear all the screen.

Categories