ソースを参照

broken tetris implementation

Thomas Buck 1年前
コミット
9de90e735c
2個のファイルの変更272行の追加7行の削除
  1. 6
    7
      pi.py
  2. 266
    0
      tetris.py

+ 6
- 7
pi.py ファイルの表示

@@ -17,14 +17,13 @@ from rgbmatrix import RGBMatrix, RGBMatrixOptions
17 17
 from PIL import Image
18 18
 
19 19
 class PiMatrix:
20
-    def __init__(self):
21
-        # TODO configurable
22
-        self.width = 32
23
-        self.height = 32
20
+    def __init__(self, w = 32, h = 32):
21
+        self.width = w
22
+        self.height = h
24 23
 
25 24
         options = RGBMatrixOptions()
26
-        options.rows = 32
27
-        options.cols = 32
25
+        options.rows = w
26
+        options.cols = h
28 27
         options.chain_length = 1
29 28
         options.parallel = 1
30 29
         options.row_address_type = 0
@@ -63,5 +62,5 @@ class PiMatrix:
63 62
         self.image.putpixel((int(x), int(y)), color)
64 63
 
65 64
 if __name__ == "__main__":
66
-    t = PiMatrix()
65
+    t = PiMatrix(32, 32)
67 66
     t.debug_loop(lambda: t.set_pixel(15, 15, (255, 255, 255)))

+ 266
- 0
tetris.py ファイルの表示

@@ -0,0 +1,266 @@
1
+#!/usr/bin/env python3
2
+
3
+# ----------------------------------------------------------------------------
4
+# "THE BEER-WARE LICENSE" (Revision 42):
5
+# <xythobuz@xythobuz.de> wrote this file.  As long as you retain this notice
6
+# you can do whatever you want with this stuff. If we meet some day, and you
7
+# think this stuff is worth it, you can buy me a beer in return.   Thomas Buck
8
+# ----------------------------------------------------------------------------
9
+
10
+from draw import ScrollText
11
+import time
12
+import random
13
+
14
+class Tetris:
15
+    def __init__(self, g, i, ts = 0.5, to = 60.0):
16
+        self.gui = g
17
+        self.input = i
18
+        self.timestep = ts
19
+        self.timeout = to
20
+
21
+        self.endText = ScrollText(self.gui, "Game Over!", "uushi",
22
+                                   2, 75, (251, 72, 196))
23
+        self.scoreText = ScrollText(self.gui, "Score:", "uushi",
24
+                                    2, 75, (63, 255, 33))
25
+
26
+        self.bg = (0, 0, 0)
27
+        self.colors = [
28
+            (251, 72, 196), # camp23 pink
29
+            (63, 255, 33), # camp23 green
30
+            (255, 0, 0),
31
+            #(0, 255, 0),
32
+            (0, 0, 255),
33
+            (255, 255, 0),
34
+            (0, 255, 255),
35
+            (255, 0, 255),
36
+            #(255, 255, 255),
37
+        ]
38
+
39
+        # all [y][x] sub-lists must be the same length
40
+        self.pieces = [
41
+            # "I"
42
+            [
43
+                [1],
44
+                [1],
45
+                [1],
46
+                [1],
47
+            ],
48
+
49
+            # "L"
50
+            [
51
+                [1, 0],
52
+                [1, 0],
53
+                [1, 1],
54
+            ],
55
+
56
+            # "J"
57
+            [
58
+                [0, 1],
59
+                [0, 1],
60
+                [1, 1],
61
+            ],
62
+
63
+            # "T"
64
+            [
65
+                [1, 1, 1],
66
+                [0, 1, 0],
67
+            ],
68
+
69
+            # "O"
70
+            [
71
+                [1, 1],
72
+                [1, 1],
73
+            ],
74
+
75
+            # "S"
76
+            [
77
+                [0, 1, 1],
78
+                [1, 1, 0],
79
+            ],
80
+
81
+            # "Z"
82
+            [
83
+                [1, 1, 0],
84
+                [0, 1, 1],
85
+            ],
86
+        ]
87
+
88
+        random.seed()
89
+        self.restart()
90
+
91
+    def restart(self):
92
+        self.start = time.time()
93
+        self.last = time.time()
94
+        self.button = None
95
+        self.score = 0
96
+        self.done = False
97
+        self.data = [[self.bg for y in range(self.gui.height)] for x in range(self.gui.width)]
98
+        self.piece = None
99
+
100
+    def finished(self):
101
+        if self.input == None:
102
+            # backup timeout for "AI"
103
+            if (time.time() - self.start) >= self.timeout:
104
+                return True
105
+
106
+        if self.done:
107
+            # game over screen
108
+            return self.scoreText.finished()
109
+
110
+        return False
111
+
112
+    # TODO collision detection is broken
113
+    # TODO not working for pixels outside of vertical center line???
114
+    # TODO something like that...
115
+    def collision(self):
116
+        # check for collision of piece with data
117
+        pos = (self.piece[2], self.piece[3])
118
+        for y in range(0, len(self.piece[0])):
119
+            for x in range(0, len(self.piece[0][y])):
120
+                # only check where piece actually is
121
+                if self.piece[0][y][x] == 0:
122
+                    continue
123
+
124
+                # check for collision with bottom wall
125
+                if (y + pos[1]) >= self.gui.height:
126
+                    return True
127
+
128
+                # check for collision with previous pieces
129
+                if self.data[x + pos[0]][y + pos[1]] != self.bg:
130
+                    return True
131
+        return False
132
+
133
+    # copy piece into data buffer
134
+    def put(self, clear, pos = None, pie = None):
135
+        position = pos
136
+        if position == None:
137
+            position = (self.piece[2], self.piece[3])
138
+
139
+        piece = pie
140
+        if piece == None:
141
+            piece = self.piece[0]
142
+
143
+        for y in range(0, len(piece)):
144
+            for x in range(0, len(piece[y])):
145
+                remove = False
146
+                if piece[y][x] == 0:
147
+                    remove = True
148
+
149
+                if clear or remove:
150
+                    self.data[x + position[0]][y + position[1]] = self.bg
151
+                else:
152
+                    self.data[x + position[0]][y + position[1]] = self.piece[1]
153
+
154
+    def step(self):
155
+        if self.piece == None:
156
+            justPlaced = True
157
+
158
+            # select a new piece type and color
159
+            self.piece = [
160
+                self.pieces[random.randrange(0, len(self.pieces))], # piece
161
+                self.colors[random.randrange(0, len(self.colors))], # color
162
+                0, # x
163
+                0, # y
164
+            ]
165
+
166
+            # center the piece on top of the playing board
167
+            self.piece[2] = int((self.gui.width - len(self.piece[0][0])) / 2)
168
+
169
+            if self.collision():
170
+                # new piece immediately collided. game over!
171
+                return False
172
+
173
+            # copy piece into data buffer
174
+            self.put(False)
175
+
176
+            # don't move in the placement-step
177
+            return True
178
+
179
+        oldPosition = (self.piece[2], self.piece[3])
180
+        oldPiece = [x[:] for x in self.piece[0]]
181
+
182
+        # button input
183
+        if self.button == "u":
184
+            # rotate piece
185
+            # https://stackoverflow.com/a/48444999
186
+            self.piece[0] = [list(x) for x in zip(*self.piece[0][::-1])]
187
+        elif self.button == "l":
188
+            if self.piece[2] > 0:
189
+                self.piece[2] -= 1
190
+        elif self.button == "r":
191
+            if self.piece[2] < (self.gui.width - 1):
192
+                self.piece[2] += 1
193
+        else:
194
+            # one pixel down
195
+            self.piece[3] += 1
196
+
197
+        # clear out piece from its old location
198
+        self.put(True, oldPosition, oldPiece)
199
+
200
+        collision = self.collision()
201
+        if collision:
202
+            # piece collided, put it back
203
+            self.put(False, oldPosition, oldPiece)
204
+            self.piece[0] = oldPiece
205
+            self.piece[2] = oldPosition[0]
206
+            self.piece[3] = oldPosition[1]
207
+
208
+            if (self.button != "l") and (self.button != "r"):
209
+                # but only stop playing it if it was moving down
210
+                self.piece = None
211
+        else:
212
+            # copy piece at new location into buffer
213
+            self.put(False)
214
+
215
+        # clear previous input
216
+        self.button = None
217
+
218
+        return True
219
+
220
+    def buttons(self):
221
+        keys = self.input.get()
222
+        if keys["left"]:
223
+            self.button = "l"
224
+        elif keys["right"]:
225
+            self.button = "r"
226
+        elif keys["up"]:
227
+            self.button = "u"
228
+        elif keys["down"]:
229
+            self.button = "d"
230
+
231
+    def draw(self):
232
+        if self.done:
233
+            if self.endText.finished():
234
+                self.scoreText.draw()
235
+            else:
236
+                self.endText.draw()
237
+                self.scoreText.restart()
238
+            return
239
+
240
+        if self.input != None:
241
+            self.buttons()
242
+        else:
243
+            # TODO "AI"
244
+            self.button = None
245
+
246
+        if (self.button != None) or ((time.time() - self.last) >= self.timestep):
247
+            self.last = time.time()
248
+            cont = self.step()
249
+            if cont == False:
250
+                self.done = True
251
+                self.scoreText.setText("Score: " + str(self.score), "uushi")
252
+                self.endText.restart()
253
+
254
+        for x in range(0, self.gui.width):
255
+            for y in range(0, self.gui.height):
256
+                self.gui.set_pixel(x, y, self.data[x][y])
257
+
258
+if __name__ == "__main__":
259
+    import util
260
+    t = util.getTarget()
261
+
262
+    from gamepad import InputWrapper
263
+    i = InputWrapper()
264
+
265
+    d = Tetris(t, i, 0.1)
266
+    t.debug_loop(d.draw)

読み込み中…
キャンセル
保存