I am making a C# aplication. I have got one main process for verifying data from a database. A timer checks every 100 ticks if I have user input. After I get user input my main process continues (it waits for userinput at the start). After verifying and doing multiple things the method is done. The thing is, I would like it to go to the beginning again waiting for the next bit of input.
I was thinking of calling the method again at every possible end of the process. I have a feeling that this will create a resource heavy program though (not the worst thing, but better no bad habits than a few right?).
Example:
bool cont = false;
public void process()
{
while (cont == false) {;}
//Various sorting criteria that all end up with cont = false; process(), the userinput has been processed.
}
timer1 tick event
{
if (userinput)
cont = true;
}
As you don't saw how you will get the user input, i don't implemented this one. But the main logic to your question is :
class MainClass
{
public static void Main()
{
MyRecursiveFunction();
AfterUserInput();
}
public static void MyRecursiveFunction()
{
if (userinput)
{ return; }
// Waits 100 ticks to check again
Thread.Sleep(new TimeSpan(100));
MyRecursiveFunction();
}
public static void AfterUserInput()
{
// All that you need to do after the user input
}
}
Did a simple scissor paper stone game. When you press a button (3 diff buttons one for each choice scissor/ paper/ stone), it returns if you win, lose or draw. It also colors the choice(rectangle) which human and computer chose plus a message to tell if the human won or lost.
The method game.play calculates who won based on its parameter input. 1 is rock, 2 is paper and 3 is scissor. The computer choice is random.
The following code works but find it messy and trying to find a way to place all the coloring in one method and all messaging in one method. Quite confused considering there can be so many options for the coloring and messaging. Following code is for the choice of paper made by human. Do advice. Thank you.
private void button2_Paper(object sender, RoutedEventArgs e) // Human chose Paper
{
if (game.play(2) == "Draw")
{
rect2.Fill = red;
MessageBox.Show("It is a draw. both chose Paper");
}
else if (game.play(2) == "Win")
{
rect2.Fill = green;
rect1.Fill = yellow;
MessageBox.Show("Congratulations! Paper beats Rock");
}
else if (game.play(2) == "Lose")
{
rect2.Fill = green;
rect3.Fill = yellow;
MessageBox.Show("You lose. Scissor beats Paper");
}
gameReset();
}
If you want to clean up your code, you should try to search for things that look like they were copy and pasted. I assume that you have a similar method to the one you posted here for "Rock" and "Scissor".
In that case you could restructure your Game class to hold a temporary game result, that indicates who has won. Also, you could replace your "string results" with enums.
Here is a small class to illustrate what I mean. Note that I haven't tested this class, so it might return incorrect results
namespace RockPaperScissor.GameEngine
{
public enum Move
{
Rock = 0,
Paper = 1,
Scissor = 2
}
public enum MoveResult
{
PlayerWon,
ComputerWon,
Draw
}
public class RPSEngine
{
public Move ComputerMove { get; set; }
public Move PlayerMove { get; set; }
public MoveResult Result
{
get
{
if(ComputerMove == PlayerMove)
{
return MoveResult.Draw;
}
else if(ComputerMove > PlayerMove || (ComputerMove == Move.Rock && PlayerMove == Move.Scissor))
{
return MoveResult.ComputerWon;
}
else
{
return MoveResult.PlayerWon;
}
}
}
}
}
This would allow you to update the colors in a central method, like in this example:
private void RockButton_Click(object sender, RoutedEventArgs e)
{
engine.PlayerMove = GameEngine.Move.Rock;
displayResult();
}
private void PaperButton_Click(object sender, RoutedEventArgs e)
{
engine.PlayerMove = GameEngine.Move.Paper;
displayResult();
}
private void ScissorButton_Click(object sender, RoutedEventArgs e)
{
engine.PlayerMove = GameEngine.Move.Scissor;
displayResult();
}
private void displayResult()
{
switch(engine.Result)
{
case GameEngine.MoveResult.Draw:
//Display message and change color
break;
case GameEngine.MoveResult.PlayerWon:
break;
case GameEngine.MoveResult.ComputerWon:
break;
}
}
Since you tagged your question as XAML, you could also create something like a ViewModel, that stores the color and a string of the message to display. The NotifyPropertyChanged would then cause your GUI to update.
I don't know how to access my instance in another method. I have this set of code.
Card rorbcard = new Card();
Deck deck = new Deck();
deck.Shuffle();
rorbcard = deck.TakeCard();
Start0:
Console.Clear();
Console.WriteLine("Allright lets play! Red or black?");
string userValue0 = Console.ReadLine();
switch (userValue0.ToLower())
{
case "red":
{
if (rorbcard.Suit.Equals(Suit.Diamonds))
{
Console.WriteLine("{0},\n Correct give 2 drinks",
rorbcard.ToString());
Thread.Sleep(2000);
}
else if (rorbcard.Suit.Equals(Suit.Hearts))
{
Console.WriteLine("{0},\n Correct give 2 drinks",
rorbcard.ToString());
Thread.Sleep(2000);
}
else
{
Console.WriteLine("{0},\n Wrong sucka take 2 drinks",
rorbcard.ToString());
Thread.Sleep(2000);
}
}
I am trying to use that rorbcard.ToString() in another method, but I cant figure out how to reference it. Here is the other method.
public void HighLow()
{
//highlow part of the game
Deck deck = new Deck();
deck.Shuffle();
Card highLow = new Card();
highLow = deck.TakeCard();
Start1:
Console.Clear();
Console.WriteLine("Your Hand:");
Grid.WriteAt(rorbcard.ToString(), 0, 1);
Console.WriteLine("\n\nDo you think that the next card will higher,lower,\n or
equal to the {0}. Enter high, low, or equal\n", rorbcard);
string uservalue1 = Console.ReadLine();
switch (uservalue1.ToLower())
{
case "high":
if (highLow.CardNumber > rorbcard.CardNumber) <-----Issue
{
Console.WriteLine("{0},\n Correct give 4 drinks",
highLow.ToString());
Thread.Sleep(2000);
}
else
{
Console.WriteLine("{0},\n Wrong drink 4\n", highLow.ToString());
Thread.Sleep(2000);
}
Thanks for your time in looking into this. I am stuck and have been for a bit.
You can do either
a. Pass as parameter to HighLow() like
public void HighLow(string rorbcard)
b. Create a class level variable. Assign value to it and use that value in HighLow() like
class MyClass
{
private string rorbCardClassLevel;
private void MyrorbCardMethod
{
//Other code lines.
//Inside case statement
rorbCardClassLevel = rorbcard.ToString();
}
private void HighLow()
{
//Use rorbCardClassLevel here.
}
}
All I needed to do was place my instances outside the methods and inside my class. Duh
I want to create a console application that will display the key that is pressed on the console screen, I made this code so far:
static void Main(string[] args)
{
// this is absolutely wrong, but I hope you get what I mean
PreviewKeyDownEventArgs += new PreviewKeyDownEventArgs(keylogger);
}
private void keylogger(KeyEventArgs e)
{
Console.Write(e.KeyCode);
}
I want to know, what should I type in main so I can call that event?
For console application you can do this, the do while loop runs untill you press x
public class Program
{
public static void Main()
{
ConsoleKeyInfo keyinfo;
do
{
keyinfo = Console.ReadKey();
Console.WriteLine(keyinfo.Key + " was pressed");
}
while (keyinfo.Key != ConsoleKey.X);
}
}
This will only work if your console application has focus. If you want to gather system wide key press events you can use windows hooks
Unfortunately the Console class does not have any events defined for user input, however if you wish to output the current character which was pressed, you can do the following:
static void Main(string[] args)
{
//This will loop indefinitely
while (true)
{
/*Output the character which was pressed. This will duplicate the input, such
that if you press 'a' the output will be 'aa'. To prevent this, pass true to
the ReadKey overload*/
Console.Write(Console.ReadKey().KeyChar);
}
}
Console.ReadKey returns a ConsoleKeyInfo object, which encapsulates a lot of information about the key which was pressed.
Another solution, I used it for my text based adventure.
ConsoleKey choice;
do
{
choice = Console.ReadKey(true).Key;
switch (choice)
{
// 1 ! key
case ConsoleKey.D1:
Console.WriteLine("1. Choice");
break;
//2 # key
case ConsoleKey.D2:
Console.WriteLine("2. Choice");
break;
}
} while (choice != ConsoleKey.D1 && choice != ConsoleKey.D2);
I am writing a server app and I want it to be console based. I need the user to be able to input different commands, but at the same time there is a possibility that something will be output to the console while the user is writing. This messes the buffer up. Is there any clean way of doing this?
Thanks.
I started work on a test program to show how you could divide the console into an output area and an input area, where the input area is moved down as the output area expands with more output. It's not perfect yet, but you may be able to develop it into the answer you're looking for:
static int outCol, outRow, outHeight = 10;
static void Main(string[] args)
{
bool quit = false;
System.DateTime dt = DateTime.Now;
do
{
if (Console.KeyAvailable)
{
if (Console.ReadKey(false).Key == ConsoleKey.Escape)
quit = true;
}
System.Threading.Thread.Sleep(0);
if (DateTime.Now.Subtract(dt).TotalSeconds > .1)
{
dt = DateTime.Now;
WriteOut(dt.ToString(" ss.ff"), false);
}
} while (!quit);
}
static void WriteOut(string msg, bool appendNewLine)
{
int inCol, inRow;
inCol = Console.CursorLeft;
inRow = Console.CursorTop;
int outLines = getMsgRowCount(outCol, msg) + (appendNewLine?1:0);
int outBottom = outRow + outLines;
if (outBottom > outHeight)
outBottom = outHeight;
if (inRow <= outBottom)
{
int scrollCount = outBottom - inRow + 1;
Console.MoveBufferArea(0, inRow, Console.BufferWidth, 1, 0, inRow + scrollCount);
inRow += scrollCount;
}
if (outRow + outLines > outHeight)
{
int scrollCount = outRow + outLines - outHeight;
Console.MoveBufferArea(0, scrollCount, Console.BufferWidth, outHeight - scrollCount, 0, 0);
outRow -= scrollCount;
Console.SetCursorPosition(outCol, outRow);
}
Console.SetCursorPosition(outCol, outRow);
if (appendNewLine)
Console.WriteLine(msg);
else
Console.Write(msg);
outCol = Console.CursorLeft;
outRow = Console.CursorTop;
Console.SetCursorPosition(inCol, inRow);
}
static int getMsgRowCount(int startCol, string msg)
{
string[] lines = msg.Split('\n');
int result = 0;
foreach (string line in lines)
{
result += (startCol + line.Length) / Console.BufferWidth;
startCol = 0;
}
return result + lines.Length - 1;
}
Personally i would use event handlers to managed a console that handles both input and outup at the same time, create a class ScreenManager or whatever, inside that class add a void RunProgram() mthod, create an event with handler and required variables for reading the input key "Console.ReadKey(bool).key".
static Consolekey newKey;
on your main program, creat an instance of your class "whatev you called it", then create a thread of that instances internal method, Thread coreThread = new Thread(delegate() {myinstance.myProgramMrthod()});
loop in your main until the threads up and running. while (!Thread.IsAlive) ;
then create the main program loop.
while (true)
{
}
then for safty, join your custom thread so the main program doesnt continue until the custom thread is closed/disposed.
customThread.Join();
you now have two threads running seperatly.
back to your class, create a switch inside your event handler method.
switch (newkey)
{
case Consolekey.enter
Console.WriteLine("enter pressed");
break;
ect, ect.
default:
Console.write(newkey); // writes character key that dont match above conditions to the screen.
break;
}
stick allyour logic inhere with how you want to handle keys.
How to use multiple modifier keys in C#
might be of some help.
inside your instance's method RunProgram() or whatev you choose to call it, after you've done whatever code you need to, create an infinite loop to check for key change.
while (true)
{
newKey = Console.ReadKey(true).Key;
if (newKey != oldKey)
{
KeyChange.Invoke();
}
}
this loop stores any key pressed and then checks to see if theres a new key, if true fires the event.
you now have the core of what your looking for, one string that loops askng for a new key, whilst the main loop is free to display whatever text you wish to display.
two fixable bugs with this that i can think of, one is "default" inside switch will print to console in caps or strings. and the other is any text added to the console is added at the cursor point so it adds to the text the user has just input.
hwoever i will, since i've just made it, how you have to manager the text been added to the console. again im using an event. i could use methods and functions throughout but events add move flexability to the program, i think.
okay so we want to be able to add text to the console, without it upsetting the input we enter. keeping the input at the bottom;
create a new delegate that has a signiture with a string argument, void delegate myDelegate(string Arg). then create an event with this delegate, call it newline, newinput, whatev you like.
the events handler will take a string argument (repersenting the console update text: what you want to insert into the console above the users input) it will grab the text the user has been entering into the console, store it, then print out the paramiter string onto the console, then print out the users input underneith.
personally i chose to create a static string at the top outside the method, initialise it to empty, cos its going to be frequently used and you dont want to be creating a new identifyer and then initialising the variable everytime the method is called, then dispose of it at the end of the method, only to recreate a new one again, and again.
call the string "input" or whatever.
in the default area of the keychange event handle add input +=newkey.
in the Consolekey.enter section console writline input then input = string.empty Or string = "".
in the event handler add some logic.
public void OnInsert(string Argument)
{
Console.CursorTop -= 1;
// moves the cursor to far left so new input overwrites the old.
// if arg string is longer, then print arg string then print input // string.
if (Argument.Length > input.Length)
{
Console.WriteLine(Argument);
Console.WriteLine(input);
}
else
{
// if the users input if longer than the argument text then print
// out the argument text, then print white spaces to overwrite the
// remaining input characters still displayed on screen.
for (int i = 0; i < input.Length;i++ )
{
if (i < Argument.Length)
{
Console.Write(Argument[i]);
}
else
{
Console.Write(' ');
}
}
Console.Write(Environment.NewLine);
Console.WriteLine(input);
}
}
hope this helps some of you, its not perfect, a quick put together test that works enough to be built on.
If you need to allow output to arrive while the user is typing I recommend sending the output to a new window. So, you could have one window that is used to start the application and then it spawns a thread to open a new console for input and then it continues to send any output messages to the original window. I think you will run in to too many resource locking issues if you try to keep everything in the same window.
This sort of thing becomes a somewhat simpler problem if you treat the server as a client/server application. Let the server have "n" connections to client admin applications that send commands and receive output. The client application could completely separate input and output, having one thread to handle input, and one to handle output.
The output thread could block if the input thread is in the middle of entering a line, and unblock when the line is either cancelled or committed.
I got my example working using Console.MoveBufferArea(), but note that this won't work on platforms other than Windows because the method is not implemented on those platforms.
With this example you would use Read() instead of Console.ReadLine() and Log(...) instead of Console.WriteLine(...) in your code.
class Program
{
static void Main(string[] args)
{
// Reader
new Thread(() =>
{
string line;
while ((line = Read()) != null)
{
//...
}
Environment.Exit(0);
}).Start();
// Writer
new Thread(() =>
{
while (true)
{
Thread.Sleep(1000);
Log("----------");
}
}).Start();
}
static int lastWriteCursorTop = 0;
static void Log(string message)
{
int messageLines = message.Length / Console.BufferWidth + 1;
int inputBufferLines = Console.CursorTop - lastWriteCursorTop + 1;
Console.MoveBufferArea(sourceLeft: 0, sourceTop: lastWriteCursorTop,
targetLeft: 0, targetTop: lastWriteCursorTop + messageLines,
sourceWidth: Console.BufferWidth, sourceHeight: inputBufferLines);
int cursorLeft = Console.CursorLeft;
Console.CursorLeft = 0;
Console.CursorTop -= inputBufferLines - 1;
Console.WriteLine(message);
lastWriteCursorTop = Console.CursorTop;
Console.CursorLeft = cursorLeft;
Console.CursorTop += inputBufferLines - 1;
}
static string Read()
{
Console.Write(">"); // optional
string line = Console.ReadLine();
lastWriteCursorTop = Console.CursorTop;
return line;
}
}
Have you tried calling OpenStandardInput, reading any input and resetting it's position, then writing to the output stream. Afterwards, you can call OpenStandardInput again and fill the data back into the stream.
There's no perfect way of accomplishing this, I think. What telnet does (at least the last version I used) was not print any input (just read the keystrokes) and simply print the output as it arrives. The alternative is to store any data that needs to be output to the console in a buffer, and only print it once the user has finished entering their command. (You could even timestamp the output, to make it more obvious.) I really can't see any better alternative here - you're inevitably going to run into problems using a synchronous I/O interface (i.e. the command line) together with asynchronous operations in the backend.