i'm currently trying to print a file's contents into a text file, but the data that comes out is simply an address. If anyone could give me advice it'd be much appreciated.
ostream& operator<<(ostream& out, const BusinessContact& Con)
{
out << Con.firstName << " "
<< Con.lastName << " "
<< Con.phoneNumber<< " "
<< Con.emailAddress<< " "
<< Con.company << " "<<endl;
return out;
}
BusinessContact* Alfred = new BusinessContact("Alfred", "Butler", "999-999-9999", "Alfred#Wayne.ent", "Gotham");
BusinessContact* Bruce = new BusinessContact("Bruce", "Wayne", "999-999-0000", "Batman#Wayne.ent", "Gotham");
BusinessContact* Clark = new BusinessContact("Clark", "Kent", "888-888-8888", "Superman#Kryponyte.wrd", "Metropolis");
BusinessContact* Luther = new BusinessContact ("Lex", "Luther", "888-888-1313", "Evil#Evil.Ent", "Metropolis");
array<BusinessContact*, 10> listBContacts{Alfred, Bruce, Clark, Luther};
void arrayTransform()
{
try
{
cout << "Write Contacts to file..." << endl;
ofstream OUT("Contacts.txt", ios::out);
if (!OUT)
throw new string("Contacts.txt not opened... ");
for (int i = 0; i < listBContacts.size(); ++i)
{
OUT << listBContacts[i];
} OUT.close();
system("pause");
} catch(string*msg)
{
cerr<< "Exception: " << *msg << endl;
}
}
Array listBContacts contains pointers, not values. You need to dereference pointers first to be able to print them: OUT << *(listBContacts[i]);
Related
I have a vector of objects with quite a few variables (name, type, length etc) which I am trying to write to file.
vector <Boat> berths;
void Boat::write_boats()
{
ofstream file("records_file.txt");
for (Boat b : berths)
{
file << owner_name << "; " << boat_name << "; " << type << "; " << length << "; " << draft << '\n';
}
file.close();
}
void save_records()
{
for (unsigned int i = 1; i < berths.size(); i++)
{
berths[i].write_boats();
}
}
I call the save_records() function with a menu option that ends the application.
The output i get is:
1) If i register a boat object, close the app and go in the text file, I can see the object written twice.
2) If i register 2 objects and I go in the text file, only the last (second) object has been written to file, and it shows 3 times.
Now my questions are:
What causes the double output?
Why is only the last object written to file? I thought the loop would fix that but it didn't
One problem I can spot: "i = 1" in the loop should be "i = 0", because array indexes start from 0. The second: you iterate 'berths' array, so you will get N * N boats saved, if you have N boats in 'berths'.
The simple solution would be
void save_all()
{
ofstream file("records_file.txt");
for (Boat b : berths)
{
file << b.owner_name << "; " << b.boat_name << "; " << b.type << "; " << b.length << "; " << b.draft << '\n';
}
}
If you have to make 'owner_name', 'type' and the rest of the fields as private, then you would have to declare
void Boat::save(std::ofstream& f) const
{
file << owner_name << "; " << boat_name << "; " << type << "; " << length << "; " << draft << '\n';
}
and modify 'save_all' to
void save_all()
{
ofstream file("records_file.txt");
for (const Boat& b: berths)
b.save(f);
}
Every time ofstream file("records_file.txt"); is called, it created a new file and overwrite it, if you want to append in the file you have to open it by this way:
ofstream file("records_file.txt", ios::app);
See: http://www.cplusplus.com/doc/tutorial/files/
I guess you are using something like while(!bla.eof()), if so then it reaches the end of the buffer but it needs to go past it to raise the flag, so you have the same output twice at the end.
my program is reading in 2 text files, one is going into an array and one is priming read normally. The one that is being read into an array has an item code, price, quantity, and item name. When the item code matches with the code on the other text document I need to get the price associated with it and cant figure out how.
while (!purchasesFile.eof())
{
purchasesFile >> PurchaseItem >> purchaseQty;
cout << purchaseNum << " " << PurchaseItem << " " << setw(4) <<
purchaseQty << " # " << dollarSign << endl;
int n = 0;
if (inventoryRec[n].itemCode != PurchaseItem)
{
inventoryRec[n+1];
}
else
{
cout << inventoryRec[n].itemPrice << endl;
inventoryRec[n+1];
}
if (PurchaseItem == inventoryRec[itemCount].itemCode)
{
inventoryRec[itemCount].itemOnHand - purchaseQty;
purchaseAmount = inventoryRec[itemCount].itemPrice * purchaseQty;
cout << purchaseAmount << " " <<
inventoryRec[itemCount].itemOnHand;
purchaseCount++;
}
purchasesFile >> purchaseNum;
}
purchasesFile.close();
There are several statements in your code that do nothing:
inventoryRec[n+1];
inventoryRec[itemCount].itemOnHand - purchaseQty;
What you are looking for is probably something like the STL map
typedef struct inventory_item_t {
inventory_item_t(const std::string& item_code, double price, int quantity) :
item_code(item_code),
price(price),
quantity(quanity) { }
std::string item_code;
double price;
int quantity;
} inventory_item_t;
typedef std::map<std::string, inventory_item_t> inventory_items_t;
inventory_items_t inventory_items;
inventory_items.insert(make_pair("item1", inventory_item_t("item1", 1.0, 1)));
inventory_items.insert(make_pair("item2", inventory_item_t("item2", 1.1, 2)));
inventory_items.insert(make_pair("item3", inventory_item_t("item3", 1.2, 3)));
inventory_items_t::iterator inventory_item = inventory_items.find("item1");
if(inventory_item != inventory_items.end()) {
std::cout << "Inventory Item found - item_code: ["
<< inventory_item->first
<< "], price: ["
<< inventory_item->second.price
<< "]"
<< std::endl;
} else {
std::cout << "Inventory Item not found" << std::endl;
}
I am trying to load a text file and import the contents into a vector of structs.
Here are my definitions
typedef struct
{
string pcName, pcUsername, pcPassword, pcMessage, pcAdvertisement; //I know that
//this is incorrect convention. It was originally a char*
}
ENTRY;
vector<ENTRY> entries;
fstream data;
Here is my display data function
void DisplayData()
{
std::cout << (int)(entries.size() / 5) <<" entries" << endl;
for(int i = 1; i <=(int)entries.size()/5; i++)
{
cout << endl << "Entry " << i << ":" << endl
<< "Name: " << entries[i].pcName << endl
<< "Username: " << entries[i].pcUsername << endl
<< "Password: " << entries[i].pcPassword << endl
<< "Message: " << entries[i].pcMessage << endl
<< "Advertisement: " << entries[i].pcAdvertisement << endl;
}
}
and here is my Load Data function
bool LoadData(const char* filepath)
{
std::string lineData ;
int linenumber = 1 ;
data.open(filepath, ios::in);
ENTRY entry_temp;
if(!data.is_open())
{
cerr << "Error loading file" << endl;
return false;
}
while(getline(data, lineData))
{
if(linenumber==1) {entry_temp.pcName = lineData;}
else if(linenumber==2) {entry_temp.pcUsername = lineData;}
else if(linenumber==3) {entry_temp.pcPassword = lineData;}
else if(linenumber==4) {entry_temp.pcMessage = lineData;}
else if(linenumber==5) {entry_temp.pcAdvertisement = lineData;}
entries.push_back(entry_temp);
if(linenumber == 5)
{
linenumber = 0;
}
linenumber++;
}
data.close();
puts("Database Loaded");
return true;
}
Here is the text file I am loading:
Name1
Username1
Password1
Message1
Ad1
And here is the result of the display data function after calling load data:
1 entries
Entry 1:
Name: Name1
Username Username1
Password:
Message:
Advertisement:
As you can see, the first two load but the last three don't. When I did this with an array instead of a vector, it worked fine so I don't know what I'm doing wrong. Thanks.
I suggest that you read each line directly into the data field where it goes:
getline(data, entry_temp.pcName);
getline(data, entry_temp.pcUsername);
getline(data, entry_temp.pcPassword);
getline(data, entry_temp.pcMessage);
getline(data, entry_temp.pcAdvertisement);
entries.push_back(entry_temp);
This makes your intent much clearer than your current while loop. It also creates a single entry for all 4 input lines rather than one for each input line (with the other three blank). Now you can read several "entries" by using a while loop that checks if you have reached the end of the file.
Doing this will also make printing out the data much easier since the vector will have exactly the number of entries rather than five times as many as you expect (which also eats up a lot more memory than you need to).
Your DisplayData function is a little weird, and so is your LoadData.
Your LoadData pushes back a new copy of the current ENTRIES entry with every line. Your DisplayData starts at 1 (which is not the beginning of any vector or array), and iterates only up to the 1/5th entry of the entire vector.
This needs a heavy rework.
First, the size() member of any standard container returns the number of elements that it contains, and will not take the number of fields in a contained struct into account.
For future reference, you'll want to post your question in a complete, standalone example that we can immediately compile to help. (see http://sscce.org/)
Try this modified data, which runs correctly, and see if you can tell what is being done differently:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
typedef struct
{
string pcName, pcUsername, pcPassword, pcMessage, pcAdvertisement;
}
ENTRY;
vector<ENTRY> entries;
fstream data;
bool LoadData(const char* filepath)
{
std::string lineData ;
int linenumber = 1 ;
data.open(filepath, ios::in);
ENTRY entry_temp;
if(!data.is_open())
{
cerr << "Error loading file" << endl;
return false;
}
while(getline(data, lineData))
{
if(linenumber==1) {entry_temp.pcName = lineData;}
else if(linenumber==2) {entry_temp.pcUsername = lineData;}
else if(linenumber==3) {entry_temp.pcPassword = lineData;}
else if(linenumber==4) {entry_temp.pcMessage = lineData;}
else if(linenumber==5) {entry_temp.pcAdvertisement = lineData;}
if(linenumber == 5)
{
entries.push_back(entry_temp);
linenumber = 0;
}
linenumber++;
}
data.close();
puts("Database Loaded");
return true;
}
void DisplayData()
{
std::cout << entries.size() <<" entries" << endl;
for(int i = 0; i < entries.size(); i++)
{
cout << endl << "Entry " << i << ":" << endl
<< "Name: " << entries[i].pcName << endl
<< "Username: " << entries[i].pcUsername << endl
<< "Password: " << entries[i].pcPassword << endl
<< "Message: " << entries[i].pcMessage << endl
<< "Advertisement: " << entries[i].pcAdvertisement << endl;
}
}
int main()
{
LoadData("/tmp/testdata");
DisplayData();
return (0);
}
While I think #code-guru has the right idea, I'd take the same idea just a little further, and make your code work a little more closely with the standard library. I'd do that by reading a data item with a stream extractor, and displaying it with stream inserter. So, the extractor would look something like this:
std::istream &operator>>(std::istream &is, ENTRY &e) {
getline(is, e.pcName);
getline(is, e.pcUsername);
getline(is, e.pcPassword);
getline(is, e.pcMessage);
getline(is, e.pcAdvertisement);
return is;
}
..and the inserter would look something like this:
std::ostream &operator<<(std::ostream &os, ENTRY const &e) {
os << e.pcName << "\n";
os << e.pcUsername << "\n";
os << e.pcPassword << "\n";
os << e.pcMessage << "\n";
os << e.pcAdvertisement << "\n";
return os;
}
With those in place, loading and displaying the data becomes fairly straightforward.
Load the data:
std::ifstream in("yourfile.txt");
std::vector<ENTRY> data((std::istream_iterator<ENTRY>(in)),
std::istream_iterator<ENTRY>());
Display the data:
for (auto const & e: data)
std::cout << e << "\n";
For the moment, I haven't tried to duplicate the format you were using to display the data -- presumably the modifications for that should be fairly obvious.
I feel really stupid coming to ask this question here today after bugging everyone yesteday on understanding the algorithm. But I am not looking at this thing straight anymore. Anyways, it is a knapsack probled, solved with memoization and dynamic progrmming. The problem is that the printout of my answers is not matching the requierements.
All I want is a second look at it and if someone can point me where I am wrong at.
Appreciated for all the help.
This is the ProfitHeader.h file
#ifndef PROFITHEADER_H_
#define PROFITHEADER_H_
#include <string>
#include <map>
#include <vector>
using namespace std;
namespace kproblem{
typedef int Money;
typedef int Labor;
struct Resources{
Money liquidity;
Labor officeWork;
Labor programmingWork;
Resources(Money li, Labor of, Labor pro) : liquidity(li), officeWork(of), programmingWork(pro){}
//operator -=
Resources & operator -=( const Resources &rhs ){
liquidity -=rhs.liquidity;
officeWork -=rhs.officeWork;
programmingWork -=rhs.programmingWork;
return *this;
}
//operator< Used to make sure that key elements Match. will not modify (this)
bool operator<(const Resources & rhs) const{
if(this->liquidity < rhs.liquidity)
return true;
else if(this->liquidity > rhs.liquidity)
return false;
else if(this->officeWork < rhs.officeWork)
return true;
else if(this->officeWork > rhs.officeWork)
return false;
//this is the iff conditional
else if(this->programmingWork < rhs.programmingWork)
return true;
else
return false;
}
};
//Global Operator-. This will not modify (this).
Resources operator-( const Resources & lhs, const Resources & rhs ){
return Resources(lhs.liquidity - rhs.liquidity,
lhs.officeWork - rhs.officeWork, lhs.programmingWork - rhs.programmingWork);
}
//This is the Project Struct. It should contain the resources and data from the file.
struct Project{
string name;
Resources resources;
Money profit;
Project(string n, Resources re, Money p) : name(n), resources(re), profit(p) {}
};
//Definition of the ValueMap
typedef map<pair<Resources, vector<Project>::size_type>, pair<Money, bool>> ValueMap;
}
#endif
This is my main.cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <exception>
#include "ProfitHeader.h"
using namespace std;
using namespace kproblem;
//The following was provided to us on the program
class IO_Exception : public runtime_error
{
public:
IO_Exception(const string & message) : runtime_error(message) { }
};
void readProjects(vector<Project> & projects, const string & fileName)
{
ifstream infile(fileName.c_str());
if (!infile)
throw IO_Exception("Could not open " + fileName);
string oneLine;
unsigned int lineNum = 0;
while (getline(infile, oneLine))
{
istringstream st(oneLine);
lineNum++;
string name;
Money liquidity;
Labor officeWork;
Labor programmingWork;
Money profit;
st >> name;
st >> liquidity;
st >> officeWork;
st >> programmingWork;
st >> profit;
if (st.fail())
{
cerr << "Skipping line number " << lineNum << ": "
<< oneLine << endl;
continue;
}
string junk;
if (st >> junk)
{
cerr << "Skipping line number " << lineNum << ": "
<< oneLine << endl;
continue;
}
projects.push_back(Project(name, Resources(liquidity, officeWork, programmingWork), profit));
}
if (!infile.eof())
throw IO_Exception("Error reading from " + fileName);
}
//Class Best Profit.
//This class will calculate the best possible profit we can get.
Money bestProfit(const vector<Project> & projects, Resources res, ValueMap & valMap,int n){
//initialize the best 2 possible solutions.
Money best1;
Money best2;
Money map; // the map where ou answers are stored
// First check if we are not at the end of the projects
if(n == 0){
return 0;
}
//now we are going to check the best project possible.
//Check the subinstance if it was solved.
if(valMap.find(make_pair(res, n-1)) != valMap.end()){
map = valMap.find(make_pair(res, n-1))->second.first;
return map;
}//check if the subinstance is solved. if it is return the value.
best1 = bestProfit(projects, res, valMap, n-1);//first best possible solution
//check the resources for the last project only. Fopr the second best possible solution.
if(res.liquidity >= projects.at(n-1).resources.liquidity
&& res.officeWork >= projects.at(n-1).resources.officeWork
&& res.programmingWork >= projects.at(n-1).resources.programmingWork){// feasability Check.
//all the above are requiered as it is necessary to check for all of them when doing the calculations.
best2 = bestProfit(projects, res - projects[n-1].resources, valMap, n-1) + projects[n-1].profit;
}
else{
best2 = 0;
}
//after the whole check compare the results and store the best possible result in the map.
if(best1 >= best2){
valMap.insert(make_pair(make_pair(res, n), make_pair(best1,false)));
return best1;
}
else{
valMap.insert(make_pair(make_pair(res, n), make_pair(best2,true)));
return best2;
}
}
//reportBestProfit. This will call Best profit and help us print the final results.
void reportBestProfit(vector<Project> projects, Resources resources){
ValueMap valueMap;
//Variables for the total resources used.
Money liq = 0;
Money ow = 0;
Money pw = 0;
int n = 1000; //number of projects, put here for fast testing
Money bestP = bestProfit(projects, resources, valueMap, n);
//Iterate the valuemap and print the best projects available to us.
cout << "Selected Projects -" << endl;
for(int i= 1; i <= 1000; i++){
//if(valueMap.find(make_pair(resources, i-1)) == valueMap.end()){
if(valueMap.find(make_pair(resources, i))->second.second == true){
//if(valueMap.find(make_pair(resources, i))->second.first != valueMap.find(make_pair(resources, i-1))->second.first){
//cout << valueMap.find(make_pair(resources, i))->second.first; //money
//cout <<" "<< valueMap.find(make_pair(resources, i))->second.second; //boolean
cout << " " << projects.at(i-1).name << " " << projects.at(i-1).resources.liquidity <<" ";//projects
cout << projects.at(i-1).resources.officeWork << " " << projects.at(i-1).resources.programmingWork;
cout << " " << projects.at(i-1).profit << endl;//profit
//}
}
}
cout << "Total Resources Used -" << endl;
//Print the resources consumed.
for(int i= 1; i <= 1000; i++){
if(valueMap.find(make_pair(resources, i))->second.second == true){
liq += projects.at(i-1).resources.liquidity;
ow += projects.at(i-1).resources.officeWork;
pw += projects.at(i-1).resources.programmingWork;
}
}
cout << " " << "Liquidity: " << liq <<endl;
cout << " " << "Office Work: " << ow <<endl;
cout << " " << "Programming Work: " << pw <<endl;
//Print the total Profit.
cout << "Profit: " << bestP << endl;
system("PAUSE");
}
int main()
{
vector<Project> projects;
try
{
readProjects(projects, "Proj5Data.txt");
}
catch (const IO_Exception & ex)
{
cerr << "IO error from: " << ex.what() << endl;
return 1;
}
//these values can be changed for different analysis on projects.
Money liquidity = 200;
Labor officeWork = 450;
Labor programmingWork = 1000;
cout << "Available resources - " << endl
<< " Liquidity: " << liquidity << endl
<< " Office Work: " << officeWork << endl
<< " Programming Work: " << programmingWork << endl;
reportBestProfit(projects, Resources(liquidity, officeWork, programmingWork));
return 0;
}
The project file that contains the projects can be downloaded temporarily here:
https://rapidshare.com/files/459861869/Proj5Data.txt
my guess is the problem is on the valmap find, but I have tried all kinds of combinations and it does not work at all.
Finally this is the final printout I should be getting from this:
But instead I am getting all these other results, including some of the ones I need:
Again thank you for the one that can slap me in the head and say, you FOO, you shouldn't be doing this anymore :).
removing this would get rid of the leading numbers on the second part of the output
cout << valueMap.find(make_pair(resources, i))->second.first; //money
cout <<" "<< valueMap.find(make_pair(resources, i))->second.second; //boolean
cout << " "
the values you print at this point haven't been filtered by and ordered by which is why i think your printing these values
but you don't have code to print "The total resources used -" part
OK, so yes I do have an answer. Is now complete (after edit)
void reportBestProfit(vector<Project> projects, Resources resources){
ValueMap valueMap;
//Variables for the total resources used.
Money liq = 0;
Money ow = 0;
Money pw = 0;
vector<Project> result;
int n = 1000; //number of projects, put here for fast testing
Money bestP = bestProfit(projects, resources, valueMap, n);
//Iterate the valuemap and print the best projects available to us.
cout << "Selected Projects -" << endl;
// this loop just iterates through the values, it does not check the initial resources.
for(int i= 999; i > 0; i--){
//if(valueMap.find(make_pair(resources, i-1)) == valueMap.end()){
//check first If I still have resources available
if(resources.liquidity >=0 && resources.officeWork >= 0 && resources.programmingWork >= 0){
if(valueMap.find(make_pair(resources, i))->second.second == true){
//when I find the first true, I need to substract the resources of it from the base resources,
//to ask the question again.
resources.liquidity -= projects.at(i-1).resources.liquidity;
resources.officeWork -= projects.at(i-1).resources.officeWork;
resources.programmingWork -= projects.at(i-1).resources.programmingWork;
//Push the results into a vector for the printout
result.push_back(Project(projects.at(i-1).name,
Resources(projects.at(i-1).resources.liquidity,
projects.at(i-1).resources.officeWork,
projects.at(i-1).resources.programmingWork),
projects.at(i-1).profit));
//Also in one shot add together the resources used
liq += projects.at(i-1).resources.liquidity;
ow += projects.at(i-1).resources.officeWork;
pw += projects.at(i-1).resources.programmingWork;
}
}
}
//Print the saved vector in reverse order
for(int size = result.size(); size != 0; size--){
cout << " " << result.at(size -1).name;
cout << " " << result.at(size -1).resources.liquidity;
cout << " " << result.at(size -1).resources.officeWork;
cout << " " << result.at(size -1).resources.programmingWork;
cout << " " << result.at(size -1).profit << endl;
}
cout << "Total Resources Used -" << endl;
////Print the resources consumed.
cout << " " << "Liquidity: " << liq <<endl;
cout << " " << "Office Work: " << ow <<endl;
cout << " " << "Programming Work: " << pw <<endl;
//Print the total Profit.
cout << "Profit: " << bestP << endl;
system("PAUSE");
}
Basically I was not substracting the resources, so I was always having over resources, but once I did that viola! it works. Thank you guys for looking at it, I guess I just needed inspiration this morning.
I have have the following problem:
When I drag and drop a file to my tool (exe) when ifstream fails to open the file.
If I give it manually though the console it works!
I don't get where the diffenence is, because I am cutting the path and passing just the filename.
Have a look at the code:
int main(int argc, char* argv[]) {
if (argc < 2) {
cout
<< "ERROR: Wrong amount of arguments! Give at least one argument ...\n"
<< endl;
cout << "\n" << "Programm finished...\n\n" << endl;
cin.ignore();
exit(1);
return 0;
}
vector<string> files;
for (int g = 1; g < argc; g++) {
string s = argv[g];
cout<<"parameter at: " << g << " = " << argv[g] << "\n" << endl;
string filename = "";
int pos = s.find_last_of("\\", s.size());
if (pos != -1) {
filename.append(s.substr(pos + 1));
// cout<<" cutted path: " << s.substr(0,s.size()-filename.size()) << endl;
// cout << "argv[1] " << argv[1] << endl;
cout << "\n filename: " << filename << "\t pos: " << pos << endl;
files.push_back(filename);
}
files.push_back(s);
}
for (unsigned int k = 0; k < files.size(); k++)
{
cout << "files.at( " << k << " ): " << files.at(k).c_str() << endl;
Converter a(files.at(k).c_str());
a.getCommandsFromCSV();
a.saveConvertedFile();
}
cout << "\n" << "Programm finished...\n\n" << endl;
cin.ignore();
return 0;
}
It fails already on the constructor:
Converter::Converter(const char* file) {
filename = file;
myfile.open(filename.c_str(), ios_base::in);
cout << (myfile ? "open successful on constructor " : "some error on constructor");
cin.ignore();
trace_raw = "";
}
You have any idea why?
UPDATE:
The file as parameter works now. The solution was to leave the full path.
Anyway I have the same error on a hard coded file. I thought it may be the same that's why I added .\ at the beginning of the file name... without success.
The code:
void GenericCommandConverter::getATCommandsFromCSV() {
cout << "\t| +++++++++++getATCommandsFromCSV() started+++++++++++++ |"
<< endl;
/*
* CSV file name is hardcoded
*/
string filename_csv = ".\\test.csv";
string commands = "";
int pos_start = 0;
int pos_end = 0; // "|"
int substrLength = 0;
int separator_count = 0;
char c;
vector<string> lines;
vector<string> commandList;
vector<vector<string> > linesSeparated;
ifstream csvFile;
csvFile.open(filename_csv.c_str(), ios_base::in);
cout << (myfile ? "open successful on getATCommandsFromCSV " : "some error on getATCommandsFromCSV ");
cin.ignore();
...
UPDATE2:
The solution was: on dropping a file to the exe, the "root" folder changes to the one where the dropped file comes from. Giving the hardcoded file the path from the *.exe solved it!
I am guessing your current directory is wrong. Don't cut the path off. Anyway you should do error checking / debugging to see why it couldn't open the file. Diligent debugging is essential for solving problems without having to make blind guesses.