Skip to content

Commit 518b834

Browse files
committed
Minesweeper game added
1 parent 02c19a5 commit 518b834

9 files changed

Lines changed: 504 additions & 8 deletions

File tree

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package ru.ivannovr.games.minesweeper;
2+
3+
import ru.ivannovr.games.minesweeper.entities.Cell;
4+
import ru.ivannovr.games.minesweeper.entities.Flag;
5+
import ru.ivannovr.games.minesweeper.entities.Mine;
6+
import ru.ivannovr.games.minesweeper.entities.NumberCell;
7+
8+
import java.util.Random;
9+
10+
public class MineField {
11+
private final Cell[][] grid;
12+
private final int width;
13+
private final int height;
14+
private final int mineCount;
15+
private boolean lose;
16+
private int closedCount;
17+
18+
public MineField(int width, int height, int mineCount) {
19+
this.width = width;
20+
this.height = height;
21+
this.mineCount = mineCount;
22+
this.grid = new Cell[width][height];
23+
this.lose = false;
24+
this.closedCount = width * height;
25+
26+
for (int x = 0; x < width; x++) {
27+
for (int y = 0; y < height; y++) {
28+
grid[x][y] = new NumberCell(x, y, 0);
29+
}
30+
}
31+
}
32+
33+
public void placeMines(int safeX, int safeY) {
34+
Random random = new Random();
35+
int placed = 0;
36+
while (placed < mineCount) {
37+
int x = random.nextInt(width);
38+
int y = random.nextInt(height);
39+
if (!(grid[x][y] instanceof Mine) && (x != safeX || y != safeY)) {
40+
grid[x][y] = new Mine(x, y);
41+
placed++;
42+
}
43+
}
44+
calculateNumbers();
45+
}
46+
47+
private void calculateNumbers() {
48+
for (int x = 0; x < width; x++) {
49+
for (int y = 0; y < height; y++) {
50+
if (!(grid[x][y] instanceof Mine)) {
51+
int minesAround = countMinesAround(x, y);
52+
grid[x][y] = new NumberCell(x, y, minesAround);
53+
}
54+
}
55+
}
56+
}
57+
58+
private int countMinesAround(int x, int y) {
59+
int count = 0;
60+
for (int dx = -1; dx <= 1; dx++) {
61+
for (int dy = -1; dy <= 1; dy++) {
62+
int nx = x + dx;
63+
int ny = y + dy;
64+
if (nx >= 0 && nx < width && ny >= 0 && ny < height && grid[nx][ny].isMine()) {
65+
count++;
66+
}
67+
}
68+
}
69+
return count;
70+
}
71+
72+
public int reveal(int x, int y) {
73+
if (x < 0 || x >= width || y < 0 || y >= height || grid[x][y].isRevealed() || grid[x][y].isFlag()) {
74+
return 0;
75+
}
76+
Cell cell = grid[x][y];
77+
cell.reveal();
78+
closedCount--;
79+
80+
if (cell.isMine()) {
81+
lose = true;
82+
revealAllMines();
83+
return 0;
84+
}
85+
86+
int revealed = cell.getScoreValue();
87+
if (cell instanceof NumberCell numberCell && numberCell.getMineCount() == 0) {
88+
for (int dx = -1; dx <= 1; dx++) {
89+
for (int dy = -1; dy <= 1; dy++) {
90+
revealed += reveal(x + dx, y + dy);
91+
}
92+
}
93+
}
94+
return revealed;
95+
}
96+
97+
private void revealAllMines() {
98+
for (int x = 0; x < width; x++) {
99+
for (int y = 0; y < height; y++) {
100+
if (grid[x][y].isMine()) {
101+
grid[x][y].reveal();
102+
}
103+
}
104+
}
105+
}
106+
107+
public void toggleFlag(int x, int y) {
108+
if (x < 0 || x >= width || y < 0 || y >= height || grid[x][y].isRevealed()) {
109+
return;
110+
}
111+
if (grid[x][y].isFlag()) {
112+
grid[x][y] = ((Flag) grid[x][y]).removeFlag();
113+
} else {
114+
grid[x][y] = new Flag(x, y, grid[x][y]);
115+
}
116+
}
117+
118+
public boolean isWin() {
119+
return closedCount == mineCount && !lose;
120+
}
121+
122+
public boolean isLose() {
123+
return lose;
124+
}
125+
126+
public Cell getCell(int x, int y) {
127+
return grid[x][y];
128+
}
129+
130+
public int getWidth() {
131+
return width;
132+
}
133+
134+
public int getHeight() {
135+
return height;
136+
}
137+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package ru.ivannovr.games.minesweeper;
2+
3+
import ru.ivannovr.games.common.AbstractGame;
4+
import ru.ivannovr.utils.DatabaseManager;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
public class MinesweeperGame extends AbstractGame {
10+
private final MineField field;
11+
private final int width = 20;
12+
private final int height = 20;
13+
private final int mineCount = 40;
14+
private boolean firstClick;
15+
private long startTime;
16+
private long elapsedTime;
17+
18+
public MinesweeperGame(String username, DatabaseManager dbManager) {
19+
super("Minesweeper", username, dbManager);
20+
this.field = new MineField(width, height, mineCount);
21+
this.firstClick = true;
22+
this.startTime = 0;
23+
this.elapsedTime = 0;
24+
}
25+
26+
@Override
27+
public void update() {
28+
if (gameOver) return;
29+
30+
if (startTime > 0) {
31+
elapsedTime = System.currentTimeMillis() - startTime;
32+
}
33+
34+
if (field.isWin()) {
35+
calculateFinalScore();
36+
endGame();
37+
} else if (field.isLose()) {
38+
endGame();
39+
}
40+
}
41+
42+
public void reveal(int x, int y) {
43+
if (firstClick) {
44+
field.placeMines(x, y);
45+
startTime = System.currentTimeMillis();
46+
firstClick = false;
47+
}
48+
int revealedScore = field.reveal(x, y);
49+
score.addPoints(revealedScore);
50+
}
51+
52+
public void toggleFlag(int x, int y) {
53+
field.toggleFlag(x, y);
54+
}
55+
56+
private void calculateFinalScore() {
57+
int timeSeconds = (int) (elapsedTime / 1000);
58+
int maxTime = 600;
59+
int timeBonus = Math.max(0, (maxTime - timeSeconds) * 10);
60+
score.addPoints(timeBonus);
61+
score.addPoints(100);
62+
}
63+
64+
@Override
65+
public void setControl(Object control) {}
66+
67+
@Override
68+
public List<Object> getRenderData() {
69+
List<Object> data = new ArrayList<>();
70+
data.add(field);
71+
data.add(elapsedTime);
72+
return data;
73+
}
74+
75+
public MineField getField() {
76+
return field;
77+
}
78+
79+
public long getElapsedTime() {
80+
return elapsedTime;
81+
}
82+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package ru.ivannovr.games.minesweeper.entities;
2+
3+
import java.awt.Color;
4+
5+
public abstract class Cell {
6+
private final int x;
7+
private final int y;
8+
private boolean revealed;
9+
10+
public Cell(int x, int y) {
11+
this.x = x;
12+
this.y = y;
13+
this.revealed = false;
14+
}
15+
16+
public int getX() {
17+
return x;
18+
}
19+
20+
public int getY() {
21+
return y;
22+
}
23+
24+
public boolean isRevealed() {
25+
return revealed;
26+
}
27+
28+
public void reveal() {
29+
this.revealed = true;
30+
}
31+
32+
public abstract boolean isMine();
33+
public abstract boolean isFlag();
34+
public abstract Color getColor();
35+
public abstract String getDisplayText();
36+
public abstract int getScoreValue();
37+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package ru.ivannovr.games.minesweeper.entities;
2+
3+
import java.awt.Color;
4+
5+
public class Flag extends Cell {
6+
private final Cell underlyingCell;
7+
8+
public Flag(int x, int y, Cell underlyingCell) {
9+
super(x, y);
10+
this.underlyingCell = underlyingCell;
11+
}
12+
13+
public Cell removeFlag() {
14+
return underlyingCell;
15+
}
16+
17+
@Override
18+
public boolean isMine() {
19+
return underlyingCell.isMine();
20+
}
21+
22+
@Override
23+
public boolean isFlag() {
24+
return true;
25+
}
26+
27+
@Override
28+
public Color getColor() {
29+
return Color.RED;
30+
}
31+
32+
@Override
33+
public String getDisplayText() {
34+
return "F";
35+
}
36+
37+
@Override
38+
public int getScoreValue() {
39+
return 0;
40+
}
41+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ru.ivannovr.games.minesweeper.entities;
2+
3+
import java.awt.Color;
4+
5+
public class Mine extends Cell {
6+
public Mine(int x, int y) {
7+
super(x, y);
8+
}
9+
10+
@Override
11+
public boolean isMine() {
12+
return true;
13+
}
14+
15+
@Override
16+
public boolean isFlag() {
17+
return false;
18+
}
19+
20+
@Override
21+
public Color getColor() {
22+
return Color.RED;
23+
}
24+
25+
@Override
26+
public String getDisplayText() {
27+
return isRevealed() ? "*" : "";
28+
}
29+
30+
@Override
31+
public int getScoreValue() {
32+
return 0;
33+
}
34+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package ru.ivannovr.games.minesweeper.entities;
2+
3+
import java.awt.Color;
4+
5+
public class NumberCell extends Cell {
6+
private final int mineCount;
7+
8+
public NumberCell(int x, int y, int mineCount) {
9+
super(x, y);
10+
this.mineCount = mineCount;
11+
}
12+
13+
public int getMineCount() {
14+
return mineCount;
15+
}
16+
17+
@Override
18+
public boolean isMine() {
19+
return false;
20+
}
21+
22+
@Override
23+
public boolean isFlag() {
24+
return false;
25+
}
26+
27+
@Override
28+
public Color getColor() {
29+
return switch (mineCount) {
30+
case 1 -> Color.BLUE;
31+
case 2 -> Color.GREEN;
32+
case 3 -> Color.RED;
33+
case 4 -> Color.MAGENTA;
34+
case 5 -> Color.ORANGE;
35+
case 6 -> Color.CYAN;
36+
case 7 -> Color.PINK;
37+
case 8 -> Color.BLACK;
38+
default -> Color.GRAY;
39+
};
40+
}
41+
42+
@Override
43+
public String getDisplayText() {
44+
return isRevealed() && mineCount > 0 ? String.valueOf(mineCount) : "";
45+
}
46+
47+
@Override
48+
public int getScoreValue() {
49+
return isRevealed() ? 10 : 0;
50+
}
51+
}

0 commit comments

Comments
 (0)