自制2048小游戏(附源码)

Posted on 2017-03-25 15:15  Hamilton算符  阅读(1657)  评论(0编辑  收藏  举报

概述

  作者这几天去一趟湖南,这快车真“快”啊,跨越3个省需要接近一天时间。。。坐火车实在无聊就去玩2048,结果一遍一遍的手滑失误,导致心态爆炸。想了想干脆自己做个2048算了,顺便还可以写外挂上分!

Python Code

MainWindow:

  1 #!/usr/bin/python
  2 #  -*- coding:utf-8 -*-
  3 '''
  4 Created on Mar 24, 2017
  5 
  6 @author: zhengli
  7 '''
  8 
  9 import copy
 10 import numpy
 11 from PyQt5.QtCore import Qt
 12 from PyQt5.QtGui import (QIcon, QFont)
 13 from PyQt5.QtWidgets import (QAction,  QDesktopWidget, QGridLayout, QMainWindow, QMessageBox, QToolTip, QWidget)
 14 import GameCanvas
 15 
 16 
 17 class App(QMainWindow):
 18     """
 19     Main Window.
 20     """
 21 
 22     # noinspection PyArgumentList
 23     def __init__(self):
 24 
 25         QMainWindow.__init__(self)
 26 
 27         # noinspection PyCallByClass,PyTypeChecker
 28         QToolTip.setFont(QFont('SansSerif', 10))
 29         self.setGeometry(100, 100, 600, 600)
 30         self.frameGeometry().moveCenter(QDesktopWidget().availableGeometry().center())
 31         self.move(self.frameGeometry().topLeft())
 32         self.setWindowTitle('2048')
 33         self.setWindowIcon(QIcon('python.png'))
 34         self.setWindowFlags(Qt.WindowStaysOnTopHint)
 35 
 36         self.action = dict()
 37         self.actionLoad()
 38         self.menuBarLoad()
 39 
 40         self.data = dict()
 41         self.canvas = 0
 42         self.gameImage(4, 4)
 43 
 44         self.statusBar().showMessage('Ready')
 45 
 46         self.show()
 47 
 48     def actionLoad(self):
 49         """
 50         set MainData.action
 51         """
 52         self.action["4X4"] = QAction('4X4', self)
 53         self.action["4X4"].setShortcut('Ctrl+4')
 54         self.action["4X4"].setStatusTip('4X4 game')
 55         self.action["4X4"].triggered.connect(lambda: self.gameImage(4, 4))
 56 
 57         self.action["5X5"] = QAction('5X5', self)
 58         self.action["5X5"].setShortcut('Ctrl+5')
 59         self.action["5X5"].setStatusTip('5X5 game')
 60         self.action["5X5"].triggered.connect(lambda: self.gameImage(5, 5))
 61 
 62         self.action["6X6"] = QAction('6X6', self)
 63         self.action["6X6"].setShortcut('Ctrl+6')
 64         self.action["6X6"].setStatusTip('6X6 game')
 65         self.action["6X6"].triggered.connect(lambda: self.gameImage(6, 6))
 66 
 67     def menuBarLoad(self):
 68         """
 69         set MainWindow.menuBar
 70         """
 71         self.statusBar()
 72         menubar = self.menuBar()
 73 
 74         gameMenu = menubar.addMenu('&Game')
 75         gameMenu.addAction(self.action["4X4"])
 76         gameMenu.addAction(self.action["5X5"])
 77         gameMenu.addAction(self.action["6X6"])
 78 
 79     def gameImage(self, m, n):
 80         """
 81         image draw.
 82         """
 83         # noinspection PyBroadException
 84         try:
 85             data = self.data["%d_%d" % (m, n)]
 86             count = self.data["score_%d_%d" % (m, n)]
 87         except:
 88             self.data["%d_%d" % (m, n)] = numpy.zeros((m, n), dtype=int)
 89             data = self.data["%d_%d" % (m, n)]
 90             self.data["score_%d_%d" % (m, n)] = 0
 91             count = self.data["score_%d_%d" % (m, n)]
 92         self.statusBar().showMessage('Score: %d' % count)
 93 
 94         layout = QGridLayout()
 95         layout.setSpacing(10)
 96 
 97         widget = QWidget()
 98         self.canvas = GameCanvas.GameCanvas(data=data, count=count, parent=widget)
 99         self.canvas.fig.canvas.mpl_connect('button_press_event', self.button_press)
100         self.canvas.fig.canvas.mpl_connect('button_release_event', self.button_release)
101 
102         layout.addWidget(self.canvas)
103         widget.setLayout(layout)
104         self.setCentralWidget(widget)
105 
106     def button_press(self, event):
107         """
108         Get coordinates
109         """
110         self.canvas.event_x = event.x
111         self.canvas.event_y = event.y
112 
113     # noinspection PyUnresolvedReferences
114     def button_release(self, event):
115         """
116         :param event:
117         :return:
118         """
119         data_backup = copy.deepcopy(self.canvas.data)
120         if abs(self.canvas.event_x - event.x) > abs(self.canvas.event_y - event.y):
121             if event.x > self.canvas.event_x:
122                 self.canvas.right_operation(data_backup=data_backup)
123             else:
124                 self.canvas.left_operation(data_backup=data_backup)
125         else:
126             if event.y > self.canvas.event_y:
127                 self.canvas.up_operation(data_backup=data_backup)
128             else:
129                 self.canvas.down_operation(data_backup=data_backup)
130 
131         self.canvas.fig.clf()
132         self.canvas.axes = self.canvas.fig.add_axes([0, 0, 1, 1], frameon=False)
133         self.canvas.complete_draw()
134         self.canvas.fig.canvas.draw()
135 
136         self.data["score_%d_%d" % (self.canvas.m, self.canvas.n)] = self.canvas.count
137         self.statusBar().showMessage('Score: %d' % self.canvas.count)
138 
139     # noinspection PyUnresolvedReferences
140     def keyPressEvent(self, event):
141         """
142         :param event:
143         :return:
144         """
145         data_backup = copy.deepcopy(self.canvas.data)
146         if event.key() == Qt.Key_Right:
147             self.canvas.right_operation(data_backup=data_backup)
148         elif event.key() == Qt.Key_Left:
149             self.canvas.left_operation(data_backup=data_backup)
150         elif event.key() == Qt.Key_Up:
151             self.canvas.up_operation(data_backup=data_backup)
152         elif event.key() == Qt.Key_Down:
153             self.canvas.down_operation(data_backup=data_backup)
154         elif event.key() == Qt.Key_Escape:
155             self.canvas.data *= 0
156             self.canvas.count = 0
157         elif event.key() == Qt.Key_Delete:
158             print("yes ")
159 
160         self.canvas.fig.clf()
161         self.canvas.axes = self.canvas.fig.add_axes([0, 0, 1, 1], frameon=False)
162         self.canvas.complete_draw()
163         self.canvas.fig.canvas.draw()
164 
165         self.data["score_%d_%d" % (self.canvas.m, self.canvas.n)] = self.canvas.count
166         self.statusBar().showMessage('Score: %d' % self.canvas.count)
167 
168     def closeEvent(self, event):
169         """
170         exit game.
171         """
172         # noinspection PyCallByClass,PyTypeChecker
173         reply = QMessageBox.question(self, 'Message', "Are you sure to quit?",
174                                      QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
175         if reply == QMessageBox.Yes:
176             event.accept()
177         else:
178             event.ignore()
MainWindow

GameImage:

  1 #!/usr/bin/python
  2 #  -*- coding:utf-8 -*-
  3 '''
  4 Created on Mar 24, 2017
  5 
  6 @author: zhengli
  7 '''
  8 
  9 import copy
 10 import random
 11 import numpy
 12 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
 13 from matplotlib.figure import Figure
 14 from matplotlib import collections
 15 
 16 
 17 class GameCanvas(FigureCanvasQTAgg):
 18     """
 19      basic data
 20     """
 21 
 22     def __init__(self, data=None, count=0, parent=None, width=5, height=4, dpi=100):
 23 
 24         self.data = data
 25         self.count = count
 26         self.m = len(data)
 27         self.n = len(data[0])
 28 
 29         self.event_x = 0
 30         self.event_y = 0
 31 
 32         self.fig = Figure(figsize=(width, height), dpi=dpi)
 33         self.axes = self.fig.add_axes([0, 0, 1, 1], frameon=False)
 34         self.complete_draw()
 35 
 36         FigureCanvasQTAgg.__init__(self, self.fig)
 37         self.setParent(parent)
 38 
 39     def complete_draw(self):
 40         """
 41         :return:
 42         """
 43         shape = numpy.array([[0.05, 0.05], [0.05, 0.95], [0.95, 0.95], [0.95, 0.05]])
 44         for i in range(self.m):
 45             for j in range(self.n):
 46                 rectangle = copy.deepcopy(shape)
 47                 rectangle[:, 0] += j
 48                 rectangle[:, 1] += self.m - i
 49                 if 0.1 * numpy.log2(max(2, 2 * self.data[i][j])) < 1:
 50                     alpha = 0.1 * numpy.log2(max(2, 2 * self.data[i][j]))
 51                 else:
 52                     alpha = 1
 53                 patch = collections.PolyCollection([rectangle], alpha=alpha)
 54                 self.axes.add_collection(patch)
 55                 if self.data[i][j] != 0:
 56                     self.axes.text(j + 0.5, self.m - i + 0.5, s=str(self.data[i][j]), color='white', fontsize=45,
 57                                    horizontalalignment='center', verticalalignment='center')
 58         self.axes.autoscale()
 59 
 60     def right_operation(self, data_backup):
 61         """
 62         :param data_backup:
 63         :return:
 64         """
 65         for i in range(self.m):
 66             index, = numpy.where(self.data[i, :] != 0)
 67             if len(index) != 0:
 68                 values = self.data[i, index]
 69                 if len(index) > 1:
 70                     j = len(values) - 1
 71                     while j != 0:
 72                         if values[j] == values[j - 1]:
 73                             self.count += values[j - 1]
 74                             values[j - 1] *= 2
 75                             values = numpy.hstack((values[:j], values[(j + 1):]))
 76                             break
 77                         else:
 78                             j -= 1
 79                 self.data[i, :] *= 0
 80                 for j in range(len(values)):
 81                     self.data[i][-j - 1] = values[-j - 1]
 82         if self.data.min() * (self.data - data_backup).min() == 0:
 83             index, = numpy.where(self.data[:, 0] == 0)
 84             if len(index) != 0:
 85                 i = index[random.randint(1, len(index)) - 1]
 86                 self.data[i][0] = random.randint(1, 2)
 87 
 88     def left_operation(self, data_backup):
 89         """
 90         :param data_backup:
 91         :return:
 92         """
 93         for i in range(self.m):
 94             index, = numpy.where(self.data[i, :] != 0)
 95             if len(index) != 0:
 96                 values = self.data[i, index]
 97                 if len(index) > 1:
 98                     j = 0
 99                     while j != len(values) - 1:
100                         if values[j] == values[j + 1]:
101                             self.count += values[j + 1]
102                             values[j + 1] *= 2
103                             values = numpy.hstack((values[:j], values[(j + 1):]))
104                             break
105                         else:
106                             j += 1
107                 self.data[i, :] *= 0
108                 for j in range(len(values)):
109                     self.data[i][j] = values[j]
110         if self.data.min() * (self.data - data_backup).min() == 0:
111             index, = numpy.where(self.data[:, -1] == 0)
112             if len(index) != 0:
113                 i = index[random.randint(1, len(index)) - 1]
114                 self.data[i][-1] = random.randint(1, 2)
115 
116     def up_operation(self, data_backup):
117         """
118         :param data_backup:
119         :return:
120         """
121         for j in range(self.n):
122             index, = numpy.where(self.data[:, j] != 0)
123             if len(index) != 0:
124                 values = self.data[index, j]
125                 if len(index) > 1:
126                     i = 0
127                     while i != len(values) - 1:
128                         if values[i] == values[i + 1]:
129                             self.count += values[i + 1]
130                             values[i + 1] *= 2
131                             values = numpy.hstack((values[:i], values[(i + 1):]))
132                             break
133                         else:
134                             i += 1
135                 self.data[:, j] *= 0
136                 for i in range(len(values)):
137                     self.data[i][j] = values[i]
138         if self.data.min() * (self.data - data_backup).min() == 0:
139             index, = numpy.where(self.data[-1, :] == 0)
140             if len(index) != 0:
141                 j = index[random.randint(1, len(index)) - 1]
142                 self.data[-1][j] = random.randint(1, 2)
143 
144     def down_operation(self, data_backup):
145         """
146         :param data_backup:
147         :return:
148         """
149         for j in range(self.n):
150             index, = numpy.where(self.data[:, j] != 0)
151             if len(index) != 0:
152                 values = self.data[index, j]
153                 if len(index) > 1:
154                     i = len(values) - 1
155                     while i != 0:
156                         if values[i] == values[i - 1]:
157                             self.count += values[i - 1]
158                             values[i - 1] *= 2
159                             values = numpy.hstack((values[:i], values[(i + 1):]))
160                             break
161                         else:
162                             i -= 1
163                 self.data[:, j] *= 0
164                 for i in range(len(values)):
165                     self.data[-i - 1][j] = values[-i - 1]
166         if self.data.min() * (self.data - data_backup).min() == 0:
167             index, = numpy.where(self.data[0, :] == 0)
168             if len(index) != 0:
169                 j = index[random.randint(1, len(index)) - 1]
170                 self.data[0][j] = random.randint(1, 2)
GameCanvas

Start:

 1 #!/usr/bin/python
 2 #  -*- coding:utf-8 -*-
 3 '''
 4 Created on Mar 24, 2017
 5 
 6 @author: zhengli
 7 '''
 8 
 9 import MainWindow
10 import sys
11 from PyQt5.QtWidgets import QApplication
12 
13 if __name__ == '__main__':
14     app = QApplication(sys.argv)
15     ex = MainWindow.App()
16     sys.exit(app.exec_())
Start

Demo

鼠标操作:

键盘操作:

声明

本文由Hamilton算符”原创,未经博主允许不得转载!