【问题标题】:Magic square python魔方蟒
【发布时间】:2017-02-05 19:37:29
【问题描述】:

我正在编写一个程序,它读取文件中的一行并确定该行是否构成 Lo Shu 魔方。在这个幻方中,行之和、列之和、对角线之和必须等于 15,并且每个数字 1-9 在正方形中只能出现一次。这是我目前所拥有的:

def main():
    for line in open("Magic Square Input.txt"):
        items = line.split(" ")
        items = [int(x) for x in items]
        result = [items[0:3], items[3:6], items[6:9]]
        isMagic(result)

def isMagic(result):
    checks1 = ''
    for x in result:
        for y in range(3):
            if sum (result[y][y] for y in range(3)) == 15:
                if sum(x[y] for x in result) == 15:
                    checks1 = checkDupe(result)
                else:
                    checks1 = 'Invalid'
            else:
                checks1 = 'Invalid'

    print(checks1)

def checkDupe(result):
    checks1 = ''
    for i in range(0,8):
        counter = 0
        for j in result:
            if (j == i):
                counter += 1
        if counter > 0:
            checks1 = 'Invalid'
        else:
            checks1 = 'Valid'
    return checks1
main()

我的文本文件内容如下:

4 3 8 9 5 1 2 7 6
8 3 4 1 5 9 6 7 2
6 1 8 7 5 3 2 9 4
6 9 8 7 5 3 2 1 4
6 1 8 7 5 3 2 1 4
6 1 3 2 9 4 8 7 5
5 5 5 5 5 5 5 5 5

每行的前三个数字代表正方形的顶行,接下来的三个是中间行,最后三个是底行。我遇到的问题是前三个方块是有效的,而后四个应该是无效的。但是我的代码不断为我打印出来的是

Valid
Valid
Valid
Valid
Valid
Invalid
Valid

谁能告诉我我在哪里搞砸了?我对 python 还很陌生,我一直盯着这个几个小时试图理解它。

【问题讨论】:

  • 可能首先只检查行,然后只检查列,最后是对角线——这样更容易控制。而且不用拆分成行会更容易——行:sum(items[0:3]),列:sum([items[0], items[3], items[6]]),对角线:sum([items[0], items[4], items[8]])
  • 你可以使用len(set(items)) = 9检查数字是否不重复
  • 或者您可以检查数字 1-9 是否为 items - for x in range(1, 10): if x not in items: Invalid
  • 顺便说一句:你检查数字 0-7,而不是 1-9。
  • 如果您有问题,请使用多个print() 来检查变量中的值以及执行了哪部分代码 - 这有助于发现问题。

标签: python magic-square


【解决方案1】:

如果从平面列表开始,这个问题会更容易思考:

[4, 3, 8, 9, 5, 1, 2, 7, 6]

然后找出您需要检查的索引。总共只有八个:

indexes = (
    (0, 1, 2), (3, 4, 5), (6, 7, 8), # rows
    (0, 3, 6), (1, 4, 7), (2, 5, 8), # cols
    (0, 4, 8), (2, 4, 6),            # diag
    )

有了这样的设置,检查功能就变得非常简单了:

def main():
    for line in open('Magic Square Input.txt'):
        square = [int(n) for n in line.split()]
        if len(set(square)) != len(square):
            print('Invalid: Duplicates')
        else:
            for idx in indexes:
                if sum(square[i] for i in idx) != 15:
                    print('Invalid: Sum')
                    break
            else:
                print('Valid')

【讨论】:

    【解决方案2】:

    我的版本没有将项目拆分成行

    data = '''4 3 8 9 5 1 2 7 6
    8 3 4 1 5 9 6 7 2
    6 1 8 7 5 3 2 9 4
    6 9 8 7 5 3 2 1 4
    6 1 8 7 5 3 2 1 4
    6 1 3 2 9 4 8 7 5
    5 5 5 5 5 5 5 5 5'''
    
    def main():
        for line in data.split("\n"):
            # create list with all numbers
            items = list(map(int, line.split()))
            print(is_magic(items))
    
    def is_magic(items):
    
        # --- dups ---
    
        #print('dups')
        #print(len(set(items)) == 9)
        #for x in range(1, 10):
        #    print(x, x in items)
        if len(set(items)) != 9:
            return 'Invalid'
    
        # --- rows ---
    
        #print('rows')
        for x in range(0, 9, 3):
            l = items[x:x+3]
            #print(l, sum(l) == 15)
            if sum(l) != 15:
                return 'Invalid'
    
        # --- cols ---
    
        #print('cols')
        for x in range(3):
            l = [items[x], items[x+3], items[x+6]]
            #print(l, sum(l) == 15)
            if sum(l) != 15:
                return 'Invalid'
    
        # --- diags ---
    
        #print('diags')
        l = [items[0], items[4], items[8]]
        #print(l, sum(l) == 15)
        if sum(l) != 15:
            return 'Invalid'
    
        l = [items[2], items[4], items[6]]
        #print(l, sum(l) == 15)
        if sum(l) != 15:
            return 'Invalid'
    
        # --- OK ---
    
        return 'Valid'
    
    main()
    

    【讨论】:

      【解决方案3】:
      
          def magic_square(n):
              num=(n*((n*n)+1))/2
              print('\nThe Magic Number Is:-',num,'\n')
              f=[]
              for i in range(0,n):
                  a=[]
                  for j in range(0,n):
                      a.append(0)
                  f.append(a)
              (x,i,p,q)=(n*n,1,int(n/2),n-1)
              while x!=0:
                  if x==0:
                      (f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
                      continue
                  else:
                      if p==-1 and q==n:
                          p=0
                          q=n-2
                          if f[p][q]==0:
                              (f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
                              continue
                          else:
                              p=p+1
                              q=q-2
                              f[p][q]=i
                              i=i+1
                              p=p-1
                              q=q+1
                              x=x-1
                              continue
                      if p==-1:
                          p=n-1
                          if f[p][q]==0:
                              (f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
                              continue
                          else:
                              p=p+1
                              q=q-2
                              f[p][q]=i
                              i=i+1
                              p=p-1
                              q=q+1
                              x=x-1
                              continue
                      if q==n:
                          q=0
                          if f[p][q]==0:
                              (f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
                              continue
                          else:
                              p=p+1
                              q=q-2
                              f[p][q]=i
                              i=i+1
                              p=p-1
                              q=q+1
                              x=x-1
                              continue
                      else:
                          if f[p][q]==0:
                              (f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
                              continue
                          else:
                              p=p+1
                              q=q-2
                              f[p][q]=i
                              i=i+1
                              p=p-1
                              q=q+1
                              x=x-1
                              continue
              for i in range(len(f)):
                  for j in range(len(f[i])):
                      print(f[i][j] ,end = "   ")
                  print("\n")
      

      输入

      magic_square(5)

      输出

      幻数是:- 65.0

      9 3 22 16 15

      2 21 20 14 8

      25 19 13 7 1

      18 12 6 5 24

      11 10 4 23 17

      【讨论】:

      • 我们在 %d 之后使用空格来获得输出之间的间隙,我们在 python 中使用 end=" " 来实现同样的效果
      • 我没有提到 2 和更少的条件。您可以在开头添加 if 语句
      • 和5一样,可以得到任意大于2的奇数的幻方
      • 无法输出4的幻方:line 39, in magic_square f[p][q] = i IndexError: list index out of range
      【解决方案4】:

      为了帮助你,我应该开始说你的代码很难阅读。由于您是 Python 新手,很快您就会发现 Python 的主要优点之一是其清晰的语法,这使得很容易弄清楚一段代码在做什么。话虽如此,我解决了您的问题,使用与您相同的逻辑,但使代码更具可读性并使用一些 Python 技巧使解决方案更短、更清晰。

      def main():
      
          """Open the file, parse the input and check if it is a magic cube"""
      
          with open("Magic Square Input.txt") as f:
      
              for line in f.readlines():
      
                  numbers = line.split(" ")
                  cube = [int(x) for x in numbers]            
                  is_magic(cube)
      
      
      def is_magic(cube):
      
          """Check if cube is magic.
          There are two conditions that must be satisfied:
          1 - There must not be any repetitions of the numbers
          2 - All vertical/horizontal/diagonal sums must be 15
          """
      
          if not dupe(cube) and check_sum(cube):        
              print ('Valid')
      
          else:        
              print ('Invalid')
      
      
      def dupe(cube):
      
          """Check if there are repetitions in the cube."""
      
          if len(cube) == len(set(cube)):        
              return False
          return True
      
      
      
      def check_sum(cube):
      
          """Check if all vertical/horizontal/diagonal sums are 15"""
      
          if vertical_check(cube) and horizontal_check(cube) and diagonal_check(cube):        
              return True
      
      
      def vertical_check(cube):
      
          if sum(cube[0:9:3]) == sum(cube[1:9:3]) == sum(cube[2:9:3]) == 15:      
              return True    
          return False
      
      
      def horizontal_check(cube):
      
          if sum(cube[0:3]) == sum(cube[3:6]) == sum(cube[6:9]) == 15:      
              return True    
          return False
      
      
      def diagonal_check(cube):
      
          if sum(cube[0:9:4]) == sum(cube[2:7:2]) == 15:      
              return True    
          return False
      
      main()
      

      希望你能从代码中的 cmets 中理解解决方案。如果不是这种情况,请在此处再次发布。

      【讨论】:

      • 非常感谢你的朋友,这对我帮助很大!
      • 等等,在我的原始代码中,读取后的结果必须是一个二维数组,比如如果文本文件中的行是 1 2 3 4 5 6 7 8 9,它变成 [ [1,2,3],[4,5,6],[7,8,9]]
      • 哦,我不知道二维数组是处理阶段的必需品。我使用了一个简单的列表,因为这是解决这个问题的自然方法。此外,如果需要,您可以在最后重新格式化结果。只是出于好奇,我的朋友,你为什么需要一个二维数组?
      • 我猜它看起来更明确,对我来说更容易想象如何使用二维数组来做到这一点
      • 我同意你的看法。由于我们谈论的是立方体,自然的方式是在二维数组中思考。然而,当用计算机科学术语思考时,这是不正确的。拥有一个复合列表 [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 比拥有一个简单列表更笨拙。它需要双循环来遍历所有元素,从而降低解决方案的效率并且更难理解和调试。此外,检查多维数据集是否是魔法所需的所有操作对于简单列表来说都是自然的。所以在效率和代码维护方面还是使用简单的列表比较好。
      【解决方案5】:

      我必须进行一些重大更改,但您的 checkDupe 方法似乎无法正常工作。您还只检查了一个对角线而不是两个。另外,请注意,不是使用 checks1 变量保存答案是否有效,如果有任何错误,它只会返回“无效”,这通常会使代码更简洁,并大大简化了问题。如果从不返回“无效”,则该方法最后只返回“有效”。

         def main():
          for line in open("Magic Square Input.txt"):
              items = line.split(" ")
              items = [int(x) for x in items]
              result = [items[0:3], items[3:6], items[6:9]]
              print isMagic(result)
      
      def isMagic(result):
          # check duplicates
          if(checkDupe(result) == 'Invalid'):
              return 'Invalid'
          # diagonals
          if sum (result[y][y] for y in range(3)) != 15:
              return 'Invalid'
          # other digonals
          if sum (result[2 - y][2 - y] for y in range(3)) != 15:
              return 'Invalid'
          # rows and columns
          for i in range(3):
              if sum(result[i][y] for y in range(3)) != 15:
                  return 'Invalid'
              if sum(result[x][i] for x in range(3)) != 15:
                  return 'Invalid'
          return 'Valid'
      
      def checkDupe(result):
          for x in range(1,9):
              if(not x in (result[0]+result[1]+result[2])):
                  return 'Invalid'
              return 'Valid'
      main()
      

      【讨论】:

        【解决方案6】:

        在这里,我创建了示例方法来解决此问题。在这种方法中,我们维护以下列表

        • lstAvailableNumbers:可用号码列表(在您的情况下为 1-9)
        • lstTraversedNumbers:遍历过的数字列表(一旦遍历了一个项目,它就会被移动到这个列表中)
        • 重复号码列表(所有重复号码都将添加到此列表中)
        • 重复号码索引(将存储重复号码的索引,以便替换不存在的号码
        • 还退回更换费用

        出于调试目的,我还添加了打印语句来检查不同列表的值

        def createMagicSquare(s):
            lstAvailableNumbers = list()
            lstAvailableNumbers=[1,2,3,4,5,6,7,8,9]   
            lstTraversedNumbers=set()
            lstDuplicateNumbers=list()
            dictDuplicateNumberIndex = dict()
            lstMissingNumbers=set()
            cost=0
            for item in range(len(s)):
                for colItem in range(len(s[item])):
                    num= s[item][colItem]
                    #print('Print traversed number - ' )
                    #print(num)
                    #print(lstTraversedNumbers)
        
                    if(num in lstAvailableNumbers):
                        #print('Inside if condition for  num in lstAvailableNumbers ' )
                        lstAvailableNumbers.remove(num)
                        #print(num)
        
                        if(num in lstTraversedNumbers):
                            #print('Inside if condition for  num in lstTraversedNumbers ' )
                            #print(num)                    
                            lstDuplicateNumbers.append(num)
                            lstIndexPosition =[]
                            lstIndexPosition.append(item)
                            lstIndexPosition.append(colItem)                        
                            dictDuplicateNumberIndex[num]=lstIndexPosition
                        lstTraversedNumbers.add(num)
                        #print(lstTraversedNumbers)
                    else:
                        lstDuplicateNumbers.append(num)
                        lstIndexPosition =[]
                        lstIndexPosition.append(item)
                        lstIndexPosition.append(colItem)                        
                        dictDuplicateNumberIndex[num]=lstIndexPosition
        
            i=0
            #print("Available Numbers -")
            #print(lstAvailableNumbers)
            #print("Traversed Numbers -")
            #print(lstTraversedNumbers)
            #print("Duplicate Numbers -")
            #print(lstDuplicateNumbers)
            #print("Duplicate Number index -")
            #print(dictDuplicateNumberIndex)
        
            for item in lstAvailableNumbers:        
                itemToReplace= lstDuplicateNumbers[i]
                value= dictDuplicateNumberIndex[itemToReplace]
                s[value[0]][value[1]] = item
                i+=1
                cost += abs(itemToReplace - item)
                #print(cost)    
            return cost 
        

        【讨论】:

          猜你喜欢
          • 2014-09-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多