GridWorld APCS的TableModel

时间:2015-02-21 13:45:26

标签: java swing jtable gridworld

我试图为gridworld案例研究实施GUI并陷入困境。我正在尝试使用自定义的JTable实现网格。我使用TreeMap实现了BoundedGrid和UnboundedGrid类。但是,UnboundedGrid类需要GUI动态更改行数和列数,即基于填充Grid的元素的位置。 JTable的行数和列数应由具有最大和最小x / y坐标的元素确定。我不知道如何正确扩展AbstractTableModel类。

此外,存储在Grid,Actors中的对象存储其容器Grid及其各自的位置,而Grid接口中的put和remove方法在Actor类中使用,因此Actors上的任何更改都必须调用相应的方法。 Actor类,而不是Grid接口中的那些: 例如,Actor中的一个方法是:

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;
}

此方法调用Grid接口中的put()方法并更新Actor对象的位置。这应该被考虑在内,因为我需要一个像GridManager这样的类来存储Grid和actor来更新Grid上的更改。另一个问题:GridManager应该直接扩展JTable,还是应该创建另一个类,如GridTable,它扩展了JTable并使用GridManager自动更新表。

这是我的代码:

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 个答案:

没有答案