The pictures needed for the game are placed at the end, and the pictures needed for the game are taken , The game is divided into three levels , Three types of difficulties: ordinary and simple . The game code is divided into seven categories . I put the pictures needed by the game at the end .
 The screenshot of the game is as follows :
 The game is divided into three levels 
 This is a simple level 
 
 This is an ordinary level 
 This is the most difficult level 
 
 Step on the thunder and lose directly , In the upper left corner is the number of mines . The upper right corner is the timing function , In the middle is the start button. After failure, click to restore the level and continue to break through the level .
 The test class code is as follows , This class is mainly used to run and call other classes .
package com.sxt; import javax.swing.*; import java.awt.*; import 
java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class 
GameWin extends JFrame { int wigth = 2 * GameUtil.OFFSET + GameUtil.MAP_W * 
GameUtil.SQUARE_LENGTH; int height = 4 * GameUtil.OFFSET + GameUtil.MAP_H * 
GameUtil.SQUARE_LENGTH; Image offScreenImage = null; MapBottom mapBottom = new 
MapBottom(); MapTop mapTop = new MapTop(); GameSelect gameSelect = new 
GameSelect(); // Start ,f Not started ,t start  boolean begin=false; void launch(){ 
GameUtil.START_TIME=System.currentTimeMillis(); this.setVisible(true); 
if(GameUtil.state==3){ this.setSize(500,500); }else { 
this.setSize(wigth,height); } this.setLocationRelativeTo(null); 
this.setTitle(" flower ~ Mine sweeping game "); this.setDefaultCloseOperation(EXIT_ON_CLOSE); // Mouse event  
this.addMouseListener(new MouseAdapter() { @Override public void 
mouseClicked(MouseEvent e) { super.mouseClicked(e); switch (GameUtil.state){ 
case 0 : if(e.getButton()==1){ GameUtil.MOUSE_X = e.getX(); GameUtil.MOUSE_Y = 
e.getY(); GameUtil.LEFT = true; } if(e.getButton()==3) { GameUtil.MOUSE_X = 
e.getX(); GameUtil.MOUSE_Y = e.getY(); GameUtil.RIGHT = true; } case 1 : case 2 
: if(e.getButton()==1){ if(e.getX()>GameUtil.OFFSET + 
GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2) && e.getX()<GameUtil.OFFSET + 
GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2) + GameUtil.SQUARE_LENGTH && 
e.getY()>GameUtil.OFFSET && e.getY()<GameUtil.OFFSET+GameUtil.SQUARE_LENGTH){ 
mapBottom.reGame(); mapTop.reGame(); GameUtil.FLAG_NUM=0; 
GameUtil.START_TIME=System.currentTimeMillis(); GameUtil.state=0; } } 
if(e.getButton()==2){ GameUtil.state=3; begin=true; } break; case 3: 
if(e.getButton()==1){ GameUtil.MOUSE_X = e.getX(); GameUtil.MOUSE_Y = e.getY(); 
begin = gameSelect.hard(); } break; default: } } }); while (true){ repaint(); 
begin(); try { Thread.sleep(40); } catch (InterruptedException e) { 
e.printStackTrace(); } } } void begin(){ if(begin){ begin=false; 
gameSelect.hard(GameUtil.level); dispose(); GameWin gameWin = new GameWin(); 
GameUtil.START_TIME = System.currentTimeMillis(); GameUtil.FLAG_NUM=0; 
mapBottom.reGame(); mapTop.reGame(); gameWin.launch(); } } @Override public 
void paint(Graphics g) { if(GameUtil.state==3){ g.setColor(Color.white); 
g.fillRect(0,0,500,500); gameSelect.paintSelf(g); }else { offScreenImage = 
this.createImage(wigth, height); Graphics gImage = 
offScreenImage.getGraphics(); // Set background color  gImage.setColor(Color.orange); 
gImage.fillRect(0, 0, wigth, height); mapBottom.paintSelf(gImage); 
mapTop.paintSelf(gImage); g.drawImage(offScreenImage, 0, 0, null); } } public 
static void main(String[] args) { GameWin gameWin = new GameWin(); 
gameWin.launch(); } } 
 Game map class 
package com.sxt; import java.awt.*; /** *  Bottom map  *  Draw game related components  */ public class 
MapBottom { BottomRay bottomRay = new BottomRay(); BottomNum bottomNum = new 
BottomNum(); { bottomRay.newRay(); bottomNum.newNum(); } // Reset game  void reGame(){ 
for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H 
; j++) { GameUtil.DATA_BOTTOM[i][j]=0; } } bottomRay.newRay(); 
bottomNum.newNum(); } // Drawing method  void paintSelf(Graphics g){ g.setColor(Color.red); 
// Draw a vertical line  for (int i = 0; i <= GameUtil.MAP_W; i++) { g.drawLine(GameUtil.OFFSET + 
i * GameUtil.SQUARE_LENGTH, 3*GameUtil.OFFSET, 
GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH, 
3*GameUtil.OFFSET+GameUtil.MAP_H*GameUtil.SQUARE_LENGTH); } // Draw a horizontal line  for (int i = 
0; i <=GameUtil.MAP_H; i++){ g.drawLine(GameUtil.OFFSET, 
3*GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH, 
GameUtil.OFFSET+GameUtil.MAP_W*GameUtil.SQUARE_LENGTH, 
3*GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH); } for (int i = 1; i <= 
GameUtil.MAP_W ; i++) { for (int j = 1; j <= GameUtil.MAP_H; j++) { // thunder  if 
(GameUtil.DATA_BOTTOM[i][j] == -1) { g.drawImage(GameUtil.lei, GameUtil.OFFSET 
+ (i - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.OFFSET * 3 + (j - 1) * 
GameUtil.SQUARE_LENGTH + 1, GameUtil.SQUARE_LENGTH - 2, GameUtil.SQUARE_LENGTH 
- 2, null); } // number  if (GameUtil.DATA_BOTTOM[i][j] >=0) { 
g.drawImage(GameUtil.images[GameUtil.DATA_BOTTOM[i][j]], GameUtil.OFFSET + (i - 
1) * GameUtil.SQUARE_LENGTH + 15, GameUtil.OFFSET * 3 + (j - 1) * 
GameUtil.SQUARE_LENGTH + 5, null); } } } // Draw numbers   Residual mine number , count down  
GameUtil.drawWord(g,""+(GameUtil.RAY_MAX-GameUtil.FLAG_NUM), GameUtil.OFFSET, 
2*GameUtil.OFFSET,30,Color.red); 
GameUtil.drawWord(g,""+(GameUtil.END_TIME-GameUtil.START_TIME)/1000, 
GameUtil.OFFSET + GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W-1), 
2*GameUtil.OFFSET,30,Color.red); switch (GameUtil.state){ case 0: 
GameUtil.END_TIME=System.currentTimeMillis(); g.drawImage(GameUtil.face, 
GameUtil.OFFSET + GameUtil.SQUARE_LENGTH * (GameUtil.MAP_W/2), GameUtil.OFFSET, 
null); break; case 1: g.drawImage(GameUtil.win, GameUtil.OFFSET + 
GameUtil.SQUARE_LENGTH * (GameUtil.MAP_W/2), GameUtil.OFFSET, null); break; 
case 2: g.drawImage(GameUtil.over, GameUtil.OFFSET + GameUtil.SQUARE_LENGTH * 
(GameUtil.MAP_W/2), GameUtil.OFFSET, null); break; default: } } } 
 Underlying data class 
package com.sxt; /** *  Underlying digital class  */ public class BottomNum { void newNum() { for 
(int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; 
j++) { if(GameUtil.DATA_BOTTOM[i][j]==-1){ for (int k = i-1; k <=i+1 ; k++) { 
for (int l = j-1; l <=j+1 ; l++) { if(GameUtil.DATA_BOTTOM[k][l]>=0){ 
GameUtil.DATA_BOTTOM[k][l]++; } } } } } } } } 
 Tools are as follows :
package com.sxt; import java.awt.*; /** *  Tool class  *  Storing static parameters  *  Tool method  */ public class 
GameUtil { // Number of Mines  static int RAY_MAX = 100; // Width of map  static int MAP_W = 36; 
// Height of map  static int MAP_H = 17; // Minefield offset  static int OFFSET = 45; // Lattice side length  static int 
SQUARE_LENGTH = 50; // Number of flags inserted  static int FLAG_NUM = 0; // Mouse related  // coordinate  static int 
MOUSE_X; static int MOUSE_Y; // state  static boolean LEFT = false; static boolean 
RIGHT = false; // Game status  0  Indicates in the game  1  victory  2  fail  3  Difficulty selection  static int state = 3; // Game difficulty  
static int level; // count down  static long START_TIME; static long END_TIME; // Underlying element  -1 
 thunder  0  empty  1-8  Represents the corresponding number  static int[][] DATA_BOTTOM = new int[MAP_W+2][MAP_H+2]; // top-level element   
-1  No coverage  0  cover  1  Flag insertion  2  Error flag  static int[][] DATA_TOP = new int[MAP_W+2][MAP_H+2]; 
// Load Images   static Image lei = Toolkit.getDefaultToolkit().getImage("imgs/lei.png"); 
static Image top = Toolkit.getDefaultToolkit().getImage("imgs/top.gif"); static 
Image flag = Toolkit.getDefaultToolkit().getImage("imgs/flag.gif"); static 
Image noflag = Toolkit.getDefaultToolkit().getImage("imgs/noflag.png"); static 
Image face = Toolkit.getDefaultToolkit().getImage("imgs/face.png"); static 
Image over = Toolkit.getDefaultToolkit().getImage("imgs/over.png"); static 
Image win = Toolkit.getDefaultToolkit().getImage("imgs/win.png"); static 
Image[] images = new Image[9]; static { for (int i = 1; i <=8 ; i++) { 
images[i] = Toolkit.getDefaultToolkit().getImage("imgs/num/"+i+".png"); } } 
static void drawWord(Graphics g,String str,int x,int y,int size,Color color){ 
g.setColor(color); g.setFont(new Font(" Imitation Song Dynasty ",Font.BOLD,size)); 
g.drawString(str,x,y); } } 
 Difficulty selection 
package com.sxt; import java.awt.*; /** *  Difficulty selection  */ public class GameSelect { 
// Judge whether to click the difficulty  boolean hard(){ if(GameUtil.MOUSE_X>100&&GameUtil.MOUSE_X<400){ 
if(GameUtil.MOUSE_Y>50&&GameUtil.MOUSE_Y<150){ GameUtil.level=1; 
GameUtil.state=0; return true; } 
if(GameUtil.MOUSE_Y>200&&GameUtil.MOUSE_Y<300){ GameUtil.level=2; 
GameUtil.state=0; return true; } 
if(GameUtil.MOUSE_Y>350&&GameUtil.MOUSE_Y<450){ GameUtil.level=3; 
GameUtil.state=0; return true; } } return false; } void paintSelf(Graphics g){ 
g.setColor(Color.black); g.drawRect(100,50,300,100); 
GameUtil.drawWord(g," simple ",220,100,30,Color.black); g.drawRect(100,200,300,100); 
GameUtil.drawWord(g," ordinary ",220,250,30,Color.black); g.drawRect(100,350,300,100); 
GameUtil.drawWord(g," difficulty ",220,400,30,Color.black); } void hard(int level){ 
switch (level){ case 1: GameUtil.RAY_MAX = 10; GameUtil.MAP_W = 9; 
GameUtil.MAP_H = 9; break; case 2: GameUtil.RAY_MAX = 40; GameUtil.MAP_W = 16; 
GameUtil.MAP_H = 16; break; case 3: GameUtil.RAY_MAX = 99; GameUtil.MAP_W = 30; 
GameUtil.MAP_H = 16; break; default: } } } 
 Top level map class :
package com.sxt; import java.awt.*; /** *  Top level map class  *  Draw top-level components  *  Judgment logic  */ public 
class MapTop { // Grid position  int temp_x; int temp_y; // Reset game  void reGame(){ for (int i 
= 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { 
GameUtil.DATA_TOP[i][j]=0; } } } // Judgment logic  void logic(){ temp_x=0; temp_y=0; 
if(GameUtil.MOUSE_X>GameUtil.OFFSET && GameUtil.MOUSE_Y>3*GameUtil.OFFSET){ 
temp_x = (GameUtil.MOUSE_X - GameUtil.OFFSET)/GameUtil.SQUARE_LENGTH+1; temp_y 
= (GameUtil.MOUSE_Y - GameUtil.OFFSET * 3)/GameUtil.SQUARE_LENGTH+1; } 
if(temp_x>=1 && temp_x<=GameUtil.MAP_W && temp_y>=1 && temp_y<=GameUtil.MAP_H){ 
if(GameUtil.LEFT){ // cover , Then open it  if(GameUtil.DATA_TOP[temp_x][temp_y]==0){ 
GameUtil.DATA_TOP[temp_x][temp_y]=-1; } spaceOpen(temp_x,temp_y); 
GameUtil.LEFT=false; } if(GameUtil.RIGHT){ // Flag if covered  
if(GameUtil.DATA_TOP[temp_x][temp_y]==0){ GameUtil.DATA_TOP[temp_x][temp_y]=1; 
GameUtil.FLAG_NUM++; } // Flag insertion cancels  else if(GameUtil.DATA_TOP[temp_x][temp_y]==1){ 
GameUtil.DATA_TOP[temp_x][temp_y]=0; GameUtil.FLAG_NUM--; } else 
if(GameUtil.DATA_TOP[temp_x][temp_y]==-1){ numOpen(temp_x,temp_y); } 
GameUtil.RIGHT=false; } } boom(); victory(); } // Digital Flip  void numOpen(int x,int 
y){ // Record flag number  int count=0; if(GameUtil.DATA_BOTTOM[x][y]>0){ for (int i = x-1; i 
<=x+1 ; i++) { for (int j = y-1; j <=y+1 ; j++) { 
if(GameUtil.DATA_TOP[i][j]==1){ count++; } } } 
if(count==GameUtil.DATA_BOTTOM[x][y]){ for (int i = x-1; i <=x+1 ; i++) { for 
(int j = y-1; j <=y+1 ; j++) { if(GameUtil.DATA_TOP[i][j]!=1){ 
GameUtil.DATA_TOP[i][j]=-1; } // It must be in the minefield  
if(i>=1&&j>=1&&i<=GameUtil.MAP_W&&j<=GameUtil.MAP_H){ spaceOpen(i,j); } } } } } 
} // Failure judgment  t  Indicates failure  f  Not failed  boolean boom(){ if(GameUtil.FLAG_NUM==GameUtil.RAY_MAX){ 
for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H 
; j++) { if(GameUtil.DATA_TOP[i][j]==0){ GameUtil.DATA_TOP[i][j]=-1; } } } } 
for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H 
; j++) { if(GameUtil.DATA_BOTTOM[i][j]==-1&&GameUtil.DATA_TOP[i][j]==-1){ 
GameUtil.state = 2; seeBoom(); return true; } } } return false; } // Failure display  void 
seeBoom(){ for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j 
<=GameUtil.MAP_H ; j++) { // The bottom is ray , The top floor is not a flag , display  
if(GameUtil.DATA_BOTTOM[i][j]==-1&&GameUtil.DATA_TOP[i][j]!=1){ 
GameUtil.DATA_TOP[i][j]=-1; } // The bottom is not ray , The top floor is the flag , Display error flag  
if(GameUtil.DATA_BOTTOM[i][j]!=-1&&GameUtil.DATA_TOP[i][j]==1){ 
GameUtil.DATA_TOP[i][j]=2; } } } } // Victory judgment  t  Show victory  f  No victory  boolean victory(){ 
// Count the number of unopened cells  int count=0; for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j 
= 1; j <=GameUtil.MAP_H ; j++) { if(GameUtil.DATA_TOP[i][j]!=-1){ count++; } } 
} if(count==GameUtil.RAY_MAX){ GameUtil.state=1; for (int i = 1; i 
<=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { // Not opened , Become a flag  
if(GameUtil.DATA_TOP[i][j]==0){ GameUtil.DATA_TOP[i][j]=1; } } } return true; } 
return false; } // Open space  void spaceOpen(int x,int y){ 
if(GameUtil.DATA_BOTTOM[x][y]==0){ for (int i = x-1; i <=x+1 ; i++) { for (int 
j = y-1; j <=y+1 ; j++) { // cover , Only recursion  if(GameUtil.DATA_TOP[i][j]!=-1){ 
if(GameUtil.DATA_TOP[i][j]==1){GameUtil.FLAG_NUM--;} 
GameUtil.DATA_TOP[i][j]=-1; // It must be in the minefield  
if(i>=1&&j>=1&&i<=GameUtil.MAP_W&&j<=GameUtil.MAP_H){ spaceOpen(i,j); } } } } } 
} // Drawing method  void paintSelf(Graphics g){ logic(); for (int i = 1; i <= 
GameUtil.MAP_W ; i++) { for (int j = 1; j <= GameUtil.MAP_H; j++) { // cover  if 
(GameUtil.DATA_TOP[i][j] == 0) { g.drawImage(GameUtil.top, GameUtil.OFFSET + (i 
- 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.OFFSET * 3 + (j - 1) * 
GameUtil.SQUARE_LENGTH + 1, GameUtil.SQUARE_LENGTH - 2, GameUtil.SQUARE_LENGTH 
- 2, null); } // Flag insertion  if (GameUtil.DATA_TOP[i][j] == 1) { 
g.drawImage(GameUtil.flag, GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 
1, GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 1, 
GameUtil.SQUARE_LENGTH - 2, GameUtil.SQUARE_LENGTH - 2, null); } // Error flag  if 
(GameUtil.DATA_TOP[i][j] == 2) { g.drawImage(GameUtil.noflag, GameUtil.OFFSET + 
(i - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.OFFSET * 3 + (j - 1) * 
GameUtil.SQUARE_LENGTH + 1, GameUtil.SQUARE_LENGTH - 2, GameUtil.SQUARE_LENGTH 
- 2, null); } } } } } 
 Initialize mine class 
package com.sxt; /** *  Initialize mine  */ public class BottomRay { // Storage coordinates  static int[] 
rays = new int[GameUtil.RAY_MAX*2]; // Landmine coordinates  int x,y; // Place  T  Indicates that it can be placed  F  Not placeable  
boolean isPlace = true; // Generating mine  void newRay() { for (int i = 0; i < 
GameUtil.RAY_MAX*2 ; i=i+2) { x= (int) (Math.random()*GameUtil.MAP_W +1);//1-12 
y= (int) (Math.random()*GameUtil.MAP_H +1);//1-12 // Determine whether the coordinates exist  for (int j = 0; j 
< i ; j=j+2) { if(x==rays[j] && y==rays[j+1]){ i=i-2; isPlace = false; break; } 
} // Put coordinates into array  if(isPlace){ rays[i]=x; rays[i+1]=y; } isPlace = true; } for (int i 
= 0; i < GameUtil.RAY_MAX*2; i=i+2) { 
GameUtil.DATA_BOTTOM[rays[i]][rays[i+1]]=-1; } } } 
 The props are shown below :
 
  
 
 
 
Technology