I have very uncanny problem about Win32 console.
There are missing pixels in the console cell like that:
Okay, let's consider the problem a little bit more detailed. I figure out the bug comes, when all of this 3 factors are available:
We must use symbol that we can see the first column of pixels is missing, so 'i' will be useless in our case, because it's printed on middle of the cell, but character like '0', or better '\u2593' (which is filling the cell fully) is going to be good choice as well:
char myChar = '\u2593';
Also need to change the Console.ForegroundColor different from our default console color. For example - Yellow:
Console.ForegroundColor = ConsoleColor.Yellow;
Finally, print symbols backward through moving the cursor position, so we're going to use at least twо times this lines:
Console.SetCursorPosition(left, 0);
Console.Write(myChar);
Now we are ready to simulate our problem with the following code:
static void Main()
{
char myChar = '\u2588';
Console.ForegroundColor = ConsoleColor.Yellow;
for (int i = 5; i >= 0; i--)
{
Console.SetCursorPosition(i, 0);
Console.Write(myChar);
Console.SetCursorPosition(i, 0);
Console.Write(myChar);
}
Console.WriteLine();
}
The problem can be observe even more clearly in this console snake game:
Here's an explanation of the previous one screenshot:
So, is it possible to get rid of this irritating effect of cracked ASCII, given that I use filling symbols, change the console colors and print backward?
Related
I am learning the programming basics in C# and am studying the use of "for" function.
When working on an exercise I realised there's something wrong with my console - it seems as if it did not display top 6 rows.
I.e. with such a code:
for (int i = 1; i <= size; i++)
{
for (int j = 1; j <= size; j++)
{
Console.Write("{0,-3}", j);
}
Console.WriteLine();
}
Console.ReadKey();
My console spits out only smth like this:
[1
Dear masterminds, wwyd?
In order to increase the buffer size for the console as #Caius Jard suggested you need to press the right mouse button on the top console bar.
Press Properties
Change settings until you will see it will work for you. In the screenshot, you can find Windows default settings that I'm using.
You might need to re-run your program to notice some changes.
I am on my final project in c# for beginners, but I can't seem to get my list to work properly. It also closes automatically after being 'filled' with orders.
class Burgare
{
private string[] hamburger = new string[24];
private int no_burger = 0;
public void add_burger()//Ordering of burgers
{
Console.Clear(); //Clears console to make it look cleaner
while (true)
{
int Burger_option = 0;
do
{
Console.WriteLine("");// The options user can choose from
Console.WriteLine("Please choose burgers from our menu:");
Console.WriteLine("-------Burgers--------");
Console.WriteLine("1 Original One 109");
Console.WriteLine("2 Pig & Cow 109");
Console.WriteLine("3 Spice & Nice 109");
Console.WriteLine("4 Green One 109");
Console.WriteLine("0 Go back to main menu");
Console.WriteLine("----------------------");
Console.WriteLine("");
try //Making sure the user only picks what is on the menu
{
Burger_option = int.Parse(Console.ReadLine());
}
catch
{
Console.WriteLine("You can only choose what is on the menu!");
}
switch (Burger_option) //Depending on the number user presses on keyboard different burgers will be added to order
{
case 1:
Console.WriteLine("You've added the Original One to your order");
Console.WriteLine("If you're done press 0 to go back to the main menu");
hamburger[no_burger] = "Original One";
break;
case 2:
Console.WriteLine("You've added the Pig & Cow to your order");
Console.WriteLine("If you're done press 0 to go back to the main menu");
hamburger[no_burger] = "Pig & Cow";
break;
case 3:
Console.WriteLine("You've added the Spice & Nice to your order");
Console.WriteLine("If you're done press 0 to go back to the main menu");
hamburger[no_burger] = "Spice & Nice";
break;
case 4:
Console.WriteLine("You've added the Green One to your order");
Console.WriteLine("If you're done press 0 to go back to the main menu");
hamburger[no_burger] = "Green One";
break;
case 0: //Sends user back to main menu
Run();
break;
}
no_burger++; //Adds burger
} while (no_burger != 0);
if (no_burger <= 25) //Maximum number of orders
{
Console.WriteLine("The restaurant can't take more than 24 orders of burgers at the time");
Run(); //Sends user back to main menu when the order is over 24
}
}
}
public void print_order()
{
Console.WriteLine("-Your current order-");
foreach (var burger in hamburger) //Showing a list of what is in the order
{
Console.WriteLine(hamburger);
if (burger != null)
Console.WriteLine(burger);
else
Console.WriteLine("Empty space"); //Making empty space to show where you can add more burgers
}
}
After entering 24 orders I get the error "System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'" I've looked around a bit but still don't really understand how to fix my code. I'd like for it to return to the main menu after telling the user the order is full.
For my second problem the System.String [] problem, it appears when I enter the 'print_order'. It shows itself as
System.String []
Empty space
System.String []
Empty space
And so on. If possible I'd like to either remove it completely or at least replace it with 1,2,3...etc.
First off, please only post one question per question; you've described many problems here, but only actually asked one question. If you have multiple questions, post multiple questions.
Why do I get System.String[] in my code while debugging?
C# by default gives the name of the type when you print it out, and you're printing an array of strings. To turn an array of strings into a string, use the Join method of the string type. Be careful to not confuse it with the Join extension method on sequences.
It also closes automatically after being 'filled' with orders.
When a console program's control reaches the end of Main, it terminates the program. If you want something else to happen, write code that indicates what you'd like to happen.
After entering 24 orders I get the error "System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'" I've looked around a bit but still don't really understand how to fix my code. I'd like for it to return to the main menu after telling the user the order is full.
You've reserved space for 24 things, and you've tried to access the 25th thing. That's a fatal error. Don't do that. You are required to detect that situation and prevent it.
If you want it to return to the main menu after telling the user the order is full then write code to do that. How? Since apparently the main menu is a thing that can happen more than once, you'll want to put it in a loop. You've already written two loops; put more stuff in the loops!
While we're looking at your code, some more good advice:
Start using the conventions of the C# language now. You wrote Console.WriteLine and then made a method print_order. Follow the pattern set by the designers of the framework, not something you've just made up on your own. Types and methods should be CasedLikeThis.
Never put an int.Parse in a try-catch, ever. That's what int.TryParse is for!
Your program has a bug; what happens if someone types in, say, 7? Handle that case!
You never actually check to see how many items you've added inside your do...while loop - you only check this after the loop is complete. That's why it crashes when you try to add the 25th item.
Move the logic to handle this inside your do...while loop and you won't get the exception anymore.
Also, your array only has room for 24 items, but I assume that you meant for it to be 25.
Also, since you're new to programming, you may want to look at #Eric Lppert's helpful article on debugging techniques - it'll save you a lot of time. You should also read about how to use a step debugger to diagnose problems.
I have seen a few other posts very similar to this one, but the answers they give are not correctly answering the question. Sorry if there is something hidden away that I couldnt find...
I want to use Console.WriteLine() to print something above my current Console.ReadLine(), for example, my app prints "Hello world" and starts a thread that (in 5 seconds) will print "I just waited 5 seconds" above the line where I need to input something, like this:
Hello world
Please input something: _
Then 5 seconds will pass and it will look like this:
Hello world
I just waited 5 seconds
Please input something: _
So far I've tried using Console.SetCursorPosition(0,Console.CursorTop - 1) but this just prints over the line "Please input something: _" and if I use Console.CursorTop - 2 instead it crashes saying "[2] Out of range" (no idea why this is) and if I use Console.CursorTop - 2 it prints under "Please input something: _"... so my question is how do I print something ABOVE the line "Please input something: _"
Just moving the cursor is not good enough, the problem is that you are inserting text. That is possible, the Console.MoveBufferArea() method gives you access to the underlying screen buffer of the console and lets you move text and attributes to another line.
There are a couple of tricky corner-cases. One you already found, you have to force the console to scroll if the cursor is located at the end of the buffer. And the timer is a very difficult problem to solve, you can only really do this correctly if you can prevent Console.ReadLine() from moving the cursor at the exact same time that the timer's Elapsed event inserts the text. That requires a lock, you cannot insert a lock in Console.ReadLine().
Some sample code you can play with to get you there:
static string TimedReadline(string prompt, int seconds) {
int y = Console.CursorTop;
// Force a scroll if we're at the end of the buffer
if (y == Console.BufferHeight - 1) {
Console.WriteLine();
Console.SetCursorPosition(0, --y);
}
// Setup the timer
using (var tmr = new System.Timers.Timer(1000 * seconds)) {
tmr.AutoReset = false;
tmr.Elapsed += (s, e) => {
if (Console.CursorTop != y) return;
int x = Cursor.Left;
Console.MoveBufferArea(0, y, Console.WindowWidth, 1, 0, y + 1);
Console.SetCursorPosition(0, y);
Console.Write("I just waited {0} seconds", seconds);
Console.SetCursorPosition(x, y + 1);
};
tmr.Enabled = true;
// Write the prompt and obtain the user's input
Console.Write(prompt);
return Console.ReadLine();
}
}
Sample usage:
static void Main(string[] args) {
for (int ix = 0; ix < Console.BufferHeight; ++ix) Console.WriteLine("Hello world");
var input = TimedReadline("Please input something: ", 2);
}
Note the test on the Console.Top property, it ensures that nothing goes drastically wrong when the user typed too much text and forced a scroll or if Console.ReadLine() completed at the exact same time that the timer ticked. Proving that it is thread-safe in all possible cases is hard to do, there will surely be trouble when Console.ReadLine() moves the cursor horizontally at the exact same time that the Elapsed event handler runs. I recommend you write your own Console.ReadLine() method so you can insert the lock and feel confident it is always safe.
You can use carriage-return (\r, or U+000D) to return the cursor to the start of the current line, and then overwrite what's there. Something like
// A bunch of spaces to clear the previous output
Console.Write("\r ");
Console.WriteLine("\rI just waited 5 seconds");
Console.Write("Please input something: ");
However, if the user has started typing already this won't work anymore (as you may not overwrite all they have typed, and they will lose what they've typed on the screen, although it's still there in memory.
To properly solve this you actually need to modify the console's character buffer. You have to move everything above the current line one line up, and then insert your message. You can use Console.MoveBufferArea to move an area up. Then you need to save the current cursor position, move the cursor to the start of the line above, write your message, and reset the cursor position again to the saved one.
And then you have to hope that the user doesn't type while you're writing your message, because that would mess things up. I'm not sure you can solve that while using ReadLine, though, as you cannot temporarily lock something while ReadLine is active. To properly solve that you may have to write your own ReadLine alternative that reads individual keypresses and will lock on a common object when writing the resulting character to avoid having two threads writing to the console at the same time.
Was profiling my code and found that the way we are doing colored console text is very expensive (majority of the runtime).
DateTime dt = DateTime.Now;
for (int i = 0; i <= 20000; i++)
{
ConsoleColor cf = Console.ForegroundColor;
ConsoleColor cb = Console.BackgroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.BackgroundColor = ConsoleColor.Blue;
Console.WriteLine("Hello World");
Console.ForegroundColor = cf;
Console.BackgroundColor = cb;
}
System.Diagnostics.Debug.WriteLine((DateTime.Now - dt).TotalMilliseconds);
This simple loop takes 2.8 seconds to run on my machine. If I just do the WriteLine, its only 600ms.
Now, before I get troll answers :) asking why I keep setting the color when its hardcoded, THIS IS TEST CODE, in the real code, the foreground and background colors are calculated on a few different factors. That part is irrelevant. This code is just assuming that the color will change and thus saves the originals, changes the colors, then changes it back to the original.
I've also tried using the native SetConsoleTextAttribute method through pinvoke since using ILSpy, it seemed like the Console.xxx methods were doing a lot of extra crap, but I got about the same timings.
Not really. As you've already noted, the properties built in to Console interact with SetConsoleTextAttribute directly, which is the way to set console output properties in Windows.
If ANSI colors are an option, which would be substantial changes to logic you have working with console colors, it is faster. A minimal case
for (int i = 0; i <= 20000; i++)
{
Console.WriteLine("\x1b[31m\x1b[44mHello World\x1b[39m\x1b[49m");
}
runs in about 1200 ms on my machine, compared to about 7000 ms with the Console.xxxColor properties.
You'll need a compatible shell. Ansicon works.
With ANSI colors, you can additionally batch your output for even more times savings. Even batches of lines of 20 chop the run time above in half.* If you're spamming to the console for whatever reason, that could help significantly.
*On my machine.
See this answer to "How can I write fast colored output to Console?" and note this solution requires p-invoking of WriteConsoleOutput.
The color information is in the CharInfo struct, using Console.ForegroundColor in the lower 4 bits and BackgroundColor in the upper 4 bits of the short Attributes field.
Here is the constructor I use for the struct:
public CharInfo(char character, ConsoleColor? foreground = null, ConsoleColor? background = null) {
this.Char = new CharUnion() { UnicodeChar = character };
this.Attributes = (ushort)((int)(foreground ?? 0) | (((int)(background ?? 0)) << 4));
}
(you will also need to have CharSet=CharSet.Unicode in a couple places in the [StructLayout...] attributes to get Unicode to work)
Do some buffering by constructing an array CharInfo[] sized for the console window, then flush it to screen all at once for immensely-fast* updates!
*Fast relative Console.Write... methods at least. 160x80 can still take over 100ms.
I'm a student and I got a homework i need some minor help with =)
Here is my task:
Write an application that prompts the user to enter the size of a square and display a square of asterisks with the sides equal with entered integer. Your application works for side’s size from 2 to 16. If the user enters a number less than 2 or greater then 16, your application should display a square of size 2 or 16, respectively, and an error message.
This is how far I've come:
start:
int x;
string input;
Console.Write("Enter a number between 2-16: ");
input = Console.ReadLine();
x = Int32.Parse(input);
Console.WriteLine("\n");
if (x <= 16 & x >= 2)
{
control statement
code
code
code
}
else
{
Console.WriteLine("You must enter a number between 2 and 16");
goto start;
}
I need help with...
... what control statment(if, for, while, do-while, case, boolean) to use inside the "if" control.
My ideas are like...
do I write a code that writes out the boxes for every type of number entered? That's a lot of code...
..there must be a code containing some "variable++" that could do the task for me, but then what control statement suits the task best?
But if I use a "variable++" how am I supposed to write the spaces in the output, because after all, it has to be a SQUARE?!?! =)
I'd love some suggestions on what type of statements to use, or maybe just a hint, of course not the whole solution as I am a student!
It's not the answer you're looking for, but I do have a few suggestions for clean code:
Your use of Int32.Parse is a potential exception that can crash the application. Look into Int32.TryParse (or just int.TryParse, which I personally think looks cleaner) instead. You'll pass it what it's parsing and an "out" parameter of the variable into which the value should be placed (in this case, x).
Try not to declare your variables until you actually use them. Getting into the habit of declaring them all up front (especially without instantiated values) can later lead to difficult to follow code. For my first suggestions, x will need to be declared ahead of time (look into default in C# for default instantiation... it's, well, by default, but it's good information to understand), but the string doesn't need to be.
Try to avoid using goto when programming :) For this code, it would be better to break out the code which handles the value and returns what needs to be drawn into a separate method and have the main method just sit around and wait for input. Watch for hard infinite loops, though.
It's never too early to write clean and maintainable code, even if it's just for a homework assignment that will never need to be maintained :)
You do not have to write code for every type of number entered. Instead, you have to use loops (for keyword).
Probably I must stop here and let you do the work, but I would just give a hint: you may want to do it with two loops, one embedded in another.
I have also noted some things I want to comment in your code:
Int32.Parse: do not use Int32, but int. It will not change the meaning of your code. I will not explain why you must use int instead: it is quite difficult to explain, and you would understand it later for sure.
Avoid using goto statement, except if you were told to use it in the current case by your teacher.
Console.WriteLine("\n");: avoid "\n". It is platform dependent (here, Linux/Unix; on Windows it's "\r\n", and on MacOS - "\n\r"). Use Environment.NewLine instead.
x <= 16 & x >= 2: why & and not ||?
You can write string input = Console.ReadLine(); instead of string input; followed by input = Console.ReadLine();.
Since it's homework, we can't give you the answer. But here are some hints (assuming solid *'s, not white space in-between):
You're going to want to iterate from 1 to N. See for (int...
There's a String constructor that will allow you to avoid the second loop. Look at all of the various constructors.
Your current error checking does not meet the specifications. Read the spec again.
You're going to throw an exception if somebody enters a non-parsable integer.
goto's went out of style before bell-bottoms. You actually don't need any outer control for the spec you were given, because it's "one shot and go". Normally, you would write a simple console app like this to look for a special value (e.g., -1) and exit when you see that value. In that case you would use while (!<end of input>) as the outer control flow.
If x is greater or equal to 16, why not assign 16 to it (since you'll eventually need to draw a square with a side of length 16) (and add an appropriate message)?
the control statement is:
for (int i = 0; i < x; i++)
{
for ( int j = 0; j < x; j++ )
{
Console.Write("*");
}
Console.WriteLine();
}
This should print a X by X square of asterisks!
I'ma teacher and I left the same task to my students a while ago, I hope you're not one of them! :)