How can I stream different lines of input from one text file? - c++

I'm trying to create a simulation in which I have objects moving within a rectangular grid. Information is given in the form of a text file. Sample input is as follows:
5 5
0 1 N
PFPFFSF
2 3 S
FSFFSFFSPF
First line is the dimension of the grid (in this case 5 x 5 assuming the bottom left coordinate is 0,0)
The rest of the input is just info in regards to the object and how it moves. Each object has 2 lines of input. First line is it's starting coordinates and orientation while the second line describes its movements.
When using an input stream, how can I grab the input so that it groups accordingly?
I know for the first line, I can just use
simulationSettings >> x >> y;
to grab the size of the grid.
However, is there a way of grabbing the rest of the input and grouping the info by 2 lines (for each object)?
So, for example, stream the input so that my object1 will have 0 1 N and PFPFFSF while object 2 has 2 3 S and FSFFSFFPF and so on should there be more objects.

If you can simply ignore how the file is actually structured in line, you structure is just:
2 integer values for the grid size
n times (per object):
2 integers for the initial position
one string for the initial direction
one string for the movements
You could just use:
simulationSettings >> x >> y;
if (! simulationSettings.good()) {
// process error condition and exit
}
for(;;) {
int xinit, yinit;
std::string direction, movements;
simulationSettings >> xinit;
if (simulationSettings.eof()) break; // normal end of file
simulationSetting >> yinit >> direction >> movements;
if (! simulationSettings.good()) {
// process error condition and at least break from the loop
}
// process the object
}

Related

How to keep taking 2 integers as input until program encounters a single integer?

I was given a question where the input will be like:
10 8
4 9
6 12
5 4
3
1
Here I don't know the number of lines that contains 2 integers. Those sets of 2 integers will be taken into an array. But when the program encounters "3", it will start taking input in another array.
I have tried this with
while(cin>>a>>b){ //some porcess with a and b }
but it doesn't work because it recognizes 3 and 1 as another set of two integers. Please help me to solve this problem.
cin >> a >> b skips not only spaces, but any delimeter characters too ('\n', '\t', ' ').
Here you actually may want to read input line-by-line and then check if there are two integers or one. Consider use of std::getline for retrieving each line of text. Then you can use read string as std::istream (like in example in the link above) and read from it with counting, how many numbers you read totally.
So think about your problem. Essentially it is, read one line at a time, and if it contains two numbers do one thing, but if it contains one number do something else.
But the code you have written reads numbers not lines. That is where the problem is.
Instead write your code to read only line at a time, analyse that line to see if it contains one or two numbers (or something else) and then proceed from there.
What you need is the ability to read a line of text into a string, and then read from that string into your numbers. To do that you use an istringstream. Something like this
#include <iostream>
#include <sstream>
#include <string>
int a, b;
string s;
getline(cin, s); // read one line from standard input
istringstream line(s); // put that string to a stream we can read from
if (line >> a) // try and read the first number from the stream
{
// got the first number
if (line >> b) // try and read the second number from the stream
{
// got the second number
...
}
else
{
// only one number
...
}
}
else
{
// didn't get any numbers, some sort of error
...
}

Finding a certain character from lines of input

I am currently trying to solve this kattis problem in C++:
Ecape Wall Maria
Wall Maria has been broken! Eren must evacuate as soon as possible from his house. He must find the fastest route to escape within Wall Maria before the titans rush in. Wall Maria is represented as a N×M grid in which Eren can move horizontally or vertically.
There are burning houses and buildings which prevent Eren from passing through them. The burning houses and buildings are represented as ‘1’. Unburned or safe areas are represented as ‘0’. There are some areas which can be entered but only from a specific direction. These areas can be represented by either ‘U’, ‘D’, ‘L’, or ‘R’. For example, if there is an ‘R’ that means that area can only be entered from the right neighboring tile within Wall Maria’s grid. Similarly, ‘U’ tiles can only be entered from above, ‘D’ tiles can only be entered from below, and ‘L’ tiles can only be entered from the left.
Eren knows the time t at which the titans will rush in. It takes 1 unit of time to traverse 1 zone (which corresponds to 1 tile in the grid). Once he reaches any border of Wall Maria he is safe.
Eren’s starting position is represented by the letter ‘S’. If Eren escapes at or before time t, he is safe. Given his position within Wall Maria determine if it is possible to escape. If it is possible determine the number of zones that must be traversed to lead to the quickest escape.
Input
The input consists of a single test case. The first line contains three integers t (1≤t≤200) , N (1≤N≤100) and M (1≤M≤100). The rest of N lines will be Wall Maria’s grid containing characters ‘1‘, ‘0‘, ‘S‘, ‘U‘, ‘D‘, ‘L‘, or ‘R‘. There is exactly one ‘S‘ in the input.
Output
If it is possible to escape Wall Maria, output the minimum number of zones that must be traversed to escape. If it is not possible to escape, print “NOT POSSIBLE”!
I am having some issues with finding the character "S" in the matrix on input.
I am thinking that once we have the input of the matrix, we find the character "S" and then look to the right, left, up and down of that character. If the character is not = 1 then you repeat the process from that character until you have "left" the matrix.
However, I have tried writing code to look for the starting point (the character "S) but I have been unsuccessful in doing that.
Furthermore, I am not sure how to look around the character once I have found it. I have only gotten to the point where I can accept input, not much further. Help would be appreciated
This is my code so far:
int main(){
int M;
int N;
int t;
string wall;
cin >> t >> N >> M;
//Takes the matrix input
for (int i = 0; i < N; i++)
{
cin >> wall;
}
}
The two steps are:
Decide what data structure you want to use to represent the grid you're about to traverse. std::vector<std::string> is a standard choice here.
Read the grid into the vector line by line, storing the row and column for 'S' as you go.
Here's one approach:
#include <iostream>
#include <string>
#include <vector>
int main() {
int M;
int N;
int t;
int sx = 0;
int sy = 0;
std::cin >> t >> N >> M;
std::vector<std::string> grid(N);
for (int i = 0; i < N; i++) {
std::cin >> grid[i];
size_t pos = grid[i].find("S");
if (pos != std::string::npos) {
sx = pos;
sy = i;
}
}
// show the position; remove when you're ready to solve the problem
std::cout << sx << ", " << sy << "\n";
}
Here's the output on two of the samples:
$ ./a
1 4 4
1S01
1001
1011
0U11
1, 0
$ ./a
2 4 4
1111
1S01
1011
0U11
1, 1

std::cin with more complex objects

I have a text file which first describes some lines and then describes some colorful lines:
1 2 3 4
5 6 7 8
9 10 11 12
red 1 0 0 1 2 3 4
green 0 1 0 5 6 7 8
blue 0 0 1 9 10 11 12
The number of lines in each section is unknown at time of execution
I overloaded the std::cin >> operator for these structs:
struct Point { int x, y; }
struct Line { Point a, b; }
struct Color { float r, g, b; std::string name; };
struct ColorfulLine { Line line; Color color; };
(Full example here: http://ideone.com/bMOaL1 [already works - edited according to the accepted answer])
Now I need to iterate over the file using Lines and ColorfulLines:
Line line;
while(cin >> line) { cout << "We've got a line!\n"; }
ColorfulLine color_line;
while(cin >> color_line) { cout << "We've got a colorful line!\n"; }
// actually I'm putting them into std::lists but I skipped this part for simplicity
And here is the problem - the colorful lines are never fetched, i.e. the second loop is not executed.
I have an assumption why it happens but don't know how to fix it:
When std::cin tries to fetch the 4th Line, it fails because instead of a number there's the string "red".
Next, in the second while loop, std::cin tries to read a string (Color.name) but it sees a number, and then fails too.
I tried to put some random word before the ColorfulLines section hoping that when the first loop fails, the second will start reading from the "red" string, but it didn't.
How to fix this?
After the first loop breaks, std::cin is in a bad state. That's why the loop breaks in the first place. Performing reads on a bad stream fails immediately, thus the second loop is never entered.
To solve this, reset the error state after the first loop breaks with
std::cin.clear();

Reading from a file with multiple columns of integers and putting them into arrays

I am creating a command-line minesweeper game which has a save and continue capability. My code generates a file called "save.txt" which stores the position of the mines and the cells that the player has opened. It is separated into two columns delimited by a space where the left column represents the row of the cell and the right column represents the column of the cell in the matrix generated by my code. The following is the contents of save.txt after a sample run:
3 7
3 9
5 7
6 7
8 4
Mine end
2 9
1 10
3 5
1 1
Cell open end
You may have noticed Mine end and Cell open end. These two basically separate the numbers into two groups where the first one is for the position of the mines and the latter is for the position of the cells opened by the player. I have created a code which generates an array for each column provided that the text file contains integers:
int arrayRow[9];
int arrayCol[9];
ifstream infile("save.txt");
int a, b;
while(infile >> a >> b){
for(int i = 0; i < 9; i++){
arrayRow[i] = a;
arrayCol[i] = b;
}
}
As you can see, this won't quite work with my text file since it contains non-integer text. Basically, I want to create four arrays: mineRow, mineCol, openedRow, and openedCol as per described by the first paragraph.
Aside from parsing the string yourself and doing string operations, you can probably redefine the file format to have a header. Then you can parse the once and keep everything in numbers. Namely:
Let the Header be the first two rows
Row 1 = mineRowLen mineColLen
Row 2 = openedRowLen openedColLen
Row 3...N = data
save.txt:
40 30
20 10
// rest of the entries
Then you just read 40 for the mineRow, 30 for mineCol, 20 for openedRow, 10 for openedCol since you know their lengths. This will be potentially harder to debug, but would allow you to hide the save state better to disallow easy modification of it.
You can read the file line by line.
If the line matches "Mine end" or "Cell open end", continue;
Else, split the line by space (" "), and fill the array.

Filling an array or struct by file in C++

I'm writing a simple 2D game in C++ (a language that is still quite new to me) using DirectX that involves a grid of 26x26 tiles sorted in a Cartesian-like manner - with the origin being the top leftmost space at 0,0. Each tile needs to contain the values:
int tileX (from 0 to 25)
int tileY (from 0 to 25)
int tileType (0 is empty)
int tileState
These values will be stored in a text file stage_n.txt (228 lines long) which is formatted like the following:
2 2 1
3 2 1
6 2 1
7 2 1
10 2 1
11 2 1
...
Each set of tile values are separated by a new line, while each value is separated by a space. The first value is tileX, the second value is tileY, the third value is tileType. All tiles are initially assumed to have a tileState of 8.
These values will be looped through to draw the stage at the start of the game, and will be changed often in the code.Note that only tiles that are occupied are listed in the file. Tiles that are empty are not listed.
My first thought was to use a multidimensional array tileMap[25][25][1] like the following:
tileMap[0] = 0 (X value) // All tiles on line X0
tileMap[0][0] = 0 (Y value) // First tile on line 0 (at Y0)
tileMap [0][0][0] // Tile type
tileMap [0][0][1] // Tile state
tileMap[0][1] = 1 (Y value) // Second tile on line 0 (at Y1)
tileMap [0][1][0] // Tile type
tileMap [0][1][1] // Tile state
... through to 25 (the last tile on line 0)
tileMap[1] = 1 (X value) // All tiles on line X1
tileMap[1][0] = 0 (Y value)
...
tileMap[1][0] = 1 (Y value)
...
...
... through to 25 (the last line)
But I was also considering using a structure:
struct tileData{
int tileX;
int tileY;
int tileType;
int tileState;
} tile[676]; // 676 is the total amount of tiles.
Going back to my question; in this situation, would it be more efficient to use a struct or an array? How would I go about initializing/filling the easier option using data in the above text file? I've tried to imitate many examples online (that have used ifstream), but none of them have seemed to work.
This question has probably been answered a lot, but I just can't get my head around how to do it. I hope this makes enough sense. Thanks!
EDIT: Additionally, where should I place my text file if I'm using VS2013?
I doubt there would be any different in performance, since both accessing an array and accessing a member of a struct just involve accessing some baked-in offset from some address. If it really matters because you've discovered this code to be a bottleneck, then you'll need to do some performance measures. I can almost guarantee that the compiled code will be identical in either case.
Anyway, it looks to me like it would be most appropriate to use a struct. While all the members of the struct are the same type, they do not have the same meaning. It's certainly possible that they could have different types. A struct nicely groups together these different yet related values.
Reading into your 1D array should be as simple as:
std::ifstream file("stage_n.txt");
int i = 0;
while (file >> tile[i].tileX
>> tile[i].tileY
>> tile[i].tileType) {
tile[i].tileState = 0;
++i;
}
There's no reason you can't have a 2D array of structs, though. That would better represent your grid. In that case, you would just need to keep track of an x and y position as you read from the file (instead of i).
The file reading code above doesn't do much in the way of error checking. If you want to be precise, you should consider what exactly should be valid. For example, the above code would still accept the data even if it were all on one line. If you want to read the file on a line-by-line basis, you'll need to use std::getline and then parse each line.
i would use a 2d array of Tile objects (or std::vector or std::array, always preferred to naked arrays)
struct Tile
{
int tileType;
int tileState;
}
Tile grid[25][25];
dont put the X/Y of the tile in the struct. This knowledge is implicitly encoded in its position in the array
I think there is no difference in performance between an array and a struct. But there is a difference in better code - use the struct tilData and write a istream-operator for it.
std::istream& operator>>( std::istream& in, tileData& td )
{
if( in >> td.tileX >> td.tileY >> td.tileType )
td.tileState = 8;
return in;
}
You can read it in this way:
size_t n = 0;
for( ; file >> tile[n]; ++n )
;
if( file.eof() ) // check whether End Of File is reached
{
cout << "Ok " << n << "Tiles read\n";
}