[python][покритикуйте код] Задача Да Винчи
От: DemAS http://demas.me
Дата: 29.09.10 12:21
Оценка:
Покритикуйте, пожалуйста, код и подскажите как его сделать лучше, с учетом выбранного языка программирования.

Смысл кода — задача Да Винчи. Есть квадрат заданной размерности у которого все клетки белые. Мы можем отметить любую клетку квадрата, окрасив ее в черный цвет. При этом смежные клетки сменят свой цвет на противоположный. Код ищет все коомбинации клеток, которые надо отметить, чтобы квадрат полностью сменил свой цвет.

Так вызов:

c = Calculator(Board(2))
c.run()


Дает результат:

['1', '1', '1', '1']


Что говорит о том, что все вершины (они считаются сверху вниз и слева направо) нужно пометить.

Если интресно, то, насколько я знаю, задача не имеет доказательства, но методом перебора (для тех размерностей квадрата, что поддаются этому перебору) удалось показать, что решение существует для квадратов всех размерностей. Более того, решение существует для прямоугольников. И более того, оно существует для любой фигуры, составленной из клеток, даже с пустотами внутри.

Сам код:

'''
Created on 29.09.2010

@author: ademidov
'''

import copy

class Combination:
    def __init__(self, combination, board):
        self.orig = copy.copy(combination)
        self.combination = combination
        self.board = board
        
    def mask(self):
        mask = dict()
        for i in range(len(self.combination)):
            mask[i] = 0
                 
        for pos, element in enumerate(self.combination):            
            if (element == '1'):                               
                for neighbour in self.board.neighbours(pos):                     
                    mask[neighbour] = mask[neighbour] + 1
                            
        return mask

    def check(self):
        for element in self.combination:
            if (element == '0'):
                return False
        return True    
    
    def calc(self):        
        for pos, value in self.mask().items():                        
            if ((value == 1) or (value == 3)):
                self.invert(pos)
    
    def invert(self, pos):
        if(self.combination[pos] == '0'):
            self.combination[pos] = '1';
        else:
            self.combination[pos] = '0'
    
    def original(self):
        return self.orig

class Board:
    def __init__(self, size):
        self.side = size
        self.size = size * size
    
    def posToXY(self, pos):
        y = round(pos / self.side)
        x = pos - y * self.side 
        return [x, y]
    
    def xyToPos(self, x, y):
        return y * self.side + x
    
    def neighbours(self, pos):
        result = []
        [x, y] = self.posToXY(pos)
              
        if( x > 0):            
            result.append(self.xyToPos(x - 1, y))
        if( x < self.side - 1):            
            result.append(self.xyToPos(x + 1, y))            
        if( y > 0):            
            result.append(self.xyToPos(x, y - 1))
        if( y < self.side - 1):            
            result.append(self.xyToPos(x, y + 1))
            
        return result    

class Calculator:
    def __init__(self, board):
        self.board = board
        self.side = board.side
        self.size = board.size            

    def combinations(self):
        result = []
        for n in range(2**self.size):
            binVal = bin(n)[2:].zfill(self.size)        
            result.append(Combination([ x for x in binVal], self.board))
        return result
                                 
    def processCombination(self, combination):        
        combination.calc()                
        if(combination.check()):                       
            print combination.original()
            
    def run(self):
        for combination in self.combinations():
            self.processCombination(combination)
        

c = Calculator(Board(2))
c.run()
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.