Click here to Skip to main content
15,867,330 members
Articles / Programming Languages / C#
Article

Minesweeper Solver is My Solution to Solving the Expert Level in the Minesweeper Game

Rate me:
Please Sign up or sign in to vote.
4.88/5 (13 votes)
15 Jun 2007CPOL5 min read 109.2K   1.5K   39   27
I had trouble solving the expert Minesweeper level, so I wrote a program to do it for me.
Screenshot - minesweepersolver

Introduction

Have you ever played the Minesweeper game? I didn't start playing until a few weeks ago. I found the beginner and intermediate levels not too difficult, but the expert level was a real pain. So I decided to write an app that would solve the Minesweeper game for me.

Background

While playing the Minesweeper game, I found on the expert level I was often making silly mistakes. Usually after finding 40 or 50 mines I would get mentally tired and mark something as a bomb or click somewhere that was a bomb. Anyway, I found it really difficult to get down to the last few bombs. Then when I finally would be able to get there, I would always have to guess. So I figured I would write a program that could solve the Minesweeper game for me and at least it wouldn't make the same mistakes I was making.

The Game

If you have never played the Minesweeper game, here is a quick intro to it. Depending on the level you are on, you have a certain number of squares. The goal is to find all the mines and mark them as mines without clicking on one. When you start the game you have no idea where the mines are, so you randomly left click a few squares. As you click you start to see numbers. The numbers relate to the number of mines that surround the number on the eight touching sides. When you think you know where a mine is you right click to flag it as a mine. You try to find all the mines as quickly as possible. The game is timed so you try to get the best time you can to get on the best times list.

The Problem

Being a human, I make silly mistakes when I get tired or just don't pay close enough attention. I just could not beat the expert level. So instead of playing more and more of the Minesweeper game, I wrote a program that could solve it for me.

The Solution

First I would like to note that I used these two articles to help out with the Windows messaging and screen print part of the program.

First I make sure the Minesweeper program is running. Then I get the handle to the program and force it to the forefront and put it in the upper left hand corner of the screen. This is important so I have an idea of where I need to be sending mouse clicks. Base off the screen width of the Minesweeper game I make an assumption on which level the user is playing at. Next I use the screen print of the Minesweeper game to figure out which boxes I have found. I use the colors found in the boxes to help me figure out which number I have clicked, etc. Next I wrote some code to help me figure out what all the surrounding boxes are to the current box I am looking at. Then I pass all this info into TheBrain method. I was surprised to find how simple the brain method ended up being:

C#
private Boolean TheBrain(SquareType currPos, SquareType top, 
  SquareType topRight, SquareType right, SquareType bottomRight, 
  SquareType bottom, SquareType bottomLeft, SquareType left, 
  SquareType topLeft, int x, int y)
{
 Boolean ret = true;
 int bombCnt = GetCounts(SquareType.Bomb,top,topRight,right,
                bottomRight,bottom,bottomLeft,left,topLeft);
 int unKnownsCnt = GetCounts(SquareType.Unknown, top, topRight, 
                            right, bottomRight, bottom, bottomLeft, left, topLeft);
 if (unKnownsCnt == 0)
 {
   TheSquaresPos[x, y].Complete = true;
    return ret;
  }
  int maxBombs = 0;
  String errorNumber = String.Empty;
  switch (currPos)
  {
    case SquareType.One :
      maxBombs = 1;
      errorNumber = "One";
      break;
    case SquareType.Two :
     maxBombs = 2;
     errorNumber = "Two";
     break;
    case SquareType.Three :
     maxBombs = 3;
     errorNumber = "Three";
     break;
    case SquareType.Four :
     maxBombs = 4;
     errorNumber = "Four";
     break;
    case SquareType.Five :
     maxBombs = 5;
     errorNumber = "Five";
     break;
    case SquareType.Six :
      maxBombs = 6;
      errorNumber = "Six";
      break;
     case SquareType.Seven :
       maxBombs = 7;
       errorNumber = "Seven";
        break;
    } //switch

   if (bombCnt == maxBombs)
   {
    //Any Unknowns should be checked
    ProcessUnknowns(top, topRight, right, bottomRight, bottom, 
         bottomLeft, left, topLeft, x, y);
    }
   else if (maxBombs >= 7 && bombCnt == 7 && unKnownsCnt == (maxBombs - 7))
   {
     RightClickUnknowns(top, topRight, right, bottomRight, bottom, 
         bottomLeft, left, topLeft, x, y);

    }
   else if (maxBombs >= 6 && bombCnt == 6 && unKnownsCnt == (maxBombs - 6))
   {
     RightClickUnknowns(top, topRight, right, bottomRight, bottom,
         bottomLeft, left, topLeft, x, y);

    }
   else if (maxBombs >= 5 && bombCnt == 5 && unKnownsCnt == (maxBombs - 5))
   {
     RightClickUnknowns(top, topRight, right, bottomRight, bottom, 
         bottomLeft, left, topLeft, x, y);

    }
   else if (maxBombs >= 4 && bombCnt == 4 && unKnownsCnt == (maxBombs - 4))
   {
     RightClickUnknowns(top, topRight, right, bottomRight, bottom, 
         bottomLeft, left, topLeft, x, y);

    }
   else if (maxBombs >= 3 && bombCnt == 3 && unKnownsCnt == (maxBombs - 3))
   {
     RightClickUnknowns(top, topRight, right, bottomRight, bottom, 
         bottomLeft, left, topLeft, x, y);
    }
   else if (maxBombs >= 2 && bombCnt == 2 && unKnownsCnt == (maxBombs -2))
   {
      RightClickUnknowns(top, topRight, right, bottomRight, bottom, 
          bottomLeft, left, topLeft, x, y);
    }
   else if (bombCnt == 1 && unKnownsCnt == (maxBombs - 1))
   {
      RightClickUnknowns(top, topRight, right, bottomRight, bottom, 
          bottomLeft, left, topLeft, x, y);
    }
   else if (bombCnt == 0 && unKnownsCnt == maxBombs)
   {
     RightClickUnknowns(top, topRight, right, bottomRight, bottom,
       bottomLeft, left, topLeft, x, y);
    }
   else if (bombCnt > maxBombs)
   {
     toolStripStatusLabel1.Text = "Error on "+errorNumber+" processing too many bombs!";
     ret = false;
    }
   return ret;
  }

Once the brain method made a decision on what should be done, I would either send right mouse clicks or left mouse clicks. When starting a game or when the program would get stuck, I would randomly pick the next box to click.

The Best Times from Minesweeper Solver

Best times

Note these times are legitimate. That is how long it took the program to solve the game. I found some interesting things that really sped up the time that it took the program to solve the game. First it appears the more RAM memory and CPU the Minesweeper solver has, the faster it will run. Second, I stopped reading all the pixels in the squares. I started to read only half of them. Third, I started to scan the board left to right on the first pass and then right to left on the second pass. This switching of the way I was scanning the board also helped with the speed in which the game could be solved.

Some Odds and Ends

I found that some computers and monitors would pick slightly different colors for the same colors. So I ended up putting those into the app.config file so they can be easily changed. I also found that screen resolution could affect the starting position of boxes. So when trying to get this to run on your PC, you might need to tweak the app.config file values a little before it will work. I have a check 1 button that will check on box in the grid. You can use this to figure out if you need to modify the app.config values.

Known Issues

For some reason, the Minesweeper solver program will mark a bomb twice which switches that square to a question mark. When the app randomly picks a square to click it is random, some intelligence could be programmed into it.

Conclusion

I had some time on my hands, although it only took me two days to write the core of this code. Still it was a fun exercise and helped me improve my programming skills. I found that the Minesweeper solver would solve the beginner level almost every time. It would solve the intermediate level some of the time. You guessed it. It had trouble with the expert level as well. It might solve the expert level once in a hundred tries.

History

  • 15th June, 2007: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
I started my programmer career over 26 years ago doing COBOL and SAS on a MVS mainframe. It didn't take long for me to move into windows programming. I started my windows programming in Delphi (Pascal) with a Microsoft SQL server back end. I started working with vb.net when the beta 2 came out in 2001. After spending most of my programming life as a windows programmer I started to check out asp.net in 2004. I achieved my MCSD.net in April 2005. I have done a lot of MS SQL database stuff. I have a lot of experience with Window Service and Web services as well. I spent three years as a consultant programing in C#. I really enjoyed it and found the switch between vb.net and C# to be mostly syntax. In my current position I am programming in C# working on WPF and MSSql database stuff. Lately I have been using VS2019.

On a personal note I am a born again Christian, if anyone has any questions about what it means to have a right relationship with God or if you have questions about who Jesus Christ is, send me an e-mail. ben.kubicek[at]netzero[dot]com You need to replace the [at] with @ and [dot] with . for the email to work. My relationship with God gives purpose and meaning to my life.

Comments and Discussions

 
GeneralRe: WWJD? Pin
Jasmine250121-Jun-07 6:26
Jasmine250121-Jun-07 6:26 
GeneralRe: WWJD? Pin
kubben21-Jun-07 6:47
kubben21-Jun-07 6:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.