View difference between Paste ID: NmETQEzL and h8XNm3Uf
SHOW: | | - or go back to the newest paste.
1
/** 
2
 * 
3
 * Homework 4 - Water Jug Problem
4
 * author: @rgadhia - Raj Gadhia and Albert Chen
5
 * Pledge: I pledge my honor that I have abided by the Stevens Honor System.
6
 * Date: 10/08/19
7
 */ 
8
9
#include <iostream>
10
#include <vector>
11
#include <algorithm>
12
#include <sstream>
13
#include <iomanip>
14
#include <list>
15
 
16
using namespace std;
17
 
18
// Struct to represent state of water in the jugs.
19
struct State {
20
    int a, b, c;
21
    vector<string> directions;
22
   
23
    State(int _a, int _b, int _c) : a(_a), b(_b), c(_c) { }
24
   
25
    // String representation of state in tuple form.
26
    string to_string() {
27
        ostringstream oss;
28
        oss << "(" << a << ", " << b << ", " << c << ")";
29
        return oss.str();
30
    }
31
};
32
 
33
//if been visited already, dont put it in the queue
34
//break outta queue while not empty loop when u find the goal
35
//if the queue is empty, return 0
36
//function that returns a vector that contains all the possible states u can go from current
37
//vectors of strings in the state class: add the vector after every move
38
 
39
//dhorowit@stevens.edu
40
 
41
//returns a vector of the possible moves for that state
42
vector<State> possiblepours(State s, int capA, int capB, int capC) {
43
    vector<State> possible;
44
    //C to A
45
    if (s.a != capA && s.c != 0)
46
    {
47
        State temp(s.a,s.b,s.c);
48
        int pamount;
49
        temp.directions = s.directions;
50
        if (temp.c + temp.a <= capA)
51
        {
52
            pamount = temp.c;
53
            temp.a += pamount;
54
            temp.c = 0;
55
        }
56
        else
57
        {
58
            pamount = capA - temp.a;
59
            temp.a += pamount;
60
            temp.c -= pamount;
61
        }
62
        if(pamount == 1){
63
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallon from C to A. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
64
        } else {
65
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallons from C to A. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
66
        }
67
        possible.push_back(temp);
68
    }
69
    //B to A
70
    if (s.a != capA && s.b != 0)
71
    {
72
        State temp(s.a,s.b,s.c);
73
        temp.directions = s.directions;
74
        int pamount;
75
        if (temp.b + temp.a <= capA)
76
        {
77
            pamount = temp.b;
78
            temp.a += pamount;
79
            temp.b = 0;
80
        }
81
        else
82
        {
83
            pamount = capA - temp.a;
84
            temp.a += pamount;
85
            temp.b -= pamount;
86
        }
87
        if(pamount == 1){
88
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallon from B to A. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
89
        } else {
90
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallons from B to A. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
91
        }
92
        possible.push_back(temp);
93
    }
94
    //C to B
95
    if (s.b != capB && s.c != 0)   // (0,0,8) -> (0,5,3)
96
    {
97
        State temp(s.a,s.b,s.c);
98
        temp.directions = s.directions;
99
        int pamount;
100
        if (temp.c + temp.b <= capB)
101
        {
102
            pamount = temp.c;
103
            temp.b += pamount;
104
            temp.c = 0;
105
        }
106
        else
107
        {
108
            pamount = capB - temp.b;
109
            temp.b += pamount;
110
            temp.c -= pamount;
111
        }
112
        if(pamount == 1){
113
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallon from C to B. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
114
        } else {
115
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallons from C to B. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
116
        }
117
        possible.push_back(temp);
118
    }
119
    //A to B
120
    if (s.b != capB && s.a != 0)
121
    {
122
        State temp(s.a,s.b,s.c);
123
        temp.directions = s.directions;
124
        int pamount;
125
        if (temp.a + temp.b <= capB)
126
        {
127
            pamount = temp.a;
128
            temp.b += pamount;
129
            temp.a = 0;
130
        }
131
        else
132
        {
133
            pamount = capB - temp.b;
134
            temp.b += pamount;
135
            temp.a -= pamount;
136
        }
137
        if(pamount == 1){
138
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallon from A to B. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
139
        } else {
140
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallons from A to B. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
141
        }
142
        possible.push_back(temp);
143
    }
144
    //B to C
145
    if (s.c != capC && s.b != 0)
146
    {
147
        State temp(s.a,s.b,s.c);
148
        temp.directions = s.directions;
149
        int pamount;
150
        if (temp.b + temp.c <= capC)
151
        {
152
            pamount = temp.b;
153
            temp.c += pamount;
154
            temp.b = 0;
155
        }
156
        else
157
        {
158
            pamount = capC - temp.c;
159
            temp.c += pamount;
160
            temp.b -= pamount;
161
        }
162
        if(pamount == 1){
163
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallon from B to C. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
164
        } else {
165
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallons from B to C. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
166
        }
167
        possible.push_back(temp);
168
    }
169
    //A to C
170
    if (s.c != capC && s.a != 0)
171
    {
172
        State temp(s.a,s.b,s.c);
173
        int pamount;
174
        temp.directions = s.directions;
175
        if (temp.a + temp.c <= capC)
176
        {
177
            pamount = temp.a;
178
            temp.c += pamount;
179
            temp.a = 0;
180
        }
181
        else
182
        {
183
            pamount = capC - temp.c;
184
            temp.c += pamount;
185
            temp.a -= pamount;
186
        }
187
        if(pamount == 1){
188
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallon from A to C. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
189
        } else {
190
            temp.directions.push_back("Pour " + std::to_string(pamount)+ " gallons from A to C. " + "(" + std::to_string(temp.a) + ", " + std::to_string(temp.b) + ", " + std::to_string(temp.c) + ")\n");
191
        }
192
        possible.push_back(temp);
193
    }
194
    return possible;
195
}
196
197
State breadthSearch (vector<int> nums) {
198
    int cols = nums[0]+1;
199
    int rows = nums[1]+1;
200
    bool** visited = new bool*[rows];
201
    // go through rows filling / visiting
202
    for (int i=0; i<rows; i++)
203
    {
204
        visited[i] = new bool[cols];
205
        fill(visited[i], visited[i] + cols, false);
206
    }
207
 
208
    list<State> queue;
209
    vector<State> moves;
210
    State start(0, 0, nums[2]);
211
    State goal(nums[3], nums[4], nums[5]);
212
    State current(0, 0, 0);
213
    queue.push_back(start);
214
    while (!(queue.empty())) {
215
        current = queue.front(); //extracts first element of queue
216
        queue.pop_front(); //pops it out
217
218
        if (current.a == goal.a && current.b == goal.b && current.c == goal.c)
219
        {
220
            queue.push_back(current);
221
            break;
222
        }
223
        else
224
        {
225
            moves = possiblepours(current, nums[0], nums[1], nums[2]);
226
            for (int i = 0; i < (int)moves.size(); i++)
227
            {
228
                current = moves[i];
229
                if (current.a == goal.a && current.b == goal.b && current.c == goal.c)
230
                {
231
 
232
                    for (int i = 0; i < cols; i++)
233
                    {
234
                        delete [] visited[i];
235
                    }
236
                    delete [] visited;
237
 
238
                    return current;
239
                }
240
                if (visited[current.a][current.b] == false)
241
                {
242
                    queue.push_back(current);
243
                    visited[current.a][current.b] = true;
244
                }
245
            }
246
        }
247
    }
248
    for (int i = 0; i < cols; i++) {
249
        delete [] visited[i];
250
    }
251
    
252
    delete [] visited;
253
254
    if (queue.empty()) {
255
        return State(-1, -1, -1);
256
    }
257
    return current;
258
}
259
260
int main(int argc, char * const argv[]) {
261
    vector<int> nums;
262
263
    //user input should only have seven arguments
264
    if (argc != 7)
265
    {
266
        cout << "Usage: ./waterjugpuzzle <cap A> <cap B> <cap C> <goal A> <goal B> <goal C>" << endl;
267
        return 0;
268
    }
269
   
270
   // ensure there is no error for integer capacity of jugs
271
   // whenever there is no error, we pushback the capacity and goals into the nums vector
272
    for (int i = 1; i < 4; i++) {
273
        istringstream iss(argv[i]);
274
        int isnum; 
275
        // if assigning iss to isnum fails, that means it's not an integer
276
        if (!(iss>>isnum) || isnum <= 0)
277
        {
278
            if (i == 1)
279
            {
280
                 cout << "Error: Invalid capacity '" << argv[i] << "' for jug A." << endl;
281
            }
282
            if (i == 2)
283
            {
284
                 cout << "Error: Invalid capacity '" << argv[i] << "' for jug B." << endl;
285
            }
286
            if (i == 3)
287
            {
288
                 cout << "Error: Invalid capacity '" << argv[i] << "' for jug C." << endl;
289
            }
290
            iss.clear();
291
            return 1;
292
        }
293
        nums.push_back(isnum);
294
        iss.clear();
295
    }
296
    for (int i = 4; i < 7; i++)
297
    {
298
        istringstream iss(argv[i]);
299
        int isnum;
300
        if (!(iss>>isnum) || isnum < 0)
301
        {
302
            if (i == 4)
303
            {
304
                 cout << "Error: Invalid goal '" << argv[i] << "' for jug A." << endl;
305
            }
306
            if (i == 5)
307
            {
308
                 cout << "Error: Invalid goal '" << argv[i] << "' for jug B." << endl;
309
            }
310
            if (i == 6)
311
            {
312
                 cout << "Error: Invalid goal '" << argv[i] << "' for jug C." << endl;
313
            }
314
            iss.clear();
315
            return 1;
316
        }
317
        nums.push_back(isnum);
318
        iss.clear();
319
    }
320
    for (int i = 4; i < 7; i++)
321
    {
322
        if (nums[i-1] > nums[i-4])
323
        {
324
            if (i == 4)
325
            {
326
                cout << "Error: Goal cannot exceed capacity of jug A." << endl;
327
            }
328
            if (i == 5)
329
            {
330
                cout << "Error: Goal cannot exceed capacity of jug B." << endl;
331
            }
332
            if (i == 6)
333
            {
334
                cout << "Error: Goal cannot exceed capacity of jug C." << endl;
335
            }
336
            return 1;
337
        }
338
    }
339
    if (!(nums[3] + nums[4] + nums[5] == nums[2]))
340
    {
341
        cout << "Error: Total gallons in goal state must be equal to the capacity of jug C." << endl;
342
        return 0;
343
    }
344
345
    //----------------------------------------------------------------------------------------------------
346
    // Do the BFS if there are no errors
347
348
    State found = breadthSearch(nums);
349
350
    if(found.a < 0){
351
        cout << "No solution.";
352
        return 1;
353
    }
354
355
    cout << "Initial state. (0, 0, " << nums[2] <<")" << endl;
356
357
    for (int i = 0; i < (int) found.directions.size(); i++) {
358
        cout << found.directions[i];
359
    }
360
 
361
    return 0;
362
}