I initially did not want to answer this question, because the requirements are a little bit unclear. I saw in other answers that the interpretation, or solution approach was to use std::getline
to read a line and then output that. My assumptions is that the user may want to have the values, to further operate on them. But as said, this is my assumption and others may have other assumptions. Only the OP can clarify.
Based on my observations and my very personal interpretation, there are 2 possible approaches.
- The input could come from a “competitive programming” page. The given data look somehow like that. Then, the input can always be seen as correct and very simply be read step by step. Or
- There is some serious background and we can read the data in some structured way.
In both cases it is the structure of the “nXn” map is unclear. It could be a 2-dimensional char array or a 2-dimensional array of values, for example of type integer. In any case there are obviously n rows with n columns of something.
Let us first assume simple script, as often used on “competitive programming pages”.
The important point is that we obviously need some dynamic data structures, because, first the input describes, how many data follow, then we need to create a container for that and read the data into that container.
For a dynamic container we normally use a std::vector
(a little bit depending on the later use case). On “competitive programming” pages VLAs (Variable Length Arrays) are very popular. But, since they are not C++ compliant, I will not use them.
There is also one fixed data structure, which is called “coordinate” by the OP, and obviously always contains 2 data. Maybe even an x or y coordinate for the map. But this is a guess.
Anyway, with these assumptions, we can come up with a potential solution approach.
- In the first line, we have 3 values. The dimension of the following map and 2 other properties that we do not know now
- Then we have a nXn map, with a little bit unknown content.
- A
vector
of vector
with coordinates
So, one (of many) possible solution could be:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <utility>
const std::string filename{"r:\\01"};
int main() {
// Open the file and check, if it could be opened
if (std::ifstream inputFileStream{ filename }; inputFileStream) {
// Read basic parameters
if (size_t dimensionOfMap{}, valueA{}, valueB{}; inputFileStream >> dimensionOfMap >> valueA >> valueB) {
// Define the 2d map and set the dimension
using MapDataType = char;
std::vector<std::vector<MapDataType>> nXnMap(dimensionOfMap, std::vector<MapDataType>(dimensionOfMap, {}));
// Read the comlete map
for (std::vector<MapDataType> &row : nXnMap) for (char &col : row) inputFileStream >> col;
// Next we want to read the coordinates. . We will store them in a vector of vector of pairs
using Coordinate = std::pair<int, int>;
std::vector < std::vector<Coordinate>> coordinates{};
// We will first always read the number of coordinates and the the coordinates itself
for (size_t numberOfCoordinates{}; inputFileStream >> numberOfCoordinates;) {
// Add a new coordinate set
coordinates.push_back({});
// Now read the coordinates in a loop
for (size_t index{}; index < numberOfCoordinates; ++index)
if (std::pair<int, int> temp{}; inputFileStream >> temp.first >> temp.second)
coordinates.back().push_back(temp);
else std::cerr << "\n*** Error: Could not read coordinates.\n\n";
}
// ----------------------------------------------------------------------------------------------------------------------------
// Some Debug output
std::cout << "\n\nDimension of map: " << dimensionOfMap << "\tValue a: " << valueA << "\tValue b: " << valueB << "\n\nMap:\n";
for (const std::vector<MapDataType>& row : nXnMap) {
for (char col : row) std::cout << col << ' ';
std::cout << '\n';
}
// Coordinates
std::cout << "\n\nCoordinates:\n";
for (const std::vector<Coordinate>& coordinate : coordinates) {
for (const auto& [x, y] : coordinate) std::cout << '[' << x << ',' << y << ']' << ' ';
std::cout << '\n';
}
}
else std::cerr << "\n*** Error: Could not read basic parameters.\n\n";
}
else std::cerr << "\n*** Error: Could not open input file '" << filename << "'.\n\n";
}
If we want to follow a little bit more the object-oriented approach, then we would introduce classes with data and methods, operating on those data.
We would split down the big task into smaller tasks and especially encapsulate the read and write operations in the classes with the corresponding data.
The following data need to be abstracted and implemented as a class.
- General Data
- The Map
- A List with coordinates
- The coordinate
All classes know, how to read and write their data from/to a stream. And, because of the object-oriented approach, only the classes should know that.
That makes later changes to one dedicated class possible, without interfering with other parts of the code.
We define the classes in reverse order, so that we do not need any forward declarations.
Please see the power of C++. Start always with small and easy parts and later combine them.
Have a look at main. You will just see a one liner to read all data.
#include <iostream>
#include <vector>
#include <fstream>
struct Coordinate {
// Data part
int x{};
int y{};
// Simple extractor and inverter overlaods
friend std::istream& operator >> (std::istream& is, Coordinate& c) { return is >> c.x >> c.y; }
friend std::ostream& operator << (std::ostream& os, const Coordinate& c) { return os << '[' << c.x << ',' << c.y << ']'; }
};
struct CoordinateGroup {
// Data part
std::vector<Coordinate> coordinateGroup{};
// Simple extractor and inverter overlaods
friend std::istream& operator >> (std::istream& is, CoordinateGroup& cg) {
cg.coordinateGroup.clear();
if (size_t numberOfCoordinates{}; is >> numberOfCoordinates) {
for (size_t k{}; k < numberOfCoordinates; ++k)
if (Coordinate temp{}; is >> temp)
cg.coordinateGroup.push_back(temp);
}
return is;
}
friend std::ostream& operator << (std::ostream& os, const CoordinateGroup& cg) {
for (const Coordinate c : cg.coordinateGroup) os << c << ' ';
return os;
}
};
struct Coordinates {
// Data part
std::vector<CoordinateGroup> coordinates{};
// Simple extractor and inverter overlaods
friend std::istream& operator >> (std::istream& is, Coordinates& c) {
for (CoordinateGroup cg; is >> cg; c.coordinates.push_back(cg));
return is;
}
friend std::ostream& operator << (std::ostream& os, const Coordinates& c) {
for (const CoordinateGroup& cg : c.coordinates) os << cg << '\n';
return os;
}
};
struct NxNmap {
using MapDataType = char;
// Data part
std::vector<std::vector<MapDataType>> map{};
// Set dimensions of map
void setDimension(size_t d) { map.resize(d, std::vector<MapDataType>(d)); }
// Simple extractor and inverter overlaods
friend std::istream& operator >> (std::istream& is, NxNmap& m) {
for (std::vector<MapDataType>& row : m.map) for (char& col : row) is >> col;
return is;
}
friend std::ostream& operator << (std::ostream& os, const NxNmap& m) {
for (const std::vector<MapDataType>& row : m.map) {
for (const char col : row) os << col;
os << '\n';
}
return os;
}
};
struct General {
// Data part
size_t dimensionOfMap{};
int valueA{};
int valueB{};
// Simple extractor and inverter overlaods
friend std::istream& operator >> (std::istream& is, General& g) {return is >> g.dimensionOfMap >> g.valueA >> g.valueB; }
friend std::ostream& operator << (std::ostream& os, const General& g) {
return os << "Map Dimension: " << g.dimensionOfMap << "\tValue a: " << g.valueA << "\tValue b: " << g.valueB;
}
};
struct Data {
// Data part
General general{};
NxNmap nXnMap{};
Coordinates coordinates{};
// Simple extractor and inverter overlaods
friend std::istream& operator >> (std::istream& is, Data& d) {
if (is >> d.general) {
d.nXnMap.setDimension(d.general.dimensionOfMap);
is >> d.nXnMap >> d.coordinates;
}
return is;
}
friend std::ostream& operator << (std::ostream& os, const Data& d) {
return os << d.general << "\n\nMap:\n" << d.nXnMap << "\n\nCoordinates:\n" << d.coordinates << "\n\n";
}
};
// Test/Driver Code
const std::string filename{ "01" };
int main() {
// Open the file and check, if it could be opened
if (std::ifstream inputFileStream{ filename }; inputFileStream) {
// Define data struct
Data data{};
// Read all data with a one liner
inputFileStream >> data;
// Show all data. One liner.
std::cout << data;
}
else std::cerr << "\n*** Error: Could not open input file '" << filename << "'.\n\n";
}
With this input in a file 01
4 15 30
....
....
....
....
1
1 2
3
1 2
2 1
2 2
we will get the following output:
Map Dimension: 4 Value a: 15 Value b: 30
Map:
....
....
....
....
Coordinates:
[1,2]
[1,2] [2,1] [2,2]
Just as a reminder again
- There are one million possible solutions
- Everybody can do what he wants