I'm not very experienced when it comes to using .txt files in XNA and therefore i need some help.
I'm tring to make a Tile Engine read and put information depending on what number is in the .txt document. It looks something like this:
1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 etc
Now, this document contains 50 characters in X (25 without [ , ]) and has 15 lines in Y. The problem is that it only reads the first line in Y and not the other 14 remaining ones in Y, which is causing it to crash.
Here is the code:
public void LoadMap(string MapName)
{
using (StreamReader streamReader = new StreamReader("Content/" + MapName + ".txt"))
{
do
{
string line = streamReader.ReadLine();
string[] numbers = line.Split(',');
int temp = 0;
for (int y = 0; y < loopY; y++)
{
for (int x = 0; x < loopX; x++)
{
Blocks[y, x] = new Block();
//Crashes here when temp reaches 25
if (int.Parse(numbers[temp]) == 1)
Blocks[y, x].color = Color.Blue;
else if (int.Parse(numbers[temp]) == 2)
Blocks[y, x].color = Color.Violet;
else
Blocks[y, x].color = Color.White;
temp++;
}
}
} while (!streamReader.EndOfStream);
}
}
Based on your reply to my question:
"Index was outside the bounds of the array." Yes i checked it loopX is 25 and Numbers is 25
numbers[] is zero-indexed, so the upper bounds is numbers[24]. If loopX is 25 then, yes, you'll see an exception.
You're iterating through loopX and then loopY and incrementing temp every time. You'll either need to set temp back to 0 after each loopX iteration, or just use the numbers array instead of the loop values instead.
I suggest changing your loop to use numbers instead:
for (int x = 0; x < numbers.Length; x++)
And then, to use your existing code, check value using:
if (int.Parse(numbers[x]) == 1)
EDIT: This is what I was trying to explain:
using (StreamReader streamReader = new StreamReader("Content/" + MapName + ".txt"))
{
int y = 0;
do
{
string line = streamReader.ReadLine();
string[] numbers = line.Split(',');
for (int x = 0; x < numbers.Length; x++)
{
Blocks[y, x] = new Block();
if (int.Parse(numbers[x]) == 1)
Blocks[y, x].color = Color.Blue;
else if (int.Parse(numbers[x]) == 2)
Blocks[y, x].color = Color.Violet;
else
Blocks[y, x].color = Color.White;
}
y++;
} while (!streamReader.EndOfStream);
}
I see following things in your code, which seem suspicious to say the least:
If your temp >= numbers.Length, than you will get "Index was outside the bounds of the array".
If that happens after reading the first line, of course you will not read any further lines, because you got an exception and it will break.
You are overwriting your Blocks with every new line: If you read the first line and get into x and y loops, at the very first iteration of x and y, they will both be 0. So you write Blocks[0,0] = new Block(). After you read the next line, you get again into x and y loops. They start again with 0, so at the very first iteration of x and y while processing the second line you will write Blocks[0,0] = new Block(). Which will in fact overwrite the Block you wrote previously on index [0,0] during the handling of the first line. The same problem exists for all other combinations of x and y.
Debug, step-through and watch variables. That will help you understand what is going on.
Related
So i was given this question below to answer and I initially created a for loop to do this which worked fine but i was told i could also do it in a while loop which is what i am trying now however i am not sure where I've gone wrong in my code below as i'm getting a indexoutofrange exception.
Question 4 -
Write a piece of software that compares two strings and outputs the number of characters in the same position.
E.g. “helloworld” and “worldhello” would output 2 as there are two l’s in the same positions
compare the strings below to calculate your answer.
String1 - "helloworld"
String2 - "worldhello"
My for loop code which works perfectly
string string1 = "helloworld";
string string2 = "worldhello";
int list = 0;
for (int i = 0; i < string1.Length; i++)
{
if (string1[i] == string2[i])
{
list = list + 1;
}
}
Console.WriteLine(list);
Now this is my while loop code which isn't working
string string1 = "helloworld";
string string2 = "worldhello";
int i = 0;
int total = 0;
while (i < string1.Length)
{
i++;
if (string1[i] == string2[i])
{
total = total + 1;
}
}
You are nearly there!
The third part of the for loop (i++) will run at the end of each iteration, so you should not put i++; as the first statement in the while loop version. You should put it as the last statement:
while (i < string1.Length)
{
if (string1[i] == string2[i])
{
total = total + 1;
}
i++;
}
In general, a for loop of the form:
for (x ; y ; z) { w; }
can be written as a while loop like this:
x;
while (y) {
w;
z;
}
I need a little help! I cannot figure out how to take the last three lines of a file and store each to a separate string. An array would work too if possible.
string[] lines = File.ReadAllLines(myfile);
If someone could use an array for this, how would I get only the last three lines. Please keep note that I do not know the length of the file!
Thanks
var last3lines = lines.Skip(lines.Length - 3).ToArray();
This seems a little too simple....
Update
In case the length of the array is less than 3 in size. This should either print the last three lines based on count, or less than three lines if i == -1
string[] lines = File.ReadAllLines(myFile)
// Get the last three lines
int count = 0;
for (int i = lines.length - 1; i >= 0; i++)
{
Console.WriteLine(lines[i]);
count++;
if (count == 3)
{
break;
}
}
For a way that does not require you to load all lines from the file in a big array with ReadAllLines, but just reads them a line at a time, keeping only the last (3) ones read, you can do:
var threeLines = new string[3];
var nLines = 0;
foreach (var line in File.ReadLines(myFile))
{
var ndx = nLines % 3;
threeLines[ndx] = line;
nLines++;
}
Also, this will not crash if you have less then 3 lines in your input.
for (var i = 0; i < Math.Min(nLines, 3); i++)
Console.WriteLine(threeLines[i]);
Or to get them in order of last, last-1, last-2:
for (var i = Math.Min(nLines, 3); i > 0; i--)
Console.WriteLine(threeLines[i-1]);
Inefficient but it works: lines.Reverse().Take(3).Reverse()
Alternative:
line1 = lines[lines.length-3] // Third to last
line2 = lines[lines.length-2]
line3 = lines[lines.length-1] // Last line
Okay, so this is the code I have but I am trying to figure out how to change this foreach loop to an if statement. I've been trying to figure it out by myself but it doesn't seem to be working the way I want it to. So if anyone could help that would be much appreciated. Just as something extra, I am still a noob at C#. :)
// Used to make sure that the script can read the text file
using (StreamReader sr = new StreamReader ("Maze.txt"))
{
lineArray = File.ReadAllLines("Maze.txt");
// Access one line at a time
foreach (string line in lineArray)
{
// Reset X axis for each line of the file
int x = 0;
// Access each character in the file
foreach (char c in line)
{
string currentPosition = c.ToString();
newFilePosition = Convert.ToInt32(currentPosition);
if (newFilePosition == 1)
{
// Create a cube on the X axis
NewCubePosition = new Vector3 (x, y, 0);
Instantiate (g_mazeCubes, NewCubePosition, Quaternion.identity);
}
// Loop until X axis is done
x++;
}
// Loop until Y axis is done
y++;
}
}
If you are refering to transform a foreach to a for that test an condition. Making this transformation in code means you don't need to set x=0 and y=0 before and increment them inside foreach loop.
Using for you will do initialization, the condition, and the afterthought of x and y and iterate through array at once.
As many say you don't neet StreamReader. File.ReadAllLines opens and close the file for you.
lineArray = File.ReadAllLines("Maze.txt");
// Access one line at a time
for (y = 0; y < lineArray.Count(); y++)
{
string line = lineArray[y];
// Access each character in the file
for (int x = 0 ; x < line.Count(); x++)
{
char c = line[x];
string currentPosition = c.ToString();
newFilePosition = Convert.ToInt32(currentPosition);
if (newFilePosition == 1)
{
// Create a cube on the X axis
NewCubePosition = new Vector3 (x, y, 0);
Instantiate (g_mazeCubes, NewCubePosition, Quaternion.identity);
}
}
}
You can reduce the code with a bit of LINQ, but I don't think there's anything you can do to get rid of the inner loop.
var lineArray = File.ReadAllLines("Maze.txt");
for (var y = 0; y < lineArray.Length; y++)
{
foreach (var c in lineArray[y].Select((value, i) => new { Character = value, Index = i })
.Where(x => Convert.ToInt32(x.Character) == 1))
{
Instantiate(g_mazeCubes, new Vector3(c.Index, y, 0), Quaternion.identity);
}
}
(You also don't need the StreamReader)
In my opinion if you try to reduce the the code further than this you'll obfuscate the intent with no benefit.
I'm very new to C# (And Stack Overflow, forgive me for any poor etiquette here), and I'm writing the game Mastermind in a console application. I'm trying to show a list of the user's guesses at the end of the game, and I know that using Console.WriteLine(); will just give me 30-odd lines off numbers which don't tell the user anything.
How can I alter my code so that the program displays 4 numbers in a group, at a time? For example:
1234
1234
1234
//Store numbers in a history list
ArrayList guesses = new ArrayList(); //This is the ArrayList
Console.WriteLine("Please enter your first guess.");
guess1 = Convert.ToInt32(Console.ReadLine());
guesses.Add(guess1);
foreach (int i in guesses)
{
Console.Write(i);
}
I assume that each element of your byte array is a single digit (0-9). If that assumption is invalid -- please let me know, I'll modify the code :)
Action<IEnumerable<int>> dump = null;
dump = items =>
{
if(items.Any())
{
var head = String.Join("", items.Take(4));
Console.WriteLine(head);
var tail = items.Skip(4);
dump(tail);
}
};
dump(guesses);
It looks like you're most of the way there, you have a console write that writes them all out without linebreaks. Next add an integer count and set it to zero. Increment it by one in the foreach loop. count % 4 == 0 will then be true for all counts that are a multiple of four. This means you can stick an if block there with a write-line to give you your groups of four.
List<int> endResult = new List<int>();
StringBuilder tempSb = new StringBuilder();
for(int i=0; i < groups.Count; i++)
{
if(i % 4 == 0) {
endResult.Add(int.Parse(sb.ToString()));
tempSb.Clear(); // remove what was already added
}
tempSb.Append(group[i]);
}
// check to make sure there aren't any stragglers left in
// the StringBuilder. Would happen if the count of groups is not a multiple of 4
if(groups.Count % 4 != 0) {
groups.Add(int.Parse(sb.ToString()));
}
This will give you a list of 4 digit ints and make sure you don't lose any if your the number of ints in your groups list is not a multiple of 4. Please note that I am continuing based on what you provided, so groups is the ArrayList of ints.
This is some thing I quickly put together:
Update:
ArrayList guesses = new ArrayList(); //This is the ArrayList
// Four or more
guesses.Add(1); guesses.Add(2);
guesses.Add(3);guesses.Add(4);
guesses.Add(5); guesses.Add(6); guesses.Add(7);guesses.Add(8); guesses.Add(9);
//Uncomment-Me for less than four inputs
//guesses.Add(1); guesses.Add(2);
int position = 0;
if (guesses.Count < 4)
{
for (int y = 0; y < guesses.Count; y++)
{
Console.Out.Write(guesses[y]);
}
}
else
{
for (int i = 1; i <= guesses.Count; i++)
{
if (i%4 == 0)
{
Console.Out.WriteLine(string.Format("{0}{1}{2}{3}", guesses[i - 4], guesses[i - 3],
guesses[i - 2], guesses[i - 1]));
position = i;
}
else
{
if (i == guesses.Count)
{
for (int j = position; j < i; j++)
{
Console.Out.Write(guesses[j]);
}
}
}
}
}
Im trying to get specific lines from a file and put them in a another string or maybe if we can put it in anothe textbox it wont be a prob :P
string[] msglines;
msglines = System.IO.File.ReadAllLines(#"C:\\Users\xA\Desktop\MESSAGES.txt");
for (int x = 0; x < msglines.Length; x++)
{
this.textBox5.Text = msglines[c];
c = c + 2;
}
I get a :
Index was outside the bounds of the array.
If you want to get every second line.
Change your loop to
//Odd Lines
for (int x = 0; x < msglines.Length; x = x + 2)
{
this.textBox5.Text += msglines[x];
}
//Even Lines
for (int x = 1; x < msglines.Length; x = x + 2)
{
this.textBox5.Text += msglines[x];
}
As was pointed out in the comments, you can shorten x = x + 2 to x += 2
And in the interest of LinqY Goodness...
//ODDS
msgLines
.Where((str, index) => index % 2 == 0)
.ToList()
.ForEach(str => textBox1.Text += String.Format("{0}\r\n", str));
//EVENS
msgLines
.Where((str, index) => index % 2 == 1)
.ToList()
.ForEach(str => textBox1.Text += String.Format("{0}\r\n", str));
your loop is controlled by x, but you're indexing by c [hence you need logic to prevent c getting greater than size of the array]
Because you are increasing the line index (c) by 2 each time; just use x:
this.textBox5.Text = msglines[x];
Of course, from a loop this will result in just the last line being shown. What line is it you actually want to show?
Edit re comment; in which case, simply:
StringBuilder sb = new StringBuilder();
for (int x = 1; x < msglines.Length; x+=2)
{
sb.AppendLine(msglines[x]);
}
this.textBox5.Text = sb.ToString();
In your for loop, you are using c. You need to use x. Could I suggest that you have a look at the reference for for.
Try this instead...
string[] msglines;
msglines = System.IO.File.ReadAllLines(#"C:\\Users\xA\Desktop\MESSAGES.txt");
for (int x = 0; x < msglines.Length; x++)
{
this.textBox5.Text = msglines[x];
}
Then you should use X as an index, with a step of 2, instead of 1.
Try this
string[] msglines;
msglines = System.IO.File.ReadAllLines(#"C:\Users\xA\Desktop\MESSAGES.txt");
for (int x = 0; x < msglines.Length; x++)
{
this.textBox5.Text = msglines[x++];
}
You say you want all odd-numbered lines in the TextBox, but your loop will only show the last line, as you overwrite the contents on each pass.
To show all odd-numbered lines, separated by line breaks:
string lineSep = "";
for (int x = 0; x < msglines.Length; x += 2)
{
this.textBox5.Text += lineSep + msglines[x];
lineSep = "\r\n";
}
For simplicity I'll use an example of taking every other character from a string, but the case of taking every other line from an array of strings is analogous.
Lets take "Hello" as an example for your msglines string
(source: javabat.com)
and let us say that your global variable c i initialized to 0 before you enter the for loop. Your msglines.Lenght will be 5. In the the fourth iteration through the loop (x == 3) you are going to try to access msglines[6], which is outside of the bounds of the array, hence the error.
You probably wanted something along the lines of
int x = 0;
while(x <= msglines.Lenght){
this.textBox5.Text += msglines[x];
x = x + 2;
}
or
for(x=0; x <= msglines.Lenght ; x+=2){
this.textBox5.Text += msglines[x];
}
To get the odd lines you would start with x initialized to 1.
As for which of the two fully equivalent versions above to use, I would suggest using the one that is more readable to you. In my experience that is always the better choice.
You have a double backslash in the ReadAllLines() call, causing it to fail opening the file.
Also, you are using c as an array index, it looks like you want x
The code i wrote is exactly how I want it to be.....
I actually want every odd line from my file to be sent to the textbox.and yeah P.S C initializes from 1
Besides the already mentioned indexing problems of c versus x, you are also overwriting textBox5.Text on every iteration, so you'll only ever see the last line. It seems somehow unlikely to be intended behaviour. You might want something like this instead:
this.textBox5.Text += msglines[x]; // note x instead of c
Or if you really want everything and the +2 was a typo in itself you could do this without any loop:
this.textBox5.Text = String.Join( "\n", msglines );
The following function will return an IEnumerable that gives the odd numbered lines in a file:
private IEnumerable<string> GetOddLines(string fileName)
{
string[] lines = File.ReadAllLines(fileName);
IEnumerator allLines = lines.GetEnumerator();
while (allLines.MoveNext())
{
yield return (string)allLines.Current;
if (!allLines.MoveNext())
{
break;
}
}
}
If you want the even numbered lines, just add a call to allLines.MoveNext() before the while loop.
You need to loop the array with Length -1. Array of 45 Length will only index to 44.