1
$\begingroup$

Here is a number grid:

enter image description here

And here is the rule for how to move:

A move consists of selecting two adjacent squares (either vertically, horizontally or diagonally) and dividing the sum of the two numbers evenly among those two squares. In the case that the sum of the numbers is odd, add an extra one in the square which originally had the greatest number.

Your challenge is to find the minimum number of moves it takes for all the squares in the grid to be greyed out without all the numbers ending with 22. (Note: Now I'm going to use the word lose to describe freezing the whole grid without each square in the grid ending with 22.)

Here is an example of me losing on the spot, the first one at normal speed, the second one a time lapse. I ended up with 45, though that was a random no-strategy play:

enter image description here enter image description here

I programmed the app/tool/game I used in the example above using python. You can use the code to also have access to the program:

import pygame

# You can change the grid & size to whatever you like
grid = [[33, 7, 35, 26, 30],
        [1, 8, 38, 29, 17],
        [16, 19, 9, 37, 21],
        [20, 36, 3, 11, 15],
        [32, 14, 34, 31, 28]]

size = 80
line = 5
win = sum([c for r in grid for c in r]) // len([c for r in grid for c in r])

pygame.init()
pygame.font.init()

font = pygame.font.SysFont("Arial", size-10)
wn = pygame.display.set_mode((600, 600))

grid = [c for c in zip(*grid)]
class Square():
    def __init__(self, pos, num):
        self.x = pos[0] * size + line
        self.y = pos[1] * size + line
        self.num = num
        self.color = (255, 255, 255)
        self.rect = pygame.Rect(self.x, self.y, size-line, size-line)
        self.frozen = False

    def clear(self):
        self.color = (255, 255, 255)
    
    def draw(self):
        if self.frozen:
            pygame.draw.rect(wn, (150, 150, 150), self.rect)
        else:
            pygame.draw.rect(wn, self.color, self.rect)
        if self.num == win:
            pygame.draw.circle(wn, (100, 255, 100), (self.x+size//2, self.y+size//2), size//4)
        text = font.render(str(self.num), True, (0, 0, 0))
        if len(str(self.num)) == 1:
            wn.blit(text, (self.x+size*.25, self.y*.98))
        else:
            wn.blit(text, (self.x+size*.055, self.y*.98))        


class Box():

    def __init__(self, grid, square=None):
        self.square = square
        self.grid = grid
        self.clicked = []

    def box(self): # Returns a list of all adjancent squares that can change the number of the selected square
        x, y = self.square.x//size, self.square.y//size
        y1 = x-1 if x else 0
        y2 = len(self.grid)+2 if x > len(self.grid)+2 else x+2
        x1 = y-1 if y else 0
        x2 = len(self.grid[0])+2 if y > len(self.grid[0])+2 else y+2
        b = []
        for r in self.grid[y1:y2]:
            for c in r[x1:x2]:
                if abs(c.num - self.grid[x][y].num) > 1:
                    b.append(c)
                elif c != self.square:
                    c.clear()
        return b

    def color(self, color):
        for square in self.box():
            square.color = color

    def clear(self):
        for c in self.clicked:
            c.clear()
        self.clicked.clear()


def show_moves(num):
    moves = f'{num} move' if num == 1 else f'{num} moves'
    text = font.render(moves, True, (255, 255, 255))
    wn.blit(text, (line, size*len(squares)))

def avg(n1, n2):
    n = n1 + n2
    if n % 2:
        if n1 > n2:
            return n // 2 + 1, n // 2
        return n // 2, n // 2 + 1
    return n // 2, n // 2

def won(grid):
    if all(square.num == win for row in grid for square in row):
        return 'You Win!'
    return 'You Lose!'


squares = [[Square((i, j), col) for j, col in enumerate(row)] for i, row in enumerate(grid)]
box = Box(squares)
box2 = Box(squares)
total = 0

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
        if event.type == pygame.MOUSEBUTTONDOWN:
            for row in squares:
                for square in row:
                    if square.rect.collidepoint(pygame.mouse.get_pos()):
                        if not square.frozen:
                            if not box.clicked:
                                box.clicked.append(square)
                                square.color = (140, 255, 255)
                                box.square = square
                                box.color((255, 255, 140))
                            else:
                                if square in box.box():
                                    box.clicked.append(square)
                                if square == box.clicked[0]:
                                    box.color((255, 255, 255))
                                    box.clear()
                            if len(box.clicked) == 2:
                                total += 1
                                box.clicked[0].num, box.clicked[1].num = avg(box.clicked[0].num, box.clicked[1].num)
                                box.color((255, 255, 255))
                                box.clear()
    wn.fill((0, 0, 0))
    for i in range(len(squares)):
        for j in range(len(squares[i])):
            adjacent = []
            for k in range(max(0,i-1), min(len(squares), i+2)):
                for l in range(max(0,j-1), min(len(squares[k]), j+2)):
                    if i != k or j != l:
                        adjacent.append((k, l))
            if not any((k, l) for (k, l) in adjacent if abs(squares[i][j].num - squares[k][l].num) > 1):
                squares[i][j].frozen = True
            elif squares[i][j].frozen:
                squares[i][j].frozen = False
    for row in squares:
        for square in row:
            square.draw()
    show_moves(total)
    pygame.display.update()
    if all(square.frozen for row in squares for square in row):
        wn.fill((0, 0, 0))
        text = font.render(won(squares), True, (255, 255, 255))
        wn.blit(text, (line, size*len(squares)//2))
        show_moves(total)
        pygame.display.update()
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
        break
$\endgroup$
5
  • $\begingroup$ What causes a square to be greyed out? $\endgroup$ – Anthony Ingram-Westover Nov 1 '20 at 18:06
  • 2
    $\begingroup$ @Anthony It appears that the grey squares are those with no move options. (All neighboring squares are either equal or +/- 1 in value.) A grey square can become white again if one of its neighbors' values changes. $\endgroup$ – Daniel Mathias Nov 1 '20 at 18:19
  • $\begingroup$ @AnthonyIngram-Westover What Daniel said :) $\endgroup$ – risky mysteries Nov 1 '20 at 18:25
  • 1
    $\begingroup$ Thank you for the split-speed animations! $\endgroup$ – humn Nov 1 '20 at 18:48
  • $\begingroup$ @bobble I can't believe I didn't notice that! $\endgroup$ – risky mysteries Nov 1 '20 at 19:09
2
$\begingroup$

I have managed to lock the grid in

35 moves

As shown:

enter image description here

$\endgroup$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.