我有一张桌子和几个机器人(现在只有 2 个),它们试图在表格中找到从起点到目标的最短路径。
每个 bot 都是一个线程,用于保持表中阻塞和未阻塞单元格的状态。
每个线程都订阅了其他线程。当某个线程执行并移动时,它会向其他线程发送通知,告知它已经释放了先前占用的单元并阻塞了另一个。
看起来像这样
每个线程的主循环是这样的
@Override
public void run() {
// render original position
notifyObserver(ChangeStateEvent
.builder()
.identifier(npc.getIdentifier())
.newState(
NPCWalkState.builder()
.row(startVertex.getRow())
.column(startVertex.getColumn())
.build())
.build());
while (!startVertex.equals(goalVertex)) {
ThreadUtils.delaySeconds(speed);
Vertex nextStep = pathSearch.find(startVertex, goalVertex, cellStates).get(1);
ChangeStateEvent event = ChangeStateEvent.builder()
.identifier(npc.getIdentifier())
.newState(
NPCWalkState.builder()
.row(nextStep.getRow())
.column(nextStep.getColumn())
.build())
.previousState(
NPCWalkState.builder()
.row(startVertex.getRow())
.column(startVertex.getColumn())
.build())
.build();
notifyObserver(event);
startVertex = new Vertex(nextStep);
}
}
侦听器方法看起来像这样
@Override
public void receiveNotification(ChangeStateEvent data) {
if (null != data.getPreviousState()) {
// freed cells
int free_row = data.getPreviousState().getRow();
int free_column = data.getPreviousState().getColumn();
// blocked cells
int blocked_row = data.getNewState().getRow();
int blocked_column = data.getNewState().getColumn();
cellStates[free_row][free_column] = false;
cellStates[blocked_row][blocked_column] = true;
} else {
// blocked cells
int blocked_row = data.getNewState().getRow();
int blocked_column = data.getNewState().getColumn();
cellStates[blocked_row][blocked_column] = true;
}
}
cellStates
是一个基本的布尔矩阵
private boolean[][] cellStates;
但有时那些移动的机器人会相互重叠——所以它们会同时进入同一个单元格。最终他们达到了预期的目的地。
但是我想摆脱这种行为。如何做到这一点?
据我了解,我应该阻止搜索,直到消息中的状态cellState
更新,或者如果搜索开始,则receiveNotification
阻止更新。cellState
我也不排除表本身负责重叠 - 因为它也订阅了线程事件
@Override
public void receiveNotification(ChangeStateEvent data) {
if (null != data.getPreviousState()) {
int previousRow = data.getPreviousState().getRow();
int previousColumn = data.getPreviousState().getColumn();
int currentRow = data.getNewState().getRow();
int currentColumn = data.getNewState().getColumn();
SwingUtilities.invokeLater(() -> {
List<T> oldCellContent = (List<T>) table.getValueAt(previousRow, previousColumn);
oldCellContent.remove(data.getIdentifier());
table.setValueAt(oldCellContent, previousRow, previousColumn);
List<T> newCellContent = (List<T>) table.getValueAt(currentRow, currentColumn);
newCellContent.add(0, (T) data.getIdentifier()); // on top TODO: player should be prioritized
table.setValueAt(newCellContent, currentRow, currentColumn);
});
} else {
int currentRow = data.getNewState().getRow();
int currentColumn = data.getNewState().getColumn();
SwingUtilities.invokeLater(() -> {
List<T> newCellContent = (List<T>) table.getValueAt(currentRow, currentColumn);
newCellContent.add(0, (T) data.getIdentifier());
table.setValueAt(newCellContent, currentRow, currentColumn);
});
}
}