3

I'm doing codefight's challange: minesweeper.
The description:
enter image description here

My code is as follows:

def minesweeper(matrix):

    for x in range(len(matrix)):
        matrix[x].insert(0, "x")
        #matrix[x].insert(len(matrix)+2, "x")
    frame = ["x" for i in range(len(matrix[0]))]
    matrix.insert(0, frame)
    matrix.insert(len(matrix), frame)

    output_matrix = [[0 for j in range(len(matrix[0]))] for i in range(len(matrix))]

    for i in range(0,len(matrix[0])-1):
        for j in range(0,len(matrix)-1):
            if matrix[i][j] == True:
                output_matrix[i][j+1] += 1 # one right
                output_matrix[i+1][j] += 1 # one down
                output_matrix[i][j-1] += 1 # one left
                output_matrix[i-1][j] += 1 # one up
                output_matrix[i+1][j+1] += 1 # one down, one right
                output_matrix[i+1][j-1] += 1 # one down, one right
                output_matrix[i-1][j+1] += 1 # one up, one right
                output_matrix[i-1][j-1] +=1 # one up, one left

    output_matrix.pop(0)
    output_matrix.pop(len(output_matrix)-1)

    for y in range(len(output_matrix)):
        output_matrix[y].pop(0)
        #output_matrix[y].pop(len(output_matrix))
    return output_matrix

The border created by "x", as suggested by codefight's user, is to ensure that if mine is at the border of matrix, bomb count won't transfer to the other side.
This code works fine until bomb is in the last column of the matrix, for example:

If input:

[[False, False, True],
 [False, False, False],
 [False, False, False]]


Output is:

[[0, 0, 0],
 [0, 0, 0],
 [0, 0, 0]]

Could anyone explain clearly why that's happening?
I'd appreciate if someone could suggest a better approach to this task.
Thank you in advance.

TCB
  • 61
  • 6
  • You stop at `len(matrix[0])-1` to avoid OOB errors, but doing so also avoids the last column. You need more fine-grained range control so that you can still check the last column but not update anything to its right when you do so. – Silvio Mayolo Jan 27 '18 at 23:18
  • no, he is not stopping to early since he adds a border of x around... – OBu Jan 27 '18 at 23:32
  • I get IndexError with this code. It looks like there is an added border on three sides, but no border added on the right. – Kenny Ostrom Jan 27 '18 at 23:55
  • This works correctly if I fix the code which fails to add and remove the border cells correctly. You could avoid some math to find the last item by using append, and give no argument to pop. – Kenny Ostrom Jan 28 '18 at 00:21
  • I gave an example on how to remove the border without using pop() in my answer. – OBu Jan 28 '18 at 18:58

1 Answers1

1

I just reversed your logic: I walk through the output field and add values from matrix. Please note the use of the exception (that was the hint regarding the "x"s). With this solution, you don't have to shrink your result using pop().

import itertools 

def minesweeper(matrix):

    #create the output matrix first to preserve the size
    #underscored variables to prevent warnings about unused variables
    output_matrix = [[0 for _j in range(len(matrix[0]))] for _i in range(len(matrix))]

    #unchanged
    for x in range(len(matrix)):
        matrix[x].insert(0, "x")
        matrix[x].insert(len(matrix)+2, "x")
    frame = ["x" for i in range(len(matrix[0]))]
    matrix.insert(0, frame)
    matrix.insert(len(matrix), frame)

    #to the logics the other way round: count the bombs around the output fields.
    #neighyours defines the offsets of all neighouring fields 
    neighbours = [(-1, -1), (-1, 0), (-1, 1), 
                  ( 0, -1),          ( 0, 1), 
                  ( 1, -1), ( 1, 0), ( 1, 1)] 
    for i, j in itertools.product(range(len(output_matrix[0])), range(len(output_matrix))):
        #get all indices; you could use two for-loops instead of itertools.product...
        print(i, j) # just to see how it works... please remove for final version
        for offset_i, offset_j in neighbours:
            print("   ", offset_i, offset_j ) # just to see how it works... please remove for final version
            # the exceptions do the magic here: If you add an "x", a TypeError is raised.
            # So you don't do anythithing if this happens. Otherwise you'll add 0 or 1 (adding "True" adds 1, "False" adds 0)
            try:
                output_matrix[j][i] += matrix[j + offset_j + 1][i + offset_i + 1]
                print("result = ", output_matrix[j][i]) # just to see how it works... please remove for final version
            except TypeError:
                print("pass") # just to see how it works... please remove for final version
                pass

    return output_matrix

matrix = [[False, False, True], #renamed input variable since "input" is a function name...
 [False, False, False],
 [False, False, False]]

print(minesweeper(matrix))

In general, your solution is working (if you uncomment the line #matrix[x].insert(len(matrix)+2, "x")), but you are making mistakes in your pop() sequence. You could just use 2D slicing (see the corresponding stackoverflow topic) and do

output_matrix = [output_matrix[i][1:len(output_matrix)-1] for i in range(1, len(output_matrix)-1)]

instead of all your pop()-steps.

OBu
  • 4,977
  • 3
  • 29
  • 45
  • no, since [-1] is a valid index (counting from the right)... ;-) – OBu Jan 28 '18 at 00:13
  • You fixed the bad borders, but OP had a simple if, where you use exception handling as "regular" code logic. I don't like that, but it's not so bad in python which is kind of designed for it. – Kenny Ostrom Jan 28 '18 at 00:22
  • @KennyOstrom I don't see an issue with it. It results in more readable code and a more logical flow than checking the bounds every time. It's also less prone to bugs. What don't you like about it? – Evan Weissburg Jan 28 '18 at 05:07
  • As I said, using exceptions as normal control is a bad idea in most languages, python being an exception. I was trying to make that cautionary point. – Kenny Ostrom Jan 28 '18 at 05:26
  • I added a remark that only the pop()s should be fixed and offered a 2D slicing as alternative... – OBu Jan 28 '18 at 18:57
  • Why there's +1 in `output_matrix[j][i] += matrix[j + offset_j + 1][i + offset_i + 1]` – TCB Jan 30 '18 at 19:17
  • Because of the x around the matrix – OBu Jan 30 '18 at 19:26