1
1
class IterativeTowers
2
2
{
3
3
private int towerSize ;
4
+
5
+ // Variables to represent the three disc stacks
4
6
private IntStack towerA = new IntStack ();
5
7
private IntStack towerB = new IntStack ();
6
8
private IntStack towerC = new IntStack ();
7
9
private IntStack [] towers = {towerA , towerB , towerC };
8
10
9
- private int smallDiscLoc ;
10
- private int discSizeFlag ; // Tracks which disc to move, big or small
11
+ // State tracking variables
12
+ private int smallDiscLoc ; // Location of the small disc
13
+ private int discSizeFlag ; // Tracks which disc to move, big or small
11
14
12
- private int moveDirection ;
13
- private long numMoves ;
15
+ private int moveDirection ; // Direction of movements
16
+ private long numMoves ; // # of moves left to solve the towers
17
+
18
+ private String moveList = "" ;
14
19
15
20
/******************************
16
21
*******************************
17
22
*** Constructors
18
23
******************************
19
24
******************************/
20
25
21
- IterativeTowers (int towerSize ){
26
+ IterativeTowers (int towerSize , String targetTower ){
22
27
/**
23
28
** Constructor for IterativeTower. It takes in an integer,
24
29
** which sets the number of discs to be used in the problem.
@@ -33,7 +38,7 @@ class IterativeTowers
33
38
34
39
//Error checking
35
40
if (towerSize >= Integer .MAX_VALUE ) {
36
- throw new IllegalArgumentException ("The size of the IterativeTowers must be less than " + (MAX_VALUE - 1 ) +"." );
41
+ throw new IllegalArgumentException ("The size of the IterativeTowers must be less than " + (Integer . MAX_VALUE - 1 ) +"." );
37
42
}
38
43
39
44
// Initialize Tower A
@@ -42,11 +47,20 @@ class IterativeTowers
42
47
towerA .push (i );
43
48
}
44
49
45
- // Set up start variables
50
+ // Set up state variables
46
51
this .smallDiscLoc = 0 ;
47
52
this .discSizeFlag = -1 ;
48
53
this .moveDirection = this .getMoveDirection (towerSize );
49
54
this .numMoves = this .getNumMoves (towerSize );
55
+
56
+ // The default behavior of this TOH solution is to move the discs to
57
+ // Tower C. We can cause the discs to end up on Tower B by switching
58
+ // the direction of movement that was determine when the IterativeTower
59
+ // instance was initialized. Any argument passed to solve() other than
60
+ // "B" will be ignored without any warnings being generated.
61
+ if (targetTower .equals ("B" )){
62
+ flipMoveDirection ();
63
+ }
50
64
}
51
65
52
66
/******************************
@@ -58,26 +72,27 @@ class IterativeTowers
58
72
public void solve (){
59
73
/**
60
74
** solverTower() generates a solution to the Towers of
61
- ** Hanoi problem with the discs being moved to the traditional
62
- ** target tower, Tower C (the third tower, on the opposite side
63
- ** of the peg board from the starting tower). Discs are
64
- ** always initially stacked on Tower A.
75
+ ** Hanoi problem. Discs begin on Tower A and are moved to the targetTower.
76
+ ** The problem is solved by making moves in the this.moveDirection, with
77
+ ** moves alternating between the smallest disc and the second smallest
78
+ ** disc. They are moved to the first available legal position in the
79
+ ** this.moveDirection (the pegs are treated as circular).
80
+ **
81
+ ** @param targetTower The tower that the discs should be moved to, i.e., "B" or "C".
65
82
**/
83
+
66
84
67
- solve ("C" );
68
- }
69
-
70
- public void solve (String targetTower ){
85
+
86
+ // Continue making moves until final number is reached, alternating between
87
+ // the smallest and second smallest discs.
71
88
int nextMove ;
72
89
while (this .numMoves > 0 ){
90
+
91
+ // Move smallest disc
73
92
if (this .discSizeFlag == -1 ){
74
- //Move the small disc
93
+
75
94
nextMove = findLegalMove (this .smallDiscLoc );
76
- // Print/add some output. Consider whether we should write to file as we go.
77
- // The solution is probably too big to fit in memory for large towerSizes
78
-
79
- // Move the disc in the stack
80
- this .towers [nextMove ].push ( this .towers [smallDiscLoc ].pop () );
95
+ makeMove (this .smallDiscLoc , nextMove );
81
96
82
97
// Housekeeping
83
98
this .smallDiscLoc = nextMove ;
@@ -91,19 +106,26 @@ public void solve(String targetTower){
91
106
// disc that we just moved, and it can't go onto the tower that it
92
107
// came from, so it must go on the only remaining tower.)
93
108
nextMove = 3 - startingTower - this .smallDiscLoc ;
94
-
95
- // Move the disc
96
- // PRINT/ADD OUTPUT
97
- this .towers [nextMove ].push (this .towers [startingTower ].pop ());
109
+ makeMove (startingTower , nextMove );
98
110
}
99
111
100
112
// Housekeeping
101
113
this .flipDiscSizeFlag ();
102
114
this .numMoves --;
103
115
104
116
}
105
-
106
- // DO SOME OUTPUT.
117
+ }
118
+
119
+ public String getMoveList (){
120
+ /**
121
+ ** getMoveList() provides a String containing the moves required to
122
+ ** solve the TOH problem. this.solve() MUST be called before calling
123
+ ** getMoveList().
124
+ **
125
+ ** @return String A string containing the moves required to solve the TOH problem.
126
+ **/
127
+
128
+ return this .moveList ;
107
129
}
108
130
109
131
/******************************
@@ -112,14 +134,29 @@ public void solve(String targetTower){
112
134
******************************
113
135
******************************/
114
136
137
+ private void makeMove (int startingTower , int targetTower ){
138
+ /**
139
+ ** makeMove() moves the disc on top of the startingTower to the targetTower.
140
+ ** It updates the appropriate tower IntStacks and [_____________________].
141
+ **
142
+ ** @param startingTower The tower containing the disc to be moved.
143
+ ** @param targetTower The tower that the disc should be moved to.
144
+ **
145
+ ** @return None Nothing is returned.
146
+ **/
147
+ int discNum = this .towers [startingTower ].peek ();
148
+ this .towers [targetTower ].push (this .towers [startingTower ].pop ());
149
+ this .moveList += "Move disc " + discNum + " from " + getTowerString (startingTower ) + " to " + getTowerString (targetTower ) + "\n " ;
150
+ }
151
+
115
152
private int findLegalMove (int startingTower ){
116
153
/**
117
154
** findLegalMove() determines the next permissible move for the disc
118
155
** on top of the startingTower.
119
156
**
120
157
**
121
158
**/
122
- int nextMove = (startingTower + this .moveDirection + 3 ) % 3 ; // MAYBE DONT NEED TO ADD THREE!
159
+ int nextMove = (startingTower + this .moveDirection + 3 ) % 3 ;
123
160
if (towers [nextMove ].isEmpty () || towers [startingTower ].peek () < towers [nextMove ].peek ()){
124
161
return nextMove ;
125
162
} else {
@@ -160,56 +197,87 @@ private int findSecondSmallestDisc(){
160
197
} else {
161
198
throw new RuntimeException ("Something very bad happened to IterativeTowers.smallDiscLoc--it's gone!" );
162
199
}
163
- }
164
-
165
- private void flipDiscSizeFlag (){
166
- /**
167
- ** flipDiscSizeFlag() alternates this.discSizeFlag() between the values
168
- ** 1 and -1. If it is set to 1 at the time flipDiscSizeFlag() is called,
169
- ** then, its value is changed to -1, and vice versa.
170
- **
171
- ** @return None Nothing is returned.
172
- **/
173
-
174
- this .discSizeFlag *= -1 ;
175
- }
176
-
177
- private long getNumMoves (int towerSize ){
178
- /**
179
- ** getNumMoves() calculates the number of moves required to solve the TOH
180
- ** problem given the towerSize. Using an optimum strategy, this is 2^n - 1.
181
- ** MathHelpers.exponentiate() is an exponentiation function that is able
182
- ** to handle large integer values with a level of precision not offered
183
- ** by java.lang.Math.pow(), which utilizes floating point numbers. This is
184
- ** needed due to the potentially large number of moves required to solve
185
- ** the Towers of Hanoi problem.
186
- **
187
- ** @param towerSize The number of discs to be solved for
188
- **
189
- ** @return int The minimum number of moves required to solve TOH for the given towerSize
190
- **/
191
-
192
- return MathHelpers .exponentiate (2 , towerSize ) - 1 ;
193
- }
194
-
195
- private int getMoveDirection (int towerSize ){
196
- /**
197
- ** getMoveDirection() determines whether moves should be
198
- ** made in the left or right direction while solving the TOH
199
- ** problem. If there are an even number of discs, then
200
- ** moves will be made towards the right, and if there are an
201
- ** odd number then moves will be made to the left. Rightward
202
- ** moves are indicated by a return value of 1, and leftward
203
- ** moves are indicated by -1.
204
- ** [______ADJUSTMENTS FOR DIFFERENT TOWER]
205
- **
206
- ** @param towerSize The number of discs to be solved for.
207
- ** @param targetTower [The integer identifer for the tower that discs are being moved to.]
208
- **
209
- ** @return int The integer 1 if moves are to be made to the right; -1 if to the left.
210
- **
211
- **/
212
-
213
- return towerSize % 2 == 0 ? 1 : -1 ;
214
- }
200
+ }
201
+
202
+ private void flipDiscSizeFlag (){
203
+ /**
204
+ ** flipDiscSizeFlag() alternates this.discSizeFlag() between the values
205
+ ** 1 and -1. If it is set to 1 at the time flipDiscSizeFlag() is called,
206
+ ** then, its value is changed to -1, and vice versa.
207
+ **
208
+ ** @return None Nothing is returned.
209
+ **/
210
+
211
+ this .discSizeFlag *= -1 ;
212
+ }
213
+
214
+ private void flipMoveDirection (){
215
+ /**
216
+ ** flipDiscSizeFlag() reverses the direction of movement that is used
217
+ ** to solve the TOH problem. Movement towards the right is indicated by
218
+ ** setting this.moveDirection to 1, and movements to the left is indicated
219
+ ** by -1. To reverse the direction, we simply this.moveDirection *= -1.
220
+ **
221
+ ** @return None Nothing is returned.
222
+ **/
223
+
224
+ this .moveDirection *= -1 ;
225
+ }
226
+
227
+ private long getNumMoves (int towerSize ){
228
+ /**
229
+ ** getNumMoves() calculates the number of moves required to solve the TOH
230
+ ** problem given the towerSize. Using an optimum strategy, this is 2^n - 1.
231
+ ** MathHelpers.exponentiate() is an exponentiation function that is able
232
+ ** to handle large integer values with a level of precision not offered
233
+ ** by java.lang.Math.pow(), which utilizes floating point numbers. This is
234
+ ** needed due to the potentially large number of moves required to solve
235
+ ** the Towers of Hanoi problem.
236
+ **
237
+ ** @param towerSize The number of discs to be solved for
238
+ **
239
+ ** @return int The minimum number of moves required to solve TOH for the given towerSize
240
+ **/
241
+
242
+ return MathHelpers .exponentiate (2 , towerSize ) - 1 ;
243
+ }
244
+
245
+ private int getMoveDirection (int towerSize ){
246
+ /**
247
+ ** getMoveDirection() determines whether moves should be
248
+ ** made in the left or right direction while solving the TOH
249
+ ** problem. If there are an even number of discs, then
250
+ ** moves will be made towards the right, and if there are an
251
+ ** odd number then moves will be made to the left. Rightward
252
+ ** moves are indicated by a return value of 1, and leftward
253
+ ** moves are indicated by -1.
254
+ ** [______ADJUSTMENTS FOR DIFFERENT TOWER]
255
+ **
256
+ ** @param towerSize The number of discs to be solved for.
257
+ ** @param targetTower [The integer identifer for the tower that discs are being moved to.]
258
+ **
259
+ ** @return int The integer 1 if moves are to be made to the right; -1 if to the left.
260
+ **
261
+ **/
262
+
263
+ return towerSize % 2 == 0 ? 1 : -1 ;
264
+ }
265
+
266
+ private String getTowerString (int towerNum ){
267
+ String towerString ;
268
+ switch (towerNum ){
269
+ case 0 :
270
+ towerString = "A" ;
271
+ break ;
272
+ case 1 :
273
+ towerString = "B" ;
274
+ break ;
275
+ case 2 :
276
+ towerString = "C" ;
277
+ break ;
278
+ default :
279
+ towerString = "" ;
280
+ }
281
+ return towerString ;
282
+ }
215
283
}
0 commit comments