Filling last line in console - c#

I would like to fill/update the entire bottom line of the console. Example:
static void Main(string[] args)
{
Console.BufferWidth = Console.WindowWidth;
Console.BufferHeight = Console.WindowHeight;
Console.CursorTop = Console.WindowHeight - 1;
string s = "";
for(int i = 0; i < Console.BufferWidth; i++)
s += (i%10).ToString();
Console.Write(s);
Console.CursorTop = 0;
Console.ReadKey();
}
The issue is that when the text is printed, it moves to a new line. Similar questions stated to move the cursor to 0,0, however that only works when the buffer size is larger than the window size, and I would like the buffer width and the window width to be equal (to remove scroll bars).
Any ideas? The closest I could get is printing to a higher line and moving it to the last line, however that will not be acceptable in the full project.
Edit:
The last sentence of the question was specifically talking about movebufferarea. The reason why that won't work can be seen by this example:
static void Main(string[] args)
{
Console.BufferWidth = Console.WindowWidth;
Console.BufferHeight = Console.WindowHeight;
while (!Console.KeyAvailable)
{
Console.CursorTop = Console.WindowHeight - 2;
string s = "";
for (int i = 0; i < Console.BufferWidth; i++)
s += (i % 10).ToString();
Console.Write(s);
Console.MoveBufferArea(0, Console.WindowHeight - 2, Console.WindowWidth, 1, 0, Console.WindowHeight - 1);
Thread.Sleep(10);
}
}
The sentence will flicker every so often because it is printed first and then moved.

Since the cursor is always trailing after the text you've written you can either write one less character to avoid going to the next line, or simply write the characters directly into the buffer (I believe, Console.MoveBufferArea can be used for that).

As Joey mentioned, using the MoveBufferArea method will do what you're looking to accomplish:
Console.BufferWidth = Console.WindowWidth;
Console.BufferHeight = Console.WindowHeight;
string s = "";
for (int i = 0; i < Console.BufferWidth; i++)
s += (i % 10).ToString();
Console.Write(s);
//
// copy the buffer from its original position (0, 0) to (0, 24). MoveBufferArea
// does NOT reposition the cursor, which will prevent the cursor from wrapping
// to a new line when the buffer's width is filled.
Console.MoveBufferArea(0, 0, Console.BufferWidth, Console.BufferHeight, 0, 24);
Console.ReadKey();
Here's the result:

Set the BufferHeight and BufferWidth after you've written the string.
Console.CursorTop = Console.WindowHeight - 1;
Console.SetCursorPosition(0, Console.CursorTop);
string s = "";
for (int i = 0; i < Console.BufferWidth; i++)
s += (i % 10).ToString();
Console.Write(s);
Console.CursorTop = 0;
Console.BufferWidth = Console.WindowWidth;
Console.BufferHeight = Console.WindowHeight;
Console.ReadKey();

Related

Falling "$" in console game

another silly question from me :D
I want to make a console game where dollars are falling from above and we as the player have to catch them. I wrote a program that reads the buttons from the keyboard and allows us to move our I don't know, say character? To the right or to the left. Well, and all in all, I don't know how to create a method that will make the "$" fall from the top, meanwhile not interfering with the system of moving the "character" (I tried using SetCursorPosition but it didn't work well). I also thought whether to make the playing field as an array (I saw it somewhere on youtube, where a guy wrote Snake) but I don't know how to do it for the hell of it. This is how it looks now:
class Program
{
public static int x = 0, y = 0;
static void Main(string[] args)
{
const string user = "###";
Console.WriteLine("Press any key to start.");
Console.ReadKey();
Console.Clear();
while (true)
{
if (Console.KeyAvailable)
{
var command = Console.ReadKey().Key;
switch (command)
{
case ConsoleKey.LeftArrow:
if (x > 0)
{
x--;
}
break;
case ConsoleKey.RightArrow:
x++;
break;
}
Write(user, x, y);
}
}
}
public static void Write(string user, int x = 0, int y = 0)
{
if (x >= 0)
{
Console.Clear();
Console.SetCursorPosition(x, 20);
Console.Write(user);
}
}
Just for illustration, I made a little application which shows random falling dollars
const int Rows = 20;
const int Columns = 60;
var buffer = new char[Rows][];
// Initialize jagged array
for (int r = 0; r < Rows; r++) {
buffer[r] = new char[Columns];
}
var random = new Random();
int currentTop = 0;
while (!Console.KeyAvailable) { // Repeat until a key is hit.
// Create random dollars in top row
for (int i = 0; i < Columns; i++) {
buffer[currentTop][i] = random.NextDouble() < 0.1 ? '$' : ' ';
}
// Display buffer
Console.Clear();
for (int row = 0; row < Rows; row++) {
int rowIndex = (row + currentTop) % Rows;
Console.CursorTop = row;
Console.CursorLeft = 0;
Console.Write(buffer[rowIndex]);
}
Thread.Sleep(100); // Display buffer during 0.1 seconds
// Move currentTop upwards. This gives the illusion of falling dollars.
currentTop = (currentTop - 1 + Rows) % Rows;
}
Note that it uses a circular buffer. I.e., we assume that the end of the buffer (the last row) is connected with the first row.
We achieve this by taking the row index modulo the number of rows. % is the modulo or Remainder operator in C#. This makes the indexes exceeding the maximum row index start over at 0.
I used Jagged Arrays to allow us writing a row with a single Console.Write(buffer[rowIndex]);

Align numbers in RichTextBox

I want to print a multiplication table in C# but it's not aligned!
When we type a number "n" in textbox means: n*n table.
What can I do?
for (int i = 1; i <= Convert.ToInt32(textBox1.Text); i++)
{
for (int j = 1; j <= Convert.ToInt32(textBox1.Text); j++)
{
richTextBox1.Text += Convert.ToString(i * j) + " ";
}
richTextBox1.Text += "\n";
}
Set the font of RichTextBox to the monospaced font Courier New, then add the text to RichTextBox using String.Format and setting alignment for the result of multiplication. Use a positive number to align right and use a negative number to align left:
var n = 5;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
this.richTextBox1.AppendText(string.Format("{0,3}", i * j));
}
this.richTextBox1.AppendText(Environment.NewLine);
}
Instead of format the result by {0,3} you can use below code to format based on maximum length of characters is a number which belongs to n*n:
Left Aligned:
string.Format("{0,-" +((n*n).ToString().Length + 1).ToString() +"}", i * j)
Right Aligned:
string.Format("{0," +((n*n).ToString().Length + 1).ToString() +"}", i * j)
If you want to align using spaces, you need to use a monospaced font (like Courier, or Consolas), otherwise you can use tabs: numbers won't be aligned this way though, and since numbers in your routine can get considerably big, you may end up having your numbers occupy more than the tab separation, and will get inconsistencies in the alignment if that happens.
As a general rule, if you want to align any kind of text box, go with a monospaced font.
You can pad with spaces, using, for example, String.PadLeft or String.PadRight.
This would be as simple as changing:
richTextBox1.Text += Convert.ToString(i * j) + " ";
With
richTextBox1.Text += Convert.ToString(i * j).PadLeft(5);
However this would assume all numbers are at maximum 5 characters in width.
For your precise routine, you could calculate the maximum width though, so you'd end up with something like:
// convert your input only once
int myNumber = Convert.ToInt32(textBox1.Text);
// pad with the maximum possible length, plus one space
int padAmount = (myNumber * myNumber).ToString().Length + 1;
for (int i = 1; i <= myNumber; i++)
{
for (int j = 1; j <= myNumber; j++)
{
// pad your input by the amount of spaces needed to fit all possible numbers
richTextBox1.Text += (i*j).ToString().PadLeft(padAmount);
}
}
// use Environment.NewLine instead of `\n`
richTextBox1.Text += Environment.NewLine;
Here's a fiddle. It's (for obvious reasons) for console, so in my fiddle the input number is fixed (it's in myNumber) and the output is just a string (instead of richTextBox1.Text), but it should show how it works.
Although I've made a few changes (I only convert the input number once, and use Environment.NewLine instead of \n), this is far from optimal though, you should build your string (using a StringBuilder) and assign it at once, instead of adding to the Text property. I've made a fiddle with this approach, and memory consumption has gone down by over 30mb (to just a handful of kb) just by using StringBuilder.
I think the best solution is using a tab instead of a special font and padding with white spaces.
For tabs you must add a "\t" after every number. The "\t" will be evaluated as an tab-character.
for (int i = 1; i <= Convert.ToInt32(textBox1.Text); i++)
{
for (int j = 1; j <= Convert.ToInt32(textBox1.Text); j++)
{
richTextBox1.Text += Convert.ToString(i * j) + "\t "; //here at the end
}
richTextBox1.Text += "\n";
}
But it is important, that a tab has a fixed width. In case your numbers are too long, you need 2 tabs for short numbers. But for small tables like yours it is no problem.
You can change the position of the tabs with the SelectionTabs property:
this.richTextBox1.SelectionTabs = new[] { 20, 40, 60, 80 };
BTW, you should use a StringBuilder to concatenate multiple string parts to one. And it would be more effective to parse the number from textBox1 only once and not during every iteration.
var sb = new StringBuilder(); //In namespace System.Text
var x = Convert.ToInt32(textBox1.Text); //parse only once
for (int i = 1; i <= x; i++)
{
for (int j = 1; j <= x; j++)
{
sb.Append(Convert.ToString(i * j));
sb.Append("\t ");
}
sb.Append("\n");
}
richTextBox1.Text += sb.ToString();

Setting the cursor's current line on a .NET TextBox

In .NET, you can easily get the line number of the cursor location of a TextBox (i.e. the "current line") by using GetLineFromCharIndex and SelectionStart:
var currentLine = textBox1.GetLineFromCharIndex(textBox1.SelectionStart);
Is there a "clean/native" way to set the cursor in a given line of a Textbox (i.e. set the "current line")? Or at least a "clean/native" way to get the char index of the first character of a given line (something like getCharIndexFromLine, the opposite of the function I put before)?
A way to do it would involve iterating over the first N-1 elements of the Lines property of the TextBox and summing their lengths plus the lengths of the linebreaks. Any other idea?
There is a GetFirstCharIndexFromLine() function that is available:
int myLine = 3;
int pos = textBox1.GetFirstCharIndexFromLine(myLine);
if (pos > -1) {
textBox1.Select(pos, 0);
}
This was the best I could come up with:
private void SetCursorLine(TextBox textBox, int line)
{
int seed = 0, pos = -1;
line -= 1;
if(line == 0) pos = 0;
else
for (int i = 0; i < line; i++)
{
pos = textBox.Text.IndexOf(Environment.NewLine, seed) + 2;
seed = pos;
}
if(pos != -1) textBox.Select(pos, 0);
}
If you want to start counting lines at 0 remove the line -= 1; segment.

Go To Line in Text Editor

I tried implementing GoTo ling in a basic editor-type app but isn't always accurate. More often than not, it gets the right line, but it seems that the more lines there are, the more of a chance it will get the line position wrong and go to the wrong line. Not sure why this isn't working. Can someone please help?
int position = 0;
int lineCount = ((TextBox)tabControl1.SelectedTab.Controls[0]).Lines.Count();
for (int i = 0; i < LineNumber; i++)
{
position += ((TextBox)tabControl1.SelectedTab.Controls[0]).Lines[i].Count();
}
((TextBox)tabControl1.SelectedTab.Controls[0]).Focus();
((TextBox)tabControl1.SelectedTab.Controls[0]).SelectionStart = position;
((TextBox)tabControl1.SelectedTab.Controls[0]).ScrollToCaret();
LineNumber = 0;
position = 0;
lineCount = 0;
I am not sure if I have understood you correctly, but a TextBox control has a method called
TextBoxBase.GetFirstCharIndexFromLine
So if your user wants to go to line 10 (and you have 10 lines) then
int pos = textBox1.GetFirstCharIndexFromLine(9);
textBox1.SelectionStart = pos;
textBox1.ScrollToCaret();
I think #Steve has got you covered with TextBox.GetFirstCharIndexFromLine().
In your original code, though, I think you just needed to account for the carriage return / line feeds at the end of each line (they aren't included when access each line thru the Lines() property). This example assumes the desired line # is 1 (one) based:
int LineNumber = 6;
TextBox TB = (TextBox)tabControl1.SelectedTab.Controls[0];
int position = 0;
for (int i = 1; i <= TB.Lines.Length && i < LineNumber; i++)
{
position += TB.Lines[i - 1].Length + Environment.NewLine.Length;
}
TB.Focus();
TB.SelectionStart = position;
TB.SelectionLength = 0;
TB.ScrollToCaret();

Push an Array forward so it will start from 150?

I have this function which is SMA (Simple Moving Average). The result in the array I display as graph in ZedGraph and now it will start from 0 to 1956. I want the graph to start from frameSize / 2 in this case example it will be 300 / 2 so 150 so the graph should start from 150 to 2016.
I don't want to make the graph to grow I mean the array should stay length as 1956 I just want it to be pushed by 150 indexes from the beginning so it will start from index 150 instead of 0.
So this is the SMA function:
private static double[] smaDoubles(int frameSize, int[] data)
{
int padding = frameSize / 2;
double sum = 0;
double[] avgPoints = new double[(padding + data.Length) - frameSize + 1];
for (int counter = padding; counter <= data.Length - frameSize; counter++)
{
int innerLoopCounter = 0;
int index = counter;
while (innerLoopCounter < frameSize)
{
sum = sum + data[index];
innerLoopCounter += 1;
index += 1;
}
avgPoints[counter] = sum / frameSize;
sum = 0;
}
return avgPoints;
}
In the for loop counter = padding before it was counter = 0 so the result of that is in the image here.
The green one is the SMA from this function. And the green start from 150 but ends at 1956 and it should end at 2106. When I moved it to start from 150 I want the whole graph to move as one unit by 150 so it will start from 150 and end in 2106. The red graph should stay the same all
How can I do it?
Now as it is in the image the graph end by 300 from the right edge.
This is the function as it is now i changed the line: double[] avgPoints = new double[data.Length - frameSize + 1]; this is how it was original so i changed it to this one now.
And the function get frameSize as 3 and data as [10] and im getting the same exception:
private static double[] smaDoubles(int frameSize, int[] data)
{
int padding = frameSize / 2;
double sum = 0;
double[] avgPoints = new double[data.Length - frameSize + 1];
for (int counter = padding; counter <= data.Length - padding; counter++)//for (int counter = padding; counter <= data.Length - frameSize; counter++)
{
int innerLoopCounter = 0;
int index = counter;
while (innerLoopCounter < frameSize)
{
// if (index < data.Length)
sum = sum + data[index];
innerLoopCounter += 1;
index += 1;
}
avgPoints[counter] = sum / frameSize;
sum = 0;
}
return avgPoints;
}
Not possible* Some languages, like pascal allow this, but not c#.
Why not just subtract the offset 150:
sum += data[index - 150];
*although not possible with an array, you can achieve the effect with a custom object that implements an indexed property.
private int[] _array;
public int this[int index]
{
get{ return _array[index - 150]; }
}
Are you sure:
for (int counter = padding; counter <= data.Length - frameSize; counter++)
shouldn't be:
for (int counter = padding; counter <= data.Length - padding; counter++)
And then your function that computes the moving average should go from counter - padding to counter + padding instead of from counter to counter + frameSize.
To debug this type of problem, it's often helpful to try it which a much smaller data set where you can compute the expected result by hand and see if your algorithm matches your expectations. I don't believe that your algorithm is necessarily calculating what you think it's calculating here. Try it with 10 data elements and a window size of 3 to see if you're getting the results that you expect.
Note, the first code line actually contains 2 logic errors, one of which is not necessarily apparent until you try the code 2nd line. The error is preserved for illustrative purposes

Categories

Resources