Last active
July 4, 2021 11:33
-
-
Save steghio/1a440b8557adfc54a68c97477f958b1c to your computer and use it in GitHub Desktop.
Minesweeper game
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Minesweeper game |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.blogspot.groglogs.minesweeper; | |
import java.util.Collections; | |
import java.util.LinkedList; | |
import java.util.List; | |
public class Minesweeper { | |
private int[][] field, play; | |
private int mines, fieldSize, fieldLength; | |
public static final int DEF_MINE = 9; | |
public Minesweeper(int size, int mines){ | |
field = new int[size][size]; | |
play = new int[size][size]; | |
this.mines = mines; | |
this.fieldSize = size * size; | |
this.fieldLength = size; | |
createField(); | |
} | |
public int getSquare(int i, int j){ | |
return field[i][j]; | |
} | |
private void createField(){ | |
int mineOrSafe, leftToPlace; | |
List<Integer> randomSquares = new LinkedList<>(); | |
//initialize coordinate lists | |
for(int i = 1; i <= fieldSize; i++){ | |
randomSquares.add(i); | |
} | |
//randomize coordinates | |
Collections.shuffle(randomSquares); | |
//if we have more mines than empty spots, place them instead of mines | |
if(mines < this.fieldSize / 2){ | |
mineOrSafe = DEF_MINE; | |
leftToPlace = this.mines; | |
} | |
else{ | |
mineOrSafe = -1; | |
leftToPlace = this.fieldSize - this.mines; | |
} | |
while(leftToPlace > 0){ | |
//pick any square at random and convert it to i,j coordinates, then place either the mine or a safe spot | |
int square = randomSquares.get(leftToPlace); | |
int i = decodeCoordinate(square, false); | |
int j = decodeCoordinate(square, true); | |
field[i][j] = mineOrSafe; | |
leftToPlace--; | |
} | |
//if we placed empty spots, add the mines now | |
if(mineOrSafe == -1){ | |
for(int i = 0; i < fieldLength; i++){ | |
for(int j = 0; j < fieldLength; j++){ | |
//default 0 initialization | |
if(field[i][j] == 0) field[i][j] = DEF_MINE; | |
} | |
} | |
} | |
//calculate the rest of the field | |
for(int i = 0; i < fieldLength; i++){ | |
for(int j = 0; j < fieldLength; j++){ | |
if(field[i][j] != DEF_MINE) field[i][j] = getFieldValue(i, j); | |
} | |
} | |
//playField is initially all undiscovered | |
for(int i = 0; i < fieldLength; i++){ | |
for(int j = 0; j < fieldLength; j++){ | |
play[i][j] = -1; | |
} | |
} | |
} | |
private int decodeCoordinate(int value, boolean is_column){ | |
//column we can find with modulus | |
//last column is 0 if we do this calculation, but we are going for random spots so we don't care to correct it | |
if(is_column) return value % fieldLength; | |
//rows we can find with a normal division and then picking the ceiling of it, converting to 0-based! | |
double a = (double) value, b = (double) fieldLength; | |
int c = (int) Math.ceil(a / b); | |
return c - 1; | |
} | |
private int getFieldValue(int i, int j){ | |
int count = 0; | |
//check all neighbour spots and increment counter for each mine we find | |
if(i - 1 >= 0 && field[i - 1][j] == DEF_MINE) count++; | |
if(i + 1 < fieldLength && field[i + 1][j] == DEF_MINE) count++; | |
if(j - 1 >= 0 && field[i][j - 1] == DEF_MINE) count++; | |
if(j + 1 < fieldLength && field[i][j + 1] == DEF_MINE) count++; | |
if(i - 1 >= 0 && j - 1 >= 0 && field[i - 1][j - 1] == DEF_MINE) count++; | |
if(i + 1 < fieldLength && j + 1 < fieldLength && field[i + 1][j + 1] == DEF_MINE) count++; | |
if(i - 1 >= 0 && j + 1 < fieldLength && field[i - 1][j + 1] == DEF_MINE) count++; | |
if(i + 1 < fieldLength && j - 1 >= 0 && field[i + 1][j - 1] == DEF_MINE) count++; | |
return count; | |
} | |
public void printField(){ | |
for(int i = 0; i < fieldLength; i++){ | |
for(int j = 0; j < fieldLength; j++){ | |
System.out.print(field[i][j] + " "); | |
} | |
System.out.println(""); | |
} | |
} | |
public void printPlay(){ | |
for(int i = 0; i < fieldLength; i++){ | |
for(int j = 0; j < fieldLength; j++){ | |
System.out.print(play[i][j] + " "); | |
} | |
System.out.println(""); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.blogspot.groglogs.minesweeper.test; | |
import com.blogspot.groglogs.minesweeper.*; | |
import org.junit.Test; | |
import static org.junit.Assert.assertEquals; | |
public class MinesweeperJTests { | |
Minesweeper m; | |
int random_test_limit = 100; | |
@Test | |
public void noMines() { | |
int size = 3, mines = 0; | |
m = new Minesweeper(size, mines); | |
int placedMines = 0; | |
for(int i = 0; i < size; i++){ | |
for(int j = 0; j < size; j++){ | |
if(m.getSquare(i, j) == Minesweeper.DEF_MINE) placedMines++; | |
} | |
} | |
assertEquals("Field 3x3 no mines has no mines", mines, placedMines); | |
} | |
@Test | |
public void allMines() { | |
int size = 3, mines = 9; | |
m = new Minesweeper(size, mines); | |
int placedMines = 0; | |
for(int i = 0; i < size; i++){ | |
for(int j = 0; j < size; j++){ | |
if(m.getSquare(i, j) == Minesweeper.DEF_MINE) placedMines++; | |
} | |
} | |
assertEquals("Field 3x3 all mines has all mines", mines, placedMines); | |
} | |
@Test | |
public void fewerMines() { | |
//we have fewer mines than half of the board, algorithm will place mines | |
//since it's random placement, run the test more times and see if it ever breaks | |
for(int test = 0; test < random_test_limit; test++) { | |
int size = 3, mines = 3; | |
m = new Minesweeper(size, mines); | |
int placedMines = 0; | |
for (int i = 0; i < size; i++) { | |
for (int j = 0; j < size; j++) { | |
if (m.getSquare(i, j) == Minesweeper.DEF_MINE) placedMines++; | |
} | |
} | |
assertEquals("Field 3x3 3 mines has 3 mines", mines, placedMines); | |
size = 5; | |
mines = 10; | |
m = new Minesweeper(size, mines); | |
placedMines = 0; | |
for (int i = 0; i < size; i++) { | |
for (int j = 0; j < size; j++) { | |
if (m.getSquare(i, j) == Minesweeper.DEF_MINE) placedMines++; | |
} | |
} | |
assertEquals("Field 5x5 10 mines has 10 mines", mines, placedMines); | |
} | |
} | |
@Test | |
public void moreMines() { | |
//we have more mines than half of the board, algorithm will place empty spaces | |
//since it's random placement, run the test more times and see if it ever breaks | |
for (int test = 0; test < random_test_limit; test++) { | |
int size = 3, mines = 5; | |
m = new Minesweeper(size, mines); | |
int placedMines = 0; | |
for (int i = 0; i < size; i++) { | |
for (int j = 0; j < size; j++) { | |
if (m.getSquare(i, j) == Minesweeper.DEF_MINE) placedMines++; | |
} | |
} | |
assertEquals("Field 3x3 5 mines has 5 mines", mines, placedMines); | |
size = 5; | |
mines = 15; | |
m = new Minesweeper(size, mines); | |
placedMines = 0; | |
for (int i = 0; i < size; i++) { | |
for (int j = 0; j < size; j++) { | |
if (m.getSquare(i, j) == Minesweeper.DEF_MINE) placedMines++; | |
} | |
} | |
assertEquals("Field 5x5 15 mines has 15 mines", mines, placedMines); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Full description at: http://groglogs.blogspot.ch/2018/02/java-minesweeper.html