简体   繁体   English

Python:如何使我的4着色检查器更具可读性

[英]Python: How to make my 4-coloring checker more readable

I was trying to write a general program to check The 17x17 problem SOLVED! 我试图编写一个通用程序来检查17x17问题已解决! , 4-coloring of a17x17 grid with no monochromatic rectangles. ,a17x17网格的4色,没有单色矩形。 Solution link: 17.txt . 解决方案链接: 17.txt

This is what I wrote: 这就是我写的:

from itertools import product

def is_solution(myfile,m,n):
    """ m-lines, n-columns """
    grid = [c.strip() for c in line.split(',')] for line in open(myfile).readlines()]
    for x0,y0 in product(xrange(m),xrange(n)):
        start = grid[x0][y0]
        for x in xrange(x0+1,m):
            if grid[x][y0] == start:
                for y in xrange(y0+1,n):
                    if grid[x0][y] == start == grid[x][y]:
                            return False
    return True


print is_solution('17.txt',17,17)

Is there a more readable, concise or efficient way (in that order of priority) to write this? 是否有更可读,简洁或有效的方式(按照优先顺序)来写这个? Maybe a different approach with different data structures... Since i am learning Python at the moment, any advice is very welcome. 也许是采用不同数据结构的不同方法......由于我目前正在学习Python,所以非常欢迎任何建议。

  1. You should cleanly separate the logic for in-/output from the verification logic (this basically applies to any code). 您应该干净地将输入/输出的逻辑与验证逻辑分开(这基本上适用于任何代码)。 This also includes that you only put definitions at the module's top level. 这还包括您只将定义放在模块的顶层。 The actual program usually goes into a conditional like in the code below which is only executed if the file is called directly from the command line (and not if it is only import ed by another file). 实际程序通常会进入条件,如下面的代码所示,只有在直接从命令行调用文件时才会执行(而不是仅由另一个文件import )。
  2. The dimensions of the grid can be derived from the input. 网格的尺寸可以从输入中导出。 No need for separate parameters here. 这里不需要单独的参数。
  3. You should work with integers instead of strings (this is optional, but more clean, IMO) 您应该使用整数而不是字符串(这是可选的,但更干净,IMO)

My attempt (taking the file from STDIN, can be called like python script.py < 17.txt ): 我的尝试(从STDIN获取文件,可以像python script.py < 17.txt一样python script.py < 17.txt ):

import itertools

def has_monochromatic_rectangles(grid):
  # use range instead of xrange here (xrange is not in Python 3)
  points = list(itertools.product(range(len(grid)), range(len(grid[0]))))
  # check if for any rectangle, all 4 colors are equal
  # (this is more brute-force than necessary, but you placed simplicity
  # above efficiency. Also, for 17x17, it doesn't matter at all ;)
  return any(grid[x1][y1] == grid[x1][y2] == grid[x2][y1] == grid[x2][y2]
             for (x1,y1), (x2,y2) in itertools.product(points, points)
             if x1 != x2 and y1 != y2)

def has_max_colors(grid, most):
  # collect all grid values and uniquify them by creating a set
  return len(set(sum(grid, []))) <= most

if __name__ == '__main__':
  # read from STDIN (could easily be adapted to read from file, URL, ...)
  import sys
  grid = [map(int, line.split(',')) for line in sys.stdin]

  assert has_max_colors(grid, 4)
  assert not has_monochromatic_rectangles(grid)
import urllib
grid=urllib.urlopen("http://www.cs.umd.edu/~gasarch/BLOGPAPERS/17.txt")
grid=[map(int,row.split(",")) for row in grid]
print grid

def check_grid(grid):
    for i in range(17):
        for j in range(17):
            for i2 in range(i):
                for j2 in range(j):
                    colours=[grid[a][b] for a in (i,i2) for b in (j,j2)]
                    assert(len(set(colours))>1)

check_grid(grid)
grid[1][1]=2
check_grid(grid)

Obligatory one-liner*! 强制性的单线*!

Assuming you've loaded the 17x17 data into a numpy array named A (see @robertking's answer to use urllib), you can do it with one line with numpy! 假设您已将17x17数据加载到名为Anumpy array (请参阅@ robertking的使用urllib的答案),您可以使用numpy的一行来完成!

 print (array([len(set(A[i:i+k1,j:j+k2][zip(*[(0,0), (0,-1),(-1,0),(-1,-1)])])) for i in xrange(16) for j in xrange(16) for k1 in xrange(2,17) for k2 in xrange(2,17)])!=1).all()

* Don't actually do this in one-line. *实际上不要在一行中这样做。 Here it is expanded out a bit for clarity: 为了清楚起见,它稍微扩展了一下:

corners = zip(*[(0,0), (0,-1),(-1,0),(-1,-1)])

for k1 in xrange(2,17):
    for k2 in xrange(2,17):
        for i in xrange(16):
            for j in xrange(16):

                # Pull out each sub-rectange
                sub = A[i:i+k1, j:j+k2]

                # Only use the corners
                sub = sub[corners]

                # Count the number of unique elements
                uniq = len(set(sub))

                # Check if all corners are the same
                if uniq == 1: 
                    print False
                    exit()
print True

Here is another way to think about it. 这是考虑它的另一种方式。

import urllib
grid=urllib.urlopen("http://www.cs.umd.edu/~gasarch/BLOGPAPERS/17.txt")
grid=[map(int,row.split(",")) for row in grid]

def check(grid):
    colour_positions=lambda c,row:set(i for i,colour in enumerate(row) if colour==c) #given a row and a colour, where in the row does that colour occur
    to_check=[[colour_positions(c,row) for row in grid] for c in range(1,5)] #for each row and each colour, get the horizontal positions.
    from itertools import combinations
    for i in to_check:
        for a,b in combinations(i,2):
            if len(a&b)>1: #for each colour, for each combination of rows, do we ever get more than 1 horizontal position in common (e.g. a rectangle)
                return False
    return True

print check(grid)
grid[1][1]=2
print check(grid)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM