An exclusive gaming industry community targeted
to, and designed for Professionals, Businesses
and Students in the sectors and industries
of Gaming, New Media and the Web, all closely
related with it's Business and Industry.
A Rich content driven service including articles,
contributed discussion, news, reviews, networking, downloads,
and debate.
We strive to cater for cultural influencers,
technology decision makers, early adopters and business leaders in the gaming industry.
A medium to share your or contribute your ideas,
experiences, questions and point of view or network
with other colleagues here at iVirtua Community.
I wrote a very simple program to read Minesweeper's memory anddisplay a grid showing where the bombs are. I used OllyDbg fordisassembly and reversing and CheatEngine for quickly finding knownvalues in memory.
During this process, I found out that Minesweeper CHEATS, onlyspawns about half the bombs, and moves bombs mid-game. (Sometimes towhere you are clicking, sometimes it will move a bomb that you clickon.) Regardless, I consider this project a success. During this process, I found that Minesweeper will sometimes assist youand move bombs away from where you are clicking on. Originally, Ithought that Minesweeper was only "spawning" about half of the bombs,but as it turns out I misunderstood the way minefield was representedin memory and all bombs are generated at the beginning of the game and not first click or any later clicks.
My error was in thinking that minefield was stored in a 2-dimensional array (ie: minefield[x][y] = FLAGS) where max(x) (and max(y)) are the size of the grid (ie: 9x9 on Beginner) but as xumiiz on Reddit pointed out:
His program is buggy. It's not reading the grid incorrectly - it's a constant width of 32 bytes, but a window from thetop left is taken for the actual size of the playing field.
So, first bugfix to his source:
for(DWORD grid_loc = 0; grid_loc < grid_height * grid_width; grid_loc++) {
should be:
for(DWORD grid_loc = 0; grid_loc < grid_height * 32; grid_loc += ((grid_loc%32)==(grid_width-1))?(32-grid_width+1):1) {
And:
if((grid_loc % grid_width) == (grid_width - 1))
should be changed to:
if((grid_loc % 32) == (grid_width - 1))
With these fixes, it reads all the bombs properly.
Sorry but your program is reading the grid incorrectly.Minesweeper uses a grid with a fixed width of 32 bytes and the playingfield is takena s a window of that grid from the top left. e.g.beginner mode uses bytes 0 to 8 and skips bytes 9 to 31 per every 32byte row.* Fixing the program to read based on that patten shows thatMinesweeper only moves the mine if it happens to be the first squareyou click on. Apart from that, all mines are randomly placed at thestart of the game.
(* Actually it would use bytes 0 to 10, where bytes 0 and 10 are0x10 which is to indicate the border of the mine field, and bytes 1 to9 are the actual squares. but that's not really relevant to theanalysis if you're just &ing with 0x80 to find bombs.)
The source of this program is available here: (This is the original and still requires an update, my code will be fixed soon.)
http://www.room641a.net/files/projects/minehack/minehack.cpp Sample program output:
Minehack - Reverse Engineering and Coding by Sub <sub@room641a.net>
---
Fairly simple program to display already-placed bombs in minesweeper.
---
PID: 2836
Height: 9
Width: 9
---
[ ][ ][ ][ ][ ][ ] [ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
And now, probably the most important comment block of my entire program (I have updated this information here to be current, but the source file still needs updated):
/* Did you know?
*
* Minesweeper stores its minefield in an array char-sized (1 byte) multi-dimensional array. Each byte
* in memory corresponds to a specific location on the grid. It appears to use
* simple bit masks. (This section needs updating, but the information below is current.)
*
* 0x10 "Border" - Appears to mark the beginning of a row, which means my offset is off by +1
* 0x40 Button has been pressed already
* 0x80 Bomb is in place. These can move mid-game if clicked on
* Bit-wise OR with:
* 0x00 The square is exposed
* 0x0X X is 1-8 -- # on square (number of mines neighboring this square)
* 0x0D Square is marked with question mark
* 0x0E Square is marked with flag
* 0x0F Blank squares are all 0x0F
*
* AND THEN THERE'S 0xCC WHICH MEANS YOU CLICKED A DAMN BOMB AND LOST!
*/