import '../entities/cell.dart'; import '../provider/data.dart'; class BoardUtils { static printGrid(List cells) { final String IS_MINED = 'X'; final String IS_SAFE = '.'; final String MINE_FOUND = '#'; final String WRONG_MARKED_CELL = '0'; final String EXPLORED_SAFE_CELL = '.'; final String UNKNOWN_STATE = ' '; print(''); String line = '--'; for (var i = 0; i < cells[0].length; i++) { line += '-'; } print(line + ' ' + line); for (var rowIndex = 0; rowIndex < cells.length; rowIndex++) { String currentLine = ''; String solvedLine = ''; for (var colIndex = 0; colIndex < cells[rowIndex].length; colIndex++) { solvedLine += cells[rowIndex][colIndex].isMined ? IS_MINED : IS_SAFE; String cellString = UNKNOWN_STATE; if (cells[rowIndex][colIndex].isExplored) { cellString = EXPLORED_SAFE_CELL; } if (cells[rowIndex][colIndex].isMarked) { if (cells[rowIndex][colIndex].isMined) { cellString = MINE_FOUND; } else { cellString = WRONG_MARKED_CELL; } } currentLine += cellString; } print('|' + currentLine + '| |' + solvedLine + '|'); } print(line + ' ' + line); print(''); } static List createEmptyBoard(int sizeHorizontal, int sizeVertical) { int index = 0; List cells = []; for (var rowIndex = 0; rowIndex < sizeVertical; rowIndex++) { List row = []; for (var colIndex = 0; colIndex < sizeHorizontal; colIndex++) { row.add(Cell(false)); } cells.add(row); } return cells; } static int getMinesCount(int sizeHorizontal, int sizeVertical, String level) { int minesCountRatio = 0; switch(level) { case 'easy': { minesCountRatio = 5; } break; case 'medium': { minesCountRatio = 10; } break; case 'hard': { minesCountRatio = 15; } break; case 'nightmare': { minesCountRatio = 20; } break; } int minesCount = ((sizeHorizontal * sizeVertical) * minesCountRatio / 100).round(); print('Mines count: ' + minesCount.toString()); return minesCount; } static List createInitialEmptyBoard(Data myProvider) { myProvider.updateIsBoardMined(false); myProvider.updateCells(createEmptyBoard(myProvider.sizeHorizontal, myProvider.sizeVertical)); } static List createBoard(Data myProvider, int forbiddenRow, int forbiddenCol) { List cells = myProvider.cells; int sizeHorizontal = myProvider.sizeHorizontal; int sizeVertical = myProvider.sizeVertical; String level = myProvider.level; // Shuffle cells to put random mines, expect on currently selected one List allowedCells = []; for (var row = 0; row < sizeVertical; row++) { for (var col = 0; col < sizeHorizontal; col++) { if (!((forbiddenRow == row) && (forbiddenCol == col))) { allowedCells.add([row, col]); } } } allowedCells.shuffle(); // Put random mines on board int minesCount = getMinesCount(sizeHorizontal, sizeVertical, level); for (var mineIndex = 0; mineIndex < minesCount; mineIndex++) { cells[allowedCells[mineIndex][0]][allowedCells[mineIndex][1]].isMined = true; } // Compute all mines counts on cells for (var row = 0; row < sizeVertical; row++) { for (var col = 0; col < sizeHorizontal; col++) { cells[row][col].minesCountAround = getMinesCountAround(cells, row, col); } } printGrid(cells); return cells; } static void reportCell(Data myProvider, int row, int col) { if (!myProvider.cells[row][col].isExplored) { myProvider.toggleCellMark(row, col); } } static void walkOnCell(Data myProvider, int row, int col) { myProvider.setCellAsExplored(row, col); if (myProvider.cells[row][col].minesCountAround == 0) { List safeCells = getAllSafeCellsAround(myProvider.cells, row, col); for (var safeCellIndex = 0; safeCellIndex < safeCells.length; safeCellIndex++) { int safeCellRow = safeCells[safeCellIndex][0]; int safeCellCol = safeCells[safeCellIndex][1]; if (!myProvider.cells[safeCellRow][safeCellCol].isExplored) { walkOnCell(myProvider, safeCellRow, safeCellCol); } } } } static List getAllSafeCellsAround(List cells, int row, int col) { int sizeHorizontal = cells.length; int sizeVertical = cells[0].length; List safeCellsCoordinates = []; if (cells[row][col].minesCountAround == 0) { for (var deltaRow = -1; deltaRow <= 1; deltaRow++) { for (var deltaCol = -1; deltaCol <= 1; deltaCol++) { int candidateRow = row + deltaRow; int candidateCol = col + deltaCol; if ( (candidateRow >= 0 && candidateRow < sizeVertical) && (candidateCol >= 0 && candidateCol < sizeHorizontal) && !cells[candidateRow][candidateCol].isExplored ) { safeCellsCoordinates.add([candidateRow, candidateCol]); } } } } return safeCellsCoordinates; } static int getMinesCountAround(List cells, int row, int col) { int sizeHorizontal = cells.length; int sizeVertical = cells[0].length; int minesCountAround = 0; for (var deltaRow = -1; deltaRow <= 1; deltaRow++) { for (var deltaCol = -1; deltaCol <= 1; deltaCol++) { if ( (row + deltaRow >= 0 && row + deltaRow < sizeVertical) && (col + deltaCol >= 0 && col + deltaCol < sizeHorizontal) && (cells[row + deltaRow][col + deltaCol].isMined) ) { minesCountAround++; } } } return minesCountAround; } static bool checkGameIsFinished(Data myProvider) { List cells = myProvider.cells; int sizeHorizontal = cells.length; int sizeVertical = cells[0].length; printGrid(cells); myProvider.updateGameWin(false); myProvider.updateGameFail(false); for (var row = 0; row < sizeVertical; row++) { for (var col = 0; col < sizeHorizontal; col++) { // Walked on a mine if (cells[row][col].isExploded == true) { myProvider.updateGameFail(true); return false; } } } for (var row = 0; row < sizeVertical; row++) { for (var col = 0; col < sizeHorizontal; col++) { if ( // Mine not already found (cells[row][col].isMined == true && cells[row][col].isMarked == false) || // Safe cell marked as mined (cells[row][col].isMined == false && cells[row][col].isMarked == true) ) { return false; } } } print('-> ok all mines found!'); myProvider.updateGameWin(true); return true; } }