I have an input file with 3 fields on each line that are type: string, double, double. There are 15 lines with data.
The format of the input file data is:
Katmandu, -34, 28
cityName, lowTemp, highTemp
....
...
..
It's obvious that it's not getting the 3rd input on the line, based on the output.
Here is the code:
for (int index = 0; index < 15; index++)
{
getline(inFile, weatherInfo[index].city, ',');
inFile >> weatherInfo[index].low >> weatherInfo[index].high;
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
For some reason this is my output:
Katmandu (-34, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
I know my program is able to read the other lines because when I add
inFile.ignore(20);
to the beginning of my statement it the loop it outputs
28
Perth (92, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
(0, 0)
Output Code:
void ShowAll(int count) //Show entire data function
{
int x = 0; //loop through the index of city[], lowTemp[], highTemp[], and print them.
while (x < count)
{
cout << weatherInfo[x].city << " (" << weatherInfo[x].low << ", " << weatherInfo[x].high << ")" << endl;
x++;
}
cout << endl;
}
If the data in a line are separated by commas then you should use the following approach
#include <sstream>
//...
std::string line;
for ( int index = 0; index < 15 && std::getline( inFile, line ); index++)
{
std::istringstream is( line );
getline( is, weatherInfo[index].city, ',');
std::string field;
if ( getline( is, field, ',') ) weatherInfo[index].low = std::stod( field );
if ( getline( is, field, ',') ) weatherInfo[index].high = std::stod( field );
}
The problem with your code is that an error occurs when you are trying to read double values and a comma is encountered. In this case ths state of the stream will be erroneous and all other input will be ignored.
Also you should check what is the point representation for doubles in the locale you are using.
Related
I am trying to map some chars in a string to some integer values using enum. Please tell where am I going wrong?
enum moves{U,R,D,L};
class Solution {
public:
bool judgeCircle(string moves) {
// moves is a string having values like ULLDDRR, ULRD, UULLDDRR
int X[] = {0,1,0,-1};
int Y[] = {1,0,-1,0};
// while iterating the string if I get a 'U' , I want to use it as an index
//with U representing the 0th index, R as index=1 and so on.. as specified
//in the enum
int x=0 , y=0;
enum moves ind;
for( int i = 0 ; i < moves.length() ; i++ ) {
ind = moves[i]; // but this line here gives error
x += X[ind];
y += Y[ind];
}
if(!x && !y)
return true;
else
return false;
}
};
I would drop the idea with an enum because I feel it has no use for the actual problem – to map characters to navigation moves. For this, I would use a std::map or a std::unordered_map. (Considering, that there are 4 entries only, the performance difference is probably hard to measure.)
While I was preparing a sample code, πάντα ῥεῖ gave a similar hint. Though, I would even recommend to bundle x and y of moves together:
#include <map>
#include <iomanip>
#include <iostream>
// bundle x and y for a move (which needs both of them)
struct Move {
int dx, dy;
};
// a type to map chars to moves
using MoveMap = std::map<char, Move>;
// a pre-defined move map
static const MoveMap mapMoves = {
{ 'U', { 0, 1 } },
{ 'R', { 1, 0 } },
{ 'D', { 0, -1 } },
{ 'L', { -1, 0 } }
};
/* a function to use move map
*
* id ... one of U R D L
* x, y ... coordinates (update)
* return: true if successful, (false e.g. for wrong id)
*/
bool move(char id, int &x, int &y)
{
const MoveMap::const_iterator iter = mapMoves.find(id);
return iter != mapMoves.end()
? x += iter->second.dx, y += iter->second.dy, true
: false;
}
// check it out:
int main()
{
int x = 0, y = 0;
const char test[] = "ULLDDRR, ULRD, UULLDDRR";
for (char id : test) {
std::cout << "(" << x << ", " << y << "): "
<< "Move '" << id << "' -> ";
if (move(id, x, y)) {
std::cout << "(" << x << ", " << y << ")\n";
} else std::cout << "failed\n";
}
return 0;
}
Output:
(0, 0): Move 'U' -> (0, 1)
(0, 1): Move 'L' -> (-1, 1)
(-1, 1): Move 'L' -> (-2, 1)
(-2, 1): Move 'D' -> (-2, 0)
(-2, 0): Move 'D' -> (-2, -1)
(-2, -1): Move 'R' -> (-1, -1)
(-1, -1): Move 'R' -> (0, -1)
(0, -1): Move ',' -> failed
(0, -1): Move ' ' -> failed
(0, -1): Move 'U' -> (0, 0)
(0, 0): Move 'L' -> (-1, 0)
(-1, 0): Move 'R' -> (0, 0)
(0, 0): Move 'D' -> (0, -1)
(0, -1): Move ',' -> failed
(0, -1): Move ' ' -> failed
(0, -1): Move 'U' -> (0, 0)
(0, 0): Move 'U' -> (0, 1)
(0, 1): Move 'L' -> (-1, 1)
(-1, 1): Move 'L' -> (-2, 1)
(-2, 1): Move 'D' -> (-2, 0)
(-2, 0): Move 'D' -> (-2, -1)
(-2, -1): Move 'R' -> (-1, -1)
(-1, -1): Move 'R' -> (0, -1)
(0, -1): Move '' -> failed
Live Demo on coliru
I'm learning C++.
I'm trying to convert a text file like this one:
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,
...
Into a file like this one:
int grid[20][30] =
{
{ 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 },
Both piece of text file are only and example to show you what I'm trying to do. The first text file doesn't generate the second text file.
I have written down this code:
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char *argv[])
{
if ((argc == 1) || (argc != 5)) {
cout << "Usage: format rows columns input_file output_file\n";
return 0;
}
// Number of rows in the image.
int rows = atoi(argv[1]);
// Number of columns in the image.
int columns = atoi(argv[2]);
// Character read from the input file.
char ch;
// Counter to create arrays of "columns" elements.
int colCount = 0;
// Counter for the number of rows added to the grid.
int rowCount = 0;
// Output file.
ofstream fout;
fout.open(argv[4], ios::out);
// Write the header to output file.
fout << "int grid[" << rows << "][" << columns << "] = {";
// Read input file.
fstream fin(argv[3], fstream::in);
while (fin >> noskipws >> ch)
{
if (colCount == 0)
fout << "\n{";
if ((!isspace(ch)) && ((ch == '1') || (ch == '0') || (ch == ','))) {
fout << ch;
colCount++;
}
if (colCount == columns) {
colCount = 0;
rowCount++;
if (rowCount != rows)
fout << "},";
}
}
fout << "}};\n";
fout.close();
return 0;
}
But it seems that it never enters into the main loop (while (fin >> noskipws >> ch)). I get this output in the text file:
int grid[365][484] = {}};
I'm compiling with g++ on Linux (Ubuntu) with the following command line:
g++ FormatMatrix.cpp -o format
What am I doing wrong?
Check if create/open your input stream 'fin' succeeded before you enter the while loop.
I am making a function that validates a user input is a grid reference, between A0 and J9 (a 10 x 10 grid).
I can validate the integer part fine, but am wondering how to validate the alphabetical part, without saying for example:
if(Column == 'A' || Column == 'a' || Column == 'B' ....)
In a similar fashion to saying if int Row < 10.
Also, is there a way to convert to a single character, such as stoi for string to integer?
Here is my functions code, thank you.
void InputLocation(){
bool still_prompt = true;
while (still_prompt)
{
std::string answer;
std::cout << "Enter a grid location from A0 to J9" << std::endl;
std::getline(std::cin, answer);
std::string Column = answer.substr(0, 1);
std::string Row = answer.substr(1, 1);
if (answer.length() > 2 || answer.length() < 2){
std::cerr << "Location input must be of length 2 characters.\n";
continue;
}
else{ // If input has length 2, then get to this stage
try{
int intRow = std::stoi(Row);
if (intRow < 0 || intRow > 9){
std::cerr << "Row number must be between 0 and 9. \n";
continue;
}
}
catch (...){
std::cerr << "Second character of location input must be integer. \n";
continue;
}
}still_prompt = false;
}
}
Individual characters can be treated as numbers, so this is pretty simple to do! For example:
bool test(char character) {
return 'a' <= character && character <= 'j';
}
This function tests if a character is between 'a' and 'j'. This works because under the hood, 'a' and 'j' are just numbers. You can even see what numbers they are just by printing out the value:
int a_value = 'a'; // chars can be implictly converted to int
int j_value = 'j';
std::cout << "value of 'a'": << a_value << '\n';
std::cout << "value of j'j": << j_value << '\n';
Putting it all together. We can check if something is in the correct range just by doing a comparison. The following function will check if a character is within the range a through j.
bool testInRange(char c) {
return ('a' <= c && c <= 'j') || ('A' <= c && c <= 'J');
}
We can also write a function to convert it into an index on the grid:
int charToGridIndex(char c) {
if('A' <= c && c <= 'J')
{
return c - 'A';
}
else if('a' <= c && c <= 'j')
{
return c - 'a';
}
else
{
// Return -1 to indicate an invalid character
return -1;
}
}
Here,
charToGridIndex('a') == 0
charToGridIndex('b') == 1
charToGridIndex('c') == 2
charToGridIndex('d') == 3
charToGridIndex('e') == 4
charToGridIndex('f') == 5
charToGridIndex('g') == 6
charToGridIndex('h') == 7
charToGridIndex('i') == 8
charToGridIndex('j') == 9
I am trying to solve an exercise in recursion that goes like this.
Say you have a matrix of nxm with integers like this(just an example):
1 1 1 5 2
2 3 5 2 1
3 1 1 1 5
1 1 5 1 1
I want to find a path (starting from anywhere) that, given a number n, every step n changes by n/(number_at_that_position) and the path stops when n = 1.
I am not looking for all paths, I am just looking for a path.
So if you use symbols to map the path, you would end up with a matrix
> > V - *
- - V > ^
- - V ^ -
- - > ^ -
Where '>' means a step right, '<' means a step left, '^' is a step up and 'V 'is a step down. Once n becomes 1, we insert '*' to say the path ended.
Most important: The path has to be continuous and you cannot visit a place you have visited before.
Even more important: The function that finds the path MUST be recursive.
If no path is found, the code exits with a message saying that no path was found.
Up to now I've come up with the following code for the path finding. I've used ideas from different places, but one of them is this one Recursively finding a path through a maze c++
bool path_print(vector<vector<int> > &P, size_t line, size_t col, vector<vector<char> > &A, int n) {
if (line < 0 || line > P.size() || col < 0 || col > P[0].size()) {
return false;
}
if (A[line][col] != '-') {
return false;
}
if (n == 1) {
A[line][col] = '*';
return false;
}
printf("n = %d, line = %zu, col = %zu\n", n, line, col);
n = n/P[line][col];
if (path_print(P, line, col+1, A, n) == true){
A[line][col] = '>';
return true;
} else if (path_print(P, line-1, col, A, n) == true) {
A[line][col] = '^';
return true;
} else if (path_print(P, line+1, col, A, n) == true){
A[line][col] = 'V';
return true;
} else if (path_print(P, line, col-1, A, n) == true){
A[line][col] = '<';
return true;
}
return true;
}
P is the vector containing the values
A is the char vector that stores the path
n is the actual number you are probing
I've been working on this for a while and I am stuck. This code does not work properly. Any suggestions or help would be greatly appreciated.
Thank you in advance
In your code :
if (line < 0 || line > P.size() || col < 0 || col > P[0].size())
is wrong because :
that allows to use the indexes P.size() and P[0].size(), in the original code of the link the comparisons are made with size - 1
line is a size_t so to do line < 0 has no sense, same for col
can be :
bool path_print(vector<vector<int> > &P, int line, int col, vector<vector<char> > &A, int n) {
if (line < 0 || line >= (int) P.size() || col < 0 || col >= (int) P[0].size())
or to check col and line before to do + 1 or -1 on them in a recursive call to avoid any problem including overflow.
But this is not enough to solve your problem, because your other changes from the code of the link are wrong :
you modify A cell after the recursive calls rather than before
you do not reset A cell to '-' after
when you find the exit (in your case n is 1) you return false rather than true, so you continue to search, and you check the value of n too late after an other move
at the end of the function you return true rather than false
Note that is is useless to continue to search while n is 0 after the division
To write if (f() == true) is redundant, if (f()) is enough
A solution modifying your code is :
#include <iostream>
#include <vector>
using namespace std;
bool searchPath(const vector<vector<int> > & P,
size_t line, size_t col,
vector<vector<char> > &A,
int n) {
if (A[line][col] != '-') {
return false;
}
n = n/P[line][col];
if (n == 1) {
A[line][col] = '*';
return true;
}
if (n == 0)
return false;
A[line][col] = '>';
if ((col != (P[0].size() - 1)) && searchPath(P, line, col+1, A, n)) {
return true;
}
A[line][col] = '^';
if ((line != 0) && searchPath(P, line-1, col, A, n)) {
return true;
}
A[line][col] = 'V';
if ((line != (P.size() - 1)) && searchPath(P, line+1, col, A, n)){
return true;
}
A[line][col] = '<';
if ((col != 0) && searchPath(P, line, col-1, A, n)){
return true;
}
A[line][col] = '-';
return false;
}
int main(int argc, char ** argv)
{
vector<vector<int> > P;
vector<vector<char> > A;
// fill vectors
int lines, columns;
cout << "number of lines and columns : ";
if (!((cin >> lines) && (cin >> columns) && (lines > 0) && (columns > 0))) {
cout << "invalid sizes" << endl;
return -1;
}
P.resize(lines);
A.resize(lines);
cout << "enter maze" << endl;
for (int i = 0; i != lines; ++i) {
P[i].resize(columns);
A[i].resize(columns);
for (int j = 0; j != columns; ++j) {
int v;
if (!(cin >> v) || (v < 1)) {
cout << "invalid input : " << v << endl;
return -1;
}
P[i][j] = v;
A[i][j] = '-';
}
}
int n;
cout << "enter n : ";
if (!(cin >> n) || (n <= 0)) {
cout << "invalid value of n" << endl;
return -1;
}
// search a way from all cells
for (size_t l = 0; l != (size_t) lines; ++l) {
for (size_t c = 0; c != (size_t) columns; ++c) {
if (searchPath(P, l, c, A, n)) {
// found
cout << "found from cell line " << l << " column " << c << endl;
for (l = 0; l != (size_t) lines; ++l) {
for (c = 0; c != (size_t) columns; ++c) {
cout << A[l][c] << ' ';
}
cout << endl;
}
return 0;
}
}
}
cout << "no solution" << endl;
return 0;
}
Examples :
number of lines and columns : 4 5
enter maze
1 1 1 5 2
2 3 5 2 1
3 1 1 1 5
1 1 5 1 1
enter n : 200
found from cell line 0 column 0
> > > > V
- * - - V
- ^ < < V
- - - ^ <
number of lines and columns : 4 5
enter maze
1 1 1 5 2
2 3 5 2 1
3 1 1 1 5
1 1 5 1 1
enter n : 999999
no solution
I'm trying to solve one problem, which I found on website https://open.kattis.com/problems/coast. Tl;dr version of problem is, that for given map of landscape, I should print out length of coastline (without inner islands).
My idea was, to solve this by adding additional layer and then start DFS, so the algorithm will walk through every possible tile in map, and then watch on every tile, how many borders are around the tile.
However, for specific input, is my algorithm not working. When I've submitted the solution on this site (open.kattis), it says, that my program is giving wrong answer in 9th of 26 tests (previous 8 test were ok), but without any further explanation.
Can somebody look at my program, and say me, why is it bad? Where did I do mistake? Thanks
#include <iostream>
#include <stack>
#include <sstream>
using namespace std;
int main() {
string line;
getline(cin, line);
int rows = 0;
int columns = 0;
stringstream stream(line);
stream >> rows;
stream >> columns;
int map[rows][columns];
for (int i = 0; i < rows; i++) {
getline(cin, line);
for (int j = 0; j < columns; j++) {
map[i][j] = line[j] - 48;
}
}
//parsed landscape into 2d array
// int rows = 5;
// int columns = 6;
// int map[rows][columns] = {
// {0, 1, 1, 1, 1, 0,},
// {0, 1, 0, 1, 1, 0,},
// {1, 1, 1, 0, 0, 0,},
// {0, 0, 0, 0, 1, 0,},
// {0, 0, 0, 0, 0, 0,},
// };
int bigMap[rows+2][columns+2];
bool visited[rows+2][columns+2];
//create bigger map, so DFS can start from corner and assume
//that there is water around everywhere
//also initialize array visited for DFS
//add 2 new rows, before and after existing one
for (int i = 0; i < columns+2; i++) {
bigMap[0][i] = 0;
bigMap[rows + 1][i] = 0;
visited[0][i] = false;
visited[rows + 1][i] = false;
}
//add 2 new columns, before and after existing
//copy original map to new one
for (int i = 0; i < rows; i++) {
bigMap[i+1][0] = 0;
bigMap[i+1][columns + 1] = 0;
visited[i+1][0] = false;
visited[i+1][columns + 1] = false;
for (int j = 0; j < columns; j++) {
bigMap[i+1][j+1] = map[i][j];
visited[i+1][j+1] = false;
}
}
rows += 2;
columns += 2;
//starting DFS
int x = 0, y = 0;
//visited[x][y] = true; <-- edit
pair <int, int> coordinates;
coordinates.first = x;
coordinates.second = y;
stack<pair <int, int> > st;
//first vertex in stack
st.push(coordinates);
//total sum of borders
int borders = 0;
while(!st.empty()) {
//check coordinates in each round
x = st.top().first;
y = st.top().second;
//navigate to new vertex (only if new vertex wasn't visited (visited[x][y] == 0) and only
//if there is water (bigMap[x][y] == 0) and check if new vertex is still in the map
//if there is no possible vertex, then we reached the end so then pop the vertex and
//look in another way
if (visited[x][y+1] == 0 && bigMap[x][y+1] == 0 && y + 1 < columns) {
y++;
coordinates.second = y;
st.push(coordinates);
} else {
if (visited[x+1][y] == 0 && bigMap[x+1][y] == 0 && x + 1 < rows) {
x++;
coordinates.first = x;
st.push(coordinates);
} else {
if (visited[x][y-1] == 0 && bigMap[x][y-1] == 0 && y > 0) {
y--;
coordinates.second = y;
st.push(coordinates);
} else {
if (visited[x-1][y] == 0 && bigMap[x-1][y] == 0 && x > 0) {
x--;
coordinates.first = x;
st.push(coordinates);
} else {
st.pop();
continue;
}
}
}
}
//visited new vertex, so look around him and count borders
visited[x][y] = true;
if (bigMap[x][y+1] == 1 && y + 1 < columns) borders++;
if (bigMap[x+1][y] == 1 && x + 1< rows) borders++;
if (bigMap[x][y-1] == 1 && y > 0) borders++;
if (bigMap[x-1][y] == 1 && x > 0) borders++;
}
cout << borders << endl;
return 0;
The issue is that you are reusing the variable coordinates each time around the loop without setting it to the correct value. Your if test cascade is assuming that coordinates is set to the current location. This is only true while you are descending in your dfs. Once you start ascending again, the coordinate will be pointing to the wrong place.
Simple solution, add
coordinates = st.top();
at the top of your loop.
Here is a sample map that it will currently get wrong.
5 6
000000
011100
001010
000100
000000
Answer should be 14, but currently you get 18 as the program reaches the lake at row 3, column 4.
To check that it is doing this, add a debugging line at the end of your loop, where it is adding the borders.
cout << "adding " << x << " " << y << "\n";
You can then verify if the program is considering any locations it shouldn't.
I think it will fail for {1,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}. This is because the walk through is prevented from completing due to setting visited=true for vertex 0,0. Set it false for 0,0 instead should improve things. Hope it helps.