python制作2048游戏,仅用8行代码

最近看到有人用418B用C语言写出了2048,想试一下py语言的能力,遂用890B完成

这里只是我目前的极限,不多说进入正文,最简代码在最后

这里是效果图,也就是不断改变16个点的像素值,然后打印出来而已

关键在于怎么减少代码量

py语言不像C语言可以多行代码写到一行,py有着严格的缩进和分行要求

所以想要减小行数,一个可行的思路是写一行的字符串,用format去代替换行/tab,然后exec

想要减小内存,即减少文字,那必然变量名全是abcd,条件语句都是单行的if else,赋值能写到一行就一行

接下来还是略微进入游戏本体部分;忘记说了本次全程无import

可以看到36行代码,2048的思路是

假如方向是上:

从第二行开始,第2行往第1行移动(或相加)

然后是第三行,第3往第2行移动(或相加),在向第1行移动或相加

然后是第四行,第4行往第3行移动(或相加),向2,向1

假如方向是下,就是第3行,第2行,第1行即可

如果是左右,先对坐标系进行转置,横变纵,纵变横,变换后在转置回来即可

以上是主体部分,还有一些细节,例如,如果进行了移动,则从移动后还剩下的空坐标处随机生成2或者4。如果没移动是不给新生成的,可以思考如下

像这样的肯定不希望往上往右,因为左下角的大数字可能有危险回不去,但实际上2048为了增加难道(游戏体验)是不允许往左往下的,就是如果位置完全不变,那么也不会生成新的,这个功能两行代码已实现

另外方块合成,新合成的不能继续合成,必须是远的先合成,然后近的

比如一条线上4440往左划就是8400而非4800

4444往左划就是8800而非16 000。这个地方由于代码量没有添加,

分析代码,

这是前几行,第一个是range(4),很明显后面会使用很多次range(4),故替换

w是16个点 0

改变一个点,不然刷不出来

定义的这个d()函数是xorshift函数,就是生成随机数的,感兴趣的可以查查xorshift算法,我不懂所以直接抄的代码,W每次都是一个随机的很大的int(每次调用这个函数W随机,不同,但是W出现的顺序是相同的,也就是说你每次运行这个程序,W序列是固定的,所以不同的地方在于传入的参数,是允许生成点的列表,也就是现在16个点中为0的点)

这里是上面说的核心部分,o是转置坐标系,s是用来检测是否变化的,也就是上面提到的不允许生成新的,当下面有方块移动或者合成是s改为1,函数最后用s判定是否生成新点,如果整个坐标系中,经过了变换之后还是占满格子(其实就是既没合成也没转移而且满了,那就gameover了,实际上呢,要四个方向都gameover才是over了,你只用了单一一个方向,所以其实我压根没有成功/失败的判定,你自己玩玩着玩着发现不会变了就知道了)

n是目前的坐标系,上下就是w,左右就是转置。记住这行代码(n=w if r ……),这里用到了单行条件语句

x,y,z就是,x是上面提到的234行或者321行,y:如果上,那么在第2行要运行换1次,在第3行要两次,在第4行要3次,还有后面的-1,自己慢慢想把。反正这样就能把上下合并成一个for x了,左右也是

条件语句a-b:这种形式就是说a-b!=0,也就是a!=b,看看是不是少了一个字(哈哈,呜呜,难受,夹缝生存)

for j in range(4): 假如是上,那每一行有4个吧,p,q就是近的和远的数,远的为0,就把近的移过去,近的变成0,远的近的一样,就把两个加起来放到远的,近的为0

下面那个u=set()也是精华,说白了,找到16个点中的0。一般都是新建空列表,两层for 循环(坐标系本身是两层,w也是两层,然后条件判断一下),我这里十分精简了。

首先是列表里面的for循环,这个很基础了,单行的if else不规范,但是简洁。如果那个点是0就加上他的坐标,否则加上0, 这样新的列表就是位置个数0和一些坐标

怎么去掉0呢,又不知道个数又不知道是否存在,pop要索引,remove只删除一个,del更垃圾

所以先转为集合,集合用diacard(没有这个元素不报错),集合.remove没有该元素就报错了

然后转回来为列表,现在就3行代码得到了为0的点,也就是允许生成新点(2&4)的坐标,然后放入之前定义的随机函数里生出来,f很明显是0或1,也就是你生成的是2还是4

核心部分完了,最后加个while循环获取输入即可

小细节又来了,怎么打印呢用for循环?怎么处理空格呢,1位数2位数3位数4位数呢

这里有个tip很多地方可以用,("0"+str(i))[-2::] 也就是1变为01, 2变为02,10是10,43是43,就整齐了

所以这里转为4个字符长度,细节又来了,用join打印不仅更快而且省代码(比for循环打印)

最后,用上前面说的format即可

附上完整代码如下:

A,B="\n","\t"
C='b=(0,1,2,3){0}w=[[0 for i in b] for j in b]{0}w[2][2]=2{0}X,Y,Z,W=123456789,362436069,521288629,88675123{0}def d(r):{1}global X,Y,Z,W{1}t,X,Y,Z=X^(X<<11),Y,Z,W{1}W=W^(W>>19)^t^(t>>8){1}return r[W%len(r)],W%2{0}def e(r):{1}global w{1}o,s,=[[w[i][j] for i in b] for j in b],0{1}n=w if r in "ws" else o{1}x,y,z=([1,2,3],0,-1) if r in "aw" else ([2,1,0],3,1){1}for i in x:{2}while i-y:{3}for j in b:{4}p,q=n[i][j],n[i+z][j]{4}if p and (q==0 or q==p):{5}n[i+z][j]=p if q==0 else p+q{5}n[i][j]=0{5}s=1{3}i+=z{1}u=set([(x,y) if n[x][y]==0 else 0 for x in b for y in b]){1}u.discard(0){1}u,c=list(u),len(u){1}if c and s:{2}e,f = d(u){2}n[e[0]][e[1]] = 2*f+2{1}if r in "da":{2}w=[[n[i][j] for i in b] for j in b]'.format(*[A+D*B for D in range(6)])
exec(C)
while 1:
    e(input("?"))
    for i in w:
        v=[(B+str(j))[-4::] for j in i]
        print("".join(v),end=A+A)

在多说一点,格式化字符也有说法

1最开始是f“{}”型格式化,"\n"、"\t"都是4个字符,换成A,B就简化了

2有的缩进是5缩进,连续5个{B}

3上面的5个{B}改为{5*B}

4{A}{B}改为{A+B}

5发现还是format好用,前面的A+B,A+2*B,A+3*B直接用一个数字即可

6format可以用列表作为参数,加上*号即可

个人愚见,欢迎大家指正以及讨论

对了把上面的C打印出来就是源代码了,exec里不允许有while,所以下面自己添加,

还有直接打印出来的制表符格式不对,不是python标准缩进,总之会报错,自己改改缩进就行

(明显能看出来缩进很宽)而且很少呢,840B

猜你喜欢

转载自blog.csdn.net/m0_52285505/article/details/128587266