ifstream fails without any reason? - c++

I have a list of 3d spheres, when I save the list, I loop through:
void Facade::Save(std::ostream& fs)
{
fs<<x<<" "<<y<<" "<<z<<" "<<r<<" "; //save fields
fs<<color[0]<<" "<<color[1]<<" "<<color[2]<<std::endl;
}
and when I restore the list, I use:
void Facade::Load(std::ifstream& fs, BallList* blist)
{
GLfloat c[3];
fs>>x>>y>>z>>r;
//fails there, why
fs>>c[0]>>c[1]>>c[2];
.....
}
I don't know what goes wrong, but when reading the last line, the color components of the last sphere cannot be read, the stream fails after reading the radius of the last sphere. I checked the sphere list file:
7.05008 8.99167 -7.16849 2.31024 1 0 0
3.85784 -3.93902 -1.46886 0.640751 1 0 0
9.33226 3.66375 -6.93533 2.25451 1 0 0
6.43361 1.64098 -6.17298 0.855785 1 0 0
6.34388 -0.494705 -6.88894 1.50784 1 0 0
This looks good. Can somebody tell me why is this happening? Is this a bug of ifstream?
I'm using Unicode by the way.
The loops are attached below:
void BallList::Load(std::istream& fs)
{
Clear();
Facade ball1;
while(!fs.fail() && !fs.eof())
{
ball1.Load(fs, this);
Add(ball1);
}
/*
balls.pop_back(); //this is a work around, get rid of the last one
originalballs.pop_back();
*/
}
void BallList::Save(std::ostream& fs)
{
vector<Facade>::iterator itero = this->originalballs.begin();
while (itero != this->originalballs.end())
{
itero->Save(fs);
itero++;
}
/*
//work around the ifstream problem: the color of the last sphere cannot be read
//add a dummy item as the last
itero = this->originalballs.begin();
if(itero != this->originalballs.end())
{
itero->Save(fs);
}
*/
}

I would expect this to fail after reading 5 balls (spheres) correctly.
The loop is designed so that attempting to read the 6th ball will fail but Add() is still called!!
You should redefine your code a bit:
std::ifstream& Facade::Load(std::ifstream& fs, BallList* blist)
{
GLfloat c[3];
fs>>x>>y>>z>>r; // This will fail if there is no input.
// Once all 5 balls have been read
// There is only a new line character on the stream.
// Thus the above line will fail and the fail bit is now set.
fs>>c[0]>>c[1]>>c[2];
return fs; // returned so it can be tested in loop.
}
void BallList::Load(std::istream& fs)
{
Clear();
Facade ball1;
while(ball1.Load(fs, this)) // Only enter loop if the load worked
{ // Load worked if the stream is in a good state.
// Only call Add() if Load() worked.
Add(ball1);
}
}
PS. White space is your friend. Personally I think this is easier to read:
fs >> x >> y >> z >> r;

Related

LZW Decompression

I am implementing a LZW algorithm in C++.
The size of the dictionary is a user input, but the minimum is 256, so it should work with binary files. If it reaches the end of the dictionary it goes around to the index 0 and works up overwriting it from there.
For example, if i put in a alice in wonderland script and compress it with a dictionary size 512 i get this dictionary.
But i have a problem with decompression and the output dictionary from decompressing the compressed file looks like this.
And my code for decompressing looks like this
struct dictionary
{
vector<unsigned char> entry;
vector<bool> bits;
};
void decompress(dictionary dict[], vector<bool> file, int dictionarySize, int numberOfBits)
{
//in this example
//dictionarySize = 512, tells the max size of the dictionary, and goes back to 0 if it reaches 513
//numberOfBits = log2(512) = 9
//dictionary dict[] contains bits and strings (strings can be empty)
// dict[0] =
// entry = (unsigned char)0
// bits = (if numberOfBits = 9) 000000001
// dict[255] =
// entry = (unsigned char)255
// bits = (if numberOfBits = 9) 011111111
// so the next entry will be dict[next] (next is currently 256)
// dict[256] =
// entry = what gets added in the code below
// bits = 100000000
// all the bits are already set previously (dictionary size is int dictionarySize) so in this case all the bits from 0 to 511 are already set, entries are set from 0 to 255, so extended ASCII
vector<bool> currentCode;
vector<unsigned char> currentString;
vector<unsigned char> temp;
int next=256;
bool found=false;
for(int i=0;i<file.size();i+=numberOfBits)
{
for(int j=0;j<numberOfBits;j++)
{
currentCode.push_back(file[i+j]);
}
for(int j=0;j<dictionarySize;j++)
{
// when the currentCode (size numberOfBits) gets found in the dictionary
if(currentCode==dict[j].bits)
{
currentString = dict[j].entry;
// if the current string isnt empty, then it means it found the characted in the dictionary
if(!currentString.empty())
{
found = true;
}
}
}
//if the currentCode in the dictionary has a string value attached to it
if(found)
{
for(int j=0;j<currentString.size();j++)
{
cout<<currentString[j];
}
temp.push_back(currentString[0]);
// so it doesnt just push 1 character into the dictionary
// example, if first read character is 'r', it is already in the dictionary so it doesnt get added
if(temp.size()>1)
{
// if next is more than 511, writing to that index would cause an error, so it resets back to 0 and goes back up
if(next>dictionarySize-1) //next > 512-1
{
next = 0;
}
dict[next].entry.clear();
dict[next].entry = temp;
next++;
}
//temp = currentString;
}
else
{
currentString = temp;
currentString.push_back(temp[0]);
for(int j=0;j<currentString.size();j++)
{
cout<<currentString[j];
}
// if next is more than 511, writing to that index would cause an error, so it resets back to 0 and goes back up
if(next>dictionarySize-1)
{
next = 0;
}
dict[next].entry.clear();
dict[next].entry = currentString;
next++;
//break;
}
temp = currentString;
// currentCode gets cleared, and written into in the next iteration
currentCode.clear();
//cout<<endl;
found = false;
}
}
Im am currently stuck and dont know what to fix here to fix the output.
I have also noticed, that if i put a dictionary big enough, so it doesnt go around the dictionary (it doesnt reach the end and begin again at 0) it works.
start small
you are using files that is too much data to debug. Start small with strings. I took this nice example from Wikli:
Input: "abacdacacadaad"
step input match output new_entry new_index
a 0
b 1
c 2
d 3
1 abacdacacadaad a 0 ab 4
2 bacdacacadaad b 1 ba 5
3 acdacacadaad a 0 ac 6
4 cdacacadaad c 2 cd 7
5 dacacadaad d 3 da 8
6 acacadaad ac 6 aca 9
7 acadaad aca 9 acad 10
8 daad da 8 daa 11
9 ad a 0 ad 12
10 d d 3
Output: "0102369803"
So you can debug your code step by step with cross matching both input/output and dictionary contents. Once that is done correctly then you can do the same for decoding:
Input: "0102369803"
step input output new_entry new_index
a 0
b 1
c 2
d 3
1 0 a
2 1 b ab 4
3 0 a ba 5
4 2 c ac 6
5 3 d cd 7
6 6 ac da 8
7 9 aca aca 9
8 8 da acad 10
9 0 a daa 11
10 3 d ad 12
Output: "abacdacacadaad"
Only then move to files and clear dictionary handling.
bitstream
once you succesfully done the LZW on small alphabet you can try to use the full alphabet and bit encoding. You know the LZW stream can be encoded at any bitlength (not just 8/16/32/64 bits) which can greatly affect compression ratios (in respect to used data properties). So I would try to do univeral access to data at variable (or predefined bitlength).
Was a bit curious so I encoded a simple C++/VCL example for the compression:
//---------------------------------------------------------------------------
// LZW
const int LZW_bits=12; // encoded bitstream size
const int LZW_size=1<<LZW_bits; // dictinary size
// bitstream R/W
DWORD bitstream_tmp=0;
//---------------------------------------------------------------------------
// return LZW_bits from dat[adr,bit] and increment position (adr,bit)
DWORD bitstream_read(BYTE *dat,int siz,int &adr,int &bit,int bits)
{
DWORD a=0,m=(1<<bits)-1;
// save tmp if enough bits
if (bit>=bits){ a=(bitstream_tmp>>(bit-bits))&m; bit-=bits; return a; }
for (;;)
{
// insert byte
bitstream_tmp<<=8;
bitstream_tmp&=0xFFFFFF00;
bitstream_tmp|=dat[adr]&255;
adr++; bit+=8;
// save tmp if enough bits
if (bit>=bits){ a=(bitstream_tmp>>(bit-bits))&m; bit-=bits; return a; }
// end of data
if (adr>=siz) return 0;
}
}
//---------------------------------------------------------------------------
// write LZW_bits from a to dat[adr,bit] and increment position (adr,bit)
// return true if buffer is full
bool bitstream_write(BYTE *dat,int siz,int &adr,int &bit,int bits,DWORD a)
{
a<<=32-bits; // align to MSB
// save tmp if aligned
if ((adr<siz)&&(bit==32)){ dat[adr]=(bitstream_tmp>>24)&255; adr++; bit-=8; }
if ((adr<siz)&&(bit==24)){ dat[adr]=(bitstream_tmp>>16)&255; adr++; bit-=8; }
if ((adr<siz)&&(bit==16)){ dat[adr]=(bitstream_tmp>> 8)&255; adr++; bit-=8; }
if ((adr<siz)&&(bit== 8)){ dat[adr]=(bitstream_tmp )&255; adr++; bit-=8; }
// process all bits of a
for (;bits;bits--)
{
// insert bit
bitstream_tmp<<=1;
bitstream_tmp&=0xFFFFFFFE;
bitstream_tmp|=(a>>31)&1;
a<<=1; bit++;
// save tmp if aligned
if ((adr<siz)&&(bit==32)){ dat[adr]=(bitstream_tmp>>24)&255; adr++; bit-=8; }
if ((adr<siz)&&(bit==24)){ dat[adr]=(bitstream_tmp>>16)&255; adr++; bit-=8; }
if ((adr<siz)&&(bit==16)){ dat[adr]=(bitstream_tmp>> 8)&255; adr++; bit-=8; }
if ((adr<siz)&&(bit== 8)){ dat[adr]=(bitstream_tmp )&255; adr++; bit-=8; }
}
return (adr>=siz);
}
//---------------------------------------------------------------------------
bool str_compare(char *s0,int l0,char *s1,int l1)
{
if (l1<l0) return false;
for (;l0;l0--,s0++,s1++)
if (*s0!=*s1) return false;
return true;
}
//---------------------------------------------------------------------------
AnsiString LZW_encode(AnsiString raw)
{
AnsiString lzw="";
int i,j,k,l;
int adr,bit;
DWORD a;
const int siz=32; // bitstream buffer
BYTE buf[siz];
AnsiString dict[LZW_size]; // dictionary
int dicts=0; // actual size of dictionary
// init dictionary
for (dicts=0;dicts<256;dicts++) dict[dicts]=char(dicts); // full 8bit binary alphabet
// for (dicts=0;dicts<4;dicts++) dict[dicts]=char('a'+dicts); // test alphabet "a,b,c,d"
l=raw.Length();
adr=0; bit=0;
for (i=0;i<l;)
{
i&=i;
// find match in dictionary
for (j=dicts-1;j>=0;j--)
if (str_compare(dict[j].c_str(),dict[j].Length(),raw.c_str()+i,l-i))
{
i+=dict[j].Length();
if (i<l) // add new entry in dictionary (if not end of input)
{
// clear dictionary if full
if (dicts>=LZW_size) dicts=256; // full 8bit binary alphabet
// if (dicts>=LZW_size) dicts=4; // test alphabet "a,b,c,d"
else{
dict[dicts]=dict[j]+AnsiString(raw[i+1]); // AnsiString index starts from 1 hence the +1
dicts++;
}
}
a=j; j=-1; break; // full binary output
// a='0'+j; j=-1; break; // test ASCII output
}
// store result to bitstream
if (bitstream_write(buf,siz,adr,bit,LZW_bits,a))
{
// append buf to lzw
k=lzw.Length();
lzw.SetLength(k+adr);
for (j=0;j<adr;j++) lzw[j+k+1]=buf[j];
// reset buf
adr=0;
}
}
if (bit)
{
// store the remainding bits with zeropad
bitstream_write(buf,siz,adr,bit,LZW_bits-bit,0);
}
if (adr)
{
// append buf to lzw
k=lzw.Length();
lzw.SetLength(k+adr);
for (j=0;j<adr;j++) lzw[j+k+1]=buf[j];
}
return lzw;
}
//---------------------------------------------------------------------------
AnsiString LZW_decode(AnsiString lzw)
{
AnsiString raw="";
int adr,bit,siz,ix;
DWORD a;
AnsiString dict[LZW_size]; // dictionary
int dicts=0; // actual size of dictionary
// init dictionary
for (dicts=0;dicts<256;dicts++) dict[dicts]=char(dicts); // full 8bit binary alphabet
// for (dicts=0;dicts<4;dicts++) dict[dicts]=char('a'+dicts); // test alphabet "a,b,c,d"
siz=lzw.Length();
adr=0; bit=0; ix=-1;
for (adr=0;(adr<siz)||(bit>=LZW_bits);)
{
a=bitstream_read(lzw.c_str(),siz,adr,bit,LZW_bits);
// a-='0'; // test ASCII input
// clear dictionary if full
if (dicts>=LZW_size){ dicts=4; ix=-1; }
// new dictionary entry
if (ix>=0)
{
if (a>=dicts){ dict[dicts]=dict[ix]+AnsiString(dict[ix][1]); dicts++; }
else { dict[dicts]=dict[ix]+AnsiString(dict[a ][1]); dicts++; }
} ix=a;
// update decoded output
raw+=dict[a];
}
return raw;
}
//---------------------------------------------------------------------------
and output using // test ASCII input lines:
txt="abacdacacadaad"
enc="0102369803"
dec="abacdacacadaad"
where AnsiString is the only VCL stuff I used and its just self allocating string variable beware its indexes starts at 1.
AnsiString s;
s[5] // character access (1 is first character)
s.Length() // returns size
s.c_str() // returns char*
s.SetLength(size) // resize
So just use any string you got ...
In case you do not have BYTE,DWORD use unsigned char and unsigned int instead ...
Looks like its working for long texts too (bigger than dictionary and or bitstream buffer sizes). However beware that the clearing might be done in few different places of code but must be synchronized in both encoder/decoder otherwise after clearing the data would corrupt.
The example can use either just "a,b,c,d" alphabet or full 8it one. Currently is set for 8bit. If you want to change it just un-rem the // test ASCII input lines and rem out the // full 8bit binary alphabet lines in the code.
To test crossing buffers and boundary you can play with:
const int LZW_bits=12; // encoded bitstream size
const int LZW_size=1<<LZW_bits; // dictinary size
and also with:
const int siz=32; // bitstream buffer
constants... The also affect performance so tweak to your liking.
Beware the bitstream_write is not optimized and can be speed up considerably ...
Also in order to debug 4bit aligned coding I am using hex print of encoded data (hex string is twice as long as its ASCII version) like this (ignore the VCL stuff):
AnsiString txt="abacdacacadaadddddddaaaaaaaabcccddaaaaaaaaa",enc,dec,hex;
enc=LZW_encode(txt);
dec=LZW_decode(enc);
// convert to hex
hex=""; for (int i=1,l=enc.Length();i<=l;i++) hex+=AnsiString().sprintf("%02X",enc[i]);
mm_log->Lines->Add("\""+txt+"\"");
mm_log->Lines->Add("\""+hex+"\"");
mm_log->Lines->Add("\""+dec+"\"");
mm_log->Lines->Add(AnsiString().sprintf("ratio: %i%",(100*enc.Length()/dec.Length())));
and result:
"abacdacacadaadddddddaaaaaaaabcccddaaaaaaaaa"
"06106206106306410210510406106410FFFFFF910A10706110FFFFFFD10E06206311110910FFFFFFE11410FFFFFFD0"
"abacdacacadaadddddddaaaaaaaabcccddaaaaaaaaa"
ratio: 81%

seekg() not getting the correct position returned by tellg() on Windows, but works fine on macOS using xcode

first time posting on stackoverflow.
I am using file stream to save and read parameters of a set of neural networks. In the file there is a flag at the beginning of each line, followed by some values. A simpler example would be like:
NeuroNum 1 2 1
Weight 0.1 0.1 0.1 0.1
AnotherFlag ...
...
Break
NeuroNum 1 2 1
Weight 0.2 0.2 0.2 0.2
AnotherFlag ...
...
Break
...
The Break flag indicates the end of one network and the next line would be the parameters of another network.
I define a vector networks and use the following code to set the parameters
std::ifstream networkFile;
std::streampos pos;
...
pos = networkFile.tellg();
...
for (auto i = 0; i < num; ++i) {
networks.emplace_back(Network());
if (!networks[i].ReadNetwork(pos))
return false;
}
The ReadNetwork() function is defined as follows. Every time when it is called, it uses seekg(pos) to locate the pointer position. When it reads the Break flag, it uses tellg() to store the pointer, which will be used for the next call for ReadNetwork(pos). So through the for-loop, parameters of all networks can be set.
bool Network::ReadNetwork(std::streampos &pos) {
std::ifstream networkFile;
networkFile.open(NETWORK_FILE);
std::string flag;
if (networkFile.is_open()) {
networkFile.seekg(pos);
while (networkFile >> flag) {
if (flag == "NeuroNum") {
// do something
}
else if (flag == "Weight") {
// do something
}
else if (flag == "AnotherFlag") {
// do something
}
else if (flag == "Break") {
pos = networkFile.tellg();
break;
}
else {
std::cout << "File type error!\n";
return false;
}
}
networkFile.close();
return true;
}
...
}
I first tested the code using xcode and it worked fine. But when running the code on Windows (the IDE is codebolcks, compiler mingw32-g++), I could not get the expected position. It would return
File type error!
I am not sure if it is because of seekg() not getting the correct position or tellg() not returning it, and I am wondering why.

c++ - 3 bears in a vector of a struct, how can I change this code so the specific bear at the exit is removed?

void updateGameData(const char g[][SIZEX], vector<Item>& bears, vector<Item>& bombs, Item& detonator, Item& exit, const int key, string& message, int& bearsSaved, bool& bombsActive, int& moves)
{ //move bear in required direction
bool isArrowKey(const int k);
void setKeyDirection(int k, int& dx, int& dy, int& moves);
void gameLost(string& message);
assert(isArrowKey(key));
//reset message to blank
message = " "; //reset message to blank
//calculate direction of movement for given key
int dx(0), dy(0);
setKeyDirection(key, dx, dy, moves);
//save number of bears saved ready to output later for the user
//check new target position in grid and update game data (incl. bear coordinates) if move is possible
for (unsigned int bearNo = 0; bearNo < bears.size(); ++bearNo)
{
switch (g[bears.at(bearNo).y + dy][bears.at(bearNo).x + dx])
{ //...depending on what's on the target position in grid...
case TUNNEL: //can move
{
bears.at(bearNo).y += dy; //go in that Y direction
bears.at(bearNo).x += dx; //go in that X direction
}
break;
case WALL: //hit a wall and stay there
{
cout << '\a'; //beep the alarm
message = "CANNOT GO THERE!";
}
break;
case BOMB:
{
bears.at(bearNo).y += dy; //go in that Y direction
bears.at(bearNo).x += dx;
//sets the bomb to active, how to pass this through to cheat??
if (bombsActive)
{
cout << "\a";
message = "BOOM!";
bears.clear(); // Remove all bears from the vector/end the game
if (bears.size() == 0)
gameLost(message);
}
}
break;
// The pop_back function only removes the last item in a (non-empty) vector, causing the size of the vector to decrease automatically.
// To remove an item knowing its position on the vector the above has been used (bears.begin() + 0 removes the first element)
case DETONATOR:
{
bears.at(bearNo).y += dy; //go in that Y direction
bears.at(bearNo).x += dx; //go in that X direction, means the bear can walk over the detonator and that it reappears afterwards
cout << "\a";
message = "BOMBS DISABLED!";
bombs.clear();
}
break;
case EXIT:
{
// Case for the exit symbol on the grid, if a bear walks into it that bear 'escapes' by being removed from the vector, and then the amount of
// bears saved by the user is increased and incorporated into their high score
cout << "\a";
message = "BEAR IS FREE!";
bears.erase(bears.begin() + ((bears.at(bearNo).y) || (bears.at(bearNo).x))); //I'm assuming it's because of the bears.begin line, but I don't know how to otherwise change it to delete the bear at the y || x coordinate
bearsSaved++;
}
break;
}
}
}
The case for exit is where I'm having the issue - as soon as a bear reaches the same coordinate at the exit, any bear in particular seems to disappear and another bear, that may be at the other side of the map, is placed at the side of the exit.
bears.erase(bears.begin() + ((bears.at(bearNo).y) || (bears.at(bearNo).x)));
//I'm assuming it's because of the bears.begin line, but I don't know
//how to otherwise change it to delete the bear at the y || x coordinate
For reference I've included some images that better illustrate what I'm talking about. There's other code where the bears are drawn and the grid (the name of my array) are initialised as well, but I don't think they're relevant.
The before image (the # symbols are the bears, the X is the exit)
The after image, the bear near the T has disappeared, instead of the one in the exit
You are using an iterator type to delete. For proof, see http://en.cppreference.com/w/cpp/container/vector/erase
bears.begin() is an iterator referring to the first bear.
bears.begin() + 1 is an iterator referring to the second bear.
bears.begin() + 2 an iterator referring to is the third ...
Your code is
bears.erase(bears.begin() + ((bears.at(bearNo).y) || (bears.at(bearNo).x)));
so you are deleting either the first or second bear, depending on the result of this expression (something1 || something2). Logical or can only be true or false, which will then be 0 or 1 when you convert it to an int to increment the iterator returned by bears.begin()
Besides the number being wrong, it doesn't make sense. You want to delete a bear from the vector of bears. Therefore where the bear is on the game board is completely irrelevant. If you use x or y, it's probably wrong.
If you want to delete the bear at bearNo, you could use
bears.erase( bears.begin() + bearNo )
But that will cause the for loop to be wrong. The next bear moves to bearNo, but you never look at it. The easiest fix is to start at the back and iterate forward. That way, when you change the vector, you don't change anything in the part you have not yet evaluated. (This will change some of the tricks players can exploit if they know which bear is which -- if you want no change to the code you will have to handle incrementing bearNo inside the for loop based on whether or not you deleted a bear.)
#include <iostream>
#include <vector>
struct bear_type { int x, y; };
static const int XSIZE = 10;
static const int YSIZE = 10;
int main(){
char gameboard[XSIZE][YSIZE];
memset(gameboard, '\0', sizeof(gameboard));
gameboard[3][3] = 'D';
std::vector<bear_type> bears = {{ 5, 7 }, { 3, 3 }, { 0, 0 }};
for (int bearnum = bears.size()-1; bearnum >= 0; --bearnum){
const bear_type &bear = bears[bearnum];
char gamepiece = gameboard[bear.x][bear.y];
if ('D' == gamepiece){
bears.erase(bears.begin() + bearnum);
}
}
}
If you used iterator based iteration, there are some other ways to do it, like std::remove_if, but I didn't want to mess with your code too much.

C++: Issues with manipulating a PPM file

I'm working on a program that can perform various effects and manipulations on a PPM file. However for testing reasons, it uses cin rather than an input file. It is supposed to be able to perform multiple effects at once, but I am having trouble even getting one right. I'll run a removeBlue() on a line that will work, then try again with different values and it will remove red or green instead. That sort of thing. There's a lot of code, so I'll try to include only what is necessary.
#include <vector>
#include <stdlib.h>
#include <cstdlib>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
class SimpleImageEffect
{
public:
virtual void processImage(vector<Point> &points) = 0;
};
class RemoveRed : public SimpleImageEffect
{
public:
virtual void processImage(vector<Point> &points)
{
for (Point& p : points)
{
p.setRed(0);
}
}
};
//Just an example of one of the effect classes.
//The code in them is correct, so I won't include the others unless needed.
vector<Point> parse_line(string line)
{
istringstream scanner{line};
vector<Point> result{};
int red = -1;
int green = -1;
int blue = -1;
int counter = 0;
while(scanner.good())
{
if (counter == 0)
{
counter++;
scanner >> red;
}
else if (counter == 1)
{
counter++;
scanner >> green;
}
else if (counter == 2)
{
scanner >> blue;
Point p{ red, green, blue };
result.push_back(p);
counter = 0;
}
}
return result;
}
void readFromCin()
{
string line = "";
vector<string> lines_in_file{};
int i, effect_choice;
SimpleImageEffect *effect = nullptr;
getline(cin, line);
while (line.length() > 0)
{
lines_in_file.push_back(line);
getline(cin, line);
}
for (int i = 0; i < lines_in_file.size(); i++)
{
if (lines_in_file[i] != "P3")
{
effect_choice = strToInt(lines_in_file[i]);
}
else if (lines_in_file[i] == "P3")
{
cout << lines_in_file[i] << endl;
cout << lines_in_file[i+1] << endl;
cout << lines_in_file[i+2] << endl;
}
vector<Point> points = parse_line(lines_in_file[i]);
if (effect_choice == 1) effect = new RemoveRed;
if (effect_choice == 2) effect = new RemoveGreen;
if (effect_choice == 3) effect = new RemoveBlue;
if (effect_choice == 4) effect = new NegateRed;
if (effect_choice == 5) effect = new NegateGreen;
if (effect_choice == 6) effect = new NegateBlue;
if (effect_choice == 7) effect = new AddNoise;
if (effect_choice == 8) effect = new HighContrast;
if (effect_choice == 9) effect = new ConvertToGrayscale;
effect->processImage(points);
for (auto p : points)
{
cout << p;
cout << endl;
}
}
}
int main(int argc, char** argv)
{
string menu_choice;
getline(cin, menu_choice);
if (menu_choice == "1")
{
readFromFile();
}
else
{
readFromCin();
}
return 0;
}
So for example, running it with an input of
2
1
P3
1 1
255
50 50 50
will return
P3
1 1
255
0 50 50
but if I run it with
2
3
P3
1 2
255
50 50 50
1 2 3
it returns
P3
1 2
255
0 50 50
0 2 3
I have absolutely no idea what's causing the issue, so any help at all would be greatly appreciated. Thanks.
Your algorithm logic structure smells a lot, this is what I see:
read all non empty lines into lines_in_file (looks good to me)
for EVERY line (problematic, requires additional logic in inner loop):
if not "P3", try to parse [EVERY] line as integer and set effect_choice (it's not clear from your code, what happens on lines where several integers are provided, but judging from your problem description the first integer is successfully parsed by strToInt function)
if "P3", the current line and next two are copied to output
[EVERY] line is parsed as vector of triplets of numbers
effect is set by new effect for actual value of effect_choice (for EVERY line, also you don't delete the effect at end, so you are leaking memory in per-line counts. Also your current effects look like they may be implemented as static functions of "process" function type, so you don't need to allocate each of them, just store the particular memory address of requested function. And you call it processImage, while you are processing only line, not whole image.
effect is run for current line triplets
the line triplets are outputted
loop to next line (!)
So for example for input:
2
3
P3
1 2
255
50 50 50
1 2 3
I believe (can't run it, as you didn't provide lot of code) this happens:
lines are read, and per particular line this happens:
line "2": effect_choice = 2, effect = RemoveGreen, zero triplets parsed into points, RemoveGreen::processImage() run over empty vector, empty vector printed (ie nothing).
line "3": effect_choice = 3, effect = RemoveBlue, zero triplets parsed into points, RemoveBlue::processImage() run over empty vector, empty vector printed.
line "P3": Lines: {"P3", "1 2", "255"} are printed, zero triplets parsed into points, RemoveGreen::processImage() run over empty vector, empty vector printed.
line "1 2": effect_choice = 1, effect = RemoveRed, zero triplets parsed into points, RemoveRed::processImage() run over empty vector, empty vector printed.
line "255": effect_choice = 255, zero triplets parsed into points, RemoveRed::processImage() run over empty vector, empty vector printed.
line "50 50 50": effect_choice = 50, one triplet {50, 50, 50} parsed into points, RemoveRed::processImage() run over it, modified triplet outputs {0, 50, 50}.
line "1 2 3": effect_choice = 1, effect = RemoveRed, one triplet {1, 2, 3} parsed into points, RemoveRed::processImage() run over it, modified triplet outputs {0, 2, 3}.
All of this should be clearly visible in debugger, while stepping over the code, so you probably are not debugging it, which gets downvoting the question from me, and you will pay in tremendous pain over time, as debugging without debugger is lot more difficult.
Also writing code without thinking about algorithm and code architecture makes the need of debugging lot more likely, so you wasted even more time here, by starting by writing the code.
You should have first design some algorithm and code architecture (what data are processed, how, when new memory is needed, how it will be freed, where the code need to loop, where it need to skip over, or run only once, etc).
Write only overview of how it will work into single-line comments, then split too generic comments into simpler steps until they can be implemented by few lines of C++ code, and move/modify them around until you feel the wanted algorithm will be implemented with minimal "cruft" added (most of the comments does, what is really requested, like "set red in point to zero", and any processing/preparations/moving/etc is minimized only to cases where you can't avoid it by smarter design). (for example in your current code you can read through the header of the file without looping, and start looping only after the pixel data pours in)
Then write the code, start probably with some empty function definition so you can already "run" it in debugger and verify the emptiness works, then implement the comment (or small group of them) which you feel is clear enough to be implemented and can be tested easily (no big dependency on yet-to-implement parts). Debug + test new code. If it works, try to clean up the source to remove anything not really needed, work-in-progress variable names, etc... Then verify it works in final version.
And do it again for another comment (group of), until the implementation is done.
Using unit-testing makes the write-short-code, test+debug, clean-up-source rounds even easier, especially in cases like this, where I/O are pure data, so it's easy to feed specialized test input data into test, and verify the expected output data were produced.

Cartesian plane infinite line?

I'm trying to make a program that makes a cartesian plane; you put in input the basic information of the line and he draws the line.
Too bad that it doesn't work well. Basically this is the loop that puts an X char in every point of the line:
for(int x=0;x<MAP_HEIGHT;x++)
{
piano.griglia[x][a*x+b]='X';
}
But it does not work well! here is the result:
http://i.imgur.com/u01Bdk7.jpg
notice how there are 3 lines where it should be only one. Here's the code of the plane, it may help:
class Cartesiano
{
public:
char griglia[MAP_LENGHT+1][MAP_HEIGHT+1];
Cartesiano( void )
{
for(int y=0;y<=MAP_HEIGHT;y++)
{
for(int x=0;x<=MAP_LENGHT;x++)
{
if (y==0)griglia[x][y]='_';
else
{
if(x==0)griglia[x][y]='|';
else griglia[x][y]=' ';
}
}
}
}
void Draw( void )
{
for(int y=MAP_HEIGHT;y>=0;y--)
{
for(int x=0;x<=MAP_LENGHT;x++)cout<<griglia[x][y];
cout<<"\n";
}
}
}piano;
Any ideas?
When your y values exceed 49 (MAP_HEIGHT - 1) you are overflowing your array. If in your draw loop you calculate y=a*x+b and print Z instead of X you'll see the first line is X's and the overflowed errors are all Z's
for(int x=0;x<MAP_LENGTH;x++)
{
int y = a*x+b;
if(y<MAP_HEIGHT) {
piano.griglia[x][y]='X';
} else {
piano.griglia[x][y]='Z';
}
}
This is due to the way memory for the arrays is stored in C++, it just happens writing outside one array here causes you to write into the next one. In general doing this will crash your program.
Also note that here the x loop should be over MAP_LENGTH.
I would also strongly advise getting a proper graphics library