forked from biblelamp/JavaExercises
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGameMines.java
More file actions
200 lines (178 loc) · 7.49 KB
/
Copy pathGameMines.java
File metadata and controls
200 lines (178 loc) · 7.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/**
* Java. Classic Game Minesweeper
*
* @author Sergey Iryupin
* @version 0.3.2 dated September 23, 2016
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.util.Timer;
class GameMines extends JFrame {
final String TITLE_OF_PROGRAM = "Mines";
final String SIGN_OF_FLAG = "f";
final int BLOCK_SIZE = 30; // size of one block
final int FIELD_SIZE = 9; // in blocks
final int FIELD_DX = 6; // determined experimentally
final int FIELD_DY = 28 + 17;
final int START_LOCATION = 200;
final int MOUSE_BUTTON_LEFT = 1; // for mouse listener
final int MOUSE_BUTTON_RIGHT = 3;
final int NUMBER_OF_MINES = 10;
final int[] COLOR_OF_NUMBERS = {0x0000FF, 0x008000, 0xFF0000, 0x800000, 0x0};
Cell[][] field = new Cell[FIELD_SIZE][FIELD_SIZE];
Random random = new Random();
int countOpenedCells;
boolean youWon, bangMine; // flags for win and bang/fail
int bangX, bangY; // for fix the coordinates of the explosion
public static void main(String[] args) {
new GameMines();
}
GameMines() {
setTitle(TITLE_OF_PROGRAM);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(START_LOCATION, START_LOCATION, FIELD_SIZE * BLOCK_SIZE + FIELD_DX, FIELD_SIZE * BLOCK_SIZE + FIELD_DY);
setResizable(false);
final TimerLabel timeLabel = new TimerLabel();
timeLabel.setHorizontalAlignment(SwingConstants.CENTER);
final Canvas canvas = new Canvas();
canvas.setBackground(Color.white);
canvas.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
int x = e.getX()/BLOCK_SIZE;
int y = e.getY()/BLOCK_SIZE;
if (!bangMine && !youWon) {
if (e.getButton() == MOUSE_BUTTON_LEFT) // left button mouse
if (field[y][x].isNotOpen()) {
openCells(x, y);
youWon = countOpenedCells == FIELD_SIZE*FIELD_SIZE - NUMBER_OF_MINES; // winning check
if (bangMine) {
bangX = x;
bangY = y;
}
}
if (e.getButton() == MOUSE_BUTTON_RIGHT) field[y][x].inverseFlag(); // right button mouse
if (bangMine || youWon) timeLabel.stopTimer(); // game over
canvas.repaint();
}
}
});
add(BorderLayout.CENTER, canvas);
add(BorderLayout.SOUTH, timeLabel);
setVisible(true);
initField();
}
void openCells(int x, int y) { // recursive procedure of opening the cells
if (x < 0 || x > FIELD_SIZE - 1 || y < 0 || y > FIELD_SIZE - 1) return; // wrong coordinates
if (!field[y][x].isNotOpen()) return; // cell is already open
field[y][x].open();
if (field[y][x].getCountBomb() > 0 || bangMine) return; // the cell is not empty
for (int dx = -1; dx < 2; dx++)
for (int dy = -1; dy < 2; dy++) openCells(x + dx, y + dy);
}
void initField() { // initialization of the playing field
int x, y, countMines = 0;
// create cells for the field
for (x = 0; x < FIELD_SIZE; x++)
for (y = 0; y < FIELD_SIZE; y++)
field[y][x] = new Cell();
// to mine field
while (countMines < NUMBER_OF_MINES) {
do {
x = random.nextInt(FIELD_SIZE);
y = random.nextInt(FIELD_SIZE);
} while (field[y][x].isMined());
field[y][x].mine();
countMines++;
}
// to count dangerous neighbors
for (x = 0; x < FIELD_SIZE; x++)
for (y = 0; y < FIELD_SIZE; y++)
if (!field[y][x].isMined()) {
int count = 0;
for (int dx = -1; dx < 2; dx++)
for (int dy = -1; dy < 2; dy++) {
int nX = x + dx;
int nY = y + dy;
if (nX < 0 || nY < 0 || nX > FIELD_SIZE - 1 || nY > FIELD_SIZE - 1) {
nX = x;
nY = y;
}
count += (field[nY][nX].isMined()) ? 1 : 0;
}
field[y][x].setCountBomb(count);
}
}
class Cell { // playing field cell
private int countBombNear;
private boolean isOpen, isMine, isFlag;
void open() {
isOpen = true;
bangMine = isMine;
if (!isMine) countOpenedCells++;
}
void mine() { isMine = true; }
void setCountBomb(int count) { countBombNear = count; }
int getCountBomb() { return countBombNear; }
boolean isNotOpen() { return !isOpen; }
boolean isMined() { return isMine; }
void inverseFlag() { isFlag = !isFlag; }
void paintBomb(Graphics g, int x, int y, Color color) {
g.setColor(color);
g.fillRect(x*BLOCK_SIZE + 7, y*BLOCK_SIZE + 10, 18, 10);
g.fillRect(x*BLOCK_SIZE + 11, y*BLOCK_SIZE + 6, 10, 18);
g.fillRect(x*BLOCK_SIZE + 9, y*BLOCK_SIZE + 8, 14, 14);
g.setColor(Color.white);
g.fillRect(x*BLOCK_SIZE + 11, y*BLOCK_SIZE + 10, 4, 4);
}
void paintString(Graphics g, String str, int x, int y, Color color) {
g.setColor(color);
g.setFont(new Font("", Font.BOLD, BLOCK_SIZE));
g.drawString(str, x*BLOCK_SIZE + 8, y*BLOCK_SIZE + 26);
}
void paint(Graphics g, int x, int y) {
g.setColor(Color.lightGray);
g.drawRect(x*BLOCK_SIZE, y*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
if (!isOpen) {
if ((bangMine || youWon) && isMine) paintBomb(g, x, y, Color.black);
else {
g.setColor(Color.lightGray);
g.fill3DRect(x*BLOCK_SIZE, y*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, true);
if (isFlag) paintString(g, SIGN_OF_FLAG, x, y, Color.red);
}
} else
if (isMine) paintBomb(g, x, y, bangMine? Color.red : Color.black);
else
if (countBombNear > 0)
paintString(g, Integer.toString(countBombNear), x, y, new Color(COLOR_OF_NUMBERS[countBombNear - 1]));
}
}
class TimerLabel extends JLabel { // label with stopwatch
Timer timer = new Timer();
TimerLabel() { timer.scheduleAtFixedRate(timerTask, 0, 1000); } // TimerTask task, long delay, long period
TimerTask timerTask = new TimerTask() {
volatile int time;
Runnable refresher = new Runnable() {
public void run() {
TimerLabel.this.setText(String.format("%02d:%02d", time / 60, time % 60));
}
};
public void run() {
time++;
SwingUtilities.invokeLater(refresher);
}
};
void stopTimer() { timer.cancel(); }
}
class Canvas extends JPanel { // my canvas for painting
@Override
public void paint(Graphics g) {
super.paint(g);
for (int x = 0; x < FIELD_SIZE; x++)
for (int y = 0; y < FIELD_SIZE; y++) field[y][x].paint(g, x, y);
}
}
}