Title: Polymorphic Examples
Course: CPS 261: Advanced Java Concepts ~ DL & MM MASTER

Polymorphic Examples

Polymorphism and Abstract classes

First a dumb example (you have seen something like this if you took cps161 from me). Create a class called animal with a few properties like name and weight and a method called makeNoise(). Create classes Cow and Snake derived from animal. Create a main which has an array of Animal, but fills it with instances of Snake, Cow, and Animal.

Change the example so that makeNoise is abstract and see how it changes. Note that Animal can be abstract without having any abstract methods. Also note that an abstract class cannot be constructed.

I would like to now create a minimal chess game to demonstrate these concepts. We will start out not using Polymorphism or abstract class. We will create 2 classes.

1. The first class with be the Piece class. Each chess piece will be represents by a unique Piece object. Our ChessGame class will contain an array of Piece objects for each chess piece on our chess board.
2. In our Piece class we will contain the data:


    private int xSquare, ySquare;
    private String pieceType;
    private String color;


3. We will also contain the following methods:


  public Piece (String p, String c, int xSquare, int ySquare) // actually a constructor
  public boolean isLegalMove(int x, int y)
  boolean isCaptured()
  public void capturePiece()
  public void moveLoc(int x, int y)
  public boolean areYouHere(int xSelectLoc, int ySelectLoc)
  public String myType()
  public String toString()


4. In our first version of the Piece class, we have a class that has common information about chess pieces as well as specific information such as the movement allowed for each specific chess piece type.
5. In our second version, we want to have the 2 methods isLegalMove(int, int) and String typeName() being overridden by more specific classes named Pawn, Rook, Bishop, Knight, Queen and King. In this version we have general characteristics in the Piece class and more specific information for each chess piece type buried in a dedicated class for the details of a specific class such as the Bishop class.
6. In our third version, we would like to make the typeName() class abstract, and we would like to make the overall Piece class abstract. This will mean that we can't directly construct the Piece class. The Piece class will now get constructed as part of a more general class construction such as the Bishop class.
7. Note that the isLegalMove method in the specific class (i.e. Bishop) gets called first, but this method can then call the more generic Piece isLegalMove method using the super. notation.

Sample Programs from Video

Polymorphism_interface_zip - Sample code that we will attempt to recreate in class

Traditional Programming approach to Chess


// Each of the following classes needs to be in a separate file

package chessTraditional;

public class Piece
{
    private int xSquare, ySquare;
    private String pieceType;
    private String color;


    public Piece (String p, String c, int xSquare, int ySquare)
    {
        //I don't like negative logic like this, but this will get better with later versions.
        if (!c.equals("Black") && !c.equals("White"))
                throw new RuntimeException("Illegal Color");
        if (!p.equals("Rook") && !p.equals("Bishop") && !p.equals("Knight") &&
                !p.equals("Queen") && !p.equals("King") && !p.equals("Pawn"))
            throw new RuntimeException("Illegal Piece Type");


        this.pieceType=p;
        this.color =c;
        this.xSquare = xSquare;
        this.ySquare = ySquare;
    }

    public boolean isLegalMove(int x, int y)
    {
        if (x < 0 || y < 0 || x >= 8 || y >= 8)
            return false;

        if (pieceType.equals("Rook"))
        {
            if (xSquare == x || ySquare ==y)
                return true;
        }
        else if (pieceType.equals("Bishop"))
        {
            // .....
        }
        else if (pieceType.equals("Knight"))
        {
            // .....
        }
        else if (pieceType.equals("Queen"))
        {
            // .....
        }
        else if (pieceType.equals("King"))
        {
            // .....
        }
        else if (pieceType.equals("Pawn"))
        {
            // .....
        }
        return false;
    }

    boolean isCaptured()
    {
        if (xSquare < 0 || ySquare < 0)
            return true;
        else
            return false;
    }

    public void capturePiece()
    {
        xSquare = ySquare = -1;
    }

    public void moveLoc(int x, int y)
    {
        if (isLegalMove(x,y))
        {
            xSquare = x;
            ySquare = y;
        }
        else
            System.out.println("Can't move to x="+x + " y=" + y + " for " +toString());
    }
    public boolean areYouHere(int xSelectLoc, int ySelectLoc)
    {
        if (xSelectLoc == xSquare && ySelectLoc == ySquare)
            return true;
        else
            return false;
    }

    public String myType()
    {
        return color +":" + pieceType;
    }

    public String toString()
    {
        if (isCaptured())
            return myType() + " Captured ";
        else
            return myType() +" at x="+xSquare + " y="+ySquare;
    }


}


// ********************************************************************
package chessTraditional;

import java.util.Scanner;

public class ChessGame {

    Piece[] pieces = new Piece[32];

    public ChessGame()
    {
        String[] types = {"Rook", "Knight", "Bishop", "Queen", "King", "Bishop", "Knight", "Rook"};

        for (int i=0; i < 8; i++)
        {
            // White Major pieces in row 0
            pieces[i] = new Piece( types[i], "White", i, 0);
            // White Pawns in row 1
            pieces[i+8] = new Piece("Pawn", "White", i, 1);

            // Black Major pieces in row 7
            pieces[i+16] = new Piece (types[i],"Black",  i, 7);
            // Black Pawns in row 6
            pieces[i+24] = new Piece("Pawn", "Black", i, 6);
        }
    }

    public void printBoard()
    {
        System.out.println();
        for (int i=0; i < pieces.length; i++)
        {
            System.out.print(i + "  ");
            System.out.println(pieces[i]);
        }
        System.out.println("*****************");
    }

    public static void main(String[] args) {
        ChessGame cg = new ChessGame();
        Scanner keyboard = new Scanner(System.in);

        while (true)
        {
            cg.printBoard();
            System.out.println("Enter pieceIndex x y");
            int index = keyboard.nextInt();
            int x = keyboard.nextInt();
            int y = keyboard.nextInt();

            // Note that there are a lot of things we could do here.
            // Check for valid inputs, check to see if a piece is already on
            //    this location.  If so what color is it, and can we do a capture, etc.

            cg.pieces[index].moveLoc(x, y);
        }
    }

}



Polymorphic Programming Approach to Chess


// Each of the following classes needs to be in a separate file

package chessPolymorph;


public abstract class Piece
{
    protected int xSquare, ySquare;
    protected String color;


    public Piece ( String c, int xSquare, int ySquare)
    {
        //I don't like negative logic like this, but this will get better with later versions.
        if (!c.equals("Black") && !c.equals("White"))
                throw new RuntimeException("Illegal Color");
        this.color =c;
        this.xSquare = xSquare;
        this.ySquare = ySquare;
    }

    public abstract String typeName();

    public boolean isLegalMove(int x, int y)
    {
        if (x < 0 || y < 0 || x >= 8 || y >= 8)
            return false;


        return true;
    }

    boolean isCaptured()
    {
        if (xSquare < 0 || ySquare < 0)
            return true;
        else
            return false;
    }

    public void capturePiece()
    {
        xSquare = ySquare = -1;
    }

    public void moveLoc(int x, int y)
    {
        if (isLegalMove(x,y))
        {
            xSquare = x;
            ySquare = y;
        }
        else
            System.out.println("Can't move to x="+x + " y=" + y + " for " +toString());
    }
    public boolean areYouHere(int xSelectLoc, int ySelectLoc)
    {
        if (xSelectLoc == xSquare && ySelectLoc == ySquare)
            return true;
        else
            return false;
    }

    public String myType()
    {
        return color.toString() +":" + typeName();
    }

    public String toString()
    {
        if (isCaptured())
            return myType() + " Captured ";
        else
            return myType() +" at x="+xSquare + " y="+ySquare;
    }


}

// ***********************************************************

package chessPolymorph;

public class Rook extends Piece {

    public Rook(String c, int xSquare, int ySquare) {
        super(c, xSquare, ySquare);
    }

    public boolean isLegalMove(int x, int y)
    {
        if (super.isLegalMove(x, y))
        {
            if (x==xSquare || y== ySquare)
                return true;
        }
        return false;
    }


    public String typeName() {
        // TODO Auto-generated method stub
        return "Rook";
    }

}

// ***********************************************************

// Pawn, Knight, Bishop, Queen, and King are similar to Rook, but needs piece specific code

// ***********************************************************

package chessPolymorph;

import java.util.Scanner;

public class ChessGame {

    Piece[] pieces = new Piece[32];

    public ChessGame()
    {
        for (int i=0; i < 8; i++)
        {

            // White Pawns in row 1
            pieces[i+8] = new Pawn( "White", i, 1);


            // Black Pawns in row 6
            pieces[i+24] = new Pawn( "Black", i, 6);
            switch(i)
            {
            case 0: case 7:
                pieces[i] = new Rook(  "White", i, 0);
                pieces[i+16] = new Rook ("Black",  i, 7);
                break;
            case 1: case 6:
                pieces[i] = new Knight(  "White", i, 0);
                pieces[i+16] = new Knight ("Black",  i, 7);
                break;
            case 2: case 5:
                pieces[i] = new Bishop(  "White", i, 0);
                pieces[i+16] = new Bishop ("Black",  i, 7);
                break;
            case 3:
                pieces[i] = new Queen(  "White", i, 0);
                pieces[i+16] = new Queen ("Black",  i, 7);
                break;
            case 4:
                pieces[i] = new King(  "White", i, 0);
                pieces[i+16] = new King ("Black",  i, 7);
                break;
            }
        }
    }

    public void printBoard()
    {
        System.out.println();
        for (int i=0; i < pieces.length; i++)
        {
            System.out.print(i + "  ");
            System.out.println(pieces[i]);
        }
        System.out.println("*****************");
    }

    public static void main(String[] args) {
        ChessGame cg = new ChessGame();
        Scanner keyboard = new Scanner(System.in);

        while (true)
        {
            cg.printBoard();
            System.out.println("Enter pieceIndex x y");
            int index = keyboard.nextInt();
            int x = keyboard.nextInt();
            int y = keyboard.nextInt();

            // Note that there are a lot of things we could do here.
            // Check for valid inputs, check to see if a piece is already on
            //    this location.  If so what color is it, and can we do a capture, etc.

            cg.pieces[index].moveLoc(x, y);
        }
    }

}




Last Updated: July 22, 2013 3:03 PM