We explored the overall pouring puzzle problem in the last section and developed algorithms solving three of its main sub-problems:
The pouring puzzle solution consists of three files. The first two files form a Glass supplier, while the third file represents the client. We begin programming the solution with the first supplier file, which implements the UML class diagram. Except for the pour function, the functions are small and simple enough that we implement them in the class specification. The second supplier file initializes the class variable pours and implements the pour function. Finally, the client file consists of main, where we create the array and implement the game logic.
/*
* Implements a single glass used in a water-pouring puzzle.
* Each instance has a volume and amount. The class tracks the number of pours with a static variable.
*/
#include <iostream>
using namespace std;
class Glass
{
private:
static int pours; // number of times water is poured from 1 glass to another
int volume; // how much water the glass can hold
int amount; // how much water is in the glass now
public:
Glass(int a_volume, int a_amount) : volume(a_volume), amount(a_amount) {}
int getVolume() { return volume; }
int getAmount() { return amount; }
void display() { cout << amount << " / " << volume << endl; }
static int getPours() { return pours; }
void pour(Glass& source);
};
static variable, are private; the member functions are public. Except for the pour function, the class inlines all functions in the specification. The two "get" functions are examples of getter or accessor functions.
#include "Glass.h"
#include <algorithm> // for the min function
using namespace std;
int Glass::pours = 0; // #1: initializes static data
// Pour water from the source glass to the destination or this glass.
void Glass::pour(Glass& source) // pour from one glass to another
{
pours++; // #2: increment the number of moves
int space = volume - amount; // #3: space available in the destination glass
// #4: algorithm 1 ----------------------------------------------------------
/*if (space < source.amount)
{
source.amount -= space;
amount = volume; // destination glass in now full
// amount += space // also works
}
else
{
amount += source.amount;
source.amount = 0; // source glass is now empty
}*/
// #5: algorithm 2 -----------------------------------------------------------
int transfer = min(space, source.amount);
//int transfer = (space < source.amount) ? space : source.amount; // alternate
amount += transfer;
source.amount -= transfer;
}
static variable (the same syntax is used for both public and private variables). The pours variable tracks the number of times the pour function pours water from one glass to another; it acts as a move counter for the puzzle./*
* Implements a simple puzzle whose goal is to divide 8 ounces of water between
* three glasses so that at least one glass contains exactly 8 ounces.
* The three glasses have different capacities: 3 oz., 5 oz., and 8 oz.; the game
* begins with the 8-oz. glass full and the other two glasses empty. Divide the
* water by pouring it between glasses.
*/
#include <iostream>
#include "Glass.h"
using namespace std;
int main()
{
Glass glasses[3] { Glass(3,0), Glass(5,0), Glass(8,8) }; // #1: create array
/*
* Loops until at least one glass contains precisely 4 oz of water.
* Exits early if the player enters a 4 at any prompt.
*/
while (glasses[1].getAmount() != 4 && glasses[2].getAmount() != 4)
{
for (int i = 0; i < 3; i++) // #2: display glasses
{
cout << "Glass " << i+1 << ": ";
glasses[i].display();
}
int destination;
cout << "Pour TO glass: <1, 2, or 3; or enter 4 to quit>: ";
cin >> destination;
if (destination == 4) // end the puzzle early
exit(0);
int source;
cout << "Pour FROM glass: <1, 2, or 3; or enter 4 to quit>: ";
cin >> source;
if (source == 4) // end the puzzle early
exit(0);
if (source > 0 && source <= 3 && destination > 0 && destination <= 3)
glasses[destination - 1].pour(glasses[source - 1]); // #3: pour water
else
cout << "0 < destination <= 3 AND 0 < source <= 3" << endl;
}
cout << "\n\nYou solved the puzzle in " <<
Glass::getPours() << " pours" << endl; // #4: the total # of pours
for (int i = 0; i < 3; i++) // #5:final puzzle state
glasses[i].display();
return 0;
}
static variable pours, which counts how many steps were needed to solve the puzzle. pours is a static class variable, so it is accessed by a static class function. The program calls a static function with the class name and the scope resolution operator: Glass::getPours();.