├── LICENCE.txt ├── README.md ├── minesweeper.png └── src ├── com └── zetcode │ ├── Board.java │ └── Minesweeper.java └── resources ├── 0.png ├── 1.png ├── 10.png ├── 11.png ├── 12.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png └── 9.png /LICENCE.txt: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2023, Jan Bodnar 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java-Minesweeper-Game 2 | Java Minesweeper game source code 3 | 4 | https://zetcode.com/javagames/minesweeper/ 5 | 6 | 7 | ![Minesweeper game screenshot](minesweeper.png) 8 | -------------------------------------------------------------------------------- /minesweeper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/minesweeper.png -------------------------------------------------------------------------------- /src/com/zetcode/Board.java: -------------------------------------------------------------------------------- 1 | package com.zetcode; 2 | 3 | import java.awt.Dimension; 4 | import java.awt.Graphics; 5 | import java.awt.Image; 6 | import java.awt.event.MouseAdapter; 7 | import java.awt.event.MouseEvent; 8 | import java.util.Random; 9 | import javax.swing.ImageIcon; 10 | import javax.swing.JLabel; 11 | import javax.swing.JPanel; 12 | 13 | public class Board extends JPanel { 14 | 15 | private final int NUM_IMAGES = 13; 16 | private final int CELL_SIZE = 15; 17 | 18 | private final int COVER_FOR_CELL = 10; 19 | private final int MARK_FOR_CELL = 10; 20 | private final int EMPTY_CELL = 0; 21 | private final int MINE_CELL = 9; 22 | private final int COVERED_MINE_CELL = MINE_CELL + COVER_FOR_CELL; 23 | private final int MARKED_MINE_CELL = COVERED_MINE_CELL + MARK_FOR_CELL; 24 | 25 | private final int DRAW_MINE = 9; 26 | private final int DRAW_COVER = 10; 27 | private final int DRAW_MARK = 11; 28 | private final int DRAW_WRONG_MARK = 12; 29 | 30 | private final int N_MINES = 40; 31 | private final int N_ROWS = 16; 32 | private final int N_COLS = 16; 33 | 34 | private final int BOARD_WIDTH = N_COLS * CELL_SIZE + 1; 35 | private final int BOARD_HEIGHT = N_ROWS * CELL_SIZE + 1; 36 | 37 | private int[] field; 38 | private boolean inGame; 39 | private int minesLeft; 40 | private Image[] img; 41 | 42 | private int allCells; 43 | private final JLabel statusbar; 44 | 45 | public Board(JLabel statusbar) { 46 | 47 | this.statusbar = statusbar; 48 | initBoard(); 49 | } 50 | 51 | private void initBoard() { 52 | 53 | setPreferredSize(new Dimension(BOARD_WIDTH, BOARD_HEIGHT)); 54 | 55 | img = new Image[NUM_IMAGES]; 56 | 57 | for (int i = 0; i < NUM_IMAGES; i++) { 58 | 59 | var path = "src/resources/" + i + ".png"; 60 | img[i] = (new ImageIcon(path)).getImage(); 61 | } 62 | 63 | addMouseListener(new MinesAdapter()); 64 | newGame(); 65 | } 66 | 67 | private void newGame() { 68 | 69 | int cell; 70 | 71 | var random = new Random(); 72 | inGame = true; 73 | minesLeft = N_MINES; 74 | 75 | allCells = N_ROWS * N_COLS; 76 | field = new int[allCells]; 77 | 78 | for (int i = 0; i < allCells; i++) { 79 | 80 | field[i] = COVER_FOR_CELL; 81 | } 82 | 83 | statusbar.setText(Integer.toString(minesLeft)); 84 | 85 | int i = 0; 86 | 87 | while (i < N_MINES) { 88 | 89 | int position = (int) (allCells * random.nextDouble()); 90 | 91 | if ((position < allCells) 92 | && (field[position] != COVERED_MINE_CELL)) { 93 | 94 | int current_col = position % N_COLS; 95 | field[position] = COVERED_MINE_CELL; 96 | i++; 97 | 98 | if (current_col > 0) { 99 | cell = position - 1 - N_COLS; 100 | if (cell >= 0) { 101 | if (field[cell] != COVERED_MINE_CELL) { 102 | field[cell] += 1; 103 | } 104 | } 105 | cell = position - 1; 106 | if (cell >= 0) { 107 | if (field[cell] != COVERED_MINE_CELL) { 108 | field[cell] += 1; 109 | } 110 | } 111 | 112 | cell = position + N_COLS - 1; 113 | if (cell < allCells) { 114 | if (field[cell] != COVERED_MINE_CELL) { 115 | field[cell] += 1; 116 | } 117 | } 118 | } 119 | 120 | cell = position - N_COLS; 121 | if (cell >= 0) { 122 | if (field[cell] != COVERED_MINE_CELL) { 123 | field[cell] += 1; 124 | } 125 | } 126 | 127 | cell = position + N_COLS; 128 | if (cell < allCells) { 129 | if (field[cell] != COVERED_MINE_CELL) { 130 | field[cell] += 1; 131 | } 132 | } 133 | 134 | if (current_col < (N_COLS - 1)) { 135 | cell = position - N_COLS + 1; 136 | if (cell >= 0) { 137 | if (field[cell] != COVERED_MINE_CELL) { 138 | field[cell] += 1; 139 | } 140 | } 141 | cell = position + N_COLS + 1; 142 | if (cell < allCells) { 143 | if (field[cell] != COVERED_MINE_CELL) { 144 | field[cell] += 1; 145 | } 146 | } 147 | cell = position + 1; 148 | if (cell < allCells) { 149 | if (field[cell] != COVERED_MINE_CELL) { 150 | field[cell] += 1; 151 | } 152 | } 153 | } 154 | } 155 | } 156 | } 157 | 158 | private void find_empty_cells(int j) { 159 | 160 | int current_col = j % N_COLS; 161 | int cell; 162 | 163 | if (current_col > 0) { 164 | cell = j - N_COLS - 1; 165 | if (cell >= 0) { 166 | if (field[cell] > MINE_CELL) { 167 | field[cell] -= COVER_FOR_CELL; 168 | if (field[cell] == EMPTY_CELL) { 169 | find_empty_cells(cell); 170 | } 171 | } 172 | } 173 | 174 | cell = j - 1; 175 | if (cell >= 0) { 176 | if (field[cell] > MINE_CELL) { 177 | field[cell] -= COVER_FOR_CELL; 178 | if (field[cell] == EMPTY_CELL) { 179 | find_empty_cells(cell); 180 | } 181 | } 182 | } 183 | 184 | cell = j + N_COLS - 1; 185 | if (cell < allCells) { 186 | if (field[cell] > MINE_CELL) { 187 | field[cell] -= COVER_FOR_CELL; 188 | if (field[cell] == EMPTY_CELL) { 189 | find_empty_cells(cell); 190 | } 191 | } 192 | } 193 | } 194 | 195 | cell = j - N_COLS; 196 | if (cell >= 0) { 197 | if (field[cell] > MINE_CELL) { 198 | field[cell] -= COVER_FOR_CELL; 199 | if (field[cell] == EMPTY_CELL) { 200 | find_empty_cells(cell); 201 | } 202 | } 203 | } 204 | 205 | cell = j + N_COLS; 206 | if (cell < allCells) { 207 | if (field[cell] > MINE_CELL) { 208 | field[cell] -= COVER_FOR_CELL; 209 | if (field[cell] == EMPTY_CELL) { 210 | find_empty_cells(cell); 211 | } 212 | } 213 | } 214 | 215 | if (current_col < (N_COLS - 1)) { 216 | cell = j - N_COLS + 1; 217 | if (cell >= 0) { 218 | if (field[cell] > MINE_CELL) { 219 | field[cell] -= COVER_FOR_CELL; 220 | if (field[cell] == EMPTY_CELL) { 221 | find_empty_cells(cell); 222 | } 223 | } 224 | } 225 | 226 | cell = j + N_COLS + 1; 227 | if (cell < allCells) { 228 | if (field[cell] > MINE_CELL) { 229 | field[cell] -= COVER_FOR_CELL; 230 | if (field[cell] == EMPTY_CELL) { 231 | find_empty_cells(cell); 232 | } 233 | } 234 | } 235 | 236 | cell = j + 1; 237 | if (cell < allCells) { 238 | if (field[cell] > MINE_CELL) { 239 | field[cell] -= COVER_FOR_CELL; 240 | if (field[cell] == EMPTY_CELL) { 241 | find_empty_cells(cell); 242 | } 243 | } 244 | } 245 | } 246 | 247 | } 248 | 249 | @Override 250 | public void paintComponent(Graphics g) { 251 | 252 | int uncover = 0; 253 | 254 | for (int i = 0; i < N_ROWS; i++) { 255 | 256 | for (int j = 0; j < N_COLS; j++) { 257 | 258 | int cell = field[(i * N_COLS) + j]; 259 | 260 | if (inGame && cell == MINE_CELL) { 261 | 262 | inGame = false; 263 | } 264 | 265 | if (!inGame) { 266 | 267 | if (cell == COVERED_MINE_CELL) { 268 | cell = DRAW_MINE; 269 | } else if (cell == MARKED_MINE_CELL) { 270 | cell = DRAW_MARK; 271 | } else if (cell > COVERED_MINE_CELL) { 272 | cell = DRAW_WRONG_MARK; 273 | } else if (cell > MINE_CELL) { 274 | cell = DRAW_COVER; 275 | } 276 | 277 | } else { 278 | 279 | if (cell > COVERED_MINE_CELL) { 280 | cell = DRAW_MARK; 281 | } else if (cell > MINE_CELL) { 282 | cell = DRAW_COVER; 283 | uncover++; 284 | } 285 | } 286 | 287 | g.drawImage(img[cell], (j * CELL_SIZE), 288 | (i * CELL_SIZE), this); 289 | } 290 | } 291 | 292 | if (uncover == 0 && inGame) { 293 | 294 | inGame = false; 295 | statusbar.setText("Game won"); 296 | 297 | } else if (!inGame) { 298 | statusbar.setText("Game lost"); 299 | } 300 | } 301 | 302 | private class MinesAdapter extends MouseAdapter { 303 | 304 | @Override 305 | public void mousePressed(MouseEvent e) { 306 | 307 | int x = e.getX(); 308 | int y = e.getY(); 309 | 310 | int cCol = x / CELL_SIZE; 311 | int cRow = y / CELL_SIZE; 312 | 313 | boolean doRepaint = false; 314 | 315 | if (!inGame) { 316 | 317 | newGame(); 318 | repaint(); 319 | } 320 | 321 | if ((x < N_COLS * CELL_SIZE) && (y < N_ROWS * CELL_SIZE)) { 322 | 323 | if (e.getButton() == MouseEvent.BUTTON3) { 324 | 325 | if (field[(cRow * N_COLS) + cCol] > MINE_CELL) { 326 | 327 | doRepaint = true; 328 | 329 | if (field[(cRow * N_COLS) + cCol] <= COVERED_MINE_CELL) { 330 | 331 | if (minesLeft > 0) { 332 | field[(cRow * N_COLS) + cCol] += MARK_FOR_CELL; 333 | minesLeft--; 334 | String msg = Integer.toString(minesLeft); 335 | statusbar.setText(msg); 336 | } else { 337 | statusbar.setText("No marks left"); 338 | } 339 | } else { 340 | 341 | field[(cRow * N_COLS) + cCol] -= MARK_FOR_CELL; 342 | minesLeft++; 343 | String msg = Integer.toString(minesLeft); 344 | statusbar.setText(msg); 345 | } 346 | } 347 | 348 | } else { 349 | 350 | if (field[(cRow * N_COLS) + cCol] > COVERED_MINE_CELL) { 351 | 352 | return; 353 | } 354 | 355 | if ((field[(cRow * N_COLS) + cCol] > MINE_CELL) 356 | && (field[(cRow * N_COLS) + cCol] < MARKED_MINE_CELL)) { 357 | 358 | field[(cRow * N_COLS) + cCol] -= COVER_FOR_CELL; 359 | doRepaint = true; 360 | 361 | if (field[(cRow * N_COLS) + cCol] == MINE_CELL) { 362 | inGame = false; 363 | } 364 | 365 | if (field[(cRow * N_COLS) + cCol] == EMPTY_CELL) { 366 | find_empty_cells((cRow * N_COLS) + cCol); 367 | } 368 | } 369 | } 370 | 371 | if (doRepaint) { 372 | repaint(); 373 | } 374 | } 375 | } 376 | } 377 | } 378 | -------------------------------------------------------------------------------- /src/com/zetcode/Minesweeper.java: -------------------------------------------------------------------------------- 1 | package com.zetcode; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.EventQueue; 5 | import javax.swing.JFrame; 6 | import javax.swing.JLabel; 7 | 8 | /** 9 | * Java Minesweeper Game 10 | * 11 | * Author: Jan Bodnar 12 | * Website: http://zetcode.com 13 | */ 14 | 15 | public class Minesweeper extends JFrame { 16 | 17 | private JLabel statusbar; 18 | 19 | public Minesweeper() { 20 | 21 | initUI(); 22 | } 23 | 24 | private void initUI() { 25 | 26 | statusbar = new JLabel(""); 27 | add(statusbar, BorderLayout.SOUTH); 28 | 29 | add(new Board(statusbar)); 30 | 31 | setResizable(false); 32 | pack(); 33 | 34 | setTitle("Minesweeper"); 35 | setLocationRelativeTo(null); 36 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 37 | } 38 | 39 | public static void main(String[] args) { 40 | 41 | EventQueue.invokeLater(() -> { 42 | 43 | var ex = new Minesweeper(); 44 | ex.setVisible(true); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/resources/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/0.png -------------------------------------------------------------------------------- /src/resources/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/1.png -------------------------------------------------------------------------------- /src/resources/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/10.png -------------------------------------------------------------------------------- /src/resources/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/11.png -------------------------------------------------------------------------------- /src/resources/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/12.png -------------------------------------------------------------------------------- /src/resources/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/2.png -------------------------------------------------------------------------------- /src/resources/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/3.png -------------------------------------------------------------------------------- /src/resources/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/4.png -------------------------------------------------------------------------------- /src/resources/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/5.png -------------------------------------------------------------------------------- /src/resources/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/6.png -------------------------------------------------------------------------------- /src/resources/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/7.png -------------------------------------------------------------------------------- /src/resources/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/8.png -------------------------------------------------------------------------------- /src/resources/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janbodnar/Java-Minesweeper-Game/9c76a3453421b2d8fd3de6ee2dfe9985b79f5b85/src/resources/9.png --------------------------------------------------------------------------------