Spaces:
Running
Running
| import java.awt.*; | |
| import java.io.FileWriter; | |
| import java.io.IOException; | |
| import java.util.*; | |
| import javax.swing.*; | |
| import javax.swing.Timer; | |
| public class MazeManager extends JPanel { | |
| //Agens and queue | |
| private Queue<Agent> agentQueue; | |
| private Agent agent1; | |
| private Agent agent2; | |
| //variables | |
| private final int cols, rows; | |
| private final int cellSize = 20; | |
| private final MazeTile[][] tiles; | |
| private final boolean[][][] walls; | |
| private final Random random = new Random(); | |
| private final int trapChance; | |
| private final int powerUpChance; | |
| //Game Mechanic | |
| private boolean gameOver = false; | |
| private int currRount = 0; | |
| private Timer timer; | |
| public MazeManager(int cols, int rows, int trapChance, int powerUpChance) { | |
| //Create ways in maze | |
| this.cols = cols; | |
| this.rows = rows; | |
| this.trapChance = trapChance; | |
| this.powerUpChance = powerUpChance; | |
| this.tiles = new MazeTile[cols][rows]; | |
| this.walls = new boolean[cols][rows][4]; | |
| for (int x = 0; x < cols; x++) { | |
| for (int y = 0; y < rows; y++) { | |
| tiles[x][y] = new MazeTile(); | |
| for (int d = 0; d < 4; d++) walls[x][y][d] = true; | |
| } | |
| } | |
| boolean[][] visited = new boolean[cols][rows]; | |
| generateMaze(0, 0, visited); | |
| placeEntities(); | |
| setPreferredSize(new Dimension(cols * cellSize, rows * cellSize)); | |
| agentQueue = new Queue(10); | |
| agent1 = new Agent(0, 0, this, Color.BLUE, "Blue Agent",1); | |
| agent2 = new Agent(cols - 1, rows - 1, this, Color.ORANGE, "Orange Agent",2); | |
| agentQueue.enqueue(agent1); | |
| agentQueue.enqueue(agent2); | |
| timer = new Timer(300, e -> { | |
| if (gameOver || agentQueue.isEmpty()) return; | |
| if (currRount > 0 && currRount % 5 == 0) rotateCorridor(); | |
| repaint(); | |
| Agent currentAgent = agentQueue.dequeue(); | |
| currentAgent.moveTowardsGoal(); | |
| if (tiles[currentAgent.getX()][currentAgent.getY()].getEntity() == MazeTile.EntityType.GOAL) { | |
| gameOver = true; | |
| timer.stop(); | |
| Agent loser = currentAgent == agent1 ? agent2 : agent1; | |
| GameLog(currentAgent, loser); | |
| JOptionPane.showMessageDialog(this, | |
| finalReport(agent1, agent2, currentAgent), | |
| "Game over!", | |
| JOptionPane.INFORMATION_MESSAGE); | |
| return; | |
| } | |
| agentQueue.enqueue(currentAgent); | |
| currRount++; | |
| }); | |
| timer.start(); | |
| } | |
| private void generateMaze(int x, int y, boolean[][] visited) { | |
| visited[x][y] = true; | |
| Integer[] dirs = {0, 1, 2, 3}; | |
| Collections.shuffle(Arrays.asList(dirs)); | |
| for (int dir : dirs) { | |
| int nx = x, ny = y; | |
| switch (dir) { | |
| case 0: | |
| ny--; | |
| break; | |
| case 1: | |
| nx++; | |
| break; | |
| case 2: | |
| ny++; | |
| break; | |
| case 3: | |
| nx--; | |
| break; | |
| } | |
| if (isInMaze(nx, ny) && !visited[nx][ny]) { | |
| removeWall(x, y, dir); | |
| generateMaze(nx, ny, visited); | |
| } | |
| } | |
| } | |
| public boolean hasWall(int x, int y, int dir) { | |
| return walls[x][y][dir]; | |
| } | |
| public void removeWall(int x, int y, int dir) { | |
| walls[x][y][dir] = false; | |
| int nx = x, ny = y; | |
| int opp = (dir + 2) % 4; | |
| switch (dir) { | |
| case 0: | |
| ny--; | |
| break; | |
| case 1: | |
| nx++; | |
| break; | |
| case 2: | |
| ny++; | |
| break; | |
| case 3: | |
| nx--; | |
| break; | |
| } | |
| if (isInMaze(nx, ny)) walls[nx][ny][opp] = false; | |
| } | |
| //-WİP- | |
| private void placeEntities() { | |
| int goalX = cols / 2; | |
| int goalY = rows / 2; | |
| tiles[goalX][goalY].setEntity(MazeTile.EntityType.GOAL); | |
| int total = cols * rows; | |
| int trapCount = total * trapChance / 100; | |
| int powerCount = total * powerUpChance / 100; | |
| for (int i = 0; i < trapCount; i++) { | |
| int x, y; | |
| do { | |
| x = random.nextInt(cols); | |
| y = random.nextInt(rows); | |
| } while (tiles[x][y].getEntity() != MazeTile.EntityType.EMPTY || (x == goalX && y == goalY)); | |
| tiles[x][y].setEntity(MazeTile.EntityType.TRAP); | |
| } | |
| for (int i = 0; i < powerCount; i++) { | |
| int x, y; | |
| do { | |
| x = random.nextInt(cols); | |
| y = random.nextInt(rows); | |
| } while (tiles[x][y].getEntity() != MazeTile.EntityType.EMPTY || (x == goalX && y == goalY)); | |
| tiles[x][y].setEntity(MazeTile.EntityType.POWER_UP); | |
| } | |
| } | |
| private void rotateCorridor() { | |
| boolean rotateRow = random.nextBoolean(); | |
| int index = rotateRow ? random.nextInt(rows) : random.nextInt(cols); //1=row, 2=col | |
| int goalX = cols / 2, goalY = rows / 2; //coordinats of goal | |
| ///////////////////////////////////////////// | |
| if (rotateRow && index == goalY) | |
| { | |
| return; | |
| } | |
| if (!rotateRow && index == goalX) { | |
| return; | |
| } | |
| if (rotateRow && index == agent1.getY()) | |
| { | |
| return; | |
| } | |
| //for not touching goal,agent1, agent2 | |
| if (!rotateRow && index == agent1.getX()) { | |
| return; | |
| } | |
| if (!rotateRow && index == agent2.getX()) { | |
| return; | |
| } | |
| if (rotateRow && index == agent2.getY()) { | |
| return; | |
| } | |
| ///////////////////////////////////////////// | |
| if (rotateRow) { | |
| CircularLinkedList<MazeTile.EntityType> entityList = new CircularLinkedList<>(); | |
| CircularLinkedList<Boolean> activePowerUp = new CircularLinkedList<>(); | |
| // taking data of every tile( entity type, is trap active, is powerup active) | |
| //taking them to same circular linked list | |
| CircularLinkedList<Boolean> activeTrap = new CircularLinkedList<>(); | |
| //rewrite every tiles | |
| for (int x = 0; x < cols; x++) { | |
| MazeTile tile = tiles[x][index]; | |
| entityList.add(tile.getEntity()); | |
| activeTrap.add( tile.isTrapActive()); | |
| activePowerUp.add(tile.isPowerUpActive()); | |
| } | |
| entityList.rotateOneStep(1); | |
| activeTrap.rotateOneStep(1); | |
| activePowerUp.rotateOneStep(1); | |
| for (int x = 0; x < cols; x++) { | |
| tiles[x][index].setPowerUpActive(activePowerUp.get(x)); | |
| tiles[x][index].setEntity(entityList.get(x)); | |
| tiles[x][index].setTrapActive(activeTrap.get(x)); | |
| } | |
| } else { | |
| CircularLinkedList<Boolean> trapActiveList = new CircularLinkedList<>(); | |
| CircularLinkedList<Boolean> powerUpActiveList = new CircularLinkedList<>(); | |
| CircularLinkedList<MazeTile.EntityType> entityList = new CircularLinkedList<>(); | |
| for (int y = 0; y < rows; y++) { | |
| MazeTile tile = tiles[index][y]; | |
| entityList.add(tile.getEntity()); | |
| trapActiveList.add(tile.isTrapActive()); | |
| powerUpActiveList.add(tile.isPowerUpActive()); | |
| } | |
| entityList.rotateOneStep(1); | |
| trapActiveList.rotateOneStep(1); | |
| powerUpActiveList.rotateOneStep(1); | |
| for (int y = 0; y < rows; y++) { | |
| tiles[index][y].setEntity(entityList.get(y)); | |
| tiles[index][y].setTrapActive(trapActiveList.get(y)); | |
| tiles[index][y].setPowerUpActive(powerUpActiveList.get(y)); | |
| } | |
| } | |
| } | |
| public boolean isInMaze(int x, int y) { | |
| return x >= 0 && y >= 0 && x < cols && y < rows; | |
| } | |
| public MazeTile getTile(int x, int y) { | |
| return tiles[x][y]; | |
| } | |
| public int getCols() { | |
| return cols; | |
| } | |
| public int getRows() { | |
| return rows; | |
| } | |
| private String finalReport(Agent a1, Agent a2, Agent winner) { | |
| StringBuilder sb = new StringBuilder(); | |
| sb.append(winner.getName()).append(" reached the target!\nnumber of rount played: ").append(currRount).append("\n\n"); | |
| for (Agent agent : new Agent[]{a1, a2}) { | |
| sb.append(agent.getName()).append(":\n"); | |
| Stack<String> stack = agent.getMoveHistory(); | |
| for (int i = 0; i < stack.getSize(); i++) { | |
| sb.append(stack.getElements()[i]).append(""); | |
| } | |
| sb.append("\n"); | |
| } | |
| return sb.toString(); | |
| } | |
| private void GameLog(Agent winner, Agent loser) { | |
| // preparing console screen before printing results | |
| System.out.print("\033[H\033[2J"); | |
| System.out.flush(); | |
| //----------- | |
| System.out.println("\n=== Game Over ==="); | |
| System.out.println("Winner Agent: " + winner.getName()); | |
| System.out.println("Number of rount played: " + currRount); | |
| System.out.println("----------------------"); | |
| System.out.println(winner.getName() + " Statistics:"); | |
| System.out.println("- Step number: " + winner.getStepCount()); | |
| System.out.println("- Trap number: " + winner.getTrapHits()); | |
| System.out.println("- Power-Up usage: " + winner.getPowerUpUses()); | |
| System.out.println(); | |
| System.out.println(loser.getName() + " Statistics:"); | |
| System.out.println("- Step number: " + loser.getStepCount()); | |
| System.out.println("- Trap number: " + loser.getTrapHits()); | |
| System.out.println("- Power-Up usage: " + loser.getPowerUpUses()); | |
| try (FileWriter writer = new FileWriter("game_log.txt", true)) { | |
| writer.write("=== Game Over ===\n"); | |
| writer.write("Winner Agent: " + winner.getName() + " (ID: " + winner.getId() + ")\n"); | |
| writer.write("Number of rount played: " + currRount + "\n\n"); | |
| for (Agent agent : new Agent[]{winner, loser}) { | |
| writer.write(agent.getName() + " (ID: " + agent.getId() + ")\n"); | |
| writer.write("- Step number: " + agent.getStepCount() + "\n"); | |
| writer.write("- Trap number: " + agent.getTrapHits() + "\n"); | |
| writer.write("- Power-Up usage: " + agent.getPowerUpUses() + "\n"); | |
| writer.write("- Moves: "); | |
| Stack<String> stack = agent.getMoveHistory(); | |
| for (int i = 0; i < stack.getSize(); i++) { | |
| Object move = stack.getElements()[i]; | |
| writer.write(String.valueOf(move)); | |
| } | |
| writer.write("\n--------------------------\n"); | |
| } | |
| } catch (IOException e) { | |
| System.out.println("Log file error: "); | |
| } | |
| } | |
| protected void paintComponent(Graphics g) { | |
| super.paintComponent(g); | |
| g.setColor(Color.BLACK); | |
| for (int x = 0; x < cols; x++) { | |
| for (int y = 0; y < rows; y++) { | |
| int px = x * cellSize; | |
| int py = y * cellSize; | |
| if (walls[x][y][3]) g.drawLine(px, py, px, py + cellSize); | |
| if (walls[x][y][1]) g.drawLine(px + cellSize, py, px + cellSize, py + cellSize); | |
| if (walls[x][y][0]) g.drawLine(px, py, px + cellSize, py); | |
| if (walls[x][y][2]) g.drawLine(px, py + cellSize, px + cellSize, py + cellSize); | |
| switch (tiles[x][y].getEntity()) { | |
| case GOAL -> { | |
| g.setColor(Color.GREEN); | |
| g.fillRect(px + 4, py + 4, cellSize - 8, cellSize - 8); | |
| g.setColor(Color.BLACK); | |
| } | |
| case POWER_UP -> { | |
| g.setColor(tiles[x][y].isPowerUpActive() ? Color.YELLOW : Color.GRAY); | |
| g.fillRect(px + 4, py + 4, cellSize - 8, cellSize - 8); | |
| g.setColor(Color.BLACK); | |
| } | |
| case TRAP -> { | |
| g.setColor(tiles[x][y].isTrapActive() ? Color.RED : Color.GRAY); | |
| g.fillRect(px + 4, py + 4, cellSize - 8, cellSize - 8); | |
| g.setColor(Color.BLACK); | |
| } | |
| } | |
| } | |
| } | |
| for (Agent agent : new Agent[]{agent1, agent2}) { | |
| g.setColor(agent.passedWallThisTurn() ? Color.MAGENTA : agent.getColor()); | |
| g.fillOval(agent.getX() * cellSize + 5, agent.getY() * cellSize + 5, cellSize - 10, cellSize - 10); | |
| } | |
| g.setColor(Color.BLACK); | |
| g.drawString("Curr Round: " + currRount, 10, 15); | |
| } | |
| } | |