/
victor_t
/
maze
Обзор
Документация
Войти
/
victor_t
/
maze
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
1
CI/CD
Аналитика
Безопасность
master
src/model/Cave.java
226 строк
7 KB
Victor
relocated project folder
03 июл 2026, 03:14
03 июл 2026, 03:14
827638e
Код
Авторство
О чём код?
package model; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; import java.util.Random; import java.util.Scanner; /** * Модель пещеры на основе клеточного автомата. * * <p>Пещера представлена в виде двумерной сетки, где каждая клетка * может быть либо заполненной ({@code true}), либо пустой ({@code false}).</p> * * <p>Класс поддерживает: * <ul> * <li>загрузку и сохранение состояния из файла</li> * <li>случайную генерацию карты</li> * <li>пошаговую эволюцию по правилам клеточного автомата</li> * </ul> * </p> * * <p>Границы поля считаются всегда заполненными клетками.</p> */ public class Cave { private int rows; private int cols; private boolean[][] cave; /** * Создает пещеру по умолчанию размером 10x10 * с вероятностью заполнения 50%. */ public Cave() { generate(10, 10, 50); } /** * Загружает состояние пещеры из файла. * * <p>Формат файла: * <pre> * rows cols * 0 1 0 1 ... * ... * </pre> * где 1 — заполненная клетка, 0 — пустая.</p> * * @param fileName путь к файлу * @throws Exception если файл не найден или имеет некорректный формат */ public void loadFromFile(String fileName) throws Exception { try (Scanner sc = new Scanner(new File(fileName))) { if (!sc.hasNextInt()) { throw new Exception("File format is not correct"); } rows = sc.nextInt(); cols = sc.nextInt(); if (rows < 1 || rows > 50 || cols < 1 || cols > 50) { generate(5, 5, 50); throw new Exception("File format is not correct"); } cave = new boolean[rows][cols]; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (!sc.hasNextInt()) { throw new Exception("File format is not correct"); } int v = sc.nextInt(); if (v == 1) { cave[i][j] = true; } else if (v != 0) { throw new Exception("File format is not correct"); } } } } catch (FileNotFoundException e) { throw new Exception("Unable to open file!"); } } /** * Сохраняет текущее состояние пещеры в файл. * * <p>Формат совпадает с форматом загрузки.</p> * * @param fileName путь к файлу * @throws Exception если запись невозможна */ public void saveToFile(String fileName) throws Exception { try (PrintWriter pw = new PrintWriter(new FileWriter(fileName))) { pw.println(rows + " " + cols); for (int i = 0; i < rows; i++) { StringBuilder sb = new StringBuilder(); for (int j = 0; j < cols; j++) { if (j > 0) { sb.append(' '); } sb.append(cave[i][j] ? 1 : 0); } pw.println(sb); } } catch (IOException e) { throw new Exception("Unable to write in file"); } } /** * Генерирует случайную пещеру. * * @param row количество строк * @param col количество столбцов * @param chance вероятность (в процентах) того, * что клетка будет заполненной */ public void generate(int row, int col, int chance) { rows = row; cols = col; cave = new boolean[rows][cols]; Random rng = new Random(); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { cave[i][j] = (chance >= (rng.nextInt(100) + 1)); } } } /** * Выполняет один шаг эволюции клеточного автомата. * * <p>Правила: * <ul> * <li>Если клетка жива и число соседей меньше {@code death}, * она становится пустой</li> * <li>Если клетка пуста и число соседей больше {@code birth}, * она становится заполненной</li> * </ul> * </p> * * @param birth порог рождения клетки * @param death порог смерти клетки * @return {@code true}, если состояние изменилось, иначе {@code false} */ public boolean oneStep(int birth, int death) { boolean[][] next = new boolean[rows][cols]; for (int i = 0; i < rows; i++) { System.arraycopy(cave[i], 0, next[i], 0, cols); } for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int nearby = countAliveNeighbours(i, j); if (cave[i][j] && nearby < death) { next[i][j] = false; } else if (!cave[i][j] && nearby > birth) { next[i][j] = true; } } } if (Arrays.deepEquals(cave, next)) { return false; } cave = next; return true; } /** * Подсчитывает количество заполненных соседних клеток. * * <p>Учитываются 8 направлений (диагонали включены). * Клетки за пределами поля считаются заполненными.</p> * * @param x индекс строки * @param y индекс столбца * @return количество заполненных соседей */ private int countAliveNeighbours(int x, int y) { int[] moveX = {-1, 0, 1, 0, -1, 1, 1, -1}; int[] moveY = {0, 1, 0, -1, 1, 1, -1, -1}; int counter = 0; for (int i = 0; i < 8; i++) { int nx = x + moveX[i]; int ny = y + moveY[i]; if (nx < 0 || nx >= rows || ny < 0 || ny >= cols) { counter++; } else if (cave[nx][ny]) { counter++; } } return counter; } /** * Возвращает количество строк. * * @return количество строк */ public int getRows() { return rows; } /** * Возвращает количество столбцов. * * @return количество столбцов */ public int getCols() { return cols; } /** * Возвращает текущее состояние пещеры. * * @return двумерный массив клеток */ public boolean[][] getCave() { return cave; } }