CS111 Lab 6 Answers- Recursion II

ScaryWorld

barelyScary

public Picture barelyScary(int levels, Picture p1) {
  if (levels<1) {
    return empty();
  } else {
    Picture p2 = barelyScary(levels-1,p1);
    return fourPics(p1,p2,p2,clockwise90(p1));
  }
}

scary

public Picture scary(int levels, Picture p1, Picture p2) {
  if (levels<=1) {
    return empty();
  } else {
    Picture p3 = scary(levels-1,p1,p2);
    return fourPics(p1,p3,clockwise180(p1),clockwise90(p2));
  }
}

veryScary

public Picture veryScary(int levels, Picture p1, Picture p2) {
  if (levels<=1) {
    return empty();
  } else {
  Picture p3 = veryScary(levels-1,p2,p1);
  Picture p4= veryScary(levels-1,p1,p2);
    return fourPics(p1,p3,clockwise270(p4),clockwise90(p2));
  }
}

frightful

public Picture frightful(int levels, Picture p1, Picture p2) {
  if (levels<=1) {
    return empty();
  } else {
  Picture p3 = frightful(levels-1,p2,p1);
  Picture p4= frightful(levels-1,p1,p2);
    return fourPics(clockwise90(p3),clockwise180(p4),clockwise270(p4),clockwise90(p2));
  }
}


HungryWorld

Solving eatRows

public void eatRows() {
  // For each row in the grid, eats the bagels on the side of the buggle 
  // that has more bagels.
  // Does nothing if the number of bagels is the same on both sides. 
  // Does not change the state of the buggle.  
    if (isFacingWall()) { // base case
      eatRow();
    } else {    // general case
      eatRow();  // eat this row
      forward(); // go to next row
      eatRows(); // eat rest of the rows
    }
  }

Solving eatRow

public void eatRow() {
  // Eats the bagels on the side of the buggle that has more bagels.
  // Does nothing if the number of bagels is the same on both sides. 
  // Does not change the state of the buggle.  
    int bagelsToLeft = countBagelsToLeft();
    int bagelsToRight = countBagelsToRight();
    // Compare the numbers, and behave appropriately
    if (bagelsToLeft > bagelsToRight) {
      eatBagelsToLeft();
    } else if (bagelsToRight > bagelsToLeft) {
      eatBagelsToRight();
    } else { // bagelsToRight == bagelsToLeft
      // Do nothing
    }
  }

The above version of eatRow() is defined in terms of the following auxiliary methods. These are not entirely necessary; their bodies could have been "inlined" into eatRow() instead. But they encapsulate solutions to subproblems of eatRow(), and are consistent with the goal of decomposing a solution to a big problem in terms of the solutions to subproblems. They also make it easier to read the code for eatRow(). Because of these sorts of advantages, we recommend solutions that consist of "lots of little methods".

  public int countBagelsToLeft() {
  // returns the number of bagels to the left of (but not under) the buggle.
  // Does not change the state of the buggle.  
    left();
    int result = countBagels();
    right();
    return result;
  }
  
  public int countBagelsToRight() {
  // returns the number of bagels to the right of (but not under) the buggle.
  // Does not change the state of the buggle.  
    right();
    int result = countBagels();
    left();
    return result;
  }
 
  public void eatBagelsToLeft() {
  // Eats the bagels to the left of the buggle. 
  // Assumes brush is up. Does not change the state of the buggle.  
    left();
    eatBagels();
    right();
  }
  
  public void eatBagelsToRight() {
  // Eats the bagels to the right of the buggle. 
  // Assumes brush is up. Does not change the state of the buggle.  
    right();
    eatBagels();
    left();
  }

Solving countBagels


  public int countBagels() {
  // returns the number of bagels IN FRONT OF (but not under) the buggle.
  // Does not change the state of the buggle.  
    if (isFacingWall()) {
      return 0;
    } else {
      forward();
      int subCount = countBagels(); // Count bagels from next cell to wall.
      int bagelInFront = bagelsUnder(); // Remember if there's a bagel in front.
      backward();
      return subCount + bagelInFront;
    }
  }



The above version of countBagels() uses the
following bagelsUnder() auxiliary method:



  public int bagelsUnder() {
  // returns the number of bagels under this buggle (0 or 1). 
  // Does not change the state of the buggle.  
    if (isOverBagel()) {
      return 1; 
    } else {
      return 0;
    }
  }



The bagelsUnder() method simplifies the
handling of adding 0 or 1 within countBagels(). Without it, we would
need to write something like one of the following two solutions:
 



  // Alternative solution #1 to countBagels() that does not use bagelsUnder()
  public int countBagels() {
  // returns the number of bagels IN FRONT OF (but not under) the buggle.
  // Does not change the state of the buggle.  
    if (isFacingWall()) {
      return 0;
    } else {
      forward();
      int subCount = countBagels(); // Count bagels from next cell to wall.
      if (isOverBagel()) {
        backward();
        return 1 + subCount;
      } else {
        backward();
        return subCount;
      }
    }
  }
 
  // Alternative solution #2 to countBagels() that does not use bagelsUnder()
  public int countBagels() {
  // returns the number of bagels IN FRONT OF (but not under) the buggle.
  // Does not change the state of the buggle.
    int bagelsUnder = 0; 
    if (isFacingWall()) {
      return 0;
    } else {
      forward();
      int subCount = countBagels(); // Count bagels from next cell to wall.
      if (isOverBagel()) {
        bagelsUnder = 1;
      }
      backward();
      return subCount + bagelsUnder;
    }
  }
 



Alternative solution #1 involves a conditional
that performs a test on the way out of the recursion. There is
nothing wrong with this, but the two branches of the conditional are
almost exactly the same, and it is nicer to capture the fact that
they do the same thing except for the issue of adding 0 or 1.
Alternative solution #2 requires initializing a local bagelsUnder
variable to 0 and then changing it to 1 in
certain circumstances. This requires an assignment statement (in this
case, bagelsUnder = 1).


Solving eatBagels



The following solution eats the bagels and leaves a mark on the
way back out of the recursion rather than on the way into the
recursion. It also focuses on eating the bagel in front of the buggle
rather than on the one underneath the buggle. These two decisions
simplify the method, especially the case where the buggle is facing a
wall.




// Solution #1 to eatBagels() using paintCell()
public void eatBagels() {
// Eats the bagels in front of (but not under) the buggle. 
// Assumes brush is up. Does not change the state of the buggle.

  if (isFacingWall()) {
    // do nothing;
  } else {
    forward();              // Step forward to make problem smaller.
    eatBagels();            // Solve the subproblem.
    if (isOverBagel()) {    // Test for bagel on way back out.
      pickUpBagel();        // if one is there, eat it
      paintCell(Color.red); // and mark the cell 
    }
    backward();             // Step back to meet the invariant.
  }
}





// Solution #2 to eatBagels() not using paintCell()
public void eatBagels() {
// Eats the bagels in front of (but not under) the buggle. 
// Assumes brush is up. Does not change the state of the buggle.

  if (isFacingWall()) {
    // do nothing;
  } else {
    forward();           // Step forward to make problem smaller.
    eatBagels();         // Solve the subproblem.
    if (isOverBagel()) { // Test for bagel on way back out.
      pickUpBagel();     // if one is there, eat it
      brushDown();       // and mark the cell 
      backward();        // when stepping back, 
      brushUp();         // being sure to leave pen in up state.
    } else {
      backward();        // if no bagels, just step back.
    }
  }
}