У меня есть таблица и несколько ботов (пока только 2), которые пытаются найти кратчайший путь в таблице от начальной точки до цели.
Каждый бот - это поток, который сохраняет состояниезаблокированных и неблокированных клеток в таблице.
Каждый поток подписан на другие темы.Когда один поток выполняет и перемещается, он отправляет уведомление другим потокам о том, что он освободил ранее занятую ячейку и заблокировал другую.
Это выглядит так
Основной цикл каждого потока выглядит следующим образом
@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;
Но иногда эти движущиеся боты перекрывают друг друга - поэтому они одновременно попадают в одни и те же ячейки.В конце концов они достигают желаемого пункта назначения.
Однако я бы хотел избавиться от этого поведения.Как этого добиться?
Насколько я понимаю, я должен запретить поиск, пока в сообщении receiveNotification
не будет обновлено состояние cellState
, или запретить обновление 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);
});
}
}