美文网首页
用 python 写一个用命令行玩的 2048 小游戏

用 python 写一个用命令行玩的 2048 小游戏

作者: Miltonlong | 来源:发表于2017-12-28 10:54 被阅读136次

    下面是我们要达到的效果,在命令行里面玩2048,是不是很酷?
    写出这个小程序其实用的知识很少,主要是用了嵌套列表,循环,if 判断,还有一点点 random 和copy 模块。作为练习是个很好的项目。


    2048.png

    初步分析游戏的流程

    首先来分析一下这个游戏。

    1 . 游戏界面为一个 4 X 4 一共 16 的方格,开始时在随机的两个格子里面生成两个数字 2 。

    2 . 可以上下左右滑动界面,数字会向着滑动的方向移动,途中若遇到相同的数字,则合并成一个数,值为二者的和,直到移动不了为止。同时在每次移动的时候,会在空白的地方再次生成两个数字 2 。

    3 . 若没有空格子且相邻没有相同的数字,那么游戏结束。

    游戏第一步

    第一步 当然是先写一个游戏界面,为了方便后面的操作和计算,需要先来装这些数据,因为要涉及到计算和修改,那么 python 内置的只有列表和字典可以考虑,但是字典是无序的,在定位上可能会问题,所以用列表比较合适。可以用一个嵌套列表来表示位置和值,写这个界面的方法很像写九九乘法表。

    import random
    # 开始界面
    def start():
        list_2048 = [['    ', '    ', '    ', '    '], ['    ', '    ', '    ', '    '], ['    ', '    ', '    ', '    '], ['    ', '    ', '    ', '    ']]
        i = 0
        while i < 2:
            x = random.randint(0,3)
            y = random.randint(0,3)
            if list_2048[y][x] == '    ':
                list_2048[y][x] = '%4d'%2
                i += 1
        return list_2048
    
    

    我开始生成一个空的嵌套列表,里面存放的全是 4 个空格组成的字符串,是因为我玩的时候尝试过,很难玩超过四位数(实际上我只玩到过三位数....),是拿来占位用,以免在游戏玩的过程中,界面出现错位。所以我在后面往里面添加元素的时候,添加的也是长度为 4 的字符串,而不是单纯的数字 2 。

    实际上,我们写的游戏的界面就已经完成了,后面全是在此列表中的转换。列表的框架就这个样子了,放了后面方便调用,写一个关于打印的函数。

    # 将列表打印出游戏界面的效果
    def print_number(li):
        for row in li:
            for number in row:
                print(number,end='|')
            print()
    
    

    就是如下效果:

    start.png

    游戏过程

    这个游戏操作还是很简单的,只能上下左右四个方向移动,故在玩的过程中只需要把这四个过程都写一遍,后面只是一直循环调用这个四个方法而已。
    先来分析向下移动,游戏的效果是,所有的数字向下移动,如果碰到相同的数字,那么合并成一个数字。
    初看比较复杂,又要移动,又要合并,而且因为数字在的位置不同,移动的单位也不相同,同时每次移动还要随机在空白区域产生两个数字。

    简化过程:
    步骤 1 :只移动,不合并。直到数字中间没有空隙(垂直方向),移动过程就结束了。因为中间没有空隙,那说明所有的数字都移动到位了,不能再继续移动了。
    步骤 2 :只合并不移动。用循环在判断的方式来验证相应方向上有没有可以合并的。
    步骤 3 :综合两个过程,先移动,然后判断合并,因为在合并的过程中,可能会产生空隙,故还需要调用一次移动,最后在两个空白区域在产生两个数字,当然到游戏的中后段,可能只会有一个空格或者没有空格,也要做相应的判断。在我写这篇文章的时候,才发现,我在这一步的判断中的逻辑很有问题,虽然最后呈现的效果一样,但是增加了很多不必要的计算量。(由于现在深夜了,我也懒得改了,给大家留个小作业,读者自己改改吧。)

    # down_step1 是将游戏界面里面所有的元素堆在下面,使中间没有空隙
    def down_step1(old_list):
        while True:
            for x in range(3):
                for y in range(4):
                    if old_list[x][y] != '    ' and old_list[x+1][y] == '    ':
                        old_list[x][y],old_list[x+1][y] = old_list[x+1][y],old_list[x][y]
            count = 0
            for y in range(4):
                judge_list = []
                for x in range(4):
                    judge_list.append(str(old_list[x][y]))
                judge_str = ''.join(judge_list)
                judge_str = judge_str.strip()
                if '    ' in judge_str:
                    break
                else:
                    count += 1
            if count == 4:
                break
        return old_list
    
    # down_step2 是将上下相邻且相同的数字合并,因为是向下移动,故判断的时候是从下像上判断,这点很重要。
    def down_step2(old_list):
        global score
        for x in range(4):   # 将前面处理好,挨着紧凑的数据来判断最后两项是否相同,若相同就将两项合并
            if old_list[3][x] != '    ' and old_list[3][x] == old_list[2][x]:
                old_list[3][x] = '%4d'%(int(old_list[3][x]) * 2)
                old_list[2][x] = '    '
                score += int(old_list[3][x])
                if old_list[1][x] != '    ' and old_list[1][x] == old_list[0][x]:
                    old_list[1][x] = '%4d'%(int(old_list[1][x]) * 2)
                    old_list[0][x] = '    '
                    score += int(old_list[1][x])
            elif old_list[2][x] != '    ' and old_list[2][x] == old_list[1][x]:
                old_list[2][x] = '%4d'%(int(old_list[2][x]) * 2)
                old_list[1][x] = '    '
                score += int(old_list[2][x])
            elif old_list[1][x] != '    ' and old_list[1][x] == old_list[0][x]:
                old_list[1][x] = '%4d'%(int(old_list[1][x]) * 2)
                old_list[0][x] = '    '
                score += int(old_list[1][x])
        return old_list
    '''
    down 是中和两个步骤,然后在把处理完的元素堆在下面。
    这里没有用循环处理,是因为要让玩家每操作一次,也只变动一次,
    操作一次,而变动多次会使玩家捉摸不到游戏的规律性
    '''
    def down(old_list):
        judge_list = copy.deepcopy(old_list)
        old_list = down_step1(old_list)
        old_list = down_step2(old_list)
        old_list = down_step1(old_list)
        if judge_list == old_list:
            return old_list
        if old_list[0].count('    ') + old_list[1].count('    ') + old_list[2].count('    ') + old_list[3].count('    ') >= 2:
            k = 0
            while k < 2:
                x = random.randint(0,3)
                y = random.randint(0,3)
                if old_list[y][x] == '    ':
                    old_list[y][x] = '%4d'%2
                    k += 1
        elif old_list[0].count('    ') + old_list[1].count('    ') + old_list[2].count('    ') + old_list[3].count('    ') == 1:
            k = 0
            while k < 1:
                x = random.randint(0, 3)
                y = random.randint(0, 3)
                if old_list[y][x] == '    ':
                    old_list[y][x] = '%4d'%2
                    k += 1
        else:
            pass
        return old_list
    

    相同的逻辑,其他几个方向都可以写出来了,其中 score 是游戏的分数,这段代码是我从程序里面复制出来的,就不改了。在这个片段中没有实际作用。

    将四个方向写完后,那就是重复的调用了,因为是在命令行里面玩,就需要玩家通过输入命令来操作游戏。
    我设定的是通过 wsad 四个键来控制 上下左右四个方向。

    最后就是判断游戏结束的条件,此游戏的结束条件是,所有的空格都被数字填满,而且每个数字相邻的位置的数都不相同。

    为了增加游戏的趣味性,也做了一个记分规则,每次移动合并后的数字之和为本次移动所获得的分数。比如:2和2合并为4,那么分数为4。最后把所有的分数累加起来就是最后的玩家的得分。

    # 启动游戏
    
    old_list = start()
    print_number(old_list)
    
    while True:
        # 根据用户输入做出相应的移动
        print()
        user_input = input('请输入你要移动的方向[上(w)下(s)左(a)右(d)]:')
        print()
        if user_input == 'w':
            old_list = up(old_list)
            print_number(old_list)
            print()
            print('目前得分:%d 分'%score)
        elif user_input == 's':
            old_list = down(old_list)
            print_number(old_list)
            print()
            print('目前得分:%d 分' % score)
        elif user_input == 'a':
            old_list = left(old_list)
            print_number(old_list)
            print()
            print('目前得分:%d 分' % score)
        elif user_input == 'd':
            old_list = right(old_list)
            print_number(old_list)
            print()
            print('目前得分:%d 分' % score)
        else:
            print()
            print('输入错误!请输入正确的方向!')
            print_number(old_list)
        # 游戏的终止条件
        # 判断界面是否还有空位
        if old_list[0].count('    ') + old_list[1].count('    ') + old_list[2].count('    ') + old_list[3].count('    ') == 0:
            # 判断每一个数相邻是否还有相同的数字
            count = 0
            for i in range(4):          # 判断横排
                for j in range(3):
                    if old_list[i][j] == old_list[i][j+1]:
                        count += 1
            for x in range(4):
                for y in range(3):
                    if old_list[y][x] == old_list[y+1][x]:
                        count += 1
            if count == 0:
                print('很遗憾,游戏结束!')
                print('您的最终得分:%d 分' % score)
                break
    

    至此结束。如果有什么更好的做法,欢迎交流,互相学习。
    若要代码的小伙伴,可以通过下面地址去拿。
    代码 : https://gitee.com/MiltonL/codes/zhuf495dgb7loeavstyc068

    相关文章

      网友评论

          本文标题:用 python 写一个用命令行玩的 2048 小游戏

          本文链接:https://www.haomeiwen.com/subject/kdumgxtx.html