/
java56
/
Minesweeper
Обзор
Документация
Войти
/
java56
/
Minesweeper
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/main/java/com/mikhail/minesweeper/service/GameFieldService.java
209 строк
8 KB
Mikhail Gorbatenkov
41 - add a check to an already open cell
18 фев 2025, 20:13
18 фев 2025, 20:13
b852c71
Код
Авторство
О чём код?
package com.mikhail.minesweeper.service; import com.mikhail.minesweeper.model.CellValue; import com.mikhail.minesweeper.model.Game; import com.mikhail.minesweeper.model.GameStatus; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.Random; /** * @author Mikhail * <p>Сервис для генерации поля и манипуляции с ячейками (открытие, проверка на мины, завершение игры).</p> */ @Service @Slf4j public class GameFieldService { /** * Генерация игрового поля с минами. * * @param game игра, содержащая размер игрового поля и количество мин * @return игровое поле в виде списка списков */ public List<List<String>> generateGameField(Game game) { List<List<String>> gameField = initializeField(game); placeMines(game, gameField); log.info("Игровое поле успешно сгенерировано."); return gameField; } /** * Расстановка мин на поле * * @param game текущее состояние игры * @param gameField игровое поле */ private void placeMines(Game game, List<List<String>> gameField) { Random random = new Random(); int placedMines = 0; while (placedMines < game.getMinesCount()) { int x = random.nextInt(game.getHeight()); int y = random.nextInt(game.getWidth()); if (!gameField.get(x).get(y).equals(CellValue.MINE.getValue())) { gameField.get(x).set(y, CellValue.MINE.getValue()); placedMines++; } } log.debug("Мины расставлены на игровом поле."); } /** * Инициализация игрового поля пустыми ячейками * * @param game текущее состояние игры * @return игровое поле с проинициализированными значениями */ private List<List<String>> initializeField(Game game) { List<List<String>> field = new ArrayList<>(); for (int i = 0; i < game.getHeight(); i++) { List<String> row = new ArrayList<>(); for (int j = 0; j < game.getWidth(); j++) { row.add(CellValue.EMPTY.getValue()); } field.add(row); } log.debug("Ячейки игрового поля успешно проинициализированы."); return field; } /** * Открытие ячейки с числом на игровом поле. Если ячейка с миной - игра завершена. * * @param game игра * @param row строка игрового поля * @param col колонка игрового поля */ public void openCell(Game game, int row, int col) { List<List<String>> gameField = game.getField(); String cell = gameField.get(row).get(col); if (cell.equals(CellValue.MINE.getValue())) { game.setStatus(GameStatus.COMPLETED); revealAllMines(gameField); log.info("Игра завершена: открыта мина на координатах row={}, col={}", row, col); return; } String minesCount = calculateAdjacentMines(gameField, row, col); gameField.get(row).set(col, minesCount); log.debug("Открыли ячейку: row = {}, col = {}, mines_count={}", row, col, minesCount); if ("0".equals(minesCount)) { openAdjacentCells(game, row, col); } } /** * Открывает смежные ячейки рядом с ячейкой, имеющее значение "0". * @param game объект, содержащий информацию о текущем состоянии игры * @param row строка, в которой располагается ячейка, которую необходимо открыть * @param col колонка, в которой располагается ячейка, которую необходимо открыть */ private void openAdjacentCells(Game game, int row, int col) { List<List<String>> gameField = game.getField(); int height = gameField.size(); int width = gameField.get(row).size(); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { int r = row + i; int c = col + j; if (r >= 0 && r < height && c >= 0 && c < width) { String cellValue = gameField.get(r).get(c); if (cellValue.equals(CellValue.EMPTY.getValue())) { String minesCount = calculateAdjacentMines(gameField, r, c); gameField.get(r).set(c, minesCount); log.debug("Открыли смежную ячейку: row={}, col = {}, mines={}", r, c, minesCount); if("0".equals(minesCount)) { openAdjacentCells(game, r, c); } } } } } } /** * Преобразование игрового поля в список списков * для ответа (см. класс {@link com.mikhail.minesweeper.dto.response.GameInfoResponse}) * * @param game игра * @return представление игрового поля */ public List<List<String>> getFieldRepresentation(Game game) { List<List<String>> field = game.getField(); List<List<String>> maskedField = new ArrayList<>(); boolean isCompleted = game.getStatus().equals(GameStatus.COMPLETED); for (List<String> strings : field) { List<String> row = new ArrayList<>(); for (String cellValue : strings) { // Скрываем мины и неоткрытые ячейки при активной игре if (!isCompleted && (cellValue.equals(CellValue.MINE.getValue()) || cellValue.equals(CellValue.EMPTY.getValue()))) { row.add(" "); } else { row.add(cellValue); } } maskedField.add(row); } return maskedField; } /** * Открывает все мины после завершения игры * * @param gameField игровое поле */ private void revealAllMines(List<List<String>> gameField) { for (List<String> row : gameField) { for (int i = 0; i < row.size(); i++) { if (row.get(i).equals(CellValue.MINE.getValue())) { row.set(i, CellValue.EXPLODED_MINE.getValue()); } } } log.info("Мины открыты на игровом поле."); } /** * Подсчитывает мины вокруг ячейки * * @param gameField игровое поле * @param row строка игрового поля * @param col колонка игрового поля * @return количество мин */ private String calculateAdjacentMines(List<List<String>> gameField, int row, int col) { int mines = 0; int height = gameField.size(); int width = gameField.get(0).size(); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { int r = row + i; int c = col + j; if (r >= 0 && r < height && c >= 0 && c < width) { if (gameField.get(r).get(c).equals(CellValue.MINE.getValue())) { mines++; } } } } log.info("Количество мин вокруг ячейки: {}", mines); return String.valueOf(mines); } }