简体   繁体   中英

Problem when creating Minesweeper in Python

I have been tasked with creating minesweeper in the terminal as a project. I am relatively new to Python so this is quite a big task for me. For some reason I cannot get the numbers that surround the bombs to add up correctly. I have pasted the code and some outputs below. I get no errors when running the code. (I have noticed that it may have something to do with the code for the top right block above the bomb, but I've looked through everything and can't seem to find the issue. There's also sometimes less bombs than there should be.)

import random

def minesweeper(dim_size, num_bombs):

    print_list = []

    for i in range(dim_size):
        print_list.append([])
        for j in range(dim_size):
            print_list[i].append(0)

    for i in range(num_bombs):
        random_row = random.randrange(0,dim_size-1)
        random_column = random.randrange(0,dim_size-1)
        print_list[random_row][random_column] = 'X'

        # centre-top
        if random_row >= 1:
            if print_list[random_row - 1][random_column] != 'X':
                print_list[random_row - 1][random_column] += 1
        # right-top
        if random_row >= 1 and random_column > dim_size:
            if print_list[random_row - 1][random_column + 1] != 'X':
                print_list[random_row - 1][random_column + 1] += 1
        # right
        if random_column < dim_size:
            if print_list[random_row][random_column + 1] != 'X':
                print_list[random_row][random_column + 1] += 1
        # bottom-right
        if random_row < dim_size and random_column < dim_size:
            if print_list[random_row + 1][random_column + 1] != 'X':
                print_list[random_row + 1][random_column + 1] += 1
        # bottom
        if random_row < dim_size:
            if print_list[random_row + 1][random_column] != 'X':
                print_list[random_row + 1][random_column] += 1
        # bottom-left
        if random_row < dim_size and random_column >= 1:
            if print_list[random_row + 1][random_column - 1] != 'X':
                print_list[random_row + 1][random_column - 1] += 1
        # left
        if random_column >= 1:
            if print_list[random_row][random_column - 1] != 'X':
                print_list[random_row][random_column - 1] += 1
        # top-left
        if random_row >= 1 and random_column >= 1:
            if print_list[random_row - 1][random_column - 1] != 'X':
                print_list[random_row - 1][random_column - 1] += 1

    for row in range(dim_size):
        for column in range(dim_size):
            print(print_list[row][column], end='    ')
        print()

if __name__ == '__main__':
    minesweeper(5,5)

Outputs:

1    X    1    0    0    
2    3    3    1    0    
2    X    X    X    1    
X    3    3    2    1    
1    1    0    0    0  


2    X    1    0    0    
4    X    2    0    0    
X    X    3    0    0    
2    3    X    1    0    
0    1    1    1    0   


X    2    X    X    1    
X    3    2    2    1    
1    2    1    0    0    
0    1    X    1    0    
0    1    1    1    0    


X    3    X    2    0    
1    4    3    2    0    
1    1    X    1    0    
X    2    1    1    0    
1    1    0    0    0 

A couple things stand out:

random.randrange doesn't include the endpoint, so if your endpoint is dim_size-1 , that means you'll only ever generate numbers between zero and three inclusive. This means mines will never appear anywhere in the bottom row, or right-most column.

The second issue, which you've already pointed out, has to do with the way you're placing mines. You generate a random xy-coordinate, and then place a mine there. What if you happen to generate the same coordinate more than once? You simply place another mine in the same field which is already occupied by a mine.

Instead of using random.randrange , or even random.randint to generate random coordinates, I would first generate a collection of all possible coordinates, and then use random.sample to pull five unique coordinates from that collection. In the same way lottery numbers are drawn, the same numbers (coordinates in our case) can never be drawn more than once:

import random
import itertools

dim_size = 5
num_mines = 5

for x, y in random.sample(list(itertools.product(range(dim_size), repeat=2)), k=num_mines):
    print("Put a mine at {}, {}".format(x, y))

Output:

Put a mine at 4, 4
Put a mine at 4, 3
Put a mine at 3, 1
Put a mine at 1, 0
Put a mine at 3, 0
>>> 

Okay, For that 'There's also sometimes less bombs than there should be'... You need to use While loop to track number of bombs you've planted in Grid. Using for loop will run only in range(num_bombs) & it won't care if it has planted the required num of bombs. But While loop will first check if the code has planted the required num_bombs, if so... it will stop running but if not it will continue running

Also before planting the Bomb, you need to check if that row_column has Bomb, if so... don't Plant the bomb... if not plant the bomb.

here the code:

    planted_num_bomb = 0 #number of bombs planted
        while planted_num_bomb < num_bombs:
        # for i in range(num_bombs):
            random_row = random.randrange(0,dim_size-1)
            random_column = random.randrange(0, dim_size - 1)
            # check if the row_colm has a Bomb
            if print_list[random_row][random_column] == 'X': #contains the bomb
                continue #pass it
            else:
                print_list[random_row][random_column] = 'X'
                planted_num_bomb += 1

There 5 results:

    0    0    2    X    1    
    1    1    3    X    2    
    2    X    3    X    2
    2    X    3    1    1
    1    1    1    0    0
    
    1    2    1    0    0    
    1    X    X    1    0    
    2    4    X    3    0
    1    X    3    X    1
    1    1    2    1    1
    5 #number of bombs planted
    
    1    0    2    X    1    
    X    1    2    X    2    
    3    2    1    1    1
    X    X    1    0    0
    2    2    1    0    0
    5 #number of bombs planted
    
    1    0    1    1    0    
    X    2    2    X    1    
    3    3    X    2    1    
    X    X    2    1    0
    2    2    1    0    0
    5 #number of bombs planted

0    0    0    0    0    
2    2    1    0    0    
X    X    X    2    0    
X    4    3    X    1
1    1    1    1    1
5 #number of bombs planted

Now if you take a look... the code can't place a mine a column number 5... why? ANSWER is at the top(1st answer). if you find a solution to that problem, still use the while loop because for loop won't always plant the required number of bombs, why? because, in for loop, when we skip(the continue part in code when there's bomb), the for loop still counts that as an iteration.

Anyway Goodluck on Your WTC bootcamp.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM