In this module, we will cover the notion of stepwise
refinement:
This module has been written for the novice programmer who, quite
understandably, has difficult getting started after reading a word
description of a programming problem.
The main idea is to separate coding from problem-solving, and to
proceed in small steps, even if the small steps seem like
"a waste of time".
In this module, we will take up a programming problem and attack
it using the stepwise approach. We will also look at the wrong way
to attack the problem.
Answer: It is a process of programming, starting from an
idea to finished, and refined, code.
Answer: for most programming tasks!
In this problem, you are to move a chesspiece (a Knight) randomly around a chessboard and estimate how often it goes through the center of the chessboard. More precisely:
There is a temptation with the novice programmer to start coding as soon as possible. For example, the following steps, while apparently reasonable, eventually will create problems:
public class Knight { public static void main (String[] argv) { int[][] board; } }
public class Knight { public static void main (String[] argv) { int[][] board; board = new int[8][]; for (int i=0; i < 8; i++) board[i] = new int[8]; // Initialize for (int i=0; i < 8; i++) for (int j=0; j < 8; j++) board[i][j] = 0; } }
public class Knight { public static void main (String[] argv) { int[][] board; board = new int[8][]; for (int i=0; i < 8; i++) board[i] = new int[8]; // Initialize for (int i=0; i < 8; i++) for (int j=0; j < 8; j++) board[i][j] = 0; // Place Knight at (0,0) board[0][0] = 1; } }
This approach to a programming problem is, to put it bluntly, bad!
Like any other complex activity, a little thought and planning go a long way.
The key principles in Stepwise Refinement:
In the sequel, we will take our problem and apply the Stepwise Refinement procedure.
First, let's make sure we understand the problem:
So, in theory, we now understand the problem well enough that we can manually produce the output if we had to.
Things NOT to do at this time:
Now is the right time to set up the broad overall approach to the problem:
For example, here's what I wrote down:
1. Repeat this 10,000 times:
1.1 Start with Knight at (0,0).
1.2 Move it 1000 moves, and record how many moves
landed in the center.
1.3 Compute the fraction for this run.
2. Compute the average over the 10,000 runs.
3. Print results.
Some things to observe:
Next, review the outline and check to make sure it really is going
to work! For example, here's an outline that does NOT work:
1. Repeat this 10,000 times:
1.1 Start with Knight at (0,0).
1.2 Move it 1000 moves, and record how many moves
landed in the center.
1.3 Compute the fraction for this run.
1.4 Compute the average.
2. Print results
Why? The average has to be computed in the outer process, so it can't
be part of each of the 10,000 runs.
What NOT to do at this stage:
Next, we are going to write a program "shell" and put down the
pseudocode inside the shell, as comments:
public class KnightSolution {
public static void main (String[] argv)
{
// 1. Repeat this 10,000 times
// 1.1 Start with Knight at (0,0).
// 1.2 Move it 1000 moves, and record how many moves
// landed in the center.
// 1.3 Compute the fraction for this run.
// 2. Compute the average over 10,000 runs.
// 3. Print results
}
}
At this point, we don't really need to compile, but it doesn't hurt to compile either.
Next, we are going to put in some detail:
public class KnightSolution {
public static void main (String[] argv)
{
int numRuns = 10000;
// 1. Repeat this 10,000 times
double totalFrac = 0;
for (int run=1; run<=numRuns; run++) {
double frac = 0;
// 1.1 Start with Knight at (0,0).
// 1.2 Move it 1000 moves, and record how many moves
// landed in the center.
// 1.3 Compute the fraction for this run.
totalFrac = totalFrac + frac;
}
// 2. Compute the average.
double fracEstimate = totalFrac / numRuns;
// 3. Print results
System.out.println ("Estimate: " + fracEstimate);
}
}
Observe:
What NOT to do at this time:
Now, let's look at the broad outline and ask ourselves what data structures would be useful:
int x, y;
Now, we DO NOT have to get this right the first time. If our data structures are too big, or too inefficient, that's OK for a first cut.
So, let's take the following approach:
int[][] board;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0Here, the knight is at location (2,2) (viewed upside down, but that's alright for now).
int x, y;
So, at this point:
public class KnightSolution {
static int[][] board;
public static void main (String[] argv)
{
int numRuns = 10000;
// Create chessboard.
board = new int[8][];
for (int i=0; i < 8; i++) {
board[i] = new int[8];
}
// 1. Repeat this 10,000 times
double totalFrac = 0;
for (int run=1; run<=numRuns; run++) {
double frac = 0;
// 1.1 Start with Knight at (0,0).
// Initialize board here.
for (int i=0; i < 8; i++) {
for (int j=0; j < 8; j++) {
board[i][j] = 0;
}
}
// Put the knight in location (0,0).
board[0][0] = 1;
// Current location of knight.
int x=0, y=0;
// 1.2 Move it 1000 moves, and record how many moves
// landed in the center.
// 1.3 Compute the fraction for this run.
totalFrac = totalFrac + frac;
}
// 2. Compute the average.
double fracEstimate = totalFrac / numRuns;
// 3. Print results
System.out.println ("Estimate: " + fracEstimate);
}
}
Finally, we can clean up the code a little by moving some code
into methods:
public class KnightSolution {
static int[][] board;
// Create the space for the board.
static void createBoard ()
{
board = new int[8][];
for (int i=0; i < 8; i++) {
board[i] = new int[8];
}
}
// Set all board entries to 0.
static void cleanBoard ()
{
for (int i=0; i < 8; i++) {
for (int j=0; j < 8; j++) {
board[i][j] = 0;
}
}
}
public static void main (String[] argv)
{
int numRuns = 10000;
// Create chessboard.
createBoard ();
// 1. Repeat this 10,000 times
double totalFrac = 0;
for (int run=1; run<=numRuns; run++) {
double frac = 0;
// 1.1 Start with Knight at (0,0).
cleanBoard ();
// Put the knight in location (0,0).
board[0][0] = 1;
// Current location of knight.
int x=0, y=0;
// 1.2 Move it 1000 moves, and record how many moves
// landed in the center.
// 1.3 Compute the fraction for this run.
totalFrac = totalFrac + frac;
}
// 2. Compute the average.
double fracEstimate = totalFrac / numRuns;
// 3. Print results
System.out.println ("Estimate: " + fracEstimate);
}
}
At this point, we are going to fill in some detail in the inner
loop:
Since there is significant logic inside, we will first
write pseudocode:
public class KnightSolution {
static int[][] board;
// Create the space for the board.
static void createBoard ()
{
board = new int[8][];
for (int i=0; i < 8; i++) {
board[i] = new int[8];
}
}
// Set all board entries to 0.
static void cleanBoard ()
{
for (int i=0; i < 8; i++) {
for (int j=0; j < 8; j++) {
board[i][j] = 0;
}
}
}
public static void main (String[] argv)
{
int numRuns = 10000;
// Create chessboard.
createBoard ();
// 1. Repeat this 10,000 times
double totalFrac = 0;
for (int run=1; run<=numRuns; run++) {
double frac = 0;
// 1.1 Start with Knight at (0,0).
cleanBoard ();
// Put the knight in location (0,0).
board[0][0] = 1;
// Current location of knight.
int x=0, y=0;
// 1.2 Move it 1000 moves, and record how many moves
// landed in the center.
for (int move=1; move<=1000; move++) {
// Identify possible next locations.
// Pick one of them randomly.
// Set x,y to new locations.
// If new location is a center location, update count.
}
// 1.3 Compute the fraction for this run.
totalFrac = totalFrac + frac;
}
// 2. Compute the average.
double fracEstimate = totalFrac / numRuns;
// 3. Print results
System.out.println ("Estimate: " + fracEstimate);
}
}
Observe:
Once again, let's take a look at the key steps in the inner loop:
for (int move=1; move<=1000; move++) {
// Identify possible next locations.
// Pick one of them randomly.
// Set x,y to new locations.
// If new location is a center location, update count.
}
What data structures are we going to need for this part?
int[][] count; ... // if Knight lands in x,y then update count count[x][y] ++;This way, we will get the "count" for the 4 center squares:
centerCount = count[3][3] + count[3][4] + count[4][3] + count[4][4]);
Let's take this approach:
int[] possibleX = new int[8]; int[] possibleY = new int[8];
OK, now we can start attacking the details of the inner loop:
// Check each possible next location from the 8. // For each one of them, see if the location is "on board" // To check if it's on board, make sure x,y values are in the range 0-7
whichLocation = UniformRandom.uniform (0, numLocations-1);
Let's write methods for each of these small tasks:
static boolean validLocation (int x, int y) { // Check if x value is out of range. if ( (x < 0) || (x > 7) ) return false; // Check if y value is out of range. if ( (y < 0) || (y > 7) ) return false; // Otherwise, it's OK. return true; }
// Create possible locations and return number of such locations. // The input location is x,y static int identifyPossibleLocations (int x, int y) { // Check the different possibilities (x+2, y+1) etc. int numLocations = 0; // Check first one. if (validLocation (x+2, y+1)) { // Put this in the array. possibleX[numLocations] = x+2; possibleY[numLocations] = y+1; numLocations ++; } // Next: if (validLocation (x+2, y-1)) { // Put this in the array. possibleX[numLocations] = x+2; possibleY[numLocations] = y-1; numLocations ++; } // Others: 3 if (validLocation (x-2, y+1)) { // Put this in the array. possibleX[numLocations] = x-2; possibleY[numLocations] = y+1; numLocations ++; } if (validLocation (x-2, y-1)) { // 4 possibleX[numLocations] = x-2; possibleY[numLocations] = y-1; numLocations ++; } if (validLocation (x+1, y+2)) { // 5 possibleX[numLocations] = x+1; possibleY[numLocations] = y+2; numLocations ++; } if (validLocation (x+1, y-2)) { // 6 possibleX[numLocations] = x+1; possibleY[numLocations] = y-2; numLocations ++; } if (validLocation (x-1, y+2)) { // 7 possibleX[numLocations] = x-1; possibleY[numLocations] = y+2; numLocations ++; } if (validLocation (x-1, y-2)) { // 8 possibleX[numLocations] = x-1; possibleY[numLocations] = y-2; numLocations ++; } return numLocations; }
Now, let's put all of this together:
public class KnightSolution {
static int[][] board;
static int[] possibleX = new int[8];
static int[] possibleY = new int[8];
// Create the space for the board.
static void createBoard ()
{
board = new int[8][];
for (int i=0; i < 8; i++) {
board[i] = new int[8];
}
}
// Set all board entries to 0.
static void cleanBoard ()
{
for (int i=0; i < 8; i++) {
for (int j=0; j < 8; j++) {
board[i][j] = 0;
}
}
}
static boolean validLocation (int x, int y)
{
// Check if x value is out of range.
if ( (x < 0) || (x > 7) )
return false;
// Check if y value is out of range.
if ( (y < 0) || (y > 7) )
return false;
// Otherwise, it's OK.
return true;
}
// Create possible locations and return number of such locations.
// The input location is x,y
static int identifyPossibleLocations (int x, int y)
{
// Check the different possibilities (x+2, y+1) etc.
int numLocations = 0;
// Check first one.
if (validLocation (x+2, y+1)) {
// Put this in the array.
possibleX[numLocations] = x+2;
possibleY[numLocations] = y+1;
numLocations ++;
}
// Next:
if (validLocation (x+2, y-1)) {
// Put this in the array.
possibleX[numLocations] = x+2;
possibleY[numLocations] = y-1;
numLocations ++;
}
// Others: 3
if (validLocation (x-2, y+1)) {
// Put this in the array.
possibleX[numLocations] = x-2;
possibleY[numLocations] = y+1;
numLocations ++;
}
if (validLocation (x-2, y-1)) { // 4
possibleX[numLocations] = x-2;
possibleY[numLocations] = y-1;
numLocations ++;
}
if (validLocation (x+1, y+2)) { // 5
possibleX[numLocations] = x+1;
possibleY[numLocations] = y+2;
numLocations ++;
}
if (validLocation (x+1, y-2)) { // 6
possibleX[numLocations] = x+1;
possibleY[numLocations] = y-2;
numLocations ++;
}
if (validLocation (x-1, y+2)) { // 7
possibleX[numLocations] = x-1;
possibleY[numLocations] = y+2;
numLocations ++;
}
if (validLocation (x-1, y-2)) { // 8
possibleX[numLocations] = x-1;
possibleY[numLocations] = y-2;
numLocations ++;
}
return numLocations;
}
public static void main (String[] argv)
{
int numRuns = 10000;
// Create chessboard.
createBoard ();
// 1. Repeat this 10,000 times
double totalFrac = 0;
for (int run=1; run<=numRuns; run++) {
double frac = 0;
// 1.1 Start with Knight at (0,0).
cleanBoard ();
// Put the knight in location (0,0).
board[0][0] = 1;
// Current location of knight.
int x=0, y=0;
// 1.2 Move it 1000 moves, and record how many moves
// landed in the center.
int centerCount = 0;
for (int move=1; move<=1000; move++) {
// Identify possible next locations.
int numLocations = identifyPossibleLocations (x, y);
// Pick one of them randomly.
int nextLocation = (int) UniformRandom.uniform ((long) 0, (long) numLocations);
// At this time, possibleX[] and possibleY[] contain the possible locations.
// Set x,y to new locations.
x = possibleX[nextLocation];
y = possibleY[nextLocation];
// If new location is a center location, update count.
if ( ( (x==3) && (y==3) )
|| ( (x==3) && (y==4) )
|| ( (x==4) && (y==3) )
|| ( (x==4) && (y==4) ) ) {
centerCount ++;
}
// Update fraction.
frac = (double) centerCount / (double) 1000;
}
// 1.3 Compute the fraction for this run.
totalFrac = totalFrac + frac;
}
// 2. Compute the average.
double fracEstimate = totalFrac / numRuns;
// 3. Print results
System.out.println ("Estimate: " + fracEstimate);
}
}
At this point, we have most of our code. This is a good time to look over the code to see if we've missed anything, or can improve anything:
OK, let's make these changes:
/**
* KnightSolution is a static class that is used to compute the
* probability that a randomly moving chesspiece (a Knight) lands
* in the center. The approach taken has the following outline:
* 1. Repeat this 10,000 times:
* 1.1 Start with Knight at (0,0).
* 1.2 Move it 1000 moves, and record how many moves
* landed in the center.
* 1.3 Compute the fraction for this run.
* 2. Compute the average.
* 3. Print results
*
* @author Rahul Simha
*
*/
public class KnightSolution {
// Representation of board with Knight:
// board[i][j] == 1 if the Knight is at (i,j);
// board[i][j] == 0 otherwise.
static int[][] board;
// Possible locations are stored here.
// The i-th possible location has coordinates
// (possibleX[i], possibleY[j])
static int[] possibleX = new int[8];
static int[] possibleY = new int[8];
// Create the space for the board.
static void createBoard ()
{
board = new int[8][];
for (int i=0; i < 8; i++) {
board[i] = new int[8];
}
}
// Set all board entries to 0.
static void cleanBoard ()
{
for (int i=0; i < 8; i++) {
for (int j=0; j < 8; j++) {
board[i][j] = 0;
}
}
}
static boolean validLocation (int x, int y)
{
// Check if x value is out of range.
if ( (x < 0) || (x > 7) )
return false;
// Check if y value is out of range.
if ( (y < 0) || (y > 7) )
return false;
// Otherwise, it's OK.
return true;
}
// Create possible locations and return number of such locations.
// The input location is x,y
static int identifyPossibleLocations (int x, int y)
{
// Check the different possibilities (x+2, y+1) etc.
int numLocations = 0;
// Check first one.
if (validLocation (x+2, y+1)) {
// Put this in the array.
possibleX[numLocations] = x+2;
possibleY[numLocations] = y+1;
numLocations ++;
}
// Next:
if (validLocation (x+2, y-1)) {
// Put this in the array.
possibleX[numLocations] = x+2;
possibleY[numLocations] = y-1;
numLocations ++;
}
// Others: 3
if (validLocation (x-2, y+1)) {
// Put this in the array.
possibleX[numLocations] = x-2;
possibleY[numLocations] = y+1;
numLocations ++;
}
if (validLocation (x-2, y-1)) { // 4
possibleX[numLocations] = x-2;
possibleY[numLocations] = y-1;
numLocations ++;
}
if (validLocation (x+1, y+2)) { // 5
possibleX[numLocations] = x+1;
possibleY[numLocations] = y+2;
numLocations ++;
}
if (validLocation (x+1, y-2)) { // 6
possibleX[numLocations] = x+1;
possibleY[numLocations] = y-2;
numLocations ++;
}
if (validLocation (x-1, y+2)) { // 7
possibleX[numLocations] = x-1;
possibleY[numLocations] = y+2;
numLocations ++;
}
if (validLocation (x-1, y-2)) { // 8
possibleX[numLocations] = x-1;
possibleY[numLocations] = y-2;
numLocations ++;
}
return numLocations;
}
public static void main (String[] argv)
{
int numRuns = 10000;
int numMoves = 1000;
// Create chessboard.
createBoard ();
// 1. Repeat this 10,000 times
double totalFrac = 0;
for (int run=1; run<=numRuns; run++) {
double frac = 0;
// 1.1 Start with Knight at (0,0).
cleanBoard ();
// Put the knight in location (0,0).
board[0][0] = 1;
// Current location of knight.
int x=0, y=0;
// 1.2 Move it 1000 moves, and record how many moves
// landed in the center.
int centerCount = 0;
for (int move=1; move<=numMoves; move++) {
// Identify possible next locations.
int numLocations = identifyPossibleLocations (x, y);
// Pick one of them randomly.
int nextLocation = (int) UniformRandom.uniform ((long) 0, (long) numLocations);
// At this time, possibleX[] and possibleY[] contain the possible locations.
// Set x,y to new locations.
x = possibleX[nextLocation];
y = possibleY[nextLocation];
// If new location is a center location, update count.
if ( ( (x==3) && (y==3) )
|| ( (x==3) && (y==4) )
|| ( (x==4) && (y==3) )
|| ( (x==4) && (y==4) ) ) {
centerCount ++;
}
// Update fraction.
frac = (double) centerCount / (double) 1000;
}
// 1.3 Compute the fraction for this run.
totalFrac = totalFrac + frac;
}
// 2. Compute the average.
double fracEstimate = totalFrac / numRuns;
// 3. Print results
System.out.println ("Estimate: " + fracEstimate);
}
}
The wrong next step is to assume the program works.
(There is a bug in the program.)
Instead, we should build debugging output before executing the program:
Here is a "debug"-ready version of the program:
public class KnightSolution {
static boolean debug = true;
// Representation of board with Knight:
// board[i][j] == 1 if the Knight is at (i,j);
// board[i][j] == 0 otherwise.
static int[][] board;
// Possible locations are stored here.
// The i-th possible location has coordinates
// (possibleX[i], possibleY[j])
static int[] possibleX = new int[8];
static int[] possibleY = new int[8];
// Create the space for the board.
static void createBoard ()
{
board = new int[8][];
for (int i=0; i < 8; i++) {
board[i] = new int[8];
}
}
// Set all board entries to 0.
static void cleanBoard ()
{
for (int i=0; i < 8; i++) {
for (int j=0; j < 8; j++) {
board[i][j] = 0;
}
}
}
static boolean validLocation (int x, int y)
{
// Check if x value is out of range.
if ( (x < 0) || (x > 7) )
return false;
// Check if y value is out of range.
if ( (y < 0) || (y > 7) )
return false;
// Otherwise, it's OK.
return true;
}
// Create possible locations and return number of such locations.
// The input location is x,y
static int identifyPossibleLocations (int x, int y)
{
// Check the different possibilities (x+2, y+1) etc.
int numLocations = 0;
// Check first one.
if (validLocation (x+2, y+1)) {
// Put this in the array.
possibleX[numLocations] = x+2;
possibleY[numLocations] = y+1;
numLocations ++;
}
// Next:
if (validLocation (x+2, y-1)) {
// Put this in the array.
possibleX[numLocations] = x+2;
possibleY[numLocations] = y-1;
numLocations ++;
}
// Others: 3
if (validLocation (x-2, y+1)) {
// Put this in the array.
possibleX[numLocations] = x-2;
possibleY[numLocations] = y+1;
numLocations ++;
}
if (validLocation (x-2, y-1)) { // 4
possibleX[numLocations] = x-2;
possibleY[numLocations] = y-1;
numLocations ++;
}
if (validLocation (x+1, y+2)) { // 5
possibleX[numLocations] = x+1;
possibleY[numLocations] = y+2;
numLocations ++;
}
if (validLocation (x+1, y-2)) { // 6
possibleX[numLocations] = x+1;
possibleY[numLocations] = y-2;
numLocations ++;
}
if (validLocation (x-1, y+2)) { // 7
possibleX[numLocations] = x-1;
possibleY[numLocations] = y+2;
numLocations ++;
}
if (validLocation (x-1, y-2)) { // 8
possibleX[numLocations] = x-1;
possibleY[numLocations] = y-2;
numLocations ++;
}
return numLocations;
}
static void printPossibleLocations (int numLocations)
{
System.out.print ("Possible Locations: ");
for (int i=0; i < numLocations; i++)
System.out.print (" (" + possibleX[i] + "," + possibleY[i] + ")");
System.out.println ();
}
static void printBoard ()
{
System.out.println ("Board status: ");
for (int i=0; i < 8; i++) {
for (int j=0; j < 8; j++) {
System.out.print (" " + board[i][j]);
}
System.out.println ();
}
}
public static void main (String[] argv)
{
int numRuns = 1;
int numMoves = 10;
// Create chessboard.
createBoard ();
// 1. Repeat this 10,000 times
double totalFrac = 0;
for (int run=1; run<=numRuns; run++) {
if (debug)
System.out.println ("Run# " + run);
double frac = 0;
// 1.1 Start with Knight at (0,0).
cleanBoard ();
// Put the knight in location (0,0).
board[0][0] = 1;
// Current location of knight.
int x=0, y=0;
// 1.2 Move it 1000 moves, and record how many moves
// landed in the center.
int centerCount = 0;
for (int move=1; move<=numMoves; move++) {
// Identify possible next locations.
int numLocations = identifyPossibleLocations (x, y);
// Pick one of them randomly.
int nextLocation = (int) UniformRandom.uniform ((long) 0, (long) numLocations);
// Debug.
if (debug) {
System.out.println (">> Move# " + move + " cur_x=" + x + " cur_y=" + y +
" numLoc=" + numLocations + " nextLoc=" + nextLocation);
printPossibleLocations (numLocations);
printBoard ();
}
// At this time, possibleX[] and possibleY[] contain the possible locations.
// Set x,y to new locations.
x = possibleX[nextLocation];
y = possibleY[nextLocation];
// If new location is a center location, update count.
if ( ( (x==3) && (y==3) )
|| ( (x==3) && (y==4) )
|| ( (x==4) && (y==3) )
|| ( (x==4) && (y==4) ) ) {
centerCount ++;
}
// Update fraction.
frac = (double) centerCount / (double) 1000;
}
// 1.3 Compute the fraction for this run.
totalFrac = totalFrac + frac;
}
// 2. Compute the average.
double fracEstimate = totalFrac / numRuns;
// 3. Print results
System.out.println ("Estimate: " + fracEstimate);
}
}
What is the bug?
Next version:
public class KnightSolution {
static boolean debug = true;
// Representation of board with Knight:
// board[i][j] == 1 if the Knight is at (i,j);
// board[i][j] == 0 otherwise.
static int[][] board;
// Possible locations are stored here.
// The i-th possible location has coordinates
// (possibleX[i], possibleY[j])
static int[] possibleX = new int[8];
static int[] possibleY = new int[8];
// Create the space for the board.
static void createBoard ()
{
board = new int[8][];
for (int i=0; i < 8; i++) {
board[i] = new int[8];
}
}
// Set all board entries to 0.
static void cleanBoard ()
{
for (int i=0; i < 8; i++) {
for (int j=0; j < 8; j++) {
board[i][j] = 0;
}
}
}
static boolean validLocation (int x, int y)
{
// Check if x value is out of range.
if ( (x < 0) || (x > 7) )
return false;
// Check if y value is out of range.
if ( (y < 0) || (y > 7) )
return false;
// Otherwise, it's OK.
return true;
}
// Create possible locations and return number of such locations.
// The input location is x,y
static int identifyPossibleLocations (int x, int y)
{
// Check the different possibilities (x+2, y+1) etc.
int numLocations = 0;
// Check first one.
if (validLocation (x+2, y+1)) {
// Put this in the array.
possibleX[numLocations] = x+2;
possibleY[numLocations] = y+1;
numLocations ++;
}
// Next:
if (validLocation (x+2, y-1)) {
// Put this in the array.
possibleX[numLocations] = x+2;
possibleY[numLocations] = y-1;
numLocations ++;
}
// Others: 3
if (validLocation (x-2, y+1)) {
// Put this in the array.
possibleX[numLocations] = x-2;
possibleY[numLocations] = y+1;
numLocations ++;
}
if (validLocation (x-2, y-1)) { // 4
possibleX[numLocations] = x-2;
possibleY[numLocations] = y-1;
numLocations ++;
}
if (validLocation (x+1, y+2)) { // 5
possibleX[numLocations] = x+1;
possibleY[numLocations] = y+2;
numLocations ++;
}
if (validLocation (x+1, y-2)) { // 6
possibleX[numLocations] = x+1;
possibleY[numLocations] = y-2;
numLocations ++;
}
if (validLocation (x-1, y+2)) { // 7
possibleX[numLocations] = x-1;
possibleY[numLocations] = y+2;
numLocations ++;
}
if (validLocation (x-1, y-2)) { // 8
possibleX[numLocations] = x-1;
possibleY[numLocations] = y-2;
numLocations ++;
}
return numLocations;
}
static void printPossibleLocations (int numLocations)
{
System.out.print ("Possible Locations: ");
for (int i=0; i < numLocations; i++)
System.out.print (" (" + possibleX[i] + "," + possibleY[i] + ")");
System.out.println ();
}
static void printBoard ()
{
System.out.println ("Board status: ");
for (int i=0; i < 8; i++) {
for (int j=0; j < 8; j++) {
System.out.print (" " + board[i][j]);
}
System.out.println ();
}
}
public static void main (String[] argv)
{
int numRuns = 1;
int numMoves = 10;
// Create chessboard.
createBoard ();
// 1. Repeat this 10,000 times
double totalFrac = 0;
for (int run=1; run<=numRuns; run++) {
if (debug)
System.out.println ("Run# " + run);
double frac = 0;
// 1.1 Start with Knight at (0,0).
cleanBoard ();
// Put the knight in location (0,0).
board[0][0] = 1;
// Current location of knight.
int x=0, y=0;
// 1.2 Move it 1000 moves, and record how many moves
// landed in the center.
int centerCount = 0;
for (int move=1; move<=numMoves; move++) {
// Identify possible next locations.
int numLocations = identifyPossibleLocations (x, y);
// Pick one of them randomly.
int nextLocation = (int) UniformRandom.uniform ((long) 0, (long) numLocations);
// Debug.
if (debug) {
System.out.println (">> Move# " + move + " cur_x=" + x + " cur_y=" + y +
" numLoc=" + numLocations + " nextLoc=" + nextLocation);
printPossibleLocations (numLocations);
printBoard ();
}
// Clear current position
board[x][y] = 0;
// At this time, possibleX[] and possibleY[] contain the possible locations.
// Set x,y to new locations.
x = possibleX[nextLocation];
y = possibleY[nextLocation];
// Move the Knight
board[x][y] = 1;
// If new location is a center location, update count.
if ( ( (x==3) && (y==3) )
|| ( (x==3) && (y==4) )
|| ( (x==4) && (y==3) )
|| ( (x==4) && (y==4) ) ) {
centerCount ++;
}
} // End-inner-for
// Update fraction.
frac = (double) centerCount / (double) 1000;
// 1.3 Compute the fraction for this run.
totalFrac = totalFrac + frac;
} // End-outer-for
// 2. Compute the average.
double fracEstimate = totalFrac / numRuns;
// 3. Print results
System.out.println ("Estimate: " + fracEstimate);
}
}