The Practice and Philosophy of Object-Oriented Programming in Java

New Practice Problems for Chapter 8


Clock.  Implement a class that models a clock with hours, minutes, and seconds. You will need int fields for the current time and a boolean field to indicate 12-hour or 24-hour format. The following test program creates three clocks and repeatedly advances them by a fixed number of seconds.

public static void main(String[] args) {
   Clock c1 = new Clock(); 
   Clock c2 = new Clock(8, 20, 43); 
   Clock c3 = new Clock(8, 20, 43, true); // 12-hour format
        
   // starting times
   System.out.printf("%s \t %s \t %s  %n", c1, c2, c3); 

   // Advance each clock by 10,000 seconds, display, and repeat.
   final int secondsForward = 10_000;
   for (int i = 0; i < 10; i++) {
      c1.tick(secondsForward);
      c2.tick(secondsForward);
      c3.tick(secondsForward);
      System.out.printf("%s \t %s \t %s  %n", c1, c2, c3);
   }
}

You can interpret the program as specifying the public interface for the Clock class. In other words, you need to provide the necessary constructors and methods so that the program compiles, runs, and produces the results shown below.

00:00:00 	 08:20:43 	 08:20:43 AM  
02:46:40 	 11:07:23 	 11:07:23 AM  
05:33:20 	 13:54:03 	 01:54:03 PM  
08:20:00 	 16:40:43 	 04:40:43 PM  
11:06:40 	 19:27:23 	 07:27:23 PM  
13:53:20 	 22:14:03 	 10:14:03 PM  
16:40:00 	 01:00:43 	 01:00:43 AM  
19:26:40 	 03:47:23 	 03:47:23 AM  
22:13:20 	 06:34:03 	 06:34:03 AM  
01:00:00 	 09:20:43 	 09:20:43 AM  
03:46:40 	 12:07:23 	 00:07:23 PM


Towers of Hanoi.  Create a back end for the Towers of Hanoi game. In this game, there are three towers and a fixed number of disks of size 1, 2, 3, ..., n. When the game begins, all disks are stacked on the first tower in order from largest to smallest. For example, if there are 3 disks then the starting state is as follows.

Tower 1: 3 2 1 
Tower 2: 
Tower 3:

The goal is to move the entire stack from Tower 1 to one of the other towers, using the extra tower as a temporary holder for some of the disks. Only one disk can be moved at a time, and it is not permitted to put a larger disk on top of a smaller one, which means that the disks on each tower at any time must be stacked from largest to smallest. Continuing the example, the player could move a disk from Tower 1 to Tower 2, in which case the game would be in the following state:

Tower 1: 3 2  
Tower 2: 1
Tower 3:

At this point, it would not be legal to move a disk from Tower 1 to Tower 2 since that would violate the order requirement. However, the player could move a disk from Tower 1 to Tower 3, and then from Tower 2 to Tower 3, leading to the following configuration.

Tower 1: 3  
Tower 2: 
Tower 3: 2 1

By the way, it can be shown that 2n - 1 moves are needed to transfer a stack of n disks from one tower to another.

The public interface will consist of the following members.

You will find a test program (front end) and sample output in the Chapter 8 resources. The test program essentially determines the required public interface for your custom class. In other words, you should provide public constructors and methods so that the program compiles with your back end and produces correct output.

Implementation note: You could use ArrayList<Integer> for each of the three towers, but it would be even easier to use Stack<Integer>. A stack is special kind of list: items can only be added to (or removed from) the end of the list. The ArrayList method remove requires an argument specifying the index of the item to be removed, whereas the Stack method pop automatically removes the last item.


Cross Flips. 

The game of Cross Flips is similar to Lights Out (see the previous problem). The only difference is the toggle operation. When the player makes a move in Cross Flips, every light in the same row and column of the selected light is toggled. This operation is illustrated in Output 8.8.3c with the toggled cells before and after the move shown here in red for clarity.


  0 1 2 3 4 5 6 7 
  0 - # - # # # # - 
  1 # # - - # - # - 
  2 - - # - # - - - 
  3 - # # - # # # - 
  4 # # # # - # - # 

Enter your move:   2 3

  0 1 2 3 4 5 6 7  
  0 - # - - # # # - 
  1 # # - # # - # - 
  2 # # - # - # # # 
  3 - # # # # # # - 
  4 # # # - - # - #

The goal is to turn all of the lights out. Implement a class CrossFlips to serve as the back end for this game. Provide a constructor with arguments specifying the number of rows, number of columns, and level of difficulty for the game. The level of difficulty can be identified with the number of moves needed to reach the winning configuration. To initialize the game, the constructor starts from the winning configuration (all lights out) and works backwards by making a series of legal moves at randomly selected positions. Provide another constructor that takes two arguments for grid dimensions and initializes the game with a default (high) level of difficulty.

You will find a test program (front end) and sample output in the Chapter 8 resources. The test program essentially determines the required public interface for your custom class. In other words, you should provide public constructors and methods so that the program compiles with your back end and produces correct output.


Cross Flips with Hints.   Enhance your solution to the previous problem with a hint feature to suggest a good move. You can implement this feature using an array list to store the moves that have been made so far (those of the constructor as well as those made by the player during the course of the game). All of the lights can be turned off by repeating these moves in some order. When the player makes a move that is already in the list, that move must be removed from the list.

You will find a test program (front end) and sample output in the Chapter 8 resources. The test program essentially determines the required public interface for your custom class. In other words, you should provide public constructors and methods so that the program compiles with your back end and produces correct output.


Harakka.  The game of Harakka is played on a rectangular grid of numbered tiles. To make a move in the game, the player chooses a 2x2 sub-grid and rotates it clockwise. We will identify a sub-grid by its top-left tlle, and we will say that the tile in that position anchors the sub-grid. For example, if the game is currently in the state shown below on the left and the player wants to rotate the sub-grid anchored at 16, then the resulting game state will be as shown on the right.

The goal is to arrange the tiles into numerical order. For a 5x5 grid, the winning configuration is shown below.

Implement a class Harakka to serve as the back end for the game. The public interface will consist of the following members.

The level of difficulty for a game depends on the number of moves needed to reach the winning configuration. Suppose the game is to be initialized at difficulty level n (a positive integer). This means that with optimal play the winning configuration can be reached with n rotations. To ensure this, the constructor will initialize the grid to the winning configuration and then make n counter-clockwise rotations at randomly selected positions in the grid, which ensures that the game can be won by performing clockwise rotations at the same locations in reverse order. For the default (high) level of difficulty, use the total number of cells in the grid. Note that you do not need separate blocks of code for clockwise and counter-clockwise rotations: your constructor can rotate a sub-grid counter-clockwise simply by performing 3 clockwise rotations with the rotate method.

You will find a test program (front end) and sample output in the Chapter 8 resources. The test program must compile with your back end.


Return to Companion Site home page