Skip to content

Commit e272807

Browse files
committed
Afternoon commit. Both iterative and recursive solutions are functioning, but the iterative version's performance is awful. Added some meat to the driver in Lab2Main and added some argument validation. Taking a break.
1 parent 7de7426 commit e272807

File tree

4 files changed

+508
-118
lines changed

4 files changed

+508
-118
lines changed

Lab_2/IterativeTowers.java

+148-80
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
class IterativeTowers
22
{
33
private int towerSize;
4+
5+
// Variables to represent the three disc stacks
46
private IntStack towerA = new IntStack();
57
private IntStack towerB = new IntStack();
68
private IntStack towerC = new IntStack();
79
private IntStack[] towers = {towerA, towerB, towerC};
810

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
1114

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 = "";
1419

1520
/******************************
1621
*******************************
1722
*** Constructors
1823
******************************
1924
******************************/
2025

21-
IterativeTowers(int towerSize){
26+
IterativeTowers(int towerSize, String targetTower){
2227
/**
2328
** Constructor for IterativeTower. It takes in an integer,
2429
** which sets the number of discs to be used in the problem.
@@ -33,7 +38,7 @@ class IterativeTowers
3338

3439
//Error checking
3540
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) +".");
3742
}
3843

3944
// Initialize Tower A
@@ -42,11 +47,20 @@ class IterativeTowers
4247
towerA.push(i);
4348
}
4449

45-
// Set up start variables
50+
// Set up state variables
4651
this.smallDiscLoc = 0;
4752
this.discSizeFlag = -1;
4853
this.moveDirection = this.getMoveDirection(towerSize);
4954
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+
}
5064
}
5165

5266
/******************************
@@ -58,26 +72,27 @@ class IterativeTowers
5872
public void solve(){
5973
/**
6074
** 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".
6582
**/
83+
6684

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.
7188
int nextMove;
7289
while(this.numMoves > 0){
90+
91+
// Move smallest disc
7392
if(this.discSizeFlag == -1){
74-
//Move the small disc
93+
7594
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);
8196

8297
// Housekeeping
8398
this.smallDiscLoc = nextMove;
@@ -91,19 +106,26 @@ public void solve(String targetTower){
91106
// disc that we just moved, and it can't go onto the tower that it
92107
// came from, so it must go on the only remaining tower.)
93108
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);
98110
}
99111

100112
// Housekeeping
101113
this.flipDiscSizeFlag();
102114
this.numMoves--;
103115

104116
}
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;
107129
}
108130

109131
/******************************
@@ -112,14 +134,29 @@ public void solve(String targetTower){
112134
******************************
113135
******************************/
114136

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+
115152
private int findLegalMove(int startingTower){
116153
/**
117154
** findLegalMove() determines the next permissible move for the disc
118155
** on top of the startingTower.
119156
**
120157
**
121158
**/
122-
int nextMove = (startingTower + this.moveDirection + 3) % 3; // MAYBE DONT NEED TO ADD THREE!
159+
int nextMove = (startingTower + this.moveDirection + 3) % 3;
123160
if(towers[nextMove].isEmpty() || towers[startingTower].peek() < towers[nextMove].peek()){
124161
return nextMove;
125162
} else {
@@ -160,56 +197,87 @@ private int findSecondSmallestDisc(){
160197
} else {
161198
throw new RuntimeException("Something very bad happened to IterativeTowers.smallDiscLoc--it's gone!");
162199
}
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+
}
215283
}

0 commit comments

Comments
 (0)