Skip to content

Instantly share code, notes, and snippets.

@steghio
Last active July 4, 2021 11:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steghio/1a440b8557adfc54a68c97477f958b1c to your computer and use it in GitHub Desktop.
Save steghio/1a440b8557adfc54a68c97477f958b1c to your computer and use it in GitHub Desktop.
Minesweeper game
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("");
}
}
}
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);
}
}
}
@steghio
Copy link
Author

steghio commented Feb 3, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment