package model; import util.Position; import util.TargetStrategy; import java.util.*; public class FirefighterBoard implements Board<List<ModelElement>> { private final int columnCount; private final int rowCount; private final int initialFireCount; private final int initialFirefighterCount; private final int initialCloudCount; private final int initialRoadCount; private List<FireFighter> firefighters; private List<Element> elements; private Map<Position, Fire> fires = new HashMap<>(); private List<Cloud> clouds; private final Map<Position, List<Position>> neighbors = new HashMap<>(); private final Position[][] positions; private int step = 0; private final Random randomGenerator = new Random(); public FirefighterBoard(int columnCount, int rowCount, int initialFireCount, int initialFirefighterCount,int initialCloudCount,int initialRoadCount) { this.columnCount = columnCount; this.rowCount = rowCount; this.positions = new Position[rowCount][columnCount]; initializePositionsAndNeighbors(); this.initialFireCount = initialFireCount; this.initialFirefighterCount = initialFirefighterCount; this.initialCloudCount = initialCloudCount; this.initialRoadCount = initialRoadCount; initializeElements(); } private void initializePositionsAndNeighbors() { for (int column = 0; column < columnCount; column++) { for (int row = 0; row < rowCount; row++) { positions[row][column] = new Position(row, column); } } for (int column = 0; column < columnCount; column++) { for (int row = 0; row < rowCount; row++) { neighbors.put(positions[row][column], calculateNeighbors(row, column)); } } } public void initializeElements() { elements = new ArrayList<>(); fires.clear(); for (int index = 0; index < initialFireCount; index++) { Position position = randomPosition(); fires.put(position, new Fire(position)); } for (int index = 0; index < initialFirefighterCount; index++) { elements.add(new FireFighter(randomPosition())); } for (int index = 0; index < initialCloudCount; index++) { elements.add(new Cloud(randomPosition())); } for (int index = 0; index < initialRoadCount; index++) { elements.add(new Road(randomPosition())); } } private List<Position> calculateNeighbors(int row, int column) { List<Position> list = new ArrayList<>(); if (row > 0) list.add(positions[row - 1][column]); if (column > 0) list.add(positions[row][column - 1]); if (row < rowCount - 1) list.add(positions[row + 1][column]); if (column < columnCount - 1) list.add(positions[row][column + 1]); return list; } private Position randomPosition() { return positions[randomGenerator.nextInt(rowCount)][randomGenerator.nextInt(columnCount)]; } @Override public List<ModelElement> getState(Position position) { List<ModelElement> result = new ArrayList<>(); for(Element element : elements){ if(element.getPosition().equals(position))result.add(element.getElement()); } if (fires.containsKey(position)) result.add(ModelElement.FIRE); return result; } private List<Position> updateFires() { List<Position> modifiedPositions = new ArrayList<>(); if (step % 2 == 0) { Set<Position> newFirePositions = new HashSet<>(); for (Position fire : new HashSet<>(fires.keySet())) { List<Position> neighboursAvaiable = neighbors.get(fire); neighboursAvaiable.removeAll(getRoadsPosition()); newFirePositions.addAll(neighbors.get(fire)); } for (Position position : newFirePositions) { if (!fires.containsKey(position)) { fires.put(position, new Fire(position)); modifiedPositions.add(position); } } } return modifiedPositions; } public List<Position> updateElements(){ List<Position> modifiedPositions = new ArrayList<>(); for (Element element : elements) { if(element.getClass().equals(Road.class)){ continue; } modifiedPositions.addAll(element.update(this)); } return modifiedPositions; } public Position randomNeighbor(Position position) { List<Position> neighborPositions = neighbors.get(position); return neighborPositions.get(randomGenerator.nextInt(neighborPositions.size())); } public List<Position> updateToNextGeneration() { List<Position> modifiedPositions = updateElements(); modifiedPositions.addAll(updateFires()); step++; return modifiedPositions; } @Override public int stepNumber() { return step; } @Override public int rowCount() { return rowCount; } @Override public int columnCount() { return columnCount; } @Override public void reset() { step = 0; initializeElements(); } public void extinguish(Position position) { if (fires.containsKey(position)) { fires.remove(position); } } public Map<Position,Fire> getFires(){ return this.fires; } public Map<Position, List<Position>> getNeighbors() { return neighbors; } public List<Position> getRoadsPosition(){ List<Position>roadPosition = new ArrayList<>(); for(Element road: elements){ if(road.getClass().equals(Road.class)){ roadPosition.add(road.getPosition()); } } return roadPosition; } @Override public void setState(List<ModelElement> state, Position position) { extinguish(position); elements.removeIf(element -> element.getPosition().equals(position)); for (ModelElement element : state) { switch (element) { case FIRE -> fires.put(position, new Fire(position)); case FIREFIGHTER -> firefighters.add(new FireFighter(position)); case CLOUD -> clouds.add(new Cloud(position)); } } } }