DWITE Minesweeper Program

Hi guys,

This is an old DWITE contest question and I was wondering where I could find the solutions. (In c++ please).

This is the question I am talking about. http://dwite.ca/old/...lem4Oct2005.pdf
If anyone can get me a solution that would be much appreciated. I analyse the program.

Thanks!
Last edited on
bump
The link is broken.
any ideas?
closed account (D80DSL3A)
I have written code for a minesweeper game several times.
My codes need to be modified a bit to fit the problem.

Have you attempted this yourself?
Are you a programmer?

EDIT: OK. I have it producing the expected output from the given sample input in the problem statement. Do you have any other valid test data?
Last edited on
closed account (D80DSL3A)
I have adapted my code to see how lean I could get it for the specific task at hand:
1. Read a mine distribution from a file
2. Make the plays also listed in this file
3. Write the required output to a file for each play.

I eliminated the mineField class and a lot of play capabilities:

no chording - another auto-clearing move triggered by depressing both mouse buttons on a revealed space.
no marking '?' or flag.
no displaying the field in the console, etc...
The only allowed action is clicking on a covered space to clear it.

auto-clearing around a space with no neighboring mines is supported, of course.
I couldn't obtain the required output without it.

I have it all down to 126 loc involving just a few global variables and functions.
This actually runs in the shell here, but because there is zero console output the only sign it ran is a message: 'return status 1' (due to input file not opening) in the LL corner of the output window.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <fstream>

struct fieldSpace// rows x cols of these make the field
{
    char cnt;// dual use: 'M' if mine or neighboring mine count
    bool revealed;
     void init( bool mined, char Count=0 )
    { revealed = false; cnt = mined ? 'M' : Count; }
};

// core game data
int rows=0, cols=0, mines=0;
fieldSpace**  ppField = nullptr;

const int y[] = { -1, -1, -1,  1, 1, 1,  0, 0 };// 8 shifts
const int x[] = { -1,  0,  1, -1, 0, 1, -1, 1 };// to neighbors

bool createField( std::ifstream& is );// dynamic memory allocated
void destroyField();// dynamic memory cleanup
int clearSpace( int r, int c );// Recursive. returns # of spaces cleared
bool isInField( int r, int c );// validate position

int main()
{
    std::ifstream fin("sample_game.txt");// input file
    if( !fin ) return 1;// bail - no input

    std::ofstream fout("field.txt");// output file
    if( !fout ) return 2;// bail - can't save output

    if( !createField( fin ) ) return 3;// get party started ( or not )
    int r, c;
    while( fin >> r >> c )// Game loop
    {
        --r; --c;// 1 based in file. 0 based here
        int spacesCleared = clearSpace(r,c);// make play

        if( ppField[r][c].cnt == 'M' )// write required output to file
            fout << "MINE - YOU LOSE\n";
        else if( spacesCleared > 1 )
            fout << "NO MINE - " <<  spacesCleared << " SQUARES REVEALED\n";// fill clear triggered
        else
            fout << "NO MINE - " << ppField[r][c].cnt << " SURROUNDING IT\n";// one space cleared
    }

    destroyField();// cleanup
    return 0;
}

bool createField( std::ifstream& is )
{
    rows = 16;// magic numbers
    cols = 30;// not in file

    if( is )// stream good?
    {
        mines = 0;// read in the mine distribution
        bool* mineDist = new bool[rows*cols];
         for( int i=0; i<rows*cols; ++i )
         {
//             char chIn; is >> chIn;
             char chIn;
             if( !(is >> chIn) ) { delete [] mineDist; return false; }// input failure
             if( chIn == 'X' ) { mineDist[i] = true; ++mines; }
             else mineDist[i] = false;
         }

        // build field
        ppField = new fieldSpace*[rows];
        for(int r=0; r<rows; ++r)
        {
            ppField[r] = new fieldSpace[cols];
            for(int c=0; c<cols; ++c)
            {
                if( mineDist[r*cols+c] ) { ppField[r][c].init( true ); continue; }// MINE - noted. next space!

                char mineCnt = '0';// find # of neighboring mines
                for(int i=0; i<8; ++i)// visit the 8 spaces around it
                    if( isInField( r+y[i], c+x[i] ) )
                        if( mineDist[ (r+y[i])*cols + c+x[i] ] ) ++mineCnt;

                ppField[r][c].init( false, mineCnt );// NOT a mine
            }
        }// end for

        delete [] mineDist;
        return true;
    }// end if

    return false;
}

void destroyField()
{
    // release memory
    if( ppField )
    {
        for(int r=0; r<rows; ++r) delete [] ppField[r];
        delete [] ppField;
    }
    ppField = nullptr;// safed off?
}

bool isInField( int r, int c )// validate position
{
    if( r < 0 || r >= rows ) return false;
    if( c < 0 || c >= cols ) return false;
    return true;
}

// Recursive. returns # of spaces cleared
int clearSpace( int r, int c )
{
    // base case: space already uncovered
    if( ppField[r][c].revealed ) return 0;

    ppField[r][c].revealed = true;// clear the space
    int numCleared = 1;
    // was a space with zero mines around it hit?
    if( ppField[r][c].cnt == '0' )// clear the 8 spaces around this space
    {
        for(int i=0; i<8; ++i)// visit the 8 spaces around it
            if( isInField( r+y[i], c+x[i] ) )
                 numCleared += clearSpace( r+y[i], c+x[i] );// and so on as required
    }
    return numCleared;
}

Here's the sample_game.txt file contents ( from problem statement)

.....XXX.............X...X...X
..........XX...X......X.......
....X.X.......................
.............X...X......XXXX..
X....X.....X...X...X.......X..
X.X....X........X.X..X..X.X.X.
...X..X..........X.X...X..XX..
..X...X.......X.........X...X.
....XXXXX.................X...
.X.X.........X..........XX..X.
..XXXX...X.X............X.....
...XX...X.XX...X........X.X...
XXXX.X..XX....X...............
.........X.X...X...........X..
X.X.X.XX.....X..X.X...X..X..XX
..X.........X...............X.
1 6
3 8
6 2
10 18
16 29

output:

MINE - YOU LOSE
NO MINE - 1 SURROUNDING IT
NO MINE - 3 SURROUNDING IT
NO MINE - 72 SQUARES REVEALED
MINE - YOU LOSE

This matches the sample output given, so we're done here.
Nice project. Thanks!
Last edited on
Hey,
I appreciate everything that you have done! I agree it's unfortunate that the contest is over, you would have had a good shot at winning.

I tried running the program on my computer but I got an error on line 13
fieldSpace** ppField = nullptr; my compiler is saying

|13|warning: identifier 'nullptr' is a keyword in C++11 [-Wc++0x-compat]|
|13|error: 'nullptr' was not declared in this scope|
||In function 'void destroyField()':|
|100|error: 'nullptr' was not declared in this scope|

not really sure what these mean.

Again thank you for all your help.
Enes
closed account (D80DSL3A)
Glad you like the codes.
This made a nice project for a day or 2, of course it helped greatly that I already had an adaptable program written!

nullptr is a C++11 keyword. Your compiler either doesn't support the newer standard, or you may just not have it enabled. Substitute NULL to fix this particular error.
Post any others if you find them.
Last edited on
So I run the program and there are no compile errors however, when I check the sample_output.txt it is empty. Nothing is being saved onto the file.
closed account (D80DSL3A)
If it's producing an output file then it got past line 29.
Did it make it past line 31 (call to createField)? Check the return status. Is it 3?
If so, there was a problem reading the mine distribution.
Hoping input file corruption is the issue here.

If it returned 0, then it's time to #include<iostream> and put a cout in the game loop so you cansee if it's processing any plays.
That was my error, the program is not creating a output text on its own.
The program is giving me a return of 1.
closed account (D80DSL3A)
OK. I just checked the code I posted here and I somehow broke it while tinkering.
Same problem here. No output file. I am posting newly verified code to replace existing in my post above.
Sorry about that. I hope this does it!
Last edited on
Thanks again and sorry for all the trouble this is causing you.
closed account (D80DSL3A)
You're welcome, and I'd rather know that code I've posted is faulty.
I was testing changes but may have lost track of changes.
Please post back if you get it running properly.
Hey, so I got the code working! I just had to create a new text file and make a different name for it to work, which was strange.

Now I have some questions, what does null do, i haven't learned about them yet and I wanted to impress my teacher by showing that I learned something.

I wanted to display the contents on the screen (both input & output) but when i tried i only got the input file contents to display. So the code is currently looking something like this,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <iostream>
#include <fstream>

using namespace std;

struct fieldSpace// rows x cols of these make the field
{
    char cnt;// dual use: 'M' if mine or neighboring mine count
    bool revealed;
    void init( bool mined, char Count=0 )
    {
        revealed = false;
        cnt = mined ? 'M' : Count;
    }
};

// core game data
int rows=0, cols=0, mines=0;
fieldSpace**  ppField = NULL;

const int y[] = { -1, -1, -1,  1, 1, 1,  0, 0 };// 8 shifts
const int x[] = { -1,  0,  1, -1, 0, 1, -1, 1 };// to neighbors

bool createField( ifstream& is );// dynamic memory allocated
void destroyField();// dynamic memory cleanup
int clearSpace( int r, int c );// Recursive. returns # of spaces cleared
bool isInField( int r, int c );// validate position

int main()
{
    ifstream fin("DATA.txt");// input file
    if( !fin ) return 1;// bail - no input
    else
    {
        string line;
        while(getline(fin,line)) // getline returns false at EOF
        {
            cout <<line << endl;
        }

    }

    //ofstream fout("field.txt");// output file
    //if( !fout ) return 2;// bail - can't save output

    if( !createField( fin ) ) return 3;// get party started ( or not )
    int r, c;
    while( fin >> r >> c )// Game loop
    {
        --r;
        --c;// 1 based in file. 0 based here
        int spacesCleared = clearSpace(r,c);// make play

        if( ppField[r][c].cnt == 'M' )// write required output to file
            cout << "MINE - YOU LOSE\n";
        else if( spacesCleared > 1 )
            cout << "NO MINE - " <<  spacesCleared << " SQUARES REVEALED\n";// fill clear triggered
        else
            cout << "NO MINE - " << ppField[r][c].cnt << " SURROUNDING IT\n";// one space cleared
    }

    destroyField();// cleanup
    return 0;
}

bool createField(ifstream& is )
{
    rows = 16;// magic numbers
    cols = 30;// not in file

    if( is )// stream good?
    {
        mines = 0;// read in the mine distribution
        bool* mineDist = new bool[rows*cols];
        for( int i=0; i<rows*cols; ++i )
        {
//             char chIn; is >> chIn;
            char chIn;
            if( !(is >> chIn) )
            {
                delete [] mineDist;    // input failure
                return false;
            }
            if( chIn == 'X' )
            {
                mineDist[i] = true;
                ++mines;
            }
            else mineDist[i] = false;
        }

        // build field
        ppField = new fieldSpace*[rows];
        for(int r=0; r<rows; ++r)
        {
            ppField[r] = new fieldSpace[cols];
            for(int c=0; c<cols; ++c)
            {
                if( mineDist[r*cols+c] )
                {
                    ppField[r][c].init( true );    // MINE - noted. next space!
                    continue;
                }

                char mineCnt = '0';// find # of neighboring mines
                for(int i=0; i<8; ++i)// visit the 8 spaces around it
                    if( isInField( r+y[i], c+x[i] ) )
                        if( mineDist[ (r+y[i])*cols + c+x[i] ] ) ++mineCnt;

                ppField[r][c].init( false, mineCnt );// NOT a mine
            }
        }// end for

        delete [] mineDist;
        return true;
    }// end if

    return false;
}

void destroyField()
{
    // release memory
    if( ppField )
    {
        for(int r=0; r<rows; ++r) delete [] ppField[r];
        delete [] ppField;
    }
    ppField = NULL;// safed off?
}

bool isInField( int r, int c )// validate position
{
    if( r < 0 || r >= rows ) return false;
    if( c < 0 || c >= cols ) return false;
    return true;
}

// Recursive. returns # of spaces cleared
int clearSpace( int r, int c )
{
    // base case: space already uncovered
    if( ppField[r][c].revealed ) return 0;

    ppField[r][c].revealed = true;// clear the space
    int numCleared = 1;
    // was a space with zero mines around it hit?
    if( ppField[r][c].cnt == '0' )// clear the 8 spaces around this space
    {
        for(int i=0; i<8; ++i)// visit the 8 spaces around it
            if( isInField( r+y[i], c+x[i] ) )
                numCleared += clearSpace( r+y[i], c+x[i] );// and so on as required
    }
    return numCleared;
}


Topic archived. No new replies allowed.