11
									
								
								.classpath
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<classpath>
 | 
				
			||||||
 | 
						<classpathentry kind="src" path="src"/>
 | 
				
			||||||
 | 
						<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
 | 
				
			||||||
 | 
							<attributes>
 | 
				
			||||||
 | 
								<attribute name="module" value="true"/>
 | 
				
			||||||
 | 
							</attributes>
 | 
				
			||||||
 | 
						</classpathentry>
 | 
				
			||||||
 | 
						<classpathentry kind="lib" path="res"/>
 | 
				
			||||||
 | 
						<classpathentry kind="output" path="bin"/>
 | 
				
			||||||
 | 
					</classpath>
 | 
				
			||||||
							
								
								
									
										57
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					.metadata
 | 
				
			||||||
 | 
					bin/
 | 
				
			||||||
 | 
					tmp/
 | 
				
			||||||
 | 
					*.tmp
 | 
				
			||||||
 | 
					*.bak
 | 
				
			||||||
 | 
					*.swp
 | 
				
			||||||
 | 
					*~.nib
 | 
				
			||||||
 | 
					local.properties
 | 
				
			||||||
 | 
					.settings/
 | 
				
			||||||
 | 
					.loadpath
 | 
				
			||||||
 | 
					.recommenders
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# External tool builders
 | 
				
			||||||
 | 
					.externalToolBuilders/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Locally stored "Eclipse launch configurations"
 | 
				
			||||||
 | 
					*.launch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PyDev specific (Python IDE for Eclipse)
 | 
				
			||||||
 | 
					*.pydevproject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# CDT-specific (C/C++ Development Tooling)
 | 
				
			||||||
 | 
					.cproject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# CDT- autotools
 | 
				
			||||||
 | 
					.autotools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Java annotation processor (APT)
 | 
				
			||||||
 | 
					.factorypath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PDT-specific (PHP Development Tools)
 | 
				
			||||||
 | 
					.buildpath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# sbteclipse plugin
 | 
				
			||||||
 | 
					.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Tern plugin
 | 
				
			||||||
 | 
					.tern-project
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TeXlipse plugin
 | 
				
			||||||
 | 
					.texlipse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# STS (Spring Tool Suite)
 | 
				
			||||||
 | 
					.springBeans
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Code Recommenders
 | 
				
			||||||
 | 
					.recommenders/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Annotation Processing
 | 
				
			||||||
 | 
					.apt_generated/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Scala IDE specific (Scala & Java development for Eclipse)
 | 
				
			||||||
 | 
					.cache-main
 | 
				
			||||||
 | 
					.scala_dependencies
 | 
				
			||||||
 | 
					.worksheet
 | 
				
			||||||
 | 
					/scores.ser
 | 
				
			||||||
 | 
					/scores old.ser
 | 
				
			||||||
							
								
								
									
										17
									
								
								.project
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<projectDescription>
 | 
				
			||||||
 | 
						<name>Minesweeper</name>
 | 
				
			||||||
 | 
						<comment></comment>
 | 
				
			||||||
 | 
						<projects>
 | 
				
			||||||
 | 
						</projects>
 | 
				
			||||||
 | 
						<buildSpec>
 | 
				
			||||||
 | 
							<buildCommand>
 | 
				
			||||||
 | 
								<name>org.eclipse.jdt.core.javabuilder</name>
 | 
				
			||||||
 | 
								<arguments>
 | 
				
			||||||
 | 
								</arguments>
 | 
				
			||||||
 | 
							</buildCommand>
 | 
				
			||||||
 | 
						</buildSpec>
 | 
				
			||||||
 | 
						<natures>
 | 
				
			||||||
 | 
							<nature>org.eclipse.jdt.core.javanature</nature>
 | 
				
			||||||
 | 
						</natures>
 | 
				
			||||||
 | 
					</projectDescription>
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								res/flag.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/mine.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 9.9 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/mine2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 8.9 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/mine3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/mine4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/smiley.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 8.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/smiley1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/smiley2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/smiley3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 28 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/tile.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/tile2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/tile3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/tile4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.9 KiB  | 
							
								
								
									
										258
									
								
								src/dev/kske/minesweeper/Board.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,258 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.awt.BasicStroke;
 | 
				
			||||||
 | 
					import java.awt.Color;
 | 
				
			||||||
 | 
					import java.awt.Dimension;
 | 
				
			||||||
 | 
					import java.awt.Font;
 | 
				
			||||||
 | 
					import java.awt.FontMetrics;
 | 
				
			||||||
 | 
					import java.awt.Graphics;
 | 
				
			||||||
 | 
					import java.awt.Graphics2D;
 | 
				
			||||||
 | 
					import java.awt.Image;
 | 
				
			||||||
 | 
					import java.awt.event.MouseAdapter;
 | 
				
			||||||
 | 
					import java.awt.event.MouseEvent;
 | 
				
			||||||
 | 
					import java.time.Duration;
 | 
				
			||||||
 | 
					import java.time.Instant;
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.HashMap;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.Random;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.JPanel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>Board.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>22.03.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Board extends JPanel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final long	serialVersionUID	= -279269871397851420L;
 | 
				
			||||||
 | 
						private static final int	tileSize			= 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static Map<String, Image> icons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private int			boardWidth, boardHeight;
 | 
				
			||||||
 | 
						private GameState	gameState;
 | 
				
			||||||
 | 
						private int			mines, activeTiles, flaggedTiles;
 | 
				
			||||||
 | 
						private Tile[][]	board;
 | 
				
			||||||
 | 
						private BoardConfig	boardConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private Instant start, finish;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private List<GameListener> listeners;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static {
 | 
				
			||||||
 | 
							icons = new HashMap<>();
 | 
				
			||||||
 | 
							final String[] names = { "mine2", "mine4", "tile", "tile3" };
 | 
				
			||||||
 | 
							for (String name : names) {
 | 
				
			||||||
 | 
								icons.put(name, TextureLoader.loadScaledImage(name, tileSize));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Board() {
 | 
				
			||||||
 | 
							// Not using a layout manager
 | 
				
			||||||
 | 
							super(null);
 | 
				
			||||||
 | 
							listeners = new ArrayList<>();
 | 
				
			||||||
 | 
							addMouseListener(new MouseAdapter() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public void mousePressed(MouseEvent evt) {
 | 
				
			||||||
 | 
									int		n		= evt.getX() / tileSize, m = evt.getY() / tileSize;
 | 
				
			||||||
 | 
									Tile	tile	= board[n][m];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (tile.isTouched() || gameState != GameState.ACTIVE) return;
 | 
				
			||||||
 | 
									switch (evt.getButton()) {
 | 
				
			||||||
 | 
										case MouseEvent.BUTTON1:
 | 
				
			||||||
 | 
											touchTile(n, m);
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										case MouseEvent.BUTTON3:
 | 
				
			||||||
 | 
											flagTile(n, m);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void init(BoardConfig config) {
 | 
				
			||||||
 | 
							boardConfig = config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							boardWidth	= config.width;
 | 
				
			||||||
 | 
							boardHeight	= config.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							setPreferredSize(new Dimension(config.width * tileSize, config.height * tileSize));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							gameState		= GameState.ACTIVE;
 | 
				
			||||||
 | 
							mines			= config.mines;
 | 
				
			||||||
 | 
							activeTiles		= boardWidth * boardHeight;
 | 
				
			||||||
 | 
							flaggedTiles	= 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Initialize board
 | 
				
			||||||
 | 
							board = new Tile[boardWidth][boardHeight];
 | 
				
			||||||
 | 
							for (int i = 0; i < boardWidth; i++)
 | 
				
			||||||
 | 
								for (int j = 0; j < boardHeight; j++)
 | 
				
			||||||
 | 
									board[i][j] = new Tile();
 | 
				
			||||||
 | 
							initMines();
 | 
				
			||||||
 | 
							repaint();
 | 
				
			||||||
 | 
							revalidate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							start = Instant.now();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void reset() {
 | 
				
			||||||
 | 
							init(boardConfig);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public void paintComponent(Graphics g) {
 | 
				
			||||||
 | 
							super.paintComponent(g);
 | 
				
			||||||
 | 
							for (int i = 0; i < boardWidth; i++)
 | 
				
			||||||
 | 
								for (int j = 0; j < boardHeight; j++) {
 | 
				
			||||||
 | 
									Tile	tile	= board[i][j];
 | 
				
			||||||
 | 
									int		x		= i * tileSize, y = j * tileSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Draw background
 | 
				
			||||||
 | 
									g.setColor(Color.gray);
 | 
				
			||||||
 | 
									g.fillRect(x, y, x + tileSize, y + tileSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Draw tile with normal mine
 | 
				
			||||||
 | 
									if (gameState == GameState.LOST && tile.isMine()) g.drawImage(icons.get("mine2"), x, y, this);
 | 
				
			||||||
 | 
									// Draw tile with diffused mine
 | 
				
			||||||
 | 
									else if (gameState == GameState.WON && tile.isMine()) g.drawImage(icons.get("mine4"), x, y, this);
 | 
				
			||||||
 | 
									else if (tile.isTouched()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Draw tile with mine
 | 
				
			||||||
 | 
										if (tile.isMine()) g.drawImage(icons.get("mine2"), x, y, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Draw flagged tile
 | 
				
			||||||
 | 
										else if (tile.isDrawSurroundingMines() && tile.getSurroundingMines() > 0) {
 | 
				
			||||||
 | 
											// Draw number of surrounding mines
 | 
				
			||||||
 | 
											String numStr = String.valueOf(tile.getSurroundingMines());
 | 
				
			||||||
 | 
											g.setFont(new Font("Arial", Font.BOLD, 18));
 | 
				
			||||||
 | 
											g.setColor(Color.red);
 | 
				
			||||||
 | 
											FontMetrics	fm	= g.getFontMetrics();
 | 
				
			||||||
 | 
											int			w	= fm.stringWidth(numStr), h = fm.getHeight();
 | 
				
			||||||
 | 
											g.drawString(numStr, x + (tileSize - w) / 2, y + (tileSize - h) / 2 + fm.getAscent());
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Draw flagged tile
 | 
				
			||||||
 | 
									else if (tile.isFlagged()) g.drawImage(icons.get("tile3"), x, y, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Draw normal tile
 | 
				
			||||||
 | 
									else g.drawImage(icons.get("tile"), x, y, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Draw grid
 | 
				
			||||||
 | 
									((Graphics2D) g).setStroke(new BasicStroke(2.0f));
 | 
				
			||||||
 | 
									g.setColor(Color.black);
 | 
				
			||||||
 | 
									g.drawRect(x, y, x + tileSize, y + tileSize);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void registerGameListener(GameListener listener) {
 | 
				
			||||||
 | 
							listeners.add(listener);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void notifyGameStateEvent(GameOverEvent evt) {
 | 
				
			||||||
 | 
							listeners.forEach(listener -> listener.onGameOverEvent(evt));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void notifyFlaggedTilesEvent(FlaggedTilesEvent evt) {
 | 
				
			||||||
 | 
							listeners.forEach(listener -> listener.onFlaggedTilesEvent(evt));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void repaintTile(int n, int m) {
 | 
				
			||||||
 | 
							repaint(n * tileSize, m * tileSize, (n + 1) * tileSize, (n + 1) * tileSize);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void initMines() {
 | 
				
			||||||
 | 
							int		remaining	= mines;
 | 
				
			||||||
 | 
							Random	random		= new Random();
 | 
				
			||||||
 | 
							while (remaining > 0) {
 | 
				
			||||||
 | 
								// Randomly select a tile
 | 
				
			||||||
 | 
								int	n	= random.nextInt(boardWidth);
 | 
				
			||||||
 | 
								int	m	= random.nextInt(boardHeight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Check if the selected tile already is a mine and is not touched
 | 
				
			||||||
 | 
								if (!board[n][m].isMine()) {
 | 
				
			||||||
 | 
									// Decrement the counter
 | 
				
			||||||
 | 
									remaining--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Place the mine
 | 
				
			||||||
 | 
									board[n][m].setMine(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Adjust surrounding mine counters
 | 
				
			||||||
 | 
									for (int i = Math.max(0, n - 1); i < Math.min(n + 2, board.length); i++)
 | 
				
			||||||
 | 
										for (int j = Math.max(0, m - 1); j < Math.min(m + 2, board[i].length); j++)
 | 
				
			||||||
 | 
											board[i][j].setSurroundingMines(board[i][j].getSurroundingMines() + 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void touchTile(int n, int m) {
 | 
				
			||||||
 | 
							Tile tile = board[n][m];
 | 
				
			||||||
 | 
							if (!tile.isTouched()) {
 | 
				
			||||||
 | 
								tile.setTouched(true);
 | 
				
			||||||
 | 
								activeTiles--;
 | 
				
			||||||
 | 
								tile.setDrawSurroundingMines(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Adjust the number of flagged tiles if the tile was flagged
 | 
				
			||||||
 | 
								if (tile.isFlagged()) {
 | 
				
			||||||
 | 
									tile.setFlagged(false);
 | 
				
			||||||
 | 
									flaggedTiles--;
 | 
				
			||||||
 | 
									notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Test if the game is won or lost
 | 
				
			||||||
 | 
								if (tile.isMine()) {
 | 
				
			||||||
 | 
									gameState = GameState.LOST;
 | 
				
			||||||
 | 
									onGameOver();
 | 
				
			||||||
 | 
								} else if (mines == activeTiles) {
 | 
				
			||||||
 | 
									gameState = GameState.WON;
 | 
				
			||||||
 | 
									onGameOver();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Touch surrounding tiles when there are zero surrounding mines
 | 
				
			||||||
 | 
								else if (tile.getSurroundingMines() == 0)
 | 
				
			||||||
 | 
									for (int i = Math.max(0, n - 1); i < Math.min(n + 2, board.length); i++)
 | 
				
			||||||
 | 
									for (int j = Math.max(0, m - 1); j < Math.min(m + 2, board[i].length); j++)
 | 
				
			||||||
 | 
									if (i != n || j != m) touchTile(i, j);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								repaintTile(n, m);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void flagTile(int n, int m) {
 | 
				
			||||||
 | 
							Tile tile = board[n][m];
 | 
				
			||||||
 | 
							if (!tile.isTouched()) {
 | 
				
			||||||
 | 
								if (tile.isFlagged()) {
 | 
				
			||||||
 | 
									tile.setFlagged(false);
 | 
				
			||||||
 | 
									flaggedTiles--;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									tile.setFlagged(true);
 | 
				
			||||||
 | 
									flaggedTiles++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								notifyFlaggedTilesEvent(new FlaggedTilesEvent(this, flaggedTiles));
 | 
				
			||||||
 | 
								repaintTile(n, m);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void onGameOver() {
 | 
				
			||||||
 | 
							finish = Instant.now();
 | 
				
			||||||
 | 
							int duration = (int) Duration.between(start, finish).toMillis();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							repaint();
 | 
				
			||||||
 | 
							GameOverEvent evt = new GameOverEvent(this, gameState, boardConfig, duration);
 | 
				
			||||||
 | 
							notifyGameStateEvent(evt);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public int getMines() { return mines; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public int getActiveTiles() { return activeTiles; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public int getFlaggedTiles() { return flaggedTiles; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public BoardConfig getBoardConfig() { return boardConfig; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/dev/kske/minesweeper/BoardConfig.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.Serializable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>BoardConfig.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>01.04.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class BoardConfig implements Serializable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final long serialVersionUID = -6083006887427383946L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static final BoardConfig EASY = new BoardConfig(8, 8, 10), MEDIUM = new BoardConfig(16, 16, 40),
 | 
				
			||||||
 | 
								HARD = new BoardConfig(30, 16, 99);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public final int width, height, mines;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public BoardConfig(int width, int height, int mines) {
 | 
				
			||||||
 | 
							this.width	= width;
 | 
				
			||||||
 | 
							this.height	= height;
 | 
				
			||||||
 | 
							this.mines	= mines;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										112
									
								
								src/dev/kske/minesweeper/CustomDialog.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.awt.BorderLayout;
 | 
				
			||||||
 | 
					import java.awt.FlowLayout;
 | 
				
			||||||
 | 
					import java.awt.Font;
 | 
				
			||||||
 | 
					import java.awt.Frame;
 | 
				
			||||||
 | 
					import java.awt.GridLayout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.JButton;
 | 
				
			||||||
 | 
					import javax.swing.JDialog;
 | 
				
			||||||
 | 
					import javax.swing.JLabel;
 | 
				
			||||||
 | 
					import javax.swing.JPanel;
 | 
				
			||||||
 | 
					import javax.swing.JSlider;
 | 
				
			||||||
 | 
					import javax.swing.border.EmptyBorder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>CustomDialog.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>03.04.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class CustomDialog extends JDialog {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final long	serialVersionUID	= -4019516811065781434L;
 | 
				
			||||||
 | 
						private final JPanel		mcontentPanel		= new JPanel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private BoardConfig result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Create the dialog.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public CustomDialog(Frame owner) {
 | 
				
			||||||
 | 
							super(owner, ModalityType.APPLICATION_MODAL);
 | 
				
			||||||
 | 
							setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							setBounds(100, 100, 450, 300);
 | 
				
			||||||
 | 
							getContentPane().setLayout(new BorderLayout());
 | 
				
			||||||
 | 
							mcontentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
 | 
				
			||||||
 | 
							getContentPane().add(mcontentPanel, BorderLayout.CENTER);
 | 
				
			||||||
 | 
							mcontentPanel.setLayout(new GridLayout(0, 3, 0, 0));
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								JLabel lblBoardWidthText = new JLabel("Board Width:");
 | 
				
			||||||
 | 
								lblBoardWidthText.setFont(new Font("Tahoma", Font.PLAIN, 14));
 | 
				
			||||||
 | 
								mcontentPanel.add(lblBoardWidthText);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							JLabel lblBoardWidth = new JLabel("");
 | 
				
			||||||
 | 
							lblBoardWidth.setFont(new Font("Tahoma", Font.PLAIN, 14));
 | 
				
			||||||
 | 
							mcontentPanel.add(lblBoardWidth);
 | 
				
			||||||
 | 
							JSlider sliderBoardWidth = new JSlider();
 | 
				
			||||||
 | 
							sliderBoardWidth.addChangeListener((evt) -> lblBoardWidth.setText(String.valueOf(sliderBoardWidth.getValue())));
 | 
				
			||||||
 | 
							sliderBoardWidth.setValue(16);
 | 
				
			||||||
 | 
							sliderBoardWidth.setMinimum(2);
 | 
				
			||||||
 | 
							sliderBoardWidth.setMaximum(30);
 | 
				
			||||||
 | 
							mcontentPanel.add(sliderBoardWidth);
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								JLabel lblBoardHeightText = new JLabel("Board Height:");
 | 
				
			||||||
 | 
								lblBoardHeightText.setFont(new Font("Tahoma", Font.PLAIN, 14));
 | 
				
			||||||
 | 
								mcontentPanel.add(lblBoardHeightText);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							JLabel lblBoardHeight = new JLabel("");
 | 
				
			||||||
 | 
							lblBoardHeight.setFont(new Font("Tahoma", Font.PLAIN, 14));
 | 
				
			||||||
 | 
							mcontentPanel.add(lblBoardHeight);
 | 
				
			||||||
 | 
							JSlider sliderBoardHeight = new JSlider();
 | 
				
			||||||
 | 
							sliderBoardHeight
 | 
				
			||||||
 | 
								.addChangeListener((evt) -> lblBoardHeight.setText(String.valueOf(sliderBoardHeight.getValue())));
 | 
				
			||||||
 | 
							sliderBoardHeight.setValue(16);
 | 
				
			||||||
 | 
							sliderBoardHeight.setMaximum(30);
 | 
				
			||||||
 | 
							sliderBoardHeight.setMinimum(2);
 | 
				
			||||||
 | 
							mcontentPanel.add(sliderBoardHeight);
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								JLabel lblNumberOfMinesText = new JLabel("Number of Mines:");
 | 
				
			||||||
 | 
								lblNumberOfMinesText.setFont(new Font("Tahoma", Font.PLAIN, 14));
 | 
				
			||||||
 | 
								mcontentPanel.add(lblNumberOfMinesText);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							JLabel lblNumMines = new JLabel("");
 | 
				
			||||||
 | 
							lblNumMines.setFont(new Font("Tahoma", Font.PLAIN, 14));
 | 
				
			||||||
 | 
							mcontentPanel.add(lblNumMines);
 | 
				
			||||||
 | 
							JSlider sliderNumMines = new JSlider();
 | 
				
			||||||
 | 
							sliderNumMines.addChangeListener((evt) -> lblNumMines.setText(String.valueOf(sliderNumMines.getValue())));
 | 
				
			||||||
 | 
							sliderNumMines.setValue(16);
 | 
				
			||||||
 | 
							sliderNumMines.setMinimum(2);
 | 
				
			||||||
 | 
							sliderNumMines.setMaximum(200);
 | 
				
			||||||
 | 
							mcontentPanel.add(sliderNumMines);
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								JPanel buttonPane = new JPanel();
 | 
				
			||||||
 | 
								buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
 | 
				
			||||||
 | 
								getContentPane().add(buttonPane, BorderLayout.SOUTH);
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									JButton okButton = new JButton("Start Game");
 | 
				
			||||||
 | 
									okButton.setActionCommand("OK");
 | 
				
			||||||
 | 
									okButton.addActionListener((evt) -> {
 | 
				
			||||||
 | 
										result = new BoardConfig(sliderBoardWidth.getValue(), sliderBoardHeight.getValue(),
 | 
				
			||||||
 | 
												sliderNumMines.getValue());
 | 
				
			||||||
 | 
										dispose();
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
									buttonPane.add(okButton);
 | 
				
			||||||
 | 
									getRootPane().setDefaultButton(okButton);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									JButton cancelButton = new JButton("Cancel");
 | 
				
			||||||
 | 
									cancelButton.setActionCommand("Cancel");
 | 
				
			||||||
 | 
									cancelButton.addActionListener((evt) -> dispose());
 | 
				
			||||||
 | 
									buttonPane.add(cancelButton);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public BoardConfig showDialog() {
 | 
				
			||||||
 | 
							setVisible(true);
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/dev/kske/minesweeper/FlaggedTilesEvent.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.EventObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>FlaggedTilesEvent.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>03.04.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class FlaggedTilesEvent extends EventObject {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final long serialVersionUID = -5809857531886339312L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private final Board	board;
 | 
				
			||||||
 | 
						private final int	flagged;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public FlaggedTilesEvent(Object source, int flagged) {
 | 
				
			||||||
 | 
							super(source);
 | 
				
			||||||
 | 
							board			= (Board) source;
 | 
				
			||||||
 | 
							this.flagged	= flagged;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Board getBoard() { return board; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public int getFlagged() { return flagged; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/dev/kske/minesweeper/GameListener.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>GameStateListener.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>03.04.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public interface GameListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void onGameOverEvent(GameOverEvent evt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void onFlaggedTilesEvent(FlaggedTilesEvent evt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/dev/kske/minesweeper/GameOverEvent.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.EventObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>GameOverEvent.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>03.04.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class GameOverEvent extends EventObject {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final long serialVersionUID = -966111253980213845L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private final Board			board;
 | 
				
			||||||
 | 
						private final GameState		gameState;
 | 
				
			||||||
 | 
						private final BoardConfig	boardConfig;
 | 
				
			||||||
 | 
						private final int			duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public GameOverEvent(Object source, GameState gameState, BoardConfig boardConfig, int duration) {
 | 
				
			||||||
 | 
							super(source);
 | 
				
			||||||
 | 
							board				= (Board) source;
 | 
				
			||||||
 | 
							this.gameState		= gameState;
 | 
				
			||||||
 | 
							this.boardConfig	= boardConfig;
 | 
				
			||||||
 | 
							this.duration		= duration;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Board getBoard() { return board; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public GameState getGameState() { return gameState; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public BoardConfig getBoardConfig() { return boardConfig; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public int getDuration() { return duration; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/dev/kske/minesweeper/GameState.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>GameState.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>22.03.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public enum GameState {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ACTIVE, WON, LOST;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										221
									
								
								src/dev/kske/minesweeper/Minesweeper.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,221 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static dev.kske.minesweeper.BoardConfig.EASY;
 | 
				
			||||||
 | 
					import static dev.kske.minesweeper.BoardConfig.HARD;
 | 
				
			||||||
 | 
					import static dev.kske.minesweeper.BoardConfig.MEDIUM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.awt.BorderLayout;
 | 
				
			||||||
 | 
					import java.awt.EventQueue;
 | 
				
			||||||
 | 
					import java.awt.event.KeyEvent;
 | 
				
			||||||
 | 
					import java.awt.event.WindowAdapter;
 | 
				
			||||||
 | 
					import java.awt.event.WindowEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.JButton;
 | 
				
			||||||
 | 
					import javax.swing.JFrame;
 | 
				
			||||||
 | 
					import javax.swing.JLabel;
 | 
				
			||||||
 | 
					import javax.swing.JMenu;
 | 
				
			||||||
 | 
					import javax.swing.JMenuBar;
 | 
				
			||||||
 | 
					import javax.swing.JMenuItem;
 | 
				
			||||||
 | 
					import javax.swing.JOptionPane;
 | 
				
			||||||
 | 
					import javax.swing.JPanel;
 | 
				
			||||||
 | 
					import javax.swing.SwingConstants;
 | 
				
			||||||
 | 
					import javax.swing.Timer;
 | 
				
			||||||
 | 
					import javax.swing.UIManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>Minesweeper.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>21.03.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Minesweeper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final String VERSION = "1.0";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private JFrame mframe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private Board			board;
 | 
				
			||||||
 | 
						private Timer			timer;
 | 
				
			||||||
 | 
						private int				gameTime;
 | 
				
			||||||
 | 
						private ScoreManager	scoreManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Launch the application.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static void main(String[] args) {
 | 
				
			||||||
 | 
							EventQueue.invokeLater(() -> {
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									Minesweeper window = new Minesweeper();
 | 
				
			||||||
 | 
									window.mframe.setVisible(true);
 | 
				
			||||||
 | 
								} catch (Exception e) {
 | 
				
			||||||
 | 
									e.printStackTrace();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Create the application.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @wbp.parser.entryPoint
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Minesweeper() {
 | 
				
			||||||
 | 
							initialize();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Initialize the contents of the frame.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private void initialize() {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								UIManager.setLookAndFeel(UIManager.createLookAndFeel("Nimbus"));
 | 
				
			||||||
 | 
							} catch (Exception ex) {
 | 
				
			||||||
 | 
								ex.printStackTrace();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mframe = new JFrame();
 | 
				
			||||||
 | 
							mframe.addWindowListener(new WindowAdapter() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public void windowClosing(WindowEvent e) {
 | 
				
			||||||
 | 
									scoreManager.saveScores();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							mframe.setResizable(false);
 | 
				
			||||||
 | 
							mframe.setTitle("Minesweeper");
 | 
				
			||||||
 | 
							mframe.setBounds(100, 100, 359, 86);
 | 
				
			||||||
 | 
							mframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							createMenuBar();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							board = new Board();
 | 
				
			||||||
 | 
							board.init(EASY);
 | 
				
			||||||
 | 
							mframe.getContentPane().setLayout(new BorderLayout(0, 0));
 | 
				
			||||||
 | 
							mframe.getContentPane().add(board, BorderLayout.CENTER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							JPanel headerPanel = new JPanel();
 | 
				
			||||||
 | 
							mframe.getContentPane().add(headerPanel, BorderLayout.NORTH);
 | 
				
			||||||
 | 
							headerPanel.setLayout(new BorderLayout(0, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							JButton btnRestart = new JButton("Restart");
 | 
				
			||||||
 | 
							btnRestart.setHorizontalAlignment(SwingConstants.RIGHT);
 | 
				
			||||||
 | 
							headerPanel.add(btnRestart, BorderLayout.EAST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							JPanel panel = new JPanel();
 | 
				
			||||||
 | 
							headerPanel.add(panel, BorderLayout.WEST);
 | 
				
			||||||
 | 
							panel.setLayout(new BorderLayout(0, 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							JLabel lblTime = new JLabel("Time:");
 | 
				
			||||||
 | 
							panel.add(lblTime, BorderLayout.NORTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							timer = new Timer(1000, e -> lblTime.setText("Time: " + gameTime++ + "s"));
 | 
				
			||||||
 | 
							timer.setRepeats(true);
 | 
				
			||||||
 | 
							timer.setInitialDelay(0);
 | 
				
			||||||
 | 
							timer.setCoalesce(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							JLabel lblRemainingMines = new JLabel("Remaining Mines: " + EASY.mines);
 | 
				
			||||||
 | 
							panel.add(lblRemainingMines, BorderLayout.SOUTH);
 | 
				
			||||||
 | 
							lblRemainingMines.setHorizontalAlignment(SwingConstants.LEFT);
 | 
				
			||||||
 | 
							btnRestart.addActionListener((evt) -> { board.reset(); gameTime = 0; timer.restart(); });
 | 
				
			||||||
 | 
							mframe.pack();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							board.registerGameListener(new GameListener() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public void onGameOverEvent(GameOverEvent evt) {
 | 
				
			||||||
 | 
									timer.stop();
 | 
				
			||||||
 | 
									switch (evt.getGameState()) {
 | 
				
			||||||
 | 
										case LOST:
 | 
				
			||||||
 | 
											JOptionPane.showMessageDialog(mframe, "Game lost!");
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										case WON:
 | 
				
			||||||
 | 
											JOptionPane.showMessageDialog(mframe, "Game won!");
 | 
				
			||||||
 | 
											scoreManager.addScore(evt);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public void onFlaggedTilesEvent(FlaggedTilesEvent evt) {
 | 
				
			||||||
 | 
									lblRemainingMines.setText("Remaining Mines: " + (evt.getBoard().getMines() - evt.getFlagged()));
 | 
				
			||||||
 | 
									mframe.pack();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							scoreManager = new ScoreManager();
 | 
				
			||||||
 | 
							scoreManager.loadScores();
 | 
				
			||||||
 | 
							timer.start();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void createMenuBar() {
 | 
				
			||||||
 | 
							var menubar = new JMenuBar();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var gameMenu = new JMenu("Game");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var	easyMenuItem	= new JMenuItem("Easy");
 | 
				
			||||||
 | 
								var	mediumMenuItem	= new JMenuItem("Medium");
 | 
				
			||||||
 | 
								var	hardMenuItem	= new JMenuItem("Hard");
 | 
				
			||||||
 | 
								var	customMenuItem	= new JMenuItem("Custom");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								gameMenu.setMnemonic(KeyEvent.VK_G);
 | 
				
			||||||
 | 
								easyMenuItem.setMnemonic(KeyEvent.VK_E);
 | 
				
			||||||
 | 
								mediumMenuItem.setMnemonic(KeyEvent.VK_M);
 | 
				
			||||||
 | 
								hardMenuItem.setMnemonic(KeyEvent.VK_H);
 | 
				
			||||||
 | 
								customMenuItem.setMnemonic(KeyEvent.VK_C);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								easyMenuItem.addActionListener((evt) -> initGame(EASY));
 | 
				
			||||||
 | 
								mediumMenuItem.addActionListener((evt) -> initGame(MEDIUM));
 | 
				
			||||||
 | 
								hardMenuItem.addActionListener((evt) -> initGame(HARD));
 | 
				
			||||||
 | 
								customMenuItem.addActionListener((evt) -> {
 | 
				
			||||||
 | 
									BoardConfig cfg = new CustomDialog(mframe).showDialog();
 | 
				
			||||||
 | 
									if (cfg != null) initGame(cfg);
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								gameMenu.add(easyMenuItem);
 | 
				
			||||||
 | 
								gameMenu.add(mediumMenuItem);
 | 
				
			||||||
 | 
								gameMenu.add(hardMenuItem);
 | 
				
			||||||
 | 
								gameMenu.addSeparator();
 | 
				
			||||||
 | 
								gameMenu.add(customMenuItem);
 | 
				
			||||||
 | 
								menubar.add(gameMenu);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var highscoreMenu = new JMenu("Highscores");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var	easyMenuItem	= new JMenuItem("Easy");
 | 
				
			||||||
 | 
								var	mediumMenuItem	= new JMenuItem("Medium");
 | 
				
			||||||
 | 
								var	hardMenuItem	= new JMenuItem("Hard");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								highscoreMenu.setMnemonic(KeyEvent.VK_H);
 | 
				
			||||||
 | 
								easyMenuItem.setMnemonic(KeyEvent.VK_E);
 | 
				
			||||||
 | 
								mediumMenuItem.setMnemonic(KeyEvent.VK_M);
 | 
				
			||||||
 | 
								hardMenuItem.setMnemonic(KeyEvent.VK_H);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								easyMenuItem.addActionListener((evt) -> scoreManager.displayEasy());
 | 
				
			||||||
 | 
								mediumMenuItem.addActionListener((evt) -> scoreManager.displayMedium());
 | 
				
			||||||
 | 
								hardMenuItem.addActionListener((evt) -> scoreManager.displayHard());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								highscoreMenu.add(easyMenuItem);
 | 
				
			||||||
 | 
								highscoreMenu.add(mediumMenuItem);
 | 
				
			||||||
 | 
								highscoreMenu.add(hardMenuItem);
 | 
				
			||||||
 | 
								menubar.add(highscoreMenu);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var aboutMenuItem = new JMenuItem("About");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								aboutMenuItem.addActionListener((evt) -> JOptionPane.showMessageDialog(board,
 | 
				
			||||||
 | 
										"Minesweeper version " + VERSION + "\nby Kai S. K. Engelbart"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								menubar.add(aboutMenuItem);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mframe.setJMenuBar(menubar);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void initGame(BoardConfig config) {
 | 
				
			||||||
 | 
							board.init(config);
 | 
				
			||||||
 | 
							gameTime = 0;
 | 
				
			||||||
 | 
							timer.restart();
 | 
				
			||||||
 | 
							mframe.pack();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								src/dev/kske/minesweeper/Score.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.Serializable;
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>Score.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>16.04.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Score implements Comparable<Score>, Serializable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final long serialVersionUID = 3384023296639779740L;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						private final String		name;
 | 
				
			||||||
 | 
						private final int			duration;
 | 
				
			||||||
 | 
						private final Date			date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Score(String name, int duration, Date date) {
 | 
				
			||||||
 | 
							this.name			= name;
 | 
				
			||||||
 | 
							this.duration		= duration;
 | 
				
			||||||
 | 
							this.date			= date;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public String getName() { return name; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public int getDuration() { return duration; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Date getDate() { return date; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int compareTo(Score other) {
 | 
				
			||||||
 | 
							return Integer.compare(duration, other.duration);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										60
									
								
								src/dev/kske/minesweeper/ScoreDialog.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.awt.BorderLayout;
 | 
				
			||||||
 | 
					import java.awt.Font;
 | 
				
			||||||
 | 
					import java.text.SimpleDateFormat;
 | 
				
			||||||
 | 
					import java.util.Iterator;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.JDialog;
 | 
				
			||||||
 | 
					import javax.swing.JLabel;
 | 
				
			||||||
 | 
					import javax.swing.JPanel;
 | 
				
			||||||
 | 
					import javax.swing.JTable;
 | 
				
			||||||
 | 
					import javax.swing.SwingConstants;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>ScoreDialog.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>16.04.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ScoreDialog extends JDialog {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final long serialVersionUID = 3637727047056147815L;
 | 
				
			||||||
 | 
						private JTable mtable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Create the dialog.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public ScoreDialog(List<Score> scores, String boardConfigName) {
 | 
				
			||||||
 | 
							setModal(true);
 | 
				
			||||||
 | 
							setBounds(100, 100, 450, 300);
 | 
				
			||||||
 | 
							setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 | 
				
			||||||
 | 
							getContentPane().setLayout(new BorderLayout(0, 0));
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							String[]		columnNames	= { "Place", "Name", "Duration", "Date" };
 | 
				
			||||||
 | 
							String[][]		data		= new String[scores.size()][4];
 | 
				
			||||||
 | 
							Iterator<Score> iter = scores.iterator();
 | 
				
			||||||
 | 
							for(int i = 0; i < data.length; i++) {
 | 
				
			||||||
 | 
								Score s = iter.next();
 | 
				
			||||||
 | 
								data[i][0]	= String.valueOf(i + 1);
 | 
				
			||||||
 | 
								data[i][1]	= s.getName();
 | 
				
			||||||
 | 
								data[i][2]	= String.valueOf(s.getDuration());
 | 
				
			||||||
 | 
								data[i][3]	= new SimpleDateFormat().format(s.getDate());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							mtable = new JTable(data, columnNames);
 | 
				
			||||||
 | 
							getContentPane().add(mtable);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							JPanel panel = new JPanel();
 | 
				
			||||||
 | 
							getContentPane().add(panel, BorderLayout.NORTH);
 | 
				
			||||||
 | 
							panel.setLayout(new BorderLayout(0, 0));
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							panel.add(mtable.getTableHeader(), BorderLayout.CENTER);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							JLabel lblHighscores = new JLabel("Highscores: " + boardConfigName);
 | 
				
			||||||
 | 
							panel.add(lblHighscores, BorderLayout.NORTH);
 | 
				
			||||||
 | 
							lblHighscores.setFont(new Font("Tahoma", Font.BOLD, 16));
 | 
				
			||||||
 | 
							lblHighscores.setHorizontalAlignment(SwingConstants.CENTER);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										101
									
								
								src/dev/kske/minesweeper/ScoreManager.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static dev.kske.minesweeper.BoardConfig.EASY;
 | 
				
			||||||
 | 
					import static dev.kske.minesweeper.BoardConfig.HARD;
 | 
				
			||||||
 | 
					import static dev.kske.minesweeper.BoardConfig.MEDIUM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.FileInputStream;
 | 
				
			||||||
 | 
					import java.io.FileNotFoundException;
 | 
				
			||||||
 | 
					import java.io.FileOutputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.ObjectInputStream;
 | 
				
			||||||
 | 
					import java.io.ObjectOutputStream;
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.swing.JOptionPane;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>ScoreManager.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>15.05.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ScoreManager {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private List<Score>		easy, medium, hard;
 | 
				
			||||||
 | 
						private final String	scoresFile	= "scores.ser";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ScoreManager() {
 | 
				
			||||||
 | 
							easy	= new ArrayList<>();
 | 
				
			||||||
 | 
							medium	= new ArrayList<>();
 | 
				
			||||||
 | 
							hard	= new ArrayList<>();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void addScore(GameOverEvent evt) {
 | 
				
			||||||
 | 
							// Determine board config
 | 
				
			||||||
 | 
							BoardConfig config = evt.getBoardConfig();
 | 
				
			||||||
 | 
							if (config == EASY && (easy.size() < 10 || easy.get(9).getDuration() > evt.getDuration())) {
 | 
				
			||||||
 | 
								String	name	= JOptionPane.showInputDialog("Please enter your name");
 | 
				
			||||||
 | 
								Score	score	= new Score(name, evt.getDuration(), new Date());
 | 
				
			||||||
 | 
								sortInsert(score, easy);
 | 
				
			||||||
 | 
							} else if (config == MEDIUM && (medium.size() < 10 || medium.get(9).getDuration() > evt.getDuration())) {
 | 
				
			||||||
 | 
								String	name	= JOptionPane.showInputDialog("Please enter your name");
 | 
				
			||||||
 | 
								Score	score	= new Score(name, evt.getDuration(), new Date());
 | 
				
			||||||
 | 
								sortInsert(score, medium);
 | 
				
			||||||
 | 
							} else if (config == HARD && (hard.size() < 10 || hard.get(9).getDuration() > evt.getDuration())) {
 | 
				
			||||||
 | 
								String	name	= JOptionPane.showInputDialog("Please enter your name");
 | 
				
			||||||
 | 
								Score	score	= new Score(name, evt.getDuration(), new Date());
 | 
				
			||||||
 | 
								sortInsert(score, hard);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void sortInsert(Score score, List<Score> list) {
 | 
				
			||||||
 | 
							for (int i = 0; i < list.size(); i++)
 | 
				
			||||||
 | 
								if (list.get(i).getDuration() > score.getDuration()) {
 | 
				
			||||||
 | 
									list.add(i, score);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							list.add(score);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void displayEasy() {
 | 
				
			||||||
 | 
							new ScoreDialog(easy, "Easy").setVisible(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void displayMedium() {
 | 
				
			||||||
 | 
							new ScoreDialog(medium, "Medium").setVisible(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void displayHard() {
 | 
				
			||||||
 | 
							new ScoreDialog(hard, "Hard").setVisible(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@SuppressWarnings("unchecked")
 | 
				
			||||||
 | 
						public void loadScores() {
 | 
				
			||||||
 | 
							try (var in = new ObjectInputStream(new FileInputStream(scoresFile))) {
 | 
				
			||||||
 | 
								Object obj = in.readObject();
 | 
				
			||||||
 | 
								if (obj instanceof ArrayList<?>) easy = (ArrayList<Score>) obj;
 | 
				
			||||||
 | 
								obj = in.readObject();
 | 
				
			||||||
 | 
								if (obj instanceof ArrayList<?>) medium = (ArrayList<Score>) obj;
 | 
				
			||||||
 | 
								obj = in.readObject();
 | 
				
			||||||
 | 
								if (obj instanceof ArrayList<?>) hard = (ArrayList<Score>) obj;
 | 
				
			||||||
 | 
								else throw new IOException("Serialized object has the wrong class.");
 | 
				
			||||||
 | 
							} catch (FileNotFoundException ex) {} catch (IOException | ClassNotFoundException ex) {
 | 
				
			||||||
 | 
								JOptionPane.showMessageDialog(null,
 | 
				
			||||||
 | 
										"The score file seems to be corrupted. It will be replaced when closing the game.", "File error",
 | 
				
			||||||
 | 
										JOptionPane.ERROR_MESSAGE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void saveScores() {
 | 
				
			||||||
 | 
							try (var out = new ObjectOutputStream(new FileOutputStream(scoresFile))) {
 | 
				
			||||||
 | 
								out.writeObject(easy);
 | 
				
			||||||
 | 
								out.writeObject(medium);
 | 
				
			||||||
 | 
								out.writeObject(hard);
 | 
				
			||||||
 | 
							} catch (IOException ex) {
 | 
				
			||||||
 | 
								ex.printStackTrace();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/dev/kske/minesweeper/TextureLoader.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.awt.Image;
 | 
				
			||||||
 | 
					import java.awt.image.BufferedImage;
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.imageio.ImageIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>TextureLoader.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>25.03.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class TextureLoader {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private TextureLoader() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Loads an image from the resource folder and scales it to a square.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param name  The name of the file without the PNG extension in the resource
 | 
				
			||||||
 | 
						 *              folder
 | 
				
			||||||
 | 
						 * @param scale The side length of the square to which the image will be scaled
 | 
				
			||||||
 | 
						 * @return The scaled image
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Image loadScaledImage(String name, int scale) {
 | 
				
			||||||
 | 
							BufferedImage in = null;
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								in = ImageIO.read(new File("res" + File.separator + name + ".png"));
 | 
				
			||||||
 | 
							} catch (IOException e) {
 | 
				
			||||||
 | 
								e.printStackTrace();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Image scaled = in.getScaledInstance(scale, scale, Image.SCALE_SMOOTH);
 | 
				
			||||||
 | 
							return scaled;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/dev/kske/minesweeper/Tile.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					package dev.kske.minesweeper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Project: <strong>Minesweeper</strong><br>
 | 
				
			||||||
 | 
					 * File: <strong>Tile.java</strong><br>
 | 
				
			||||||
 | 
					 * Created: <strong>22.03.2019</strong><br>
 | 
				
			||||||
 | 
					 * Author: <strong>Kai S. K. Engelbart</strong>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Tile {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private boolean mine, flagged, touched;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private boolean	drawSurroundingMines;
 | 
				
			||||||
 | 
						private int		surroundingMines;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Tile() {
 | 
				
			||||||
 | 
							mine = flagged = touched = drawSurroundingMines = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							surroundingMines = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public boolean isMine() { return mine; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void setMine(boolean mine) { this.mine = mine; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public boolean isFlagged() { return flagged; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void setFlagged(boolean flagged) { this.flagged = flagged; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public boolean isTouched() { return touched; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void setTouched(boolean touched) { this.touched = touched; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public boolean isDrawSurroundingMines() { return drawSurroundingMines; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void setDrawSurroundingMines(boolean drawSurroundingMines) {
 | 
				
			||||||
 | 
							this.drawSurroundingMines = drawSurroundingMines;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public int getSurroundingMines() { return surroundingMines; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void setSurroundingMines(int surroundingMines) { this.surroundingMines = surroundingMines; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								src/module-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					module Minesweeper {
 | 
				
			||||||
 | 
						requires java.desktop;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||