C# Timer-Crop farming game error - c#

I have a short question about timers. In my code I want to create a crop farming game, with a timer that shows if the plant is finished.
Why does this:
public static string currentPlant;
public static Timer growTimer;
public static void InitGrowTimer( int time, string name )
{
growTimer = new Timer();
growTimer.Tick += new EventHandler(growTimer_Finished);
growTimer.Interval = time;
currentPlant = name;
}
public static void plantCrop(string crop)
{
if (plantActive == false)
{
if (plants.Contains(crop.ToLower()))
{
// growTimer.Interval = <plant>Time;
// proceed plants
switch (crop.ToLower())
{
case "wheat":
InitGrowTimer(wheatTime, wheatName);
growTimer.Start();
break;
default:
MessageBox.Show("FATAL ERROR\nThe plant is contained in the definition list but not in the plant menu!", "Civilisation", MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
}
}
else
{
MessageBox.Show("This plant is not available!", "Civilisation", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("There is already a plant in progress! Current plant: {0}", currentPlant);
}
}
private static void growTimer_Finished (object sender, EventArgs e)
{
growTimer.Stop();
MessageBox.Show("Your " + currentPlant + " is finished!", "Civilisation", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
not start the timer, or just doesnt show the messagebox at the end. What am I doing wrong at creating the timer or creating the tick event?
EDIT: This is my main method:
static void Main(string[] args)
{
InitializeLists();
// game begin
Farm.plantCrop("wheat");
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("Please enter your desired name: ");
QC.resetColors();
name = Console.ReadLine();
Console.WriteLine(/*Introduction*/"Welcome to the world of Civilisation. In this world it is your choice what\n" +
"you are up to. You can be a farmer, miner or fighter, whatever you want, the\n" +
"world is yours to explore! Have fun!"
);
Console.ReadKey();
Console.Clear();
while (true) // run game
{
// menu
Console.Write(" What do you want to do?\n" +
"Farm Mine Explore Go to the city\n"
);
input = Console.ReadLine();
if (menuContent.Contains(input.ToLower()))
{
if (input.ToLower() == menuContent.ElementAt(0))
{
// farm
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("-- Farm --\nSelect a crop to plant:");
Console.ForegroundColor = ConsoleColor.DarkGreen;
int icount = 0;
for ( int i = 0; i < Farm.plants.Count; i++)
{
if (icount < 3)
{
Console.Write(Farm.plants.ElementAt(i));
Console.Write("\t\t");
icount++;
}
else
{
Console.Write("\n");
icount = 0;
Console.Write(Farm.plants.ElementAt(i));
Console.Write("\t\t");
icount++;
}
}
Console.WriteLine();
QC.resetColors();
string crop = Console.ReadLine();
Farm.plantCrop(crop);
}
if (input.ToLower() == menuContent.ElementAt(1))
{
// miner
}
if (input.ToLower() == menuContent.ElementAt(2))
{
// fight
}
}
}
}

The System.Windows.Forms.Timer timer is made for a Windows Form app with a single UI thread.
You need to use the System.Threading.Timer timer instead for your console application.
It's creation and the parameters of the callback are a little different:
public static void InitGrowTimer(int time, string name)
{
growTimer = new System.Threading.Timer(GrowTimer_Finished, null, time, Timeout.Infinite);
currentPlant = name;
}
private static void GrowTimer_Finished(object sender)
{
MessageBox.Show("Your " + currentPlant + " is finished!", "Civilisation", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
You do not need any Startmethod, it will be started automatically on creation.
You don't need a Stop either; it will run only once because of the Timeout.Infinite parameter.
You can replace null with the object you want the callback to receive, if needed (i.e. what would have been in EventArgs).
Little side note: I've renamed your callback method in PascalCase. Per convention, the methods in C# should always start with a capital letter.

Because you, as you tell yourself, do not start the timer.
growTimer = new Timer();
growTimer.Tick += new EventHandler(growTimer_Finished);
growTimer.Interval = time;
growTimer.Start();

Related

Struggling to implement a timer to my C# CONSOLE Typing Game

The goal of my current Typing Game feature (code provided below) is to countdown from either 10(hard), 20(medium), or 30(easy), depending on the users difficulty selection once the game has started. Once the countdown reaches zero OR the user runs out of lives, the game is over (which stops the countdown). The game starts properly, displays the first word to be typed by the user, and begins counting down from 10. My current problem is that I can't figure out how to stop the timer from counting down past 0. I have tried using t.Change(Timeout.Infinite , Timeout.Infinite) and checking when timeLeft == 0 with no prevail. I really feel like I am overthinking this (or underthinking), some help or a nudge in the right direction would be greatly appreciated!
my code is provided below:
class Program
{
// List of words to be typed
public static string[] words = { "some", "side", "add", "another", "would", "book" ,"water", "came" ,"your" ,"big","both", "from", "learn", "been", "me" ,"school" ,"land", "took", "place",
"try", "line", "tell", "earth", "can", "do","children", "without", "my", "must", "take", "follow", "year", "is", "being", "different", "miss", "could", "on", "he", "open", "night", "were",
"line","said", "around", "an", "plant", "know", "set","been", "life","young","of", "face", "we", "hand", "while", "is", "white", "call", "live","may", "study","after" ,"down", "him", "now", "different",
"could", "over", "work","all", "mean","begin","go","fall", "really", "oil", "before","into","one","name","has","a", "well", "got","something","turn" };
// Keeps track of words array
public static int numWords = 88;
public static int correctWords = 0;
// Initialize our random number generator
public static Random rand = new Random();
// Handles user input
public static string userInput = "";
public static string endGameChoice = "";
// Handles gamestate variables
public static bool gameActive = false;
public static int numLives = 0;
public static int timeLeft;
public static System.Threading.Timer t;
// Entry Point
static void Main(string[] args)
{
// Start the game
Start();
}
// Handles gameplay
static void Play()
{
// Assigns the current word to any random word in
// the words array
string currentWord = words[rand.Next(0, 88)];
// Print the current word separated by lines
Console.WriteLine("********");
Console.WriteLine(currentWord);
Console.WriteLine("********");
// While the answser is incorrect/empty
while (!userInput.Equals("exit"))
{
// Reads user input
userInput = Console.ReadLine();
if (userInput.Equals(""))
{
Play();
}
// Checks if userInput is equal to current word
if (!(userInput.Equals(currentWord)))
{
// If incorrect, display loss of life
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Incorrect!!!");
Console.WriteLine("Lives: " + numLives);
numLives--; // Take a life away
Console.ResetColor();
}
if (numLives == -1)
{
outOfLives();
}
if (userInput.Equals(currentWord))
{
correctWords++;
Play();
}
}
if (userInput.Equals("exit"))
{
Environment.Exit(0);
}
}
// Function for running out of lives
private static void outOfLives()
{
Console.WriteLine("Game over! You typed " + correctWords + " words correctly!");
Console.WriteLine("Type anything and press enter to retry, Press Escape to Quit!");
var endGameKey = Console.ReadKey();
if (endGameKey.Key == ConsoleKey.Escape)
{
Environment.Exit(0);
}
if (endGameKey.Key == ConsoleKey.Enter)
{
restartGame();
}
else
{
outOfLives();
}
}
// Function for running out of time
private static void outOfTime()
{
Console.WriteLine("Out of time! You typed " + correctWords + " words correctly!");
Console.WriteLine("Type anything and press enter to retry, Press Escape to Quit!");
var endGameKey = Console.ReadKey();
if (endGameKey.Key == ConsoleKey.Escape)
{
Environment.Exit(0);
}
if (endGameKey.Key == ConsoleKey.Enter)
{
restartGame();
}
else
{
outOfTime();
}
}
// Prompts user for input for difficulty along with game instructions
static void StartMessage()
{
Console.WriteLine("Welcome to my Typing Practice App!");
Console.WriteLine("Type the word displayed as fast as you can");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Difficulties are listed from hardest to easiest");
Console.WriteLine();
Console.WriteLine("Select a difficulty( 1 ,2 , or 3 ): ");
Console.WriteLine();
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine("-- Press ENTER --");
Console.WriteLine("*** Satan Himself ***");
Console.WriteLine();
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("-- Type 1 --)");
Console.WriteLine("*** Software Engineer ***");
Console.WriteLine();
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("-- Type 2 --)");
Console.WriteLine("*** Social Media Fanatic ***");
Console.WriteLine();
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("-- Type 3 --)");
Console.WriteLine("*** Filthy Peasant ***");
Console.WriteLine();
Console.ResetColor();
string difficultyChoice = Console.ReadLine();
switch (difficultyChoice)
{
case "1":
numLives = 1;
Console.WriteLine("You have 2 lives! Good luck!");
timeLeft = 10;
break;
case "2":
numLives = 3;
Console.WriteLine("You have 4 lives! Good luck!");
timeLeft = 20;
break;
case "3":
numLives = 5;
Console.WriteLine("You have 6 lives! Good luck!");
timeLeft = 30;
break;
default:
numLives = 0;
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine("Miss one and you're done!!!!!");
Console.ResetColor();
timeLeft = 10;
break;
}
}
public static void restartGame()
{
Console.Clear();
//numLives = 5;
numWords = words.Length;
correctWords = 0;
Start();
}
public static void SetTimer(Object o)
{
timeLeft--;
Thread.Sleep(1000);
Console.WriteLine(timeLeft);
if (timeLeft == 0)
{
outOfTime();
}
}
public static void Start()
{
// Display start message
StartMessage();
gameActive = true;
t = new System.Threading.Timer(SetTimer, null, 0, 1250);
// While user wants to play
while (!userInput.Equals("exit"))
{
// While the game is active
while (gameActive == true)
{
// Start the game
Play();
}
}
if (userInput.Equals("exit"))
{
Environment.Exit(0);
}
}
}
}
You don't need a progammatic timer or thread to have a game timer. Just record the time at the beginning of the game:
//During initialization
var startTime = DateTime.Now;
And any time you wish to display or use a timer, compute it:
var timerValue = DateTime.Now - startTime;
Console.WriteLine("Time elapsed: {0} seconds", timerValue.Seconds);
Try to use this. Coroutines should solve your problem if you can get it to work.
you can use Timer in this way.
It works for you
var timer2 = new Timer();
timer2.Elapsed += (o, e) =>
{
Console.WriteLine("Time Elapsed {0}", e.SignalTime);
timer2.Stop();
};
timer2.Interval = 1000;
timer2.Start();
As a direct fix to the problem presented (timer going below 0), you need to stop the timer when it is no longer needed. For that, use this line:
t.Change(Timeout.Infinite, Timeout.Infinite);
You could add this line to the start of your outOfLives and outOfTime methods:
private static void outOfLives()
{
t.Change(Timeout.Infinite, Timeout.Infinite);
Console.WriteLine("Game over! You typed " + correctWords + " words correctly!");
...
and...
private static void outOfTime()
{
t.Change(Timeout.Infinite, Timeout.Infinite);
Console.WriteLine("Out of time! You typed " + correctWords + " words correctly!");
...
EDIT: Sorry. Just re-read your question and realised you had already tried this line. Did you have it in the correct place(s)?

How to read button mashing in c#

I've been trying to get a button mashing minigame working in my RPG, but I haven't managed to get it to work. This is the code I've created:
using System;
namespace CounterAttack
{
class Program
{
public static int n = 0;
public static int buttonmash = 0;
public static string buttonpressed;
public static void CounterAttack()
{
n = 0;
while (n < 4000)
{
buttonpressed = Console.ReadKey().ToString();
System.Threading.Thread.Sleep(1);
n = n + 1;
if (buttonpressed == " ")
{
buttonmash = buttonmash + 1;
buttonpressed = "a";
}
else
{
buttonpressed = "a";
}
}
Console.WriteLine($"You pressed spacebar {buttonmash} times ");
}
static void Main(string[] args)
{
CounterAttack();
System.Threading.Thread.Sleep(1000);
Console.ReadKey();
}
}
}
For reasons unknown to me, the program will not exit the while loop. This means I can't check if the other parts of code will work at all.
So my question is: How can I alter this code to read the amount of times spacebar has been pressed in 4 seconds?
This sort-of works, so long as you press the space bar after the 4 second timer is up.
static void Main(string[] args)
{
var startTime = DateTime.Now;
var n = 0;
while (DateTime.Now < startTime.AddSeconds(4))
{
var key = Console.ReadKey();
System.Threading.Thread.Sleep(1);
if (key.Key == ConsoleKey.Spacebar) n = n + 1;
}
Console.WriteLine($"You pressed spacebar {n} times ");
}
"I've been trying to get a button mashing minigame working in my RPG, but I haven't managed to get it to work."
You are doing this in a console application. So the answer is on a spectrum from "not easily" to "plain impossible". I hope somebody else can give you answer with more precision along that axis.
Game development and the GUI technologies do not mix that well to begin with. That old Solitaire game was pretty much the upper limit of what games you can do in them. Console matches it even less then that.
All the serious game development is done in any enviroment that comes with a game loop. XNA is a bit dated, but for .NET Core there is some options: https://www.microsoft.com/net/apps/gaming
Try this :
class Program
{
private static int numSpaces = 0;
static void Main(string[] args)
{
Thread th = new Thread(CheckSpace);
th.Start();
th.Join();
Console.WriteLine($"You pressed space {numSpaces} times");
Console.Read();
}
private static void CheckSpace()
{
Stopwatch sw = new Stopwatch();
sw.Start();
while (true)
{
if (Console.KeyAvailable)
{
if (Console.ReadKey().Key == ConsoleKey.Spacebar)
{
numSpaces++;
}
}
if (sw.ElapsedMilliseconds>= 4000)
{
break;
}
Thread.Sleep(10);
}
}
}
#auberg's solution is good, but you really don't need a second thread. Yeah, calling Thread.Sleep() on the main thread is a bad idea, but doing it for such a short time is un-noticeable anyway.
Try this:
public static void CountKeyPresses()
{
Console.WriteLine("OK, start pressing the space bar");
var numPresses = 0;
var stopWatch = new Stopwatch();
stopWatch.Start();
while (stopWatch.ElapsedMilliseconds < 4000)
{
if (Console.KeyAvailable && Console.ReadKey().Key == ConsoleKey.Spacebar)
{
++numPresses;
}
System.Threading.Thread.Sleep(10);
}
Console.WriteLine($"\r\nYou pressed the spacebar {numPresses} times");
}

Use multithreading to count?

I am just starting to use multi-threading, and I am trying to build a console application that starts to count with 2 different threads when the user hits the Enter key, and stops counting when the Enter key is pressed a second time, and then outputs the count for both threads (I realize that with my code, these will be 2 different numbers). I set this up, but for some reason, one of the numbers is usually negative.There is also quite a bit of a delay before I receive count output. Why am I getting negative counts, why is the delay so long, and how can I correct this?
My code so far;
class Program
{
static void Main(string[] args)
{
System.Threading.Thread threadA = new Thread(ThreadA);
System.Threading.Thread threadB = new Thread(ThreadB);
Console.WriteLine("Once you press enter, this application will count as high as it can until you press enter again.");
ConsoleKeyInfo info = Console.ReadKey();
if (info.Key == ConsoleKey.Enter)
{
threadA.Start();
threadB.Start();
}
}
private static bool continueCounting = true;
static void ThreadA()
{
int count = 0;
for (int i = 0; i < int.MaxValue ; i++)
{
count++;
}
ConsoleKeyInfo info2 = Console.ReadKey();
if (info2.Key == ConsoleKey.Enter)
continueCounting = false;
Console.WriteLine(count);
}
static void ThreadB()
{
int count = 0;
while (continueCounting)
{
count++;
}
Console.WriteLine(count);
Console.ReadLine();
}
}
one of the numbers is usually negative
That's because there was no limit guard on the ThreadB loop. It was entirely possible for count to reach MaxValue then wrap around to negative maxvalue.
I also put all keyboard checks in your main thread where they arguably should be. It is here that we set continueCounting to false when the second enter key is pressed.
I also made continueCounting volatile as it is being used by multiple threads and its value should not be CPU optimised/cached.
Try this code, this fixes the delay you were experiencing; allows both threads to count at once; and exit ASAP when the enter key is pressed.
class Program
{
#region Static fields
private static volatile bool continueCounting = true;
#endregion
#region Methods
static void Main(string[] args)
{
var threadA = new Thread(ThreadA);
var threadB = new Thread(ThreadB);
Console.WriteLine(
"Once you press enter, this application will count as high as it can until you press enter again.");
var info = Console.ReadKey();
if (info.Key == ConsoleKey.Enter)
{
threadA.Start();
threadB.Start();
}
info = Console.ReadKey();
if (info.Key == ConsoleKey.Enter)
{
continueCounting = false;
}
Console.ReadLine();
}
static void ThreadA()
{
var count = 0;
for (var i = 0; i < int.MaxValue && continueCounting; i++)
{
count++;
}
Console.WriteLine($"A: {count}");
}
static void ThreadB()
{
var count = 0;
while (continueCounting && count < int.MaxValue)
{
count++;
}
Console.WriteLine($"B: {count}");
}
#endregion
}

How to make number Count in loop in c#?

This is a simple begginer program with setter and getter concept
now i have to make it to first enter user name and password to get welcomed
and IF I ENTER WRONG INFO IT SHOULD DISPLAY INVALID AND 5 TRIES LEFT THEN if i again enter wrong info it should display 4 tries left and so on and finally when all tries are over it should hang the program or lock the screen or so
using System;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
demo obj = new demo();
string uname, pass;
Console.ForegroundColor = ConsoleColor.Green;
label1:
Console.Clear();
Console.WriteLine("Enter username");
uname = Console.ReadLine();
Console.WriteLine("Enter Password");
pass = Console.ReadLine();
obj.setName(uname);
obj.setPass(pass);
if (obj.getName() == "niit")
{
if (obj.getPass() == "1234")
{
Console.WriteLine("welcome");
}
}
else
{
Console.Clear();
Console.WriteLine("Invalid");
Console.WriteLine("\n \n \n To try again enter y");
int n = 5;
string yes = Console.ReadLine();
if (yes == "y")
{
while (n >= 1)
{
Console.Write(n + " Tries left");
goto label1;
n = --n;
}
}
}
Console.ReadKey();
}
}
class demo
{
private string name, pass;
public void setName(string name)
{
this.name = name;
}
public string getName()
{
return name;
}
public void setPass(string pass)
{
this.pass = pass;
}
public string getPass()
{
return pass;
}
}
}
Please suggest a simple begginers code to make the loop work and make the count down
A while loop should suffice. Using a boolean to detect successful password entry.
When entered, it will break out of the loop.
invalid attempts will decrement the AttemptsLeft int.
Note: I haven't tried this in Visual Studio, the logic should be sound, but I recommend debugging and stepping through it to test if it meets your criteria.
static void Main(string[] args)
{
demo obj = new demo();
string uname, pass;
Console.ForegroundColor = ConsoleColor.Green;
label1:
Console.Clear();
Console.WriteLine("Enter username");
uname = Console.ReadLine();
Console.WriteLine("Enter Password");
bool SuccessfulPassword = false;
int AttemptsLeft = 5;
while(!SuccessfulPassword && AttemptsLeft > 0){
pass = Console.ReadLine();
obj.setName(uname);
obj.setPass(pass);
if (obj.getName() == "niit")
{
if (obj.getPass() == "1234")
{
Console.WriteLine("welcome");
SuccessfulPassword = true;
}
}
else
{
AttemptsLeft--;
Console.Clear();
Console.WriteLine("Invalid");
Console.WriteLine("\n \n \n To try again enter y");
int n = 5;
string yes = Console.ReadLine();
if (yes == "y")
{
Console.Write(AttemptsLeft + " Tries left");
}
}
Console.ReadKey();
}
}
try this updated main method:
static void Main(string[] args)
{
demo obj = new demo();
int n = 5;
string uname, pass;
Console.ForegroundColor = ConsoleColor.Green;
//Console.Clear();
label1:
Console.WriteLine("\n");
Console.WriteLine("Enter username");
uname = Console.ReadLine();
Console.WriteLine("Enter Password");
pass = Console.ReadLine();
obj.setName(uname);
obj.setPass(pass);
if (obj.getName() == "niit" && obj.getPass() == "1234")
{
Console.WriteLine("welcome");
}
else
{
//Console.Clear();
if (n < 1)
{
//Add ur screenlock n hang prog code
Console.Clear();
Console.WriteLine("ScreenLock");
}
else
{
Console.WriteLine("\n Invalid");
Console.WriteLine("\n To try again enter y");
string yes = Console.ReadLine();
Console.WriteLine("\n");
if (yes == "y")
{
while (n >= 1)
{
Console.Write(n + " Tries left");
n = --n;
goto label1;
}
}
}
}
Console.ReadKey();
}
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
demo obj = new demo();
string uname, pass;
boolean successful = false;
int32 tries = 5;
Console.ForegroundColor = ConsoleColor.Green;
label1:
Do
{
Console.Clear();
Console.WriteLine("Enter username");
uname = Console.ReadLine();
Console.WriteLine("Enter Password");
pass = Console.ReadLine();
obj.setName(uname);
obj.setPass(pass);
if (obj.getName() == "niit")
{
if (obj.getPass() == "1234")
{
Console.WriteLine("welcome");
successful = true;
}
}
if (!successful)
{
tries--;
Console.Clear();
Console.WriteLine("Invalid");
if (tries > 1)
{
Console.WriteLine("Have " + tries + " attempts left");
}
ElseIf (tries == 1)
{
Console.WriteLine("Have only one more attempt left");
}
Else
{
Console.WriteLine("Maximum number of tries exceed");
Console.WriteLine("Goodbye");
}
}
} While(!successful && Tries > 0);
}
}
Everytime you get the wrong input, you remaking your count int n = 5;
so everytime you have 5 tries left.
What you can do is to declare your count outside of the static void Main(string args[]) method
just like:
int n =5;
static void Main(string args[])
{
}
you problems are the following nested if-contitions
if (obj.getName() == "niit")
{
if (obj.getPass() == "1234")
{
Console.WriteLine("welcome");
}
}
else
{
\\...
}
If the username is correct and the pass not, it wont enter the else branch.
a better solution to ask for input until it is valid id a do ... while loop
Following example has a lot of improvements over yours.
static void Main(string[] args)
{
demo obj = new demo();
string uname, pass;
Console.ForegroundColor = ConsoleColor.Green;
int maxTries;
int tries = maxTries = 5;
do
{
if (tries != maxTries)//second and more
{
Console.Clear();
Console.WriteLine("Invalid");
Console.Write("\n\t" + tries + " Tries left");
Console.WriteLine("\n\n\n\tTry again? (y/n)");
string input;
do
{
input = Console.ReadLine();
} while (input != "y" && input != "n");
if (input == "n")
{
return; // exit the program
}
}
Console.Clear();
Console.WriteLine("Enter username");
uname = Console.ReadLine();
Console.WriteLine("Enter Password");
pass = Console.ReadLine();
obj.setName(uname);
obj.setPass(pass);
tries--;
} while (obj.getName() != "niit" || obj.getPass() != "1234");
Console.WriteLine("Wellcome");
}
PS: Classes should start with a capital letter.
goto is a relict of old times, it will mess with your programm structure and make things more complicated than they are. The only propper use i know is for fallthrough in switches, which also is needed only in rare cases.
A madeup one would be:
string vehicleType = "car";
switch(vehicleType)
{
case "truck":
Console.WriteLine("two wheeles and");
goto case "car";
case "car":
Console.WriteLine("two wheeles and");
goto case "motor cycle";
case "motor cycle":
Console.WriteLine("two wheeles");
break;
case "boat":
Console.WriteLine("no wheeles");
break;
}

Unauthorizedaccessexception: how to wait on input from user. Windows Phone c#

Here I am working on creating a simple practice windows phone app that simulates a guessing game. I have a while loop that runs the game until the user guesses the correct answer; what I want to do is at the beginning of each loop, wait for the user to trigger an event from pressing enter in the textbox. I'm new to this idea and have no experience in multi-threading.
I am getting an unauthorizedaccessexception, and I'm not sure what is causing it.
public partial class MainPage : PhoneApplicationPage
{
Random r;
int guess;
static AutoResetEvent autoEvent;
// Constructor
public MainPage()
{
InitializeComponent();
r = new Random();
autoEvent = new AutoResetEvent(false);
Thread t = new Thread(PlayGuessGame);
t.Start();
}
private void PlayGuessGame()
{
bool hasWon = false;
int secretNumber = r.Next(1, 3);
int tries = 1;
messageTextBox.Text = "Guess a number";
while (!hasWon)
{
autoEvent.WaitOne();
if (guess == secretNumber) //if user wins
{
messageTextBox.Text = "Congratulations! You've guess the correct number! It took {0} tries.";
}
else
{
tries++;
if (guess < secretNumber)
messageTextBox.Text = "Guess higher!";
else
messageTextBox.Text = "Guess lower!";
lastGuessTextBox.Text = guess.ToString();
}
}
}
private void guessTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
guess = int.Parse(guessTextBox.Text);
autoEvent.Set();
}
}
}
The issue you're experiencing is because you are trying to access an object from a thread it wasn't created by. So the thread that is running your PlayGuessGame() isn't supposed to play in that sandbox. You can get around this though by using a MethodInvoder:
private void PlayGuessGame()
{
bool hasWon = false;
int secretNumber = r.Next(1, 3);
int tries = 1;
messageTextBox.Text = "Guess a number";
while (!hasWon)
{
autoEvent.WaitOne();
if (guess == secretNumber) //if user wins
{
this.Invoke(new MethodInvoker(delegate { messageTextBox.Text = "Congratulations! You've guess the correct number! It took {0} tries."; }));
}
else
{
tries++;
if (guess < secretNumber)
this.Invoke(new MethodInvoker(delegate { messageTextBox.Text = "Guess higher!"; }));
else
this.Invoke(new MethodInvoker(delegate { messageTextBox.Text = "Guess lower!"; }));
this.Invoke(new MethodInvoker(delegate { lastGuessTextBox.Text = guess.ToString(); }));
}
}
}
I would definitely recommend Brian Warshaw's comment, this should be an event driven GUI. Hope this helped though, you could use this elsewhere you are using threads!

Categories

Resources