C++ struct coin purse console application

Pages: 12
Yes this is a HW assignment, NO I am not posting looking for answer, just a beginner that needs some guidance.

1.Create a structure Coin and a class Purse.

A coin has a name and monetary value. Choose your way to implement a coin, but provide a way to check that two coins have equal names and monetary values.

A purse holds a collection of coins.

Make a Purse constructor to construct an empty purse and the following methods of the class Purse:
a. Add a number of instances of a coin to the purse.
Parameters: the coin to add and how many of it.
b. Count the number of coins in the purse that match a given coin.
Parameter: the coin to match.
Return value: the number of coins equal to the coin to match.
c. Get the total value of the coins in the purse.
Return the sum of all coin values.
d. Count the number of coins in the purse.
Return the number of coins.

2. Create a console application in which the main function will initialize an array of 10 purses and will start 10 threads working simultaneously with these purses without causing inconsistent states. Initially set up the purses with the same coins in each purse. The main function will wait for all threads to finish and then finish itself.
3. Each of the threads should have its own purse, from which it will take money and place in other purses. For this purpose it will repeatedly select a target purse at random and coins to move in the target purse. If the needed coins are not available at the moment, it should wait until they become available and do the move. Since the move of coins from one purse to another involves taking the coins out of one purse and putting them in another purse, each time select at random which operation to do first, and have a small delay between the operations, to allow for race conditions. From time to time each thread will sum up the coins of each denomination in all purses. Pay attention to the readability of the program output. If the threads are properly synchronized, the total number of coins of each denomination should be constant.
4. Provide synchronization using locks. Clearly identify with comments the points in the programs at which you obtain and release the locks, so that it is easy to find these points and test the programs with and without synchronization.
5. Test your programs with and without synchronization and note the results in the test report. Reason about the possibility of your synchronized programs to create deadlocks. If your analysis shows the possibility of a deadlock, provide test cases that could lead to deadlocks and note the results in the test report. Then change the necessary settings (initial coins, maximum numbers to move, associations between threads and purses, etc. to create a program in which a deadlock cannot occur. If your analysis shows that deadlock is impossible, change the original settings to be able to illustrate deadlocks, record the changes in the test report, and provide test cases that can lead to a deadlock. In all cases record your reasoning, the experiments, the expected and the actual results in the test report. Provide the source code before and after the changes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//purseTest.cpp using namespace System;
#include "Purse.h"
int main()	{	
	Purse^ myPurse = gcnew Purse();

	Thread^ addNickels = gcnew Thread(gcnew ParameterizedThreadStart(myPurse, &Purse::addNickels));
	Thread^ addQuarters = gcnew Thread(gcnew ParameterizedThreadStart(myPurse, &Purse::addQuarters));
	Thread^ remove = gcnew Thread(gcnew ParameterizedThreadStart(myPurse, &Purse::removeCoin));
	Thread^ count = gcnew Thread(gcnew ThreadStart(myPurse, &Purse::getTotal));
	int^ nickles = 5;
	double^ size = .05;
	addNickels->Start(dynamic_cast<Object^>(nickles));
	addQuarters->Start(dynamic_cast<Object^>(nickles));
	remove->Start(dynamic_cast<Object^>(size));
	count->Start();
	count = gcnew Thread(gcnew ThreadStart(myPurse, &Purse::getTotal));
	Thread::Sleep(200);
	count->Start();
	Console::ReadLine();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//purse.cpp using namespace System;
#include "Purse.h"
#include <random>

/**
Constructs an empty purse.
*/
Purse::Purse()
{
	nickels = 0;
	dimes = 0;
	quarters = 0;
}

/**
Add nickels to the purse.
@param count the number of nickels to add
*/
void Purse::addNickels(Object^ count)
{
	for (int i = 1; i <= static_cast<int>(count); i++){
		Monitor::Enter(this);
		nickels = nickels += 1;
		Console::WriteLine("{0} nickles added",i);
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
	}
}

/**
Add dimes to the purse.
@param count the number of dimes to add
*/
void Purse::addDimes(Object^ count){
	for (int i = 1; i <= static_cast<int>(count); i++){
		Monitor::Enter(this);
		dimes = dimes += 1;
		Console::WriteLine("{0} dimes added", i);
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
	}
}

/**
Add quarters to the purse.
@param count the number of quarters to add
*/
void Purse::addQuarters(Object^ count)
{
	for (int i = 1; i <= static_cast<int>(count); i++){
		Monitor::Enter(this);
		quarters += 1;
		Console::WriteLine("{0} Quarters added", i);
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
	}
}


void Purse::removeCoin(Object^ val){
	if (static_cast<double>(val) == NICKEL_VALUE){
		Monitor::Enter(this);
		nickels -= 1;
		Console::WriteLine("nickle removed");
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
		
	}
	else if (static_cast<double>(val) == DIME_VALUE){
		Monitor::Enter(this);
		dimes -= 1;
		Console::WriteLine("dime removed");
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
		
	}
	else if (static_cast<double>(val) == QUARTER_VALUE){
		Monitor::Enter(this);
		quarters -= 1;
		Console::WriteLine("quarter removed");
		Thread::Sleep(rand() % 20);
		Monitor::Exit(this);
		
	}
	else{
		Console::WriteLine("not a valid donomination");
	}
}

/**
Get the total value of the coins in the purse.
@return the sum of all coin values
*/
void Purse::getTotal()
{
	double total = 0;
	Monitor::Enter(this);
	total += nickels* NICKEL_VALUE;
	total += dimes* DIME_VALUE;
	total += quarters* QUARTER_VALUE;
	Thread::Sleep(rand() % 20);
	Console::WriteLine("{0} is the total amount", total);
	Monitor::Exit(this);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//purse.h using namespace System;
using namespace System::Threading;

ref class Purse
{
public:
	/**
	Constructs an empty purse.
	*/
	Purse();

	/**
	Add nickels to the purse.
	@param count the number of nickels to add
	*/
	void addNickels(Object^ count);
	
	/**
	Add dimes to the purse.
	@param count the number of dimes to add
	*/
	void addDimes(Object^ count);
	

	/**
	Add quarters to the purse.
	@param count the number of quarters to add
	*/
	void addQuarters(Object^ count);

	//removes one coin of the specifed denomination
	void removeCoin(Object^ count);
	

	/**
	Get the total value of the coins in the purse.
	@return the sum of all coin values
	*/
	void getTotal();

	

private:
	static const double NICKEL_VALUE = 0.05;
	static const double DIME_VALUE = 0.1;
	static const double QUARTER_VALUE = 0.25;

	int nickels;
	int dimes;
	int quarters;

};//ref class Purse 
Last edited on
Hello anon001,

Welcome to the forum.

You have a good start to your program, but there is one problem I see right off.

Line 1 should say #include . You are missing the "#".

The closing } of the struct and class are both missing a closing ";".

You are using this form:
1
2
3
4
struct Coin {


}


But if you use this form it makes it easier to work with:
1
2
3
4
5
struct Coin
{


};  // <--- the struct and class are missing the ;. 


Just a suggestion here. When the {}s line up in the same column it is easier to find the pair or to see a missing brace. Proper indenting helps also. Do not take me the wrong there is nothing wrong with your form it just makes it harder to see the opening { and match it to the closing }.

The "const" variables are fine, but you could use an enum for the same result. Just a thought.

As the instructions say:
A coin has a name and monetary value.

This says that you will need two variables I am thinking a "std::string", include header file "<string>", and something to hold the value. I would suggest a "double".

I would work on the struct first and then the class because the class will be more involved.

At this point I would not worry about until the struct and class has something to work with.

I do not mind guiding you through this. Do what you think is needed for the struct and post the updated code, do not edit the original as it makes it harder for others to know what you started with and what you have changed, then we can work from there.

Hope that helps,

Andy
Hello anon001,

Sorry I got off track and did not mention the using namespace std; is a bad idea.

Try to avoid using using namespace std; in your programs it may seem easy now, but WILL get you in trouble some day.

It is better to learn to qualify what is in the standard name space with "std::" and then to learn what is in the standard name space now while it is easy. And not all at once to try to keep a job.

What you are most likely to use for now is "std::cout", "std::cin" and "std::endl". About a week or so of typing this and you will not even notice that you are doing it.

And another point:

It is ALWAYS a good practice and programming to initialize your variables. If your compiler is using the C++11 standards or after the easiest way to initialize variables is with empty {}s, e.g., int num{};. This will initialize the variable to 0 (zero) or 0.0 for a double. A "char" will be initialized to "\0". "std::string"s are empty to start with an do not need initialized. Should you need to you can put a number between the {}s.You can also Initialize an array, e.g., int aNumbers[10]{};. This will initialize all elements of the array to 0 (zero). A use of
int aNumbers[10]{ 1 }; will initial the first element to "1" and the rest of the array to "0".. Following the "1" with ", 2 ..." will initialize the array with the numbers that you have used up to the entire array.

Hope that helps,

Andy
Thanks Andy!

I really appreciate your guidance. I am going to work some and post updated code! :)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <string>


using namespace std;

enum class coinType { penny, nickel, dime, quarter };




struct Coin 
{
	

};

class Purse 
{


};


int main() 
{




	return 0;
}
closed account (E0p9LyTq)
A coin has a name and monetary value.

No need for your four const global variables. An array created from your Coin struct will hold the data.

Four denominations, a four-element array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <string>

struct Coin
{
   std::string  name;
   unsigned int value;
};

int main()
{
const unsigned int num_coins = 4;
Coin Bank[num_coins] { {"Penny", 1}, {"Nickel", 5 }, {"Dime", 10}, {"Quarter", 25 } };

   for (auto loop = 0; loop < num_coins; loop++)
   {
      std::cout << "Coin: " << Bank[loop].name << ",\tvalue: " << Bank[loop].value << '\n';
   }
}

Coin: Penny,    value: 1
Coin: Nickel,   value: 5
Coin: Dime,     value: 10
Coin: Quarter,  value: 25
Hello anon001,

As I started thinking the program I realized that there is a half dollar, dollar and a two dollar coin to consider.

A suggestion when you define a const variable make the name all capital letters. This helps to recognize that it is a constant that can not be changed.

I like FurryGuy's idea and would consider using a vector along with putting this in the class.

I wish I could stay up all night, I am starting to loose focus for now. I will check back in the morning.

Hope that helps;

Andy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <string>


using namespace std;

enum class coinType { penny, nickel, dime, quarter };




struct Coin
{
	std::string  name;
	unsigned int value;
};

class Purse
{


};


int main()
{
	const unsigned int num_coins = 4;
	Coin Bank[num_coins] { {"Penny", 1}, { "Nickel", 5 }, { "Dime", 10 }, { "Quarter", 25 } };

	for (auto loop = 0; loop < num_coins; loop++)
	{
		std::cout << "Coin: " << Bank[loop].name << ",\tvalue: " << Bank[loop].value << '\n';
	}
	return 0;
}
Thank you Andy, and yes those should be considered but for the sake of my assignment I think penny,nickel,dime,quarter will suffice
closed account (E0p9LyTq)
a half dollar, dollar and a two dollar coin

No current legal US $2 coin.
https://en.wikipedia.org/wiki/Coins_of_the_United_States_dollar

There is a current legal $2 bill.
https://en.wikipedia.org/wiki/United_States_two-dollar_bill

Easy enough to change the number of coins the program deals with. Change the const num_coins variable, and add the other denominations' name and value to the initialization list of the Bank array.

@anon001,
Rewriting your enum to hold each denomination's value would be helpful:
enum class coinType { penny = 1, nickel = 5, dime = 10, quarter = 25 };

Another way to hold each coin's name and value is to use a std::vector instead of an array. Then your initializing the Bank variable automatically sets the number of coins you can work with by using the vector's size() operator.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>


using namespace std;

enum class coinType { penny=1, nickel=5, dime=10, quarter=25 };




struct Coin
{
	string  name;
	unsigned int value;
};

class Purse
{


};


int main()
{
	const unsigned int num_coins = 4;
	Coin Bank[num_coins] { {"Penny", 1}, { "Nickel", 5 }, { "Dime", 10 }, { "Quarter", 25 } };

	for (auto loop = 0; loop < num_coins; loop++)
	{
		cout << "Coin: " << Bank[loop].name << ",\tvalue: " << Bank[loop].value << '\n';
	}
	system("PAUSE");
	return 0;
}
closed account (E0p9LyTq)
1
2
3
4
5
6
7
8
9
#include <vector>
.
.
   std::vector< Coin > Bank { { "Penny", 1 }, { "Nickel", 5 }, { "Dime", 10 }, { "Quarter", 25 } };

   for (auto loop = 0; loop < Bank.size(); loop++)
   {
      std::cout << "Coin: " << Bank[loop].name << ",\tvalue: " << Bank[loop].value << '\n';
   }


Now, what does your Purse class need?
from what I understand of the assignment, Purse needs a constructor for empty purse and the following methods:

a. Add a number of instances of a coin to the purse.
Parameters: the coin to add and how many of it.
b. Count the number of coins in the purse that match a given coin.
Parameter: the coin to match.
Return value: the number of coins equal to the coin to match.
c. Get the total value of the coins in the purse.
Return the sum of all coin values.
d. Count the number of coins in the purse.
Return the number of coins.
This is what I think:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Purse
{
	
public:
           Purse();             // Constructor
   bool    insert(Purse_type);  // Put a member in the bag
   bool    remove(Purse_type);  // remove a member from the bag
   int     size();            // number of members in bag
   void    clear();           // remove all members from bag
   bool    inPurse(Purse_type);   // is a member in the bag?
   int     howmany(Purse_type); // how many member in bag.


};
closed account (E0p9LyTq)
You also need several class variables that hold the coins.

Arrays (or vectors) work well for having multiple variables grouped together.

How many elements will your array/vector contain? Either:

1. each individual coin entered. or

2. an array with each element representing a different denomination (penny, nickel, etc.) Then each element stores the number of of that type of coin added to the purse.

For me, personally, I like the latter array because it automatically stores the number of each type of coin as a single number.

Your class definition might look like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Purse
{
public:
   Purse(const std::vector<Coin>& Bank);

public:
   void AddCoin(coinType type_coin, int num_coins);
   int CountCoins(coinType type_coin) const;
   int CoinsTotalValue() const;
   int CountAllCoins() const;

private:
   std::vector<int> coins;
};

Defining the Purse constructor:
1
2
3
4
5
6
Purse::Purse(const std::vector<Coin>& Bank)
{
   // reserve enough elements to hold the number of each coin type
   // each element holds the number of coins entered
   coins.reserve(Bank.size());
}

Now how would you implement the other class functions?

(I would restore the values in the enum to represent what array/vector element each denomination points to)
enum class coinType { penny = 0, nickel, dime, quarter };

Writing a program on the fly without planning ahead can make for a lot of rewriting what was already coded and rewritten, and a lot of messy code. :)
Last edited on
1
2
3
4
void Purse::clear()  // Clear the bag
{
   count=0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool Purse::remove(purse_type value)  // Remove a value
{
   bool reply=false;
   int  index;
   if(howmany(value) == 0) return reply;
   reply=true;
   index=0;
   while(data[index] != value) index++;
   for(;index<count;index++)
      data[index]=data[index+1];
   count--;
}

int Purse::size()    // How many elements in bag?
{
   return count;
}
I updated the question & what I have worked on can someone take a look and let me know if it is on the right track please please & thank you! :)
Last edited on
Yes this is a HW assignment, NO I am not posting looking for answer, just a beginner that needs some guidance.


2. Create a console application in which the main function will initialize an array of 10 purses and will start 10 threads working simultaneously with these purses without causing inconsistent states. Initially set up the purses with the same coins in each purse. The main function will wait for all threads to finish and then finish itself.


My guidance would be that you talk to your school/instructor about transferring to a beginner programming course. This assignment is not a beginner assignment since it deals with threading (an advanced topic). If you can't even create the classes properly you'll never be able to get the multi-threading to work properly.

so what I have done isnt ok?
Pages: 12