ZMQ Multiple Publisher and Single Subscriber -- data loss observed - zeromq

I have created 2 Publishers connecting to the same static location .
Publisher1
dummyFrontEnd::dummyFrontEnd():context(1),socket(context,ZMQ_PUB) {
}
void dummyFrontEnd::Init()
{
socket.connect("tcp://127.0.0.1:5555");
cout << "Connecting .... " << endl;
}
void dummyFrontEnd::SendTwoTables()
{
cout << "In SendTwoTables" <<endl;
while(1) {
canlogreq canLogObj = canlogreq::default_instance();
canLogObj.set_fromhours(11);
canLogObj.set_fromminutes(7);
canLogObj.set_fromseconds(2);
canLogObj.set_fromday(16);
canLogObj.set_frommonth(5);
canLogObj.set_fromyear(2020);
canLogObj.set_tohours(12);
canLogObj.set_tominutes(7);
canLogObj.set_toseconds(4);
canLogObj.set_today(17);
canLogObj.set_tomonth(5);
canLogObj.set_toyear(2020);
zmq::message_t logsnippetmsg(canLogObj.ByteSizeLong() + sizeof(uint16_t));
*((uint16_t*)logsnippetmsg.data()) = 20;
canLogObj.SerializeToArray(logsnippetmsg.data()+sizeof(uint16_t), canLogObj.ByteSizeLong());
socket.send(logsnippetmsg);
usleep(1);
canLogObj.clear_fromhours();
canLogObj.clear_fromminutes();
canLogObj.clear_fromseconds();
canLogObj.clear_fromday();
canLogObj.clear_frommonth();
canLogObj.clear_fromyear();
canLogObj.clear_tohours();
canLogObj.clear_tominutes();
canLogObj.clear_toseconds();
canLogObj.clear_today();
canLogObj.clear_tomonth();
canLogObj.clear_toyear();
}
}
Publisher2:
dummyFrontEnd::dummyFrontEnd():context(1),socket(context,ZMQ_PUB) {
}
void dummyFrontEnd::Init()
{
socket.connect("tcp://127.0.0.1:5555");
cout << "Connecting .... " << endl;
}
void dummyFrontEnd:: SendData() {
while (std::getline(file, line_str)) {
std::stringstream ss(line_str);
double tdiff;
int i;
char J;
int _1939;
int pgn;
char p;
int priority;
char _0;
int source;
char dash;
std::string direction;
char d;
int length;
int data[8];
ss >> tdiff >> i >> J >> _1939 >> pgn >> p >> priority >> _0 >> source
>> dash >> direction >> d >> length >> data[0] >> data[1] >> data[2]
>> data[3] >> data[4] >> data[5] >> data[6] >> data[7];
timestamp += tdiff;
while (gcl_get_time_ms() - start_time <
uint64_t(timestamp * 1000.0) - first_time) { usleep(1); }
if (arguments.verbose) {
std::cout << timestamp << " " << i << " " << J << " " << _1939 << " "
<< pgn << " " << p << " " << priority << " " << _0 << " " << source
<< " " << dash << " " << direction << " " << d << " " << length
<< " " << data[0] << " " << data[1] << " " << data[2] << " "
<< data[3] << " " << data[4] << " " << data[5] << " " << data[6]
<< " " << data[7] << std::endl;
}
uint64_t timestamp_ms = (uint64_t)(timestamp * 1000.0);
protoTable.add_columnvalues(uint64ToString(timestamp_ms) /* timestamp */);
protoTable.add_columnvalues(intToString(pgn) /* PGN */);
protoTable.add_columnvalues(intToString(priority) /* Priority */);
protoTable.add_columnvalues(intToString(source) /* Source */);
protoTable.add_columnvalues(direction /* Direction */);
protoTable.add_columnvalues(intToString(length) /* Length */);
protoTable.add_columnvalues(intToString(data[0]) /* data1 */);
protoTable.add_columnvalues(intToString(data[1]) /* data2 */);
protoTable.add_columnvalues(intToString(data[2]) /* data3 */);
protoTable.add_columnvalues(intToString(data[3]) /* data4 */);
protoTable.add_columnvalues(intToString(data[4]) /* data5 */);
protoTable.add_columnvalues(intToString(data[5]) /* data6 */);
protoTable.add_columnvalues(intToString(data[6]) /* data7 */);
protoTable.add_columnvalues(intToString(data[7]) /* data8 */);
zmq::message_t create_values(protoTable.ByteSizeLong()+sizeof(uint16_t));
*((uint16_t*)create_values.data()) = TABLEMSG_ID; // ID
protoTable.SerializeToArray(create_values.data()+sizeof(uint16_t), protoTable.ByteSizeLong());
socket.send(create_values);
protoTable.clear_columnvalues();
usleep(1);
}
}
Subscriber
TransportLayer::TransportLayer():context(1),socket(context,ZMQ_SUB){ }
void TransportLayer::Init()
{
socket.bind("tcp://*:5555");
socket.setsockopt(ZMQ_SUBSCRIBE, "", 0);
}
void TransportLayer::Receive()
{
cout <<"TransportLayer::Receive " << " I m in server " << endl;
static int count = 1 ;
// Producer thread.
while ( true ){
zmq::message_t request;
string protoBuf;
socket.recv(&request);
uint16_t id = *((uint16_t*)request.data());
cout <<"TransportLayer : "<<"request.data: "<< request.data() << endl;
cout << "TransportLayer: count " << count<< endl; count = count+1 ;
cout <<"TransportLayer : request.data.size "<< request.size() << endl;
protoBuf = std::string(static_cast<char*>(request.data()+sizeof(uint16_t)), request.size()-sizeof(uint16_t));
cout << "ProtoBuf : " << protoBuf << endl;
InterfaceLayer *interfaceLayObj = InterfaceLayer::getInstance();
switch(id) {
case TABLEMSG_ID: cout << "Canlyser" << endl;
interfaceLayObj->ParseProtoBufTable(protoBuf);
break;
case LOGSNIPPET_ID:cout << "LogSnip" << endl;
interfaceLayObj->ParseProtoBufLogSnippet(protoBuf);
interfaceLayObj->logsnippetSignal(); // publish the signal
break;
default:
break;
}
usleep(1);
}
}
Observation :
I)
Execution Order .
1. Started Subscriber
2. Started Publisher1 ( it sent only one data value)
Subscriber missed to receive this data.
II) modified Publisher1 to send the same data in a while loop
Execution Order
1. Started Subscriber
2. Started Publisher1
3. Started Publsiher2 .
Now I see that Subscriber is receiving the data from both publishers .
This gives me an indication that there is a possibility for data loss.
How do I ensure there is absolutely no data loss.
Thanks

Your producer may be sending its one message before the subscription handshaking has completed. As a result, the publish socket discards the message because there is no subscription registered.
If you use an XPUB socket (ZMQ_XPUB -- see http://api.zeromq.org/4-2:zmq-socket) instead of a PUB socket, your program can wait for a subscribe message, so that it knows that someone is listening, before sending its message(s).

Related

Generate C++ string with space behind such that space is automatically adjusted

I am trying to create a text generator which shall generate following output:
localparam OR_CHANNEL_DATA_WIDTH = 2;
localparam RQ_CHANNEL_DATA_WIDTH = 18;
localparam RSP_CHANNEL_DATA_WIDTH = 8;
localparam VIN_CHANNEL_DATA_WIDTH = 43;
localparam VOUT_CHANNEL_DATA_WIDTH = 123;
I used std::stringstream to build the stream:
std::stringstream ss;
ss << "localparam OR_CHANNEL_DATA_WIDTH" << std::right << std::setw(80) << " = " << Sth::get() << ";\n";
ss << "localparam RQ_CHANNEL_DATA_WIDTH" << std::right << std::setw(80) << " = " << Sth::get() << ";\n";
ss << "localparam RSP_CHANNEL_DATA_WIDTH" << std::right << std::setw(80) << " = " << Sth::get() << ";\n";
Sth::get() will return number. There are many such lines that needs to be generated. But the text in the middle is not fixed. How can I achieve the above output
I am not sure you can do it in a simple streaming operation, but easily write a small function that does the job:
#include <iostream>
#include <sstream>
#include <iomanip>
const std::string adjust_width(const std::string& s, int width)
{
std::stringstream temp;
temp << std::left << std::setw(width) << s;
return temp.str();
}
int main()
{
std::stringstream ss;
ss << adjust_width("localparam OR_CHANNEL_DATA_WIDTH", 80) << " = " << 1 << ";\n";
ss << adjust_width("localparam RQ_CHANNEL_DATA_WIDTH", 80) << " = " << 12 << ";\n";
ss << adjust_width("localparam RSP_CHANNEL_DATA_WIDTH", 80) << " = " << 123 << ";\n";
ss << adjust_width("localparam VIN_CHANNEL_DATA_WIDTH", 80) << " = " << 1234 << ";\n";
std::cout << ss.str();
return 0;
}

GCC Compiler vs Mircrosoft C++ Compiler(MSVC) Issue

TDM GCC 4.9.2 not functioning properly on Windows 10 64-bit
Microsoft C++ Compiler (MSVS) runs smoothly
I tried to use file handling in a c++ source file.
The file's purpose was to read a .txt file called ClientList.txt
and write the contents
to a new file called ClientListv2.txt while modifying the pre-existing data.
Here's the contents of the .txt file ClientList.txt:
George A Harrison 713-555-1234 gaharrison#gmail.com 250 N Main Street, Baytown, TX
James K Smith 713-555-1235 jksmith#gmail.com 100 Cactus St, Baytown, TX
Alma P Sanchez 713-554-1237 apsanchez#gmail.com 312 Luella Blvd, Pasadena, TX
Samantha J Jones 713-554-1238 sjjones#gmail.com 125 Purdue Ln, Pasadena, TX
Paula Mary Henry 713-553-1239 pmhenry#gmail.com 412 Colorado Ave, League City, TX
Henry B Albertson 713-553-2345 hbalbertson#gmail.com 724 Perkins Ave, League City, TX
Samuel * Harrison 713-552-2346 sharrison#gmail.com 200 Wesley Ln, Deer Park, TX
Peter N Smith 713-552-2347 pnsmith#gmail.com 157 Briarwood Ct, Deer Park, TX
James Edward Bennett 713-551-2348 jebennett#gmail.com 330 S 6th St, La Porte, TX
Javier D Rodriquez 713-551-2349 jdrodriquez#gmail.com 245 Parkcrest Dr, La Porte, TX
The task was to create a duplicate file called ClientListv2.txt which contains all the pre-existing
information, with two addional records, as well as a change to the phone number and address of any one single line. (record)
Here's my attempt to do the process in C++:
//I started out by included my header files:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
//reading the file
fstream file;
file.open("ClientList.txt", ios::in | ios::out);
if (!file.is_open())
{
cout << "File does not exist" << endl;
exit(0);
}
char FirstName[10];
char MiddleName[10];
char LastName[15];
char Phone[15]; //one extra char for '\0' (string terminal char)
char Email[31];
char Address_num[8];
char Address_street[25];
char Town[25];
char State[8];
while (file.good())
{
file.getline(FirstName, 9, ' ');
file.getline(MiddleName, 9, ' ');
file.getline(LastName, 14, ' ');
file >> ws;
file.getline(Phone, 14, ' ');
file >> ws;
file.getline(Email, 30, ' ');
file >> ws;
file.getline(Address_num, 7, ' ');
file >> ws;
file.getline(Address_street, 24, ',');
file >> ws;
file.getline(Town, 24, ',');
file >> ws;
file.getline(State, 7);
file.clear();
file >> ws;
cout << FirstName << " " << MiddleName << " " << LastName << " " << Phone << " " << Email << " " << Address_num << " " << Address_street << " " << Town << " " << State << endl;
}
//To modify one phone and one street address of any single record(line), I used this approach...
fstream new_file;
new_file.open("ClientListv2.txt", ios::out | ios::in);
//file.clear();
file.seekg(0, ios::beg);
file.seekp(0, ios::beg);
char c;
while (file.good())
{
file.get(c);
new_file << c;
}
//declaring a string to take a whole line
string line;
int line_num;
//go to the beginning of the new_file
new_file.seekg(0, ios::beg);
new_file.seekp(0, ios::beg);
cout << "Enter Line No to Edit Phone Number (First Line is 1): " << endl;
cin >> line_num;
for (int i = 1; i < line_num; i++)
{
getline(new_file, line);
}
new_file.seekp(22, ios::cur);
new_file << "888-888-8888";
cout << new_file.tellp() << endl;
cout << new_file.tellg() << endl; //34
cout << new_file.tellp() << endl;
new_file.seekg(0, ios::beg); //moving the flag pointers to the beginning of the file
new_file.seekp(0, ios::beg);
cout << "Enter Line No to Edit Street Address (First Line is 1): " << endl;
cin >> line_num;
for (int i = 1; i < line_num; i++)
{
getline(new_file, line);
}
//65 street address
new_file.seekp(64, ios::cur);
new_file << "B Tane Stripe"; //any address you want to add
cout << new_file.tellg() << endl; //78
cout << new_file.tellp() << endl;
//move the file markers to the end of the file
new_file.seekg(0, ios::end);
new_file.seekp(0, ios::end);
cout << "\t\t\tUpdating Client List Text File\t\t\t" << endl;
//two add two addional clients
cout << "\nEnter the first addional record:\n";
cout << "Enter the FirstName" << endl;
cout << "Enter the MiddleName" << endl;
cout << "Enter the LastName" << endl;
cout << "Enter the Phone" << endl;
cout << "Enter the Email" << endl;
cout << "Enter the Address_num" << endl;
cout << "Enter the Address_street" << endl;
cout << "Enter the Town" << endl;
cout << "Enter the State" << endl;
cin >> FirstName;
cin >> MiddleName;
cin >> LastName;
cin >> Phone;
cin >> Email;
cin >> Address_num;
cin.ignore();
cin.getline(Address_street, 24);
cin.getline(Town, 24);
cin >> State;
new_file.clear();
new_file << "\n" << FirstName << " " << MiddleName << " " << LastName << " " << Phone << " " << Email << " " << Address_num << " " << Address_street << " " << Town << " " << State << endl;
cout << "\nEnter the second addional record:\n";
cout << "Enter the FirstName" << endl;
cout << "Enter the MiddleName" << endl;
cout << "Enter the LastName" << endl;
cout << "Enter the Phone" << endl;
cout << "Enter the Email" << endl;
cout << "Enter the Address" << endl;
cout << "Enter the Town" << endl;
cout << "Enter the State" << endl;
cin >> FirstName;
cin >> MiddleName;
cin >> LastName;
cin >> Phone;
cin >> Email;
cin >> Address_num;
cin.ignore();
cin.getline(Address_street, 24);
cin.getline(Town, 24);
cin >> State;
new_file << FirstName << " " << MiddleName << " " << LastName << " " << Phone << " " << Email << " " << Address_num << " " << Address_street << " " << Town << " " << State << endl;
file.close();
new_file.close();
return 0;
}
Brief Summary
After doing all of this, I've noticed that first, my code only works when I have a ClientListv2.txt manually created in my
present working directory. If not, the code doens't generate a new .txt file itself. Secondly, using a TDM GCC 4.9.2 Compiler, I get pretty strange pattern-based
sequences of outputs when examing my phone number and address accross multiple lines.
It appears, that the code overwrites some of the old text and sometimes it overwrites none of it.
For some reason, when I tried compiling and running it on Visual Studio (Microsoft C++ Compiler MSVC), I got the right results.
Why is TDM GCC 4.9.2 acting like that?
My machine runs Windows 10 64-bit. I suppose that the '\r\n' might have something responsible for this strange output. Who knows?
I used the following dummy text to input the values for two additional rows:
Sam
Billy
Jhons
299-292-9292
sambilly#gmail.com
39
2nd Street
Ventnor
NJ

‘voiture’ does not name a type and expected primary-expression before ‘for’

I'am trying to make a program about vehicle but the compiler put up an error in function main() " 'voiture' does not name a type " and " 'avion does not name a type" . I think that the problem is coming from the two last two loop in function main() but I don't know how to fix .
#include<iostream>
#include<stdio.h>
#include<string>
using namespace std;
#include<math.h>
#include<vector>
enum TYPE_AVION { REACTION , HELICES};
class Vehicule{enter code here
protected:
string marque;
unsigned int date_achat;
double prix_achat;
double prix_courant;
public :
Vehicule(string marque,unsigned int date_achat ,double prix_achat)
:marque(marque),date_achat(date_achat),prix_achat(prix_achat)
{}
void affiche(ostream& sortie) const {
sortie << marque << "date d'achat :" << date_achat << ", prix d'achat : "
<< prix_achat << ", prix actuel : " << prix_courant << endl;
}
double calculePrix(){
return prix_achat - 0.01*prix_achat*(2015-date_achat);
}
};
class Voiture : public Vehicule{
private:
double cylindree;
int nb_porte;
double puissance;
double km;
public :
Voiture(string marque,unsigned int date_achat,double prix_achat,double cylindree,int nb_porte,double puissance,double km)
:Vehicule(marque,date_achat,prix_achat),cylindree(cylindree),nb_porte(nb_porte),puissance(puissance),km(km)
{}
void affiche(ostream& sortie) const {
sortie << "----Voiture----" << endl;
sortie << sortie << marque << "date d'achat :" << date_achat << ", prix d'achat : "
<< prix_achat << ", prix actuel : " << prix_courant << endl;
sortie << cylindree << "litres, " << nb_porte << " portes," << puissance
<< " CV," << km << " km" << endl;
}
double calculePrix(){
double prix = prix_achat - 0.02*prix_achat*(2015-date_achat) - 0.05*prix_achat*(km/10000);
if ( marque == "Renault" || marque == "Fiat"){
double d = 0.1*prix_achat;
prix -= d;
}
if ( marque == "Porsche" || marque == "Ferrari"){
double z = 0.2*prix_achat;
prix += z;
}
return prix ;
}
};
class Avion :public Vehicule{
private:
TYPE_AVION type;
unsigned int nb_heure_vol;
public :
Avion(string marque1,unsigned int date_achat1,double prix_achat1,TYPE_AVION type,unsigned int nb_heure_vol)
:Vehicule(marque1,date_achat1,prix_achat),type(type),nb_heure_vol(nb_heure_vol)
{}
void affiche(ostream& sortie) const {
sortie << "----Avion a" << type << "----" << endl;
sortie << sortie << marque << "date d'achat :" << date_achat << ", prix d'achat : "
<< prix_achat << ", prix actuel : " << prix_courant << endl;
sortie << nb_heure_vol << " heures de vol." << endl;
}
double calculePrix(){
double prix1 = 0.0;
if ( type == REACTION){
prix1 = prix_achat - 0.1*(nb_heure_vol/1000);
}
if ( type == HELICES){
prix1 = prix_achat -0.1*(nb_heure_vol/1000);
}
return prix1;
}
};
int main(){
vector<Voiture> garage;
vector<Avion> hangar;
garage.push_back(Voiture("Peugeot", 1998, 147325.79, 2.5, 5, 180.0,
12000));
garage.push_back(Voiture("Porsche", 1985, 250000.00, 6.5, 2, 280.0,
81320));
garage.push_back(Voiture("Fiat", 2001, 7327.30, 1.6, 3, 65.0,
3000));
hangar.push_back(Avion("Cessna", 1972, 1230673.90, HELICES,
250));
hangar.push_back(Avion("Nain Connu", 1992, 4321098.00, REACTION,
1300));
for (auto voiture : garage) {
voiture.calculePrix();
voiture.affiche(cout);
}
for (auto avion : hangar) {
avion.calculePrix();
avion.affiche(cout);
}
return 0;
}
I looked the ancient similar post , but it does not solve my problem.

Linear interpolation is not working as expected

I have a map that represents the values of a coefficient Y for a given range of temperatures. I'm trying to get the coeff_Y whenever the input key designTempfalls anywhere between the upper and lower limits of keys. I was able to get the three cases: a) when the value of the input designTemp is below the first key then coeff_Y is the first value, b) if the value of the input designTemp is beyond the last key then coeff_Y is the last value and c) if designTemp matches a key then the coeff_Y becomes the corresponding value. The case if the key falls anywhere within the key range is not working. The code showing the failed attempt of interpolation is shown below. Please note that I'm not a programmer, I'm a piping engineer just trying to write my own programs and trying to become proficient at coding with C++. Also, if there is any better solution please show so.
`cout << "\n Enter design temp. in degF: ";
float designTemp;
cin.clear(); cin.ignore(10000, '\n'); cin >> designTemp;
map<float, float> ferriticsteels_Y = { {900, 0.4}, {950, 0.5}, {1000, 0.7} };
if (ferriticsteels_Y.find(designTemp) != ferriticsteels_Y.end())
{
float coeff_Y = ferriticsteels_Y[designTemp];
cout << "\n Y: " << coeff_Y << endl;
}
if (designTemp < ferriticsteels_Y.begin()->first)
{
float coeff_Y = ferriticsteels_Y.begin()->second;
cout << "\n Y: " << coeff_Y << endl;
}
if (designTemp > ferriticsteels_Y.rbegin()->first)
{
float coeff_Y = ferriticsteels_Y.rbegin()->second;
cout << "\n Y: " << coeff_Y << endl;
}
auto lower = ferriticsteels_Y.lower_bound(designTemp) == ferriticsteels_Y.begin() ? ferriticsteels_Y.begin() : --(ferriticsteels_Y.lower_bound(designTemp));
auto upper = ferriticsteels_Y.upper_bound(designTemp);
float coeff_Y = lower->second + (upper->second - lower->second) * float(designTemp - lower->first)/fabs(upper->first - lower->first);
time_t rawtime_end;
struct tm * timeinfo_end;
time(&rawtime_end);
timeinfo_end = localtime(&rawtime_end);
cout << "\n" << asctime(timeinfo_end);
cout << "\nEnter any character and hit enter to exit: ";
char ans;
//cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); cin >> ans;...giving error at 'max()'
cin.clear(); cin.ignore(10000, '\n'); cin >> ans;
return 0;}`
It works. I just was making stupid mistake. It only required to revise the nesting of the if-statements and to add a cout for looking the interpolated value at the last else. Below is the code which works as expected:
#include "../../std_lib_facilities.h"
#include <Windows.h>
#include <map>
int main()
{
SetConsoleTitle(TEXT("PipeTran™_v0.1"));
system("CLS");
system("color F1");
time_t rawtime_start;
struct tm * timeinfo_start;
time(&rawtime_start);
timeinfo_start = localtime(&rawtime_start);
printf(asctime(timeinfo_start));
cout << "\n Enter design temp. in degF: ";
float designTemp;
cin >> designTemp;
map<float, float> ferriticsteels_Y = { { 900, 0.4 },{ 950, 0.5 },{ 1000, 0.7 } };
if (ferriticsteels_Y.find(designTemp) != ferriticsteels_Y.end()) {
float coeff_Y = ferriticsteels_Y[designTemp];
cout << "\n Y: " << coeff_Y << endl;
}
else if (designTemp < ferriticsteels_Y.begin()->first) {
float coeff_Y = ferriticsteels_Y.begin()->second;
cout << "\n Y: " << coeff_Y << endl;
}
else if (designTemp > ferriticsteels_Y.rbegin()->first) {
float coeff_Y = ferriticsteels_Y.rbegin()->second;
cout << "\n Y: " << coeff_Y << endl;
}
else {
auto lower = ferriticsteels_Y.lower_bound(designTemp) == ferriticsteels_Y.begin() ? ferriticsteels_Y.begin() : --(ferriticsteels_Y.lower_bound(designTemp));
auto upper = ferriticsteels_Y.upper_bound(designTemp);
float coeff_Y = lower->second + (upper->second - lower->second) * float(designTemp - lower->first) / fabs(upper->first - lower->first);
cout << "\n Y: " << coeff_Y << endl;
}
time_t rawtime_end;
struct tm * timeinfo_end;
time(&rawtime_end);
timeinfo_end = localtime(&rawtime_end);
cout << "\n" << asctime(timeinfo_end);
cout << "\nEnter any character and hit enter to exit: ";
char ans;
cin.clear(); cin.ignore(10000, '\n'); cin >> ans;
return 0;
}

C++ .txt read in issues. getline reading full file

first of all, forgive my code for being ugly. The tons of ideas I've been given to try to fix this code have jumbled it up after all the potential solutions that haven't worked. Basically, I'm coding a Hearthstone rip-off that reads in two .txt files with card information and battles them to see which player wins. The issue is that when I'm trying to save the player's name (the first line in the files), it saves the whole file instead of just the first line. When I have managed to fix that, the for loop used to save the information for the card objects (format: card name, card power, card health) does not get saved properly for some reason. Any help would be appreciated, I've been trying to fix this for two days and nothing has fully solved the problem. I'll attach the read in files first before the code.
Disclaimer: It's a lot of lines and I'm sorry about that. Also I think the problem could be that my Mac is not saving the .txt in a format that has the right line endings. I'm using XCode as my IDE. Thank you so much to whomever is willing to help!
File1:
The Innkeeper
3
Tunnel Trogg
1
3
Neptulon
7
7
Fire Elemental
6
5
File2:
Malfurion
3
Leper Gnome
2
1
Aviana
5
5
Cenarius
5
8
Main:
#include "Player.h"
using namespace std;
int main()
{
cout << "Please enter file name of the first player: " << endl;
string inFile = "";
getline(cin, inFile);
Player* p1 = new Player(inFile);
cout << "Now enter the file name of the second player: " << endl;
getline(cin, inFile);
Player* p2 = new Player(inFile);
p1->battle(*p2);
delete p1;
delete p2;
return 0;
}
Player Header:
#include "Card.h"
#include <fstream>
#ifndef Player_h
#define Player_h
using namespace std;
class Player
{
private:
string playerName;
int numCards;
Card ** cards;
int wins = 0;
public:
Player(std::string inFile);
void battle(Player p2);
Card* getCard(int counter);
~Player();
};
#endif /* Player_h */
Card Header:
#include <string>
#include <iostream>
#ifndef Card_h
#define Card_h
using namespace std;
class Card
{
public:
Card();
string getName();
int getPower();
int getHealth();
void setName(string newName);
void setPower(int newPower);
void setHealth(int newHealth);
Card* duel(Card&);
friend ostream& operator<<(ostream& o, Card& c);
friend bool operator==(Card& p1Card, Card& p2Card);
private:
string name;
int power;
int health;
};
#endif /* Card_h */
Player Source:
#include "Player.h"
using namespace std;
Player::Player(string inFile)
{
ifstream in(inFile, ios::in);\
if (!in)
{
cerr << "There was a problem opening the file. Sorry, try again!" << endl;
return;
}
getline(in, playerName);
cout << playerName << endl;
in>>numCards;
playerName = "";
numCards = 0;
cards = new Card* [numCards];
string tempName = "";
int tempPower = 0;
int tempHealth = 0;
for (int i = 0; i<numCards; i++)
{
in.ignore();
cards[i] = new Card();
getline(in, tempName);
cout << "in for loop: " << endl;
cout << tempName << ",";
cards[i]->setName(tempName);
in >> tempPower;
in.ignore();
cout << tempPower << ",";
cards[i]->setPower(tempPower);
in >> tempHealth;
cout << tempHealth << " done"<< endl;
cards[i]->setHealth(tempHealth);
}
}
void Player::battle(Player p2)
{
int draws = 0;
cout << "Let the battle begin!" << endl;
cout << numCards << endl;
if (wins > p2.wins)
{
cout << playerName << " wins over " << p2.playerName << ", " << wins << " to " << p2.wins;
if (draws == 0)
{
cout << " and no ties." << endl;
}
else
{
cout << " and " << draws << " ties." << endl;
}
}
else if (p2.wins > wins)
{
cout << p2.playerName << " wins over " << playerName << ", " << p2.wins << " to " << wins;
if (draws == 0)
{
cout << " and no ties." << endl;
}
else
{
cout << " and " << draws << " ties." << endl;
}
}
else if (p2.wins == wins)
{
cout << "It is a draw between " << playerName << " and " << p2.playerName << ", with " << wins << " for each and ";
if (draws == 0)
{
cout << "no ties." << endl;
}
else
{
cout << draws << " ties." << endl;
}
}
cout << "Here are the detailed results:" << endl;
for (int i = 0; i < numCards; i++)
{
cout << *cards[i] << " vs. " << *p2.cards[i] << " - ";
if (*cards[i] == *p2.cards[i])
{
cout << "It is a draw." << endl;
}
else if (cards[i]->duel(*p2.cards[i]) == NULL)
{
cout << "It is a draw." << endl;
}
else if (*cards[i]->duel(*p2.cards[i]) == *p2.cards[i])
{
cout << p2.cards[i]->getName() << "wins for " << p2.playerName << "." << endl;
}
else if (*cards[i]->duel(*p2.cards[i]) == *cards[i])
{
cout << cards[i]->getName() << "wins for " << playerName << "." << endl;
}
}
}
Player::~Player()
{
if (cards != NULL)
{
for (int i = 0; i < numCards; i++)
{
if (cards[i] != nullptr)
{
delete cards[i];
cards[i] = NULL;
}
};
}
}
Card Source:
#include "Card.h"
using namespace std;
Card::Card()
{
name = "";
power = 0;
health = 0;
}
string Card::getName()
{
return name;
}
int Card::getPower()
{
return power;
}
int Card::getHealth()
{
return health;
}
void Card::setName(string newName)
{
name = newName;
}
void Card::setPower(int newPower)
{
power = newPower;
}
void Card::setHealth(int newHealth)
{
health = newHealth;
}
Card* Card::duel(Card& otherCard)
{
if ((otherCard.getHealth() - this->getPower() <=0) && (getHealth() - otherCard.getPower() <= 0))
{
return NULL;
}
else if ((otherCard.getHealth() - this->getPower() >0) && (getHealth() - otherCard.getPower() >0))
{
return NULL;
}
else if (otherCard.getHealth() - this->getPower() <=0)
{
return this;
}
else if (this->getHealth() - otherCard.getPower() <=0)
{
return &otherCard;
}
return NULL;
}
ostream& operator<<(ostream& o, Card& c)
{
o << c.getName() << " (" << c.power << ", " << c.health << ") " << endl;
return o;
}
bool operator==(Card& p1Card, Card& p2Card)
{
if (p1Card.health == p2Card.health &&
p1Card.power == p2Card.power &&
p1Card.name == p2Card.name)
{
return true;
}
else
{
return false;
}
}
Your code is almost right. It can read the Player's name and the card numbers, but your codes showed below:
in>>numCards;
playerName = "";
numCards = 0;
cards = new Card* [numCards];
at first, it read the num of card and store it to numCards, it is right.
next, you clear the value of the numCards, then, you lost the num of the Card, so the codes followed it are executed with numCards == 0
You can just comment the line numCards = 0, and your code is executed right.

Resources