还未发布过话题
  • 想了半天,越想越复杂,当 n 比较大的时候,且已有数字可以横着或者竖着或者斜着把这个方形切割。
    那么 n<2g
    那么 n>2g 的时候,情况就比较复杂了,截面产生后,落点只能去往截后数字多的那块区域,但进入这里面找落点还得遵循规则,还可以再产生截面。。。
    单纯的 9 宫格,大不了可以写死,而想要写一个通用性的方法,托大了。
    先留着,想到方案再接上。

  • 我再想想

  • 🙏 已修复
    在过滤重复值的时候,判断下一跳,没有把前一跳作为参数传到 available_nex() 方法去,一直用的初始的 first_num。

  • 讲下思路

    假设给出的列表都是规范的 A*A 的格式,如 1-9 三行行列,1-16 四行四列,那么大致可以把数字分为三类 (g 为长度开平方,因为前提条件,g 必定为自然数):

    • 固定的角落,有四个数值,左上:1,右下:g, 左下:1+g*(g-1), 右上: g

      • 左上-1,右下 +1 超出边界
      • 左下 +g,右上-g 超出边界
    • 四边除角落外的值,这类值,因为数值间的关系上下对称,左右对称,是可以遍历两次得到的

      • +g 或者-g 超出边界,那肯定是第一或者最后一行的数字了,反之则是第一或最后一列的数字
      • 值小于 g(也就是第一行最后一个数字),那肯定是第一行的数了,反之是最后一行的数
      • 值如果刚好是 g 的倍数关系,那肯定是在右侧了,反之则是左侧边界
    • 剩下的就是处于中间的值

    而以上三种类型,可以写三个方法定义,每一种都有特定的规律来取值,这里没说不能斜着,因此我将斜着临近的数也算进去了。

    实现代码(基于 python3.6)

    # coding:utf8
    # author: ryan
    import random
    from math import sqrt
    list_a = [1,2,3,4,5,6,7,8,9]
    L = len(list_a)
    # 每一行个数
    g = int(sqrt(L) )
     # 四个角
    corner_list = [1,g,1+2*g,L]
    # 除角落外的边界数字
    middle_list = []
    for i in range(2,g):
        # 首行
        middle_list.append(i)
        # 末行
        middle_list.append(i+2*g)
    for i in range(1+g,1+2*g,g):
        # 左侧
        middle_list.append(i)
        # 右侧
        middle_list.append(i+g-1)
    
    # 角落数字推算下一个数
    def corner_make_nextnum(x):
        temp_list =[]
        # 边角数字固定只有四个,分两种, 1 和最大值 (也就是L))往前-1或者往后+1,不在1到L之间间,是一类。 另外两个是另一类
        if x-1 not in list_a or x+1 not in list_a:
            # 1 和 len, x-1不在list_a里,是左上角,反之是右下角
            if x-1 not in list_a:
                # 左上角,符合数字,右,下,右下
                x_right = x + 1
                x_down = x + g
                x_right_down = x + g + 1
                temp_list.append(x_right)
                temp_list.append(x_down)
                temp_list.append(x_right_down)
            else:
                # 右下角,符合数字,左,上,左上
                x_left = x - 1
                x_up = x - g
                x_left_up = x - g - 1
                temp_list.append(x_left)
                temp_list.append(x_up)
                temp_list.append(x_left_up)
        else:
            # 如果x-g还在list_a里,是左下角,反之是右上角
            if x-g in list_a:
                # 左下角,符合数字:上,右上,右
                x_up = x - g
                x_right_down = x - g + 1
                x_right = x + 1
                temp_list.append(x_up)
                temp_list.append(x_right_down)
                temp_list.append(x_right)
            else:
                # 右上角,符合数字:左,左下,下
                x_left = x - 1
                x_left_down = x + g - 1
                x_down = x + g
                temp_list.append(x_left)
                temp_list.append(x_left_down)
                temp_list.append(x_down)
        next_num = random.choice(temp_list)
        return next_num
    
    # 每行中间数推算下一个数
    def line_without_corner(x):
        temp_list = []
        # 如果+g,-g不在list_a中,那就是横向的
        if x+g not in list_a or x-g not in list_a:
            x_left = x - 1
            x_right = x + 1
            # 如果x比g小,那说明是第一行的,反之是最后一行的
            if x < g:
                # 第一行符合数字为左,右,下,临近的左下,右下
                x_down = x + g
                x_left_down = x + g - 1
                x_right_down = x + g + 1
                temp_list.append(x_down)
                temp_list.append(x_left_down)
                temp_list.append(x_right_down)
            else:
                # 最后一行符合数字为左,右,上,临近的左上,右上
                x_up= x - g
                x_left_up = x - g - 1
                x_right_up = x - g + 1
                temp_list.append(x_up)
                temp_list.append(x_left_up)
                temp_list.append(x_right_up)
            temp_list.append(x_left)
            temp_list.append(x_right)
         # 纵向的,且如果是g的倍数,则表示是在右侧边界,若不是则表示在左侧边界
        else:
            # 自然数,横竖个数相同的这种排列,上下相差始终为g
            x_up = x - g
            x_down = x + g
            # 右侧边界,可以除了上下还有临近的左侧,左上,左下
            if x%g == 0:
                x_left = x - 1
                x_left_up = x - g - 1
                x_left_dwwn = x + g - 1
                temp_list.append(x_left)
                temp_list.append(x_left_up)
                temp_list.append(x_left_dwwn)
            # 左侧边界,可以除了上下还有右临近的右侧,右上,右下
            else:
                x_right = x + 1
                x_right_up = x - g + 1
                x_right_dwwn = x + g + 1
                temp_list.append(x_right)
                temp_list.append(x_right_up)
                temp_list.append(x_right_dwwn)
            temp_list.append(x_up)
            temp_list.append(x_down)
        next_num = random.choice(temp_list)
        return next_num
    
    # 中间的数字推算下一个数,上,下,左,右,左上,左下,右上,右上,固定有8个
    def middle_make_nextnum(x):
        temp_list = [x-1, x+1, x-g, x+g, x-g-1, x-g+1, x+g-1, x+g+1]
        next_num = random.choice(temp_list)
        return next_num
    
    # 根据已有数字推测下一可能数字
    def available_next(x):
        if x in corner_list:
            next_number = corner_make_nextnum(x)
        elif x in middle_list:
            next_number = line_without_corner(x)
        else: 
            next_number = middle_make_nextnum(x)
        return next_number
    
    def random_make_num(n):
        first_num = random.choice(list_a)
        passwd_list = [first_num]
        i = 1
        while i < n:
            next_num = available_next(first_num)
            # 过滤重复值
            if next_num in passwd_list:
                pass
            else:
                passwd_list.append(next_num)
                first_num = next_num
                i+=1
        return passwd_list
    
    if __name__ == "__main__":
        passwd_list = random_make_num(4)
        print(passwd_list)