0

我正在尝试为 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,还是应该创建另一个类,例如扩展 JTable 的 GridTable,并使用 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();
}
}
4

0 回答 0