-1

I am currently making a minesweeper game with Python but I have some problems withe the mines repartition:

To choose the places of the different mines, I use the Python random module to generate x and y coordinates. Firstly I chose to place all the mines before the player first plays but the problem was that the first play was generally a mine or a cas with mines as neighbours. So I decided to place the mines after the player first plays to be sure that the first cas revealed will not have mines as neighbours but the problem is that the mines's repartition is not very interesting for a mines game. How can I make it better?

Here is my function that places mines in the Board class after player first plays where pos is coords of first cas revealed:

    def place_mines(self, pos):
        posed_mines = 0
        while posed_mines < self.mines_number:
            x = random.randrange(0, COLUMN_NUMBER-1)
            y = random.randrange(0, LINE_NUMBER-1)
            if not self.Matrix[y][x].is_mined and (x < pos[0]-1 or x > pos[0]+1) and (y < pos[1]-1 or y > pos[1]+1):
                self.Matrix[y][x].mine()
            posed_mines += 1

And the result in game:

mines repartition

Here is the function that places all the mines before the player first plays:

    def place_mines(self):
        posed_mines = 0
        while posed_mines < self.mines_number:
            x = random.randrange(0, COLUMN_NUMBER-1)
            y = random.randrange(0, LINE_NUMBER-1)
            if not self.Matrix[y][x].is_mined:
                self.Matrix[y][x].mine()
                posed_mines += 1

And the result in game :

mines repartition

My question is not a duplicate because on the question linked, the mine placing is not done after player first play

Hugo
  • 59
  • 10
  • Possible duplicate of [What's the algorithm behind minesweeper generation](https://stackoverflow.com/questions/3578456/whats-the-algorithm-behind-minesweeper-generation) – T Burgis Jan 04 '19 at 09:25
  • You're preventing the mines from being in the whole row and column of the first guess, not just that one square ("cas"?) The problem is nothing to do with the random module, it's in your logic for rejecting some positions. – jonrsharpe Jan 04 '19 at 09:26
  • @jonrsharpe I don't understand. Why am I rejecting the wole row and column ? – Hugo Jan 04 '19 at 09:32
  • @jonrsharpe How can I rewrite my condition ? – Hugo Jan 04 '19 at 09:37
  • 1
    Because your logic for rejecting the x and y is wrong; your checks on vertical and horizontal placement are *independent*. If you look at the image you've posted you can clearly see two "stripes", three squares wide, clear of mines that intersect at what was presumably the first square played. Also the indentation on whether that counts as "posing" a mine looks suspect and you can never place a mine in the last row or column with either snippet. – jonrsharpe Jan 04 '19 at 09:41
  • @jonrsharpe ok thank's I understood. – Hugo Jan 04 '19 at 09:48

1 Answers1

1

If you don't care about time/space complexity and the board is small enough where you don't need to care, you can use random.sample() to do the selection:

import random, itertools

def place_mines(self, pos):
    available_cells = set(itertools.product(range(COLUMN_NUMBER-1), range(LINE_NUMBER-1))))
    available_cells.remove(pos)
    for x, y in random.sample(available_cells, self.mines_number):
        self.Matrix[y][x].mine()

There are more computationally efficient solutions if mines_number is significantly lower than the size of the board, but as long as the code above doesn't need to run in tight loop and the board is of reasonable size, the above map generation would be fine.


Now, unrelated comment about code style: why are you using COLUMN_NUMBER-1 and LINE_NUMBER-1? If COLUMN_NUMBER, LINE_NUMBER is the size of self.MATRIX, this looks like an off-by-one error. Normally, you would be able to just use range(len(lst)) or random.randrange(0, len(lst)) to get a range of the same size of lst and not have to subtract len(lst) by 1.

Lie Ryan
  • 62,238
  • 13
  • 100
  • 144