Search code examples
pythonalgorithmcyclecombinatorics

5*5 grid, in every 3*3 square of the grid must be 4 "lights"


I'm very sorry I'm asking this question, but my coding skills are not so great, so I can not solve this problem: there is a grid 5*5, and a task is to find minimal number of "lights", or "1" settled in a special way: in every 3*3 square of the big square, there must be exactly 4 "lights". Counting with a pen, I've got this minimal number equals 7 (the answer is right). So my solution looks like this:

#creates a list
grid = []

#creates lines
for row in range(5):
    grid.append([])
    #creates columns
    for column in range(5):
        grid[row].append(0)

#one "light" must be in a center
grid[2][2] = 1

#this array counts all "lights" and will notice when there are 4 of them
light_number = []

def counter():
for row in range(0, 3):
    for column in range(0, 3):
        if grid[row][column] == 1:
           light_number.append(1)
print(len(light_number))

As expected, counter() works only for the first little 3*3 square. Wanting to have only one function for searching "lights" and not 9, I`ve tried to write something like this:

def counter():

#initial range of the counter
row_min = 0
row_max = 3
column_min = 0
column_max = 3

for i in range(9):
    for row in range(row_min, row_max):
        for column in range(column_min, column_max):
            if grid[row][column] == 1:
                #write it in a list
                light_number.append(1)
            column_min += 1
            column_max += 1
        row_min += 1
        row_max += 1
    #print a number of total lights
    print(len(light_number))

But it doesn't work, saying that grid[row][column] == 1 is out of range.

So, the problem is:

  1. I can't write working counter, which should automatically see all little squares 3*3
  2. I don't know, how to write all combinations of "lights".

Please, if you have ANY idea, tell me. If you think there can be another solution, please, say also. Thanks in advance.


Solution

  • The question was about learning something about programming. As far as I can see, a simple backtrack-mechanism should be used:

    import numpy as np
    
    #initialize the grid with the middle set to one
    grid = np.zeros((5,5))
    grid[2,2] = 1
    

    First, we need a simple check function, that returns True if the global grid is gracefully filled with ones:

    # a method to check all sub squares starting at row and column 0 through 2
    def checkgrid():
        # row 0 through 2
        for r in xrange(3):
            # column 0 through 2
            for c in xrange(3):
                # sum up all entries of grid matrix
                if grid[r:r+3, c:c+3].sum() != 4:
                    return False
        return True
    

    And here we go with the main method. The idea is the following: Every grid entry has a unique identifier between zero and 24, its "idx". The aim is to find a valid configuration where the six ones are spread correctly over the 24 grid entries (25 - middle entry). All possible binom(24, 6)=134596 solutions are enumerated through a simple loop and a recursive call to place the remaining entries, until the check-method returns True the first time, i.e. when a valid configuration is found.

    # method that is recursively applied to set the next one
    def recursive_trial(first, depth, maxdepth):
        # all ones are placed: check the grid
        if depth == maxdepth:
            return checkgrid()
        # enumerate possible grid positions as idx == 5 * r + c
        for idx in xrange(first, 25 - (maxdepth - depth + 1)):
            # get row and column idx
            r = idx / 5
            c = idx % 5
            # skip the middle
            if grid[r,c] == 1:
                continue
            # set entry to one
            grid[r,c] = 1
            # call method recursively to place missing ones until 7 in the remainder of the array
            if recursive_trial(idx + 1, depth + 1, maxdepth):
                return True
            # set entry back to zero
            grid[r,c] = 0
        # at this point, we failed with the current configuration.
        return False
    

    A call to

    recursive_trial(0, 0, 6)
    print grid
    

    yields (in a matter of milliseconds)

    [[ 0.  0.  1.  0.  0.]
     [ 0.  0.  0.  0.  0.]
     [ 1.  1.  1.  1.  1.]
     [ 0.  0.  1.  0.  0.]
     [ 0.  0.  0.  0.  0.]]