Exercises


  1. In the exercises for Lesson 5, you created a method to calculate the strength of a piece based on its type and board position. Modify this method to use a switch statement instead of an if statement.

  2. Modify the strength calculation method to use a Map that associates piece types with their base strength value. In order to place double values in Map, you will need to declare the map as Map<Piece.Type,Double>.[6]

    [6] Lesson 7 includes a section on wrapper types that explains why this is so.

  3. Use lazy initialization to preload the Map of piece type to base-strength value. Note the effect on readability this change has on the code. What factors would drive you to either leave this change in the code or to remove it?

  4. Move the point values for the pieces into the piece type enumeration and use a method on the enumeration to get the point value.

  5. Move the character representation for a piece onto the Piece.Type enum. Code in Board will still need to manage uppercasing this character for a black piece.

  6. You must implement the various moves that a king can make. The basic rule is that a king can move one square in any direction. (For now, we will ignore the fact that neighboring pieces can either restrict such a move or can turn it into a capture.)

  7. The code in Board is getting complex. It now manages the mathematics of a grid, it stores pieces, it determines valid moves for pieces (the queen and king, so far), it gathers pieces and determines their strength. By the time you add move logic for the remaining pieces (queen, pawn, rook, bishop, and knight), the class will be very cluttered with conditional logic.

    There are a few ways to break things up. From my viewpoint, there are two main functions of code in Board class. One goal is to implement the 8x8 board using a data structurea list of lists of pieces. A lot of the code in Board is geared toward navigating this data structure, without respect to the rules of chess. The rest of the code in Board defines the rules of the chess game.

    Break the Board class into two classes: Game, which represents the logic of a chess game, and Board, a simple data structure that stores pieces and understands the grid layout of the board.

    This will be a significant refactoring. Move methods as incrementally as possible, making sure tests remain green with each move. If necessary, create parallel code as you refactor, then eliminate the unnecessary code once everything is working. Make sure you add tests as needed.

    Take this opportunity to begin to encapsulate the implementation details of the data structure of Board. Instead of asking for ranks and adding pieces, have the Game code use the Board method put.

  8. A queen can move any number of squares as long as it forms a straight line. Implement this capability on Piece. Note that your initial implementation will require an if statement to determine whether the piece is a queen or a king.

    The solution may involve recursionthe ability of a method to call itself. A recursive call is no big deal; it is a method call like any other. But you must be careful to provide a way for the recursion to stop, otherwise you might get stuck in an infinite loop of the method calling itself.

  9. Your code to manage moves for kings and queens includes an if statement. You can imagine that supporting further moves for pieces will involve a bunch of conditional statements. One way of cleaning things up is to create a Piece hierarchy, with separate subtypes for King, Queen, Bishop, and so on.

    In preparation for creating Piece subclasses, move the method getPossibleMoves to the Piece class.

  10. Now you are ready to create Piece subclasses. You will note that as you create subclasses for Queen and King, the Piece.Type enum seems redundant. In the next exercise, you'll eliminate this enum. Create Queen and King classes to extend Piece. Move the relevant tests from PieceTest into QueenTest and KingTest. This will force you to move code as well into the new subclasses. Also, create subclasses for the remaining pieces and alter the factory methods accordingly on Piece. Don't worry about coding up the move rules for the other pieces yet.

    Refactor at will. Eliminate duplication. Add tests where tests were missing due to moving methods onto a new class.

  11. The final step is to eliminate the need for the Type enum. Since you now have a subclass for each piece, you can move code depending on the type into that sublcass.

    You may need to test the type of the subclass created. Instead of asking each piece for its Piece.Type value, you can simply ask for its class:

     piece.getClass() 

    You can then compare this to a Class literal:

     Class expectedClass = Queen.class; assertEquals(expectedClass, piece.getClass(); 

    You also want to eliminate as much code as possible that asks for the type of an objectthat's one of the main reasons for creating the subclasses in the first place. See if you can move any code that looks like if (piece.getClass().equals(Pawn.class) into the appropriate class.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net