Python2048算法开发

源代码的链接可以在最下面找到,源代码中的2048算法包含界面的开发,但本次关于2048算法的讲解不包含界面的开发。

这个算法是我自己思考出来的,没有借鉴其他人的代码,希望大家能从中学到一点东西。算法的整体内容非常简单,主要由两个函数构成,但是在考虑这两个函数之前是什么之前,我们先考虑,怎样让一行四列的数字,完成一次2048模式的移动。比如

[4,2,2,0]

在2048中,如果我们要移动到右侧,该怎样移动。我们可以把这个过程分为两个步骤来实现。

第一个步骤,我们把该合并的块都合并起来。即我们要得到

[4,0,4,0]

第二个步骤,我们把所有的数字都移动到右侧,不留空格。即我们要得到

[0,0,4,4]

第二个步骤非常简单,我们主要考虑的就是第一个步骤的实现。2048,一次移动只有砖块上的数字相等才能合并,从这个点出发,我们只要寻找相等的砖块即可,如果找到两个相等的砖块,且他们的中间没有任何砖块相隔,就合并起来。

在四个砖块都是未知数的情况下,我们需要知道第一个有数字的砖块(即数字不为0)的位置。

我们给出一个简单的函数用于实现它。

def _2048_FindFirstNumber(start_pos:int,row:list) -> int:
    '''找到第一个不为0的数字的位置,然后返回'''

    for i in range(start_pos,len(row)):
        if i != 0:
            return i
    return -1
    

接下来是算法的核心部分,一个比较相对来说简单的函数,涵盖了我对2048的全部理解。

找到第一个不为0的数字后,记录它的位置变量为pos,开始寻找关于它的匹配砖块,从pos开始遇到的第一个不为0的砖块就是它的准配对,如果两者相等,则合并,如果两者不相等,抛弃第一个寻找到的数字,重新开始上述过程,(在配对成功的情况下)如果从pos开始遇到的第一个砖块的位置已经是第三块或者第四块砖,则结束本次函数,如果不是,则从当前位置+1处继续重复上述过程。如果你觉得思想太抽象或者看不懂的话,以下是上述这段话的代码实现.

def _2048_DiscussRow(row,start_pos=0):
    '''合并所有可以合并的数字'''

    copy_row = row[:]                              #复制一份,以防这个row是一个类变量
    pos_t = _2048_FindFirstNumber(start_pos,row)   #找到第一个数字之后
    
    # 如果pos_t为-1,即为[0,0,0,0],退出函数
    # 如果pos_t为3,即为[0,0,0,2x],也退出函数
    if pos_t == -1 or pos_t == len(copy_row) - 1:
        return copy_row
    else:
        #符合"有可能会有配对的砖块"这个条件下
        #开始寻找相匹配的砖块
        for i in range(pos_t + 1,len(copy_row)):
            if copy_row[i] != 0:
                if copy_row[i] == copy_row[pos_t]:
                    #找到了相等的砖块,合并一下
                    copy_row[i] *= 2
                    copy_row[pos_t] = 0
                    if i == len(copy_row) - 1 or i == len(copy_row) - 2:
                        return copy_row
                    else:
                        return _2048_DiscussRow(copy_row,i+1)
                else:
                    #砖块并不相等,则放弃第一个砖块
                    return _2048_DiscussRow(copy_row,i)
            else:
                #找到的砖块为0,直接pass
                pass
        #除了这块砖,没有其他砖块了,说明不需要变动,直接返回原砖块即可
        return copy_row

最终,我们只要在实现一个把所有的数字全部移动到右侧的函数即可.


def _2048_RushToWall(row):

    ret = [v for v in row if v != 0]
    return [0] * (len(row) - len(ret)) + ret

这样,整合三个函数,我们可以实现一个把4*4的Map往右移动的函数

def _2048_MoveRight(M):

    for i in range(len(M)):
        M[i] = _2048_RushToWall(_2048_DiscussRow(M[i]))
    return M

 那么四个方向的怎么实现呢?其实也很简单,我们只要通过列转行,以及反序两个操作,把它们转成可以向右移动实现的,最后再转回去即可.

    def _2048_RolToRow(M,size=4):

        ret = _2048_MakeEmptyMap(size)
        for i in range(size):
            for j in range(size):
                ret[j][size-i-1] = M[i][j]
        return ret

    def _2048_RowToRol(M,size=4):
    
        ret = _2048_MakeEmptyMap(size)
        for i in range(size):
            for j in range(size):
                ret[i][j] = M[j][size-i-1]
        return ret

    def _2048_Reversed(M,size=4):

        ret = []
        for row in M:
            ret.append(reversed(row))
        return ret

最后,整合以上所有的函数,形成一个可以

    def _2048_Move(rotation:Rotation,M):

        if rotation == Rotation.LEFT:
            return _2048_Reversed(_2048_MoveRight(_2048_Reversed(M)))
        elif rotation == Rotation.RIGHT:
            return _2048_MoveRight(M)
        elif rotation == Rotation.UP:
            return _2048_RowToRol(_2048_MoveRight(_2048_RolToRow(M)))
        elif rotation == Rotation.DOWN:
            return _2048_RowToRol(_2048_Reversed(_2048_MoveRight(_2048_Reversed(_2048_RolToRow(M)))))
        else:
            return M

以上就是本篇所有的内容了,这个代码我已经完善并上传到了csdn,大家可以前往以下页面下载。如果有任何问题,可以给我发消息或者加我的qq529324416

https://download.csdn.net/download/f529324416/10697960

你可能感兴趣的:(算法)