1024是前几年很热门的小游戏,规则很简单,就是在4x4的格子中把所有偶数加到一起,但非常让人沉迷。用Python+PyQT山寨一套并不难,网上也有很多教程。
但我们学Python并不是只是学它的语法规则而已。Python之所以最近这么流行,完全是因为它在数据分析,科研界和AI的类库非常流行,而numpy是最重要的一环。既然1024是一个4x4的格子,当然可以用numpy的array来实现。
游戏刚开始时是没有数字的,但我们可以用0来初始化一下,numpy的zeros()函数就是做这个的,但数据类型默认是float,所以要声明为int
self.allSquares = np.zeros((4, 4), dtype=int)
按下空格键后,要在随机位置新建一个数字为2的格子,这个用Python的random.randint就可以了,但有一点注意,numpy数组的访问方式是[行][列] ,而Qt的drawText是横坐标,纵传标的,看似相同,其实是要反过来的
def generate_square(self, painter):row = random.randint(0, 3)col = random.randint(0, 3)if self.allSquares[row][col] == 0:print(f"generate {row},{col}")s = Square(col, row, num=2)s.draw(painter)self.allSquares[row][col] = int(s.num)else:self.generate_square(painter)
按下左方向键后,就需要把所有非零的数字移到左边,零移到右边。刚开始我以为用numpy的trim_zeros 去掉左边的零,再用pad方法补零在右边就好。但有种情况是处理不掉的,比如[2,0,2,0] 这中间的0就看起来需要遍历下数组了。
查了下文档,其实用concatenate就可以做到,把非零提出一个列表,把零提到一个列表,然后两列表合并就正好生成一个大小和原列表相同的新列表,很巧妙吧!
queue = self.allSquares[row]queue = np.concatenate((queue[queue != 0], queue[queue == 0]))
然后就需要合并相同数字了,这个似乎可以用reduce, 但因为只要相同数字才能相加,所以还是简单的遍历实现了。
上面实现了左移,那其它方向原理类似,要再写一遍吗?最机智又最爱偷懒的程序员怎么可以这样重复自己。既然是个方向问题,旋转一下,调用左移方法,再旋转回去就好了啊。
numpy自然提供旋转数组方法np.rot90, 参数k代表旋转次数,这样我们就可以旋转180和270度了
if QKeyEvent.key() == Qt.Key_Left:print(self.allSquares)self.move_left(painter)if QKeyEvent.key() == Qt.Key_Right:self.allSquares = np.rot90(self.allSquares, k=2)print(self.allSquares)self.move_left(painter)self.allSquares = np.rot90(self.allSquares, k=2)if QKeyEvent.key() == Qt.Key_Up:self.allSquares = np.rot90(self.allSquares)self.move_left(painter)self.allSquares = np.rot90(self.allSquares, k=3)if QKeyEvent.key() == Qt.Key_Down:self.allSquares = np.rot90(self.allSquares, k=3)self.move_left(painter)self.allSquares = np.rot90(self.allSquares)
剩下的就是没什么技术含量的Qt显示图形和文本API了,如需完整源代码,请点关注或私信。
参考书目: