9
$\begingroup$

This puzzle is inspired by this puzzle that I answered: Is equality possible?

Here is the number grid from that puzzle:

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 have the number 13 in it. (Note: Now I'm going to use the word win to describe completing a grid)

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

enter image description here enter image description here

As you can probably tell, it is quite simple. There are countless ways to win. A coordinated strategy isn't necessary if all you need is to win, it's just a matter of eyeballing which two squares can nudge you closer to winning. The case might be different if you want to minimize the number of moves.


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 = [[7, 24, 12, 8, 11],
        [13, 21, 3, 20, 19],
        [10, 22, 15, 2, 9],
        [23, 1, 6, 16, 17],
        [5, 25, 14, 4, 18]]

size = 60
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$

1 Answer 1

4
$\begingroup$

I have a solution in

23 moves

As seen here:

enter image description here Google Docs link

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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