TableModel for GridWorld APCS

54 Views Asked by At

I'm trying to implement the GUI for the gridworld case study and get stuck. I am trying to implement the grid using a customized JTable. I implemented my BoundedGrid and UnboundedGrid class using a TreeMap. However, the UnboundedGrid class requires the GUI to change the numbers of rows and columns dynamically, that is, based on locations of elements populating the Grid. The number of rows and columns of the JTable should be determined by the elements with greatest and least x/y coordinates. I don't know how to correctly extend the AbstractTableModel class.

Moreover, the objects stored in the Grid, Actors, store their container Grid and their respective locations, and the put and remove methods in Grid interface are used in the Actor class so that any change on Actors must invoke the corresponding methods in Actor class, rather than those in Grid interface: For example, one method in Actor is:

public void putSelfInGrid(Grid<Actor> grid, Location loc){
    if (this.grid != null){
        throw new IllegalStateException("This actor: " + this + " is already contained in another grid.");
    }
    Actor actor = grid.get(loc);
    if (actor != null) {
        actor.removeSelfFromGrid();
    }
    grid.put(loc, this);
    this.grid = grid;
    this.location = loc;
}

This method invokes the put() method in the Grid interface AND updates the location of the Actor object. This should be taken into consideration, since I need a class like GridManager that store both the Grid and actors to update changes on the Grid. Another question: should that GridManager directly extend JTable, or should I create another class such as GridTable that extends JTable and use a GridManager to automatically update the table.

Here is my code:

https://www.dropbox.com/sh/a6qku7pphrihtf5/AABxOypOCxKlS05i-AeMpBOZa?dl=0

public interface Grid<E> {

E put(Location loc, E obj);

E remove(Location loc);

E get(Location loc);

int getNumRows();

int getNumCols();

boolean isValid(Location loc);

default boolean isEmpty(Location loc){...}

default Set<Location> getValidAdjacentLocations(Location loc){...}

default Optional<Location> getValidAdjacentLocationToward(Location loc, Location.Direction direction){...}

default Set<Location> getEmptyAdjacentLocations(Location loc){...}

default Optional<Location> getEmptyAdjacentLocationToward(Location loc, Location.Direction direction){...}

default Set<Location> getOccupiedAdjacentLocations(Location loc){...}

default Optional<Location> getOccupiedAdjacentLocationToward(Location loc, Location.Direction direction){...}

default Set<E> getNeighbors(Location loc){...}

Set<Location> getOccupiedLocations();

default Set<E> getAllElements(){...}
}

public abstract class AbstractGrid<E> implements Grid<E>{

private final int rowNum;
private final int colNum;

protected AbstractGrid(){
    this(-1, -1);
};

protected AbstractGrid(int rowNum, int colNum){
    if (rowNum < -1 || colNum < -1){
        throw new IllegalArgumentException("Invalid Dimension");
    }
    this.rowNum = rowNum;
    this.colNum = colNum;
}

protected AbstractGrid(Dimension dimension){
    this(dimension.height, dimension.width);
}

@Override
public int getNumRows() {
    return rowNum;
}

@Override
public int getNumCols() {
    return colNum;
}

//toString, equals and hashCode ...
}

public class Location implements Comparable<Location>{

public static enum Direction{

    NORTH(0),
    NORTHEAST(45),
    EAST(90),
    SOUTHEAST(135),
    SOUTH(180),
    SOUTHWEST(225),
    WEST(270),
    NORTHWEST(315),
    ;

    private final int value;

    private Direction(int value){
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public Direction turn(Turning turning){
        int newDegree = Math.floorMod(getValue() + turning.getValue(), 360);
        for (Direction direction : Direction.values()) {
            if (direction.getValue() == newDegree) {
                return direction;
            }
        }
        throw new UnknownError("missing direction values");
    }

    public int getColOffset(){
        if ((getValue() == 0 || getValue() == 180)) {
            return 0;
        } else if (0 < getValue() && getValue() < 180){
            return 1;
        } else if (180 < getValue() && getValue() < 360){
            return -1;
        } else{
            throw new UnknownError("unexpected value");
        }
    }

    public int getRowOffset(){
        if (getValue() == 90 || getValue() == 270){
            return 0;
        } else if (90 < getValue() && getValue() < 270){
            return 1;
        } else if ((0 <= getValue() && getValue() < 90) || (270 < getValue() && getValue() < 360)){
            return -1;
        } else {
            throw new UnknownError("unexpected value");
        }
    }
}

public static enum Turning{

    AHEAD(0),
    HALF_RIGHT(45),
    HALF_LEFT(-45),
    RIGHT(90),
    LEFT(-90),
    HALF_CIRCLE(180),
    CIRCLE(360),
    ;

    private final int value;

    private Turning(int value){
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

private final int row;
private final int col;

public Location(int row, int col){
    this.row = row;
    this.col = col;
}

public int getCol() {
    return col;
}

public int getRow() {
    return row;
}

public Location getAdjacentLocation(Direction direction){...}

public Set<Location> getAdjacentLocations(){...}

public Direction getDirectionToward(Location target){...}

@Override
public int compareTo(Location o) {
    if (this.row != o.row){
        return (int)Math.signum(Integer.compare(this.row, o.row));
    } else {
        return (int)Math.signum(Integer.compare(this.col, o.col));
    }
}

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Location)) return false;

    Location location = (Location) o;

    if (col != location.col) return false;
    if (row != location.row) return false;

    return true;
}

//hashCode and toString
}

public class BoundedGrid<E> extends AbstractGrid<E>{

private Map<Location, E> occupants;

public BoundedGrid(int rowNum, int colNum) {
    super(rowNum, colNum);
    occupants = new TreeMap<>();
}

@Override
public E put(Location loc, E obj) {
    if (!isValid(loc)){
        throw new IllegalArgumentException("Location " + loc + "is invalid");
    }
    return occupants.put(loc, obj);
}

@Override
public E remove(Location loc) {
    if (!isValid(loc)){
        throw new IllegalArgumentException("Location " + loc + "is invalid");
    }
    return occupants.remove(loc);
}

@Override
public E get(Location loc) {
    if (!isValid(loc)){
        throw new IllegalArgumentException("Location " + loc + "is invalid");
    }
    return occupants.get(loc);
}

@Override
public boolean isValid(Location loc) {
    return 0 <= loc.getRow() && loc.getRow() < getNumRows() && 0 <= loc.getCol() && loc.getCol() < getNumCols();
}

@Override
public Set<Location> getOccupiedLocations() {
    return occupants.keySet();
}
}

public class UnboundedGrid<E> extends AbstractGrid<E>{

public static enum Characteristics{
    HORIZONTALLY_BOUNDED, VERTICALLY_BOUNDED, UNBOUNDED;
}

private Characteristics characteristics;
private Map<Location, E> occupants;

public UnboundedGrid(){
    super();
    characteristics = Characteristics.UNBOUNDED;
    occupants = new TreeMap<>();
}

public UnboundedGrid(Characteristics characteristics, int num){
    super(characteristics == Characteristics.HORIZONTALLY_BOUNDED ? new Dimension(num, -1) : (characteristics == Characteristics.VERTICALLY_BOUNDED ? new Dimension(-1, num) : new Dimension(-1, -1)));
    this.characteristics = characteristics;
    occupants = new TreeMap<>();
}

@Override
public E put(Location loc, E obj) {
    if (!isValid(loc)){
        throw new IllegalArgumentException("Location " + loc + "is invalid");
    }
    return occupants.put(loc, obj);
}

@Override
public E remove(Location loc) {
    if (!isValid(loc)){
        throw new IllegalArgumentException("Location " + loc + "is invalid");
    }
    return occupants.remove(loc);
}

@Override
public E get(Location loc) {
    if (!isValid(loc)){
        throw new IllegalArgumentException("Location " + loc + "is invalid");
    }
    return occupants.get(loc);
}

@Override
public boolean isValid(Location loc) {
    switch (characteristics){
        case HORIZONTALLY_BOUNDED:
            return 0 <= loc.getCol() && loc.getCol() < getNumCols();
        case VERTICALLY_BOUNDED:
            return 0 <= loc.getRow() && loc.getRow() < getNumRows();
        case UNBOUNDED:
            return true;
        default:
            throw new UnknownError("Check UnboundedGrid.Characteristics");
    }
}

@Override
public Set<Location> getOccupiedLocations() {
    return occupants.keySet();
}
}
0

There are 0 best solutions below