Link’s Color Puzzle

Logic Level 4

In Nintendo's Link's Awakening's Color Dungeon, Link enters a room with a 3 × 3 3 \times 3 checkerboard pattern of blue and red balls. When Link hits one of the balls with his sword, that ball and any ball immediately above, below, left, and right of it all toggle between blue and red. To pass to the next room, Link must change all the balls to blue, which is possible by hitting just 4 4 balls:

If Link enters a room with the same set of rules but with a 5 × 5 5 \times 5 checkerboard pattern of blue and red balls instead, what is the minimum number of balls Link needs to hit in order to pass to the next room?

Note: A computer program will probably be needed to solve this problem.

7 11 10 12 not possible 9 8

This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try refreshing the page, (b) enabling javascript if it is disabled on your browser and, finally, (c) loading the non-javascript version of this page . We're sorry about the hassle.

4 solutions

Chris Lewis
Mar 4, 2020

I've just seen that this approach is not original ( @Piotr Idzik references a paper on it) but thought it might be interesting to add a different method to the discussion.

We'll work on the general n × n n \times n case, then look at a specific example.

Code the lights by their colour: use 1 1 for blue lights and 0 0 for red. Toggling a light's colour is equivalent to adding 1 1 to its value, working modulo 2 2 .

Define a "hit matrix" H \bold{H} by H i j = 1 H_{ij}=1 if the light in position ( i , j ) (i,j) is hit, and 0 0 otherwise. Define the starting checkerboard pattern as C \bold{C} , where C i j i + j + 1 ( m o d 2 ) C_{ij} \equiv i+j+1 \pmod2 . We can also define the final, all blue setup as B \bold{B} with all entries equal to 1 1 .

The final colour of the light in position ( i , j ) (i,j) is given by C i j + H i j + H i 1 , j + H i , j + 1 + H i + 1 , j + H i , j 1 C_{ij}+H_{ij}+H_{i-1,j}+H_{i,j+1}+H_{i+1,j}+H_{i,j-1} , where we ignore indices outside the range [ 1 , n ] [1,n] . We want this to be congruent to 1 ( m o d 2 ) 1 \pmod2 for all ( i , j ) (i,j) .

The idea is to solve a linear equation in H \bold{H} to find a hit matrix that works. However, to do this, we need (I think) to rewrite the entries of H \bold{H} as a column vector, H v = ( H 11 , H 12 , , H 1 n , H 21 , , H n n ) T \bold{H_v}=\left(H_{11},H_{12},\ldots,H_{1n},H_{21},\ldots,H_{nn} \right)^T . Because this column vector has n 2 n^2 entries, I'll discuss the 3 × 3 3 \times 3 case first.

Let's start writing equations modulo 2 2 . The first row of lights give:

1 + H 11 + H 12 + H 21 1 0 + H 11 + H 12 + H 13 + H 22 1 1 + H 12 + H 13 + H 23 1 \begin{aligned} 1+H_{11}+H_{12}+H_{21} &\equiv 1 \\ 0+H_{11}+H_{12}+H_{13}+H_{22} &\equiv 1 \\ 1+H_{12}+H_{13}+H_{23} &\equiv 1 \end{aligned}

Continuing this way, we get the following equation:

( 1 1 0 1 0 0 0 0 0 1 1 1 0 1 0 0 0 0 0 1 1 0 0 1 0 0 0 1 0 0 1 1 0 1 0 0 0 1 0 1 1 1 0 1 0 0 0 1 0 1 1 0 0 1 0 0 0 1 0 0 1 1 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 1 0 1 1 ) H v = M H v B C \begin{pmatrix} 1 & 1 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 1 & 1 & 1 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 1 & 1 & 0 & 0 & 1 & 0 & 0 & 0 \\ 1 & 0 & 0 & 1 & 1 & 0 & 1 & 0 & 0 \\ 0 & 1 & 0 & 1 & 1 & 1 & 0 & 1 & 0 \\ 0 & 0 & 1 & 0 & 1 & 1 & 0 & 0 & 1 \\ 0 & 0 & 0 & 1 & 0 & 0 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 1 & 1 & 1 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 1\end{pmatrix} \bold{H_v} = \bold{M}\cdot \bold{H_v} \equiv \bold{B}-\bold{C}

This looks daunting, but is linear. The determinant of M \bold{M} is odd, which means it has an inverse modulo 2 2 . This means there is a unique solution to the equation!

We can solve the equation using Cramer's rule ; as expected, the final result is

H = ( 0 1 0 1 0 1 0 1 0 ) \bold{H}=\begin{pmatrix} 0 & 1 & 0 \\ 1 & 0 & 1 \\ 0 & 1 & 0 \end{pmatrix}

Now, of course, this result in itself just repeats the animation in the question. But we get the following useful information:

  • any size grid can be encoded in this way; the pattern of the coefficient matrix M \bold{M} continues in the obvious way

  • if the determinant of M \bold{M} is odd, there is a unique solution (so there is no question of the minimum number of hits, or even of the pattern)

  • if the determinant of M \bold{M} is odd, we can use Cramer's rule to directly generate the solution

Now let's turn to the 5 × 5 5 \times 5 case of the question. We can set all the matrices and H v \bold{H_v} up in exactly the same way. And what do we find for det M \det{\bold{M}} ?

It is, of course, even.

But this just means there is not a unique solution. If we reduce the matrix by removing the first two rows and first two columns, we get a matrix M \bold{M'} whose determinant is odd.

This matrix reduction means we have some freedom of choice; we can choose which of the first two lights (in positions ( 1 , 1 ) (1,1) and ( 1 , 2 ) (1,2) ) are hit - in other words, there are four solutions. But this is exactly what we expect! As shown in the other solutions, the winning matrix is

H = ( 1 1 1 0 0 0 0 0 0 0 0 1 0 0 1 1 0 1 0 1 0 1 0 0 1 ) \bold{H}=\begin{pmatrix} 1 & 1 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 1 \\ 1 & 0 & 1 & 0 & 1 \\ 0 & 1 & 0 & 0 & 1 \end{pmatrix}

and its rotations. Each of the four rotations corresponds to a choice of which of the first two lights are hit.

So, without needing to analyse the 2 25 2^{25} different hit matrices, we have shown there is a unique solution with 10 \boxed{10} hits, up to rotation.

Some questions I have about this approach:

  • is there a better method for solving the equations than Cramer's rule? If it's possible to compute M 1 \bold{M}^{-1} easily, that would make the calculation much quicker

  • how many degrees of freedom are there for each n n ? (ie, how many hits do we have to choose before we get to a non-singular matrix?) If there are multiple valid configurations, is there a quick way to determine which ones minimise the total number of hits?

  • alternatively, which n n - like n = 3 n=3 - have det M 1 ( m o d 2 ) \det{\bold{M}} \equiv 1 \pmod2 (ie no degrees of freedom)?

  • is it possible to set up the equations so that we solve for H \bold{H} directly in its matrix form? (This seems to involve pre- and post-multiplying coefficient matrices; we essentially get an equation of the form A H + H A B C \bold{AH}+\bold{HA} \equiv \bold{B}-\bold{C} , but I'm not sure how to solve these)

OK, I've already answered one of my own questions: we don't need Cramer's rule, we can directly solve by inverting M \bold{M} . This will in general give a matrix with non-integer values; but if we multiply this by det M \det{\bold{M}} we get back to integers, which we can reduce modulo 2 2 to give the inverse we need.

Chris Lewis - 1 year, 3 months ago

Wow, nice work! (Sorry I don't have any answers for you, though.)

David Vreken - 1 year, 3 months ago
Piotr Idzik
Feb 27, 2020

We need to hit the balls on the positions: ((0, 0), (0, 1), (0, 2), (2, 1), (2, 4), (3, 0), (3, 2), (3, 4), (4, 1), (4, 4)). Above sequence is also the shortest possible. Observe, that the order of hits does not matter.

It seems, that such problems all well known and that they are efficiently solved using some linear algebra (linear spaces over the field Z 2 \mathbb{Z}_2 ). The game is called "Lights out". Cf. Marlow Anderson, Todd Feil (1998). "Turning Lights Out with Linear Algebra" . Mathematics Magazine. 71 (4): 300–303.

Besides that, I have written the following script to obtain a solution. It iterates through all of the possible hit lists (up to rotations/reflections/order of hits). It is a parallel code. But it is not really useful for bigger grids.

  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
156
157
158
159
160
161
162
163
164
165
166
167
"""
brute-fore solution of the problem:
https://brilliant.org/problems/links-color-puzzle/
"""
import time
import timeit
import copy
import itertools
from multiprocessing import Process, Queue, cpu_count

def make_hit(in_data, pos_vec):
    """
    performs a single ball hit on a given ball set
    """
    def inner(cur_data, in_x, in_y):
        if 0 <= in_x < len(in_data) and 0 <= in_y < len(in_data):
            cur_data[in_y][in_x] = not cur_data[in_y][in_x]
    out_data = copy.deepcopy(in_data)
    pos_x, pos_y = pos_vec
    inner(out_data, pos_x, pos_y)
    inner(out_data, pos_x+1, pos_y)
    inner(out_data, pos_x-1, pos_y)
    inner(out_data, pos_x, pos_y+1)
    inner(out_data, pos_x, pos_y-1)
    return out_data

def grouper(iterable, block_size, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)]*block_size
    return itertools.zip_longest(*args, fillvalue=fillvalue)

def find_correct_hits(start_data, end_data, hit_list_data, res_queue):
    """
    finds the hits from hit_list_data, which lead from start_data to end_data
    """
    local_res = set()
    for cur_hit_list in hit_list_data:
        if cur_hit_list:
            tmp_data = copy.deepcopy(start_data)
            for cur_hit in cur_hit_list:
                tmp_data = make_hit(tmp_data, cur_hit)
            if tmp_data == end_data:
                local_res.add(cur_hit_list)
    for cur_res in local_res:
        res_queue.put(cur_res)

def gen_hit_list(data_size, hit_list_len):
    """
    generator;
    generates a sequence of all (up to rotation/reflection) hits of the length hit_list_len
    """
    def flip_x_hit_list(in_hit_list, sol_size):
        def proc_single_hit(in_hit):
            return (sol_size-1-in_hit[0], in_hit[1])
        return tuple(sorted((proc_single_hit(_) for _ in in_hit_list)))

    def flip_y_hit_list(in_hit_list, sol_size):
        def proc_single_hit(in_hit):
            return (in_hit[0], sol_size-1-in_hit[1])
        return tuple(sorted((proc_single_hit(_) for _ in in_hit_list)))

    def rotate_hit_list(in_hit_list, sol_size):
        def proc_single_hit(in_hit):
            return (sol_size-1-in_hit[1], in_hit[0])
        return tuple(sorted((proc_single_hit(_) for _ in in_hit_list)))
    generated_hits = set()
    all_pos_gen = itertools.product(range(data_size), repeat=2)
    all_hit_data_gen = itertools.combinations(all_pos_gen, hit_list_len)
    for cur_hit in all_hit_data_gen:
        was_before = False
        if cur_hit in generated_hits:
            was_before = True
        elif flip_x_hit_list(cur_hit, data_size) in generated_hits:
            was_before = True
        elif flip_y_hit_list(cur_hit, data_size) in generated_hits:
            was_before = True
        else:
            tmp_hit_list = rotate_hit_list(cur_hit, data_size)
            if tmp_hit_list in generated_hits:
                was_before = True
            else:
                tmp_hit_list = rotate_hit_list(tmp_hit_list, data_size)
                if tmp_hit_list in generated_hits:
                    was_before = True
                else:
                    tmp_hit_list = rotate_hit_list(tmp_hit_list, data_size)
                    if tmp_hit_list in generated_hits:
                        was_before = True

        if not was_before:
            yield cur_hit
            generated_hits.add(cur_hit)

def find_hit_list_given_len_all_par(start_data, end_data, hit_list_len, max_proc_num, max_block_size):
    """
    tries to find a sequence (of given length) of hits
    leading from the start_data to end_data
    """
    def count_running(in_proc_list):
        res = 0
        for cur_proc in in_proc_list:
            if cur_proc.is_alive():
                res += 1
        return res
    proc_list = []

    res_queue = Queue()
    for cur_hit_list_data in grouper(gen_hit_list(len(start_data), hit_list_len), max_block_size):
        cur_proc = Process(target=find_correct_hits,
                           args=(start_data, end_data, cur_hit_list_data, res_queue, ))
        cur_proc.start()
        proc_list.append(cur_proc)
        while count_running(proc_list) >= max_proc_num:
            time.sleep(0.1)
        proc_list = [_ for _ in proc_list if _.is_alive()]
    for cur_proc in proc_list:
        cur_proc.join()

    res = set()
    while not res_queue.empty():
        res.add(res_queue.get())
    return res

def sol_to_str(in_sol, sol_size=None):
    """
    returns a eye-friendly representation of a solution
    """
    if not sol_size:
        sol_size = max(max(_) for _ in in_sol)+1
    raw_str = [['+']*sol_size for _ in range(sol_size)]
    for (pos_x, pos_y) in in_sol:
        raw_str[pos_y][pos_x] = '*'
    return '\n'.join([''.join(_) for _ in raw_str])

def find_shortest_hit_list(start_data, end_data, max_proc_num, max_block_size):
    """
    fids all (up to rotation/reflection) of the shortest hit lists leading from
    start_data to end_data
    """
    sol_set = set()
    cur_len = 1
    while len(sol_set) == 0:
        start_time = timeit.default_timer()
        cur_sol_set = find_hit_list_given_len_all_par(start_data, end_data, cur_len,
                                                      max_proc_num, max_block_size)
        end_time = timeit.default_timer()
        print(f"runTime for {cur_len}: {end_time-start_time} [s]")
        if len(cur_sol_set) > 0:
            for cur_sol in cur_sol_set:
                print(f"{cur_sol} (length: {len(cur_sol)})")
                print(sol_to_str(cur_sol))
            sol_set = cur_sol_set
        cur_len += 1
    return sol_set

if __name__ == '__main__':
    TEST_N = 5
    DATA_A = [[False]*TEST_N for _ in range(TEST_N)]
    for (p_x, p_y) in itertools.product(range(len(DATA_A)), repeat=2):
        if (p_x+p_y)%2 == 1:
            DATA_A[p_x][p_y] = True
    DATA_B = [[False]*TEST_N for _ in range(TEST_N)]
    START_TIME = timeit.default_timer()
    ALL_SOL_DATA = find_shortest_hit_list(DATA_A, DATA_B, cpu_count(), 30000)
    END_TIME = timeit.default_timer()
    print(f"runTime: {END_TIME-START_TIME} [s]")

Same solution (and same technique). Up to rotations/reflections, this was the only solution I found - did you find any others?

Chris Lewis - 1 year, 3 months ago

Log in to reply

I also used a computer program to prove that the minimum is 10, and only found this solution (along with its rotations/reflections).

David Vreken - 1 year, 3 months ago

Log in to reply

Did you try any analytical methods? It seems unlikely that an analytical method could generate the solution, but perhaps it could rule out solutions with fewer steps. There are lots of other questions here...is it always possible to solve this puzzle on an n × n n \times n grid? If not, which n n work? Is the solution always unique?

Chris Lewis - 1 year, 3 months ago

Log in to reply

@Chris Lewis Before, I thought that (sorry, I do not know, how to cross it out): "I think, that there is no solution when n n is even." Above is not true.

It turned out, that there is a solution for 6 and 8. I have found the following solutions (I am not sure, if they are the only ones up to rotations/reflections neither the shortest possible).

 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
(+ == "hit")
gridSize: 6
raw_solution: ((0, 1), (0, 3), (0, 4), (0, 5), (1, 0), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 5), (5, 0), (5, 1), (5, 2), (5, 4)) (length: 22)
0+0+++
+00+++
000+++
+++000
+++00+
+++0+0

gridSize: 7
raw_solution: ((0, 2), (0, 3), (0, 4), (2, 0), (2, 3), (2, 6), (3, 0), (3, 2), (3, 4), (3, 6), (4, 0), (4, 3), (4, 6), (6, 2), (6, 3), (6, 4)) (length: 16)
00+++00
0000000
+00+00+
+0+0+0+
+00+00+
0000000
00+++00

gridSize: 8
raw_solution: ((0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (1, 4), (1, 6), (1, 7), (2, 0), (2, 4), (2, 5), (2, 7), (3, 0), (3, 4), (3, 5), (3, 6), (3, 7), (4, 0), (4, 1), (4, 2), (4, 3), (4, 7), (5, 0), (5, 2), (5, 3), (5, 7), (6, 0), (6, 1), (6, 3), (7, 0), (7, 1), (7, 2), (7, 3), (7, 4), (7, 5)) (length: 36)
00++++++
0000+0++
+000++0+
+000++++
++++000+
+0++000+
++0+0000
++++++00

Piotr Idzik - 1 year, 3 months ago

Log in to reply

@Piotr Idzik Is there a solution for all odd n n ? (Another question is, how many hits are needed?)

Chris Lewis - 1 year, 3 months ago

Log in to reply

@Chris Lewis It turned out, that there is a solution for 6 and 8 (cf. my comment above)

Piotr Idzik - 1 year, 3 months ago

@Chris Lewis There's also 2 hits minimum required for a 2 x 2 board (hit the two original red balls)

So in summary (so far):

gridsize minimum hits required
2 x 2 2
3 x 3 4
4 x 4 not possible
5 x 5 10
6 x 6 22
7 x 7 16
8 x 8 36

I also noticed that for odd gridsize solutions, a previous odd gridsize solution is in the corner. (For example, the 3 x 3 solution is in the corner of the 5 x 5 solution.) I wonder if the coding can be improved with this recursive relation in mind, in other words, for an odd n x n solution, start with a known (n - 2) x (n - 2) solution in the top left corner and only try all possible combinations of the balls in the remaining L-shape. Unfortunately this recursive relation does not seem to be true for even gridsize solutions, though.

David Vreken - 1 year, 3 months ago

Log in to reply

@David Vreken It seems that OEIS does not know about the sequence 10, 22, 16, 36.

Piotr Idzik - 1 year, 3 months ago

@David Vreken Update: I wrote a computer program that uses a recursive relation, but unfortunately it was not very efficient (I could only prove up to a 7 x 7 grid, the 8 x 8 would grid take too long to calculate). I can verify that the solutions already found above are the only solutions for those gridsizes, except the 5 x 5 solution has 4 solutions (all rotations/reflections). Basically, the program stores all possible ways to get all blue in the top left (n - 1) x (n - 1) corner, and then uses those to test the n x n gridsize.

David Vreken - 1 year, 3 months ago

@David Vreken Here is the computer program I wrote:

  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
# Link's Color Puzzle
# Python

# set up variables
from itertools import combinations
maxn = 7
prevalmost = []
prevalmost.append([])
prevalmost.append([0])

# function that resets the grid to its
#  checkerboard pattern
def checkerboardreset():
    for a in range(0, n):
        for b in range(0, n):
            if (a + b) % 2 == 0:
                blue[a * n + b] = True
            else:
                blue[a * n + b] = False

# function that tests to see if all
#  the balls are blue
def alltest():
    bluetest = True
    for a in range(0, n * n):
        bluetest = bluetest and blue[a]
    return bluetest

# function that tests to see if the top
#  left corner of (n - 1) x (n - 1)
#  balls are all blue
def almosttest():
    bluetest = True
    for a in range(0, n - 1):
        for b in range(0, n - 1):
            bluetest = bluetest and blue[a * n + b]
    return bluetest

# function that after given a hit ball, 
#  toggles the colors of the correct balls
def hitball(x):
    blue[x] = not blue[x]
    if (x - n) >= 0:
        blue[x - n] = not blue[x - n]
    if (x + n) < n * n:
        blue[x + n] = not blue[x + n]
    if (x - 1) % n <> n - 1:
        blue[x - 1] = not blue[x - 1]
    if (x + 1) % n <> 0:
        blue[x + 1] = not blue[x + 1]


# Analyze n x n gridsizes
for n in range(2, maxn + 1):
    # reset variables
    s = []
    for a in range(0, n - 1):
        for b in range(n - 1, n):
            s.append(a * n + b)
    for a in range(n - 1, n):
        for b in range(0, n):
            s.append(a * n + b)
    blue = []
    for a in range(0, n * n):
        blue.append(False)
    almost = []
    # Go through each prevalmostsolution and every
    #  possible combination of the remaining L-shape
    #  and record almostsolutions (all top left
    #  (n - 1) x (n - 1) are blue) and allsolutions
    #  (all n x n are blue)
    for hits in range(0, len(s) + 1):
        p = list(combinations(s, hits))
        for a in range(0, len(p)):
            for b in range(0, len(prevalmost)):
                # reset board and hit all balls in
                #  prevalmost and p
                checkerboardreset()
                hitlist = []
                for c in range(0, len(prevalmost[b])):
                    col = prevalmost[b][c] % (
                        n - 1)
                    row = (prevalmost[b][c] - (
                        col)) / (n - 1)
                    hitlist.append(row * n + col)
                for c in range(0, hits):
                    hitlist.append(p[a][c])
                for c in range(0, len(hitlist)):
                    hitball(hitlist[c])
                if almosttest():
                    almost.append(hitlist)
                    if alltest():
                        # display allsolutions
                        print("Solution for " + str(
                            n) + " x " + str(
                            n) + " grid using " + str(
                            len(hitlist)) + " hits:")
                        for c in range(0, n):
                            strrow = ""
                            for d in range(0, n):
                                if c * n + d in hitlist:
                                    strrow += "X"
                                else:
                                    strrow += "-"
                            print(strrow)
                        print("")
    # switch almost to prevalmost
    prevalmost = []
    for a in range(0, len(almost)):
        prevalmost.append(almost[a])

David Vreken - 1 year, 3 months ago

@David Vreken and its output:

 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
Solution for 2 x 2 grid using 2 hits:
-X
X-

Solution for 3 x 3 grid using 4 hits:
-X-
X-X
-X-

Solution for 5 x 5 grid using 10 hits:
--XXX
-----
X--X-
X-X-X
X--X-

Solution for 5 x 5 grid using 10 hits:
X--X-
X-X-X
X--X-
-----
--XXX

Solution for 5 x 5 grid using 10 hits:
XXX--
-----
-X--X
X-X-X
-X--X

Solution for 5 x 5 grid using 10 hits:
-X--X
X-X-X
-X--X
-----
XXX--

Solution for 6 x 6 grid using 22 hits:
-X-XXX
X--XXX
---XXX
XXX---
XXX--X
XXX-X-

Solution for 7 x 7 grid using 16 hits:
--XXX--
-------
X--X--X
X-X-X-X
X--X--X
-------
--XXX--

David Vreken - 1 year, 3 months ago

@David Vreken Here is a solution I found manually for a 9 x 9 grid that uses 44 hits. I'm not sure if it's a minimum, though.

1
2
3
4
5
6
7
8
9
-X-XXX-X-
X--XXX--X
---XXX---
XXX---XXX
XXX---XXX
XXX---XXX
---XXX---
X--XXX--X
-X-XXX-X-

David Vreken - 1 year, 3 months ago

@David Vreken Here is another solution I found manually for a 9 x 9 grid that uses only 28 hits. I'm still not sure if it's a minimum, though.

1
2
3
4
5
6
7
8
9
-X--X--X-
X-X-X-X-X
-X--X--X-
---------
XXX---XXX
---------
-X--X--X-
X-X-X-X-X
-X--X--X-

David Vreken - 1 year, 3 months ago

@David Vreken In fact, this pattern can be used to show that there exists at least one solution for any odd n × n n \times n gridsize for n 3 n \geq 3 :

Let c c be the number of 3 × 3 3 \times 3 checkerboard sections going across the grid, let b b be the number of 1 × 3 1 \times 3 bars going across the grid, and let g g be the number of 1 1 square gaps going across the grid (between checkerboard sections and the bar sections). Then n = 3 c + b + g n = 3c + b + g . Now g g is one less than the total number of checkerboard and bar sections, so g = b + c 1 g = b + c - 1 , which means n = 4 c + 2 b 1 n = 4c + 2b - 1 .

There are three different cases to consider:

(1) The number of checkerboards sections is the same as the number of bar sections. Then b = c b = c so that n = 4 c + 2 c 1 = 6 c 1 n = 4c + 2c - 1 = 6c - 1 .

(2) The number of checkerboards sections is one more than the number of bar sections. Then b = c + 1 b = c + 1 so that n = 4 c + 2 ( c + 1 ) 1 = 6 c + 1 n = 4c + 2(c + 1) - 1 = 6c + 1 .

(3) The number of checkerboards sections is one less than the number of bar sections. Then b = c 1 b = c - 1 so that n = 4 c + 2 ( c 1 ) 1 = 6 c 3 n = 4c + 2(c - 1) - 1 = 6c - 3 .

Since 6 c 1 6c - 1 , 6 c + 1 6c + 1 , and 6 c 3 6c - 3 cover all the odd numbers greater than 3 3 , there is at least one solution for any odd n × n n \times n gridsize for n 3 n \geq 3 using the above pattern.


Using the above pattern, the number of hits h h is

h = 1 18 ( 5 n + 13 ) ( n 1 ) h = \frac{1}{18}(5n + 13)(n - 1) if n n is in the form 6 k + 1 6k + 1

h = 1 18 ( 5 n 3 ) ( n + 3 ) h = \frac{1}{18}(5n - 3)(n + 3) if n n is in the form 6 k + 3 6k + 3

h = 5 18 ( n + 1 ) 2 h = \frac{5}{18}(n + 1)^2 if n n is in the form 6 k 1 6k - 1

David Vreken - 1 year, 3 months ago

Log in to reply

@David Vreken Wow, that's excellent.

Chris Lewis - 1 year, 3 months ago

Do you mean this solution is the only one you found using 10 moves? Or that it is the only solution you found at all?

Matthew Feig - 1 year, 3 months ago

Log in to reply

@Matthew Feig I meant the first, but later on I found that both are true. Just to clarify, there are four different ways, but all rotations/reflections of one way:

and these are the only ways to solve the puzzle at all (without hitting an individual ball more than once)

David Vreken - 1 year, 3 months ago

idk i just guess and got it right because i played that game on nintedo , so i know that

Caleb Zylstra
Feb 28, 2020

I got this right by just estimating in my head.

I pretty much did the same thing. 👍🏻

Stephen Feig - 1 year, 3 months ago

0 pending reports

×

Problem Loading...

Note Loading...

Set Loading...