Skip to content

Commit 84c9f8e

Browse files
committed
working on TetrisTwoBlockApp
1 parent 4cdcf64 commit 84c9f8e

5 files changed

Lines changed: 350 additions & 16 deletions

File tree

dumbdisplay_examples/tetris/tetris_common.py renamed to dumbdisplay_examples/tetris/_common.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import random
2+
13
from dumbdisplay.layer_turtle import LayerTurtle
24

35

@@ -83,6 +85,20 @@ def sync_image(self):
8385
self.block_pen.setLevelAnchor(anchor_x, anchor_y)
8486

8587

88+
def _randomize_grid(randomize_row_count: int) -> Grid:
89+
grid_cells = []
90+
for y in range(_grid_n_rows):
91+
grid_row = []
92+
for x in range(_grid_n_cols):
93+
if y >= (_grid_n_rows - randomize_row_count) and random.random() < 0.7:
94+
color = random.randint(1, len(_colors) - 1)
95+
else:
96+
color = 0
97+
grid_row.append(color)
98+
grid_cells.append(grid_row)
99+
return Grid(grid_cells=grid_cells)
100+
101+
86102
def _draw(x, y, color_number, pen: LayerTurtle):
87103
screen_x = _left + (x * _block_unit_width) # each turtle 20x20 pixels
88104
screen_y = _top - (y * _block_unit_width)
@@ -110,6 +126,8 @@ def _check_block_grid_placement(block_grid: Grid, block_grid_x_off: int, block_g
110126
if block_grid.get_value(y, x) != 0:
111127
row_idx = y + block_grid_y_offset
112128
col_idx = x + block_grid_x_off
129+
if row_idx < 0:
130+
continue # never mind above the grid
113131
if row_idx < 0 or row_idx >= grid.n_rows:
114132
if not check_boundary:
115133
continue
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import random
2+
3+
from dumbdisplay_examples.tetris._common import Grid, _colors
4+
5+
_square = [[1,1],
6+
[1,1]]
7+
8+
_horizontal_line = [[1,1,1,1]]
9+
10+
_vertical_line = [[1],
11+
[1],
12+
[1],
13+
[1]]
14+
15+
_left_l = [[1,0,0,0],
16+
[1,1,1,1]]
17+
18+
_right_l = [[0,0,0,1],
19+
[1,1,1,1]]
20+
21+
_left_s = [[1,1,0],
22+
[0,1,1]]
23+
24+
_right_s = [[0,1,1],
25+
[1,1,0]]
26+
27+
_t = [[0,1,0],
28+
[1,1,1]]
29+
30+
_shapes = [_square, _horizontal_line, _vertical_line, _left_l, _right_l, _left_s, _right_s, _t]
31+
32+
33+
def _randomize_block_grid() -> Grid:
34+
block_grid = random.choice(_shapes)
35+
if False:
36+
block_grid = _vertical_line
37+
color = random.randint(1, len(_colors) - 1)
38+
block_grid = [[color if cell != 0 else 0 for cell in row] for row in block_grid]
39+
return Grid(grid_cells=block_grid)
40+
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
# ***
2+
# *** Adapted from TETRIS CLASSIC\tetris_turtle.py of https://github.com/DimaGutierrez/Python-Games
3+
# *** - modified from dumbdisplay_examples/tetris/tetris_two_block.py
4+
# ***
5+
6+
import random
7+
import time
8+
9+
from dumbdisplay.core import *
10+
from dumbdisplay.layer_graphical import DDRootLayer
11+
from dumbdisplay.layer_turtle import LayerTurtle
12+
from dumbdisplay.layer_lcd import LayerLcd
13+
from dumbdisplay_examples.tetris._common import Grid, _colors, _grid_n_rows, _grid_n_cols, _block_unit_width, \
14+
_width, _height, _left, _top, _draw_grid, _commit_block_grid, Block, \
15+
_check_block_grid_placement, _randomize_grid
16+
from dumbdisplay_examples.tetris._shapes import _randomize_block_grid
17+
18+
from dumbdisplay_examples.utils import DDAppBase, create_example_wifi_dd
19+
20+
_RANDOMIZE_ROW_COUNT = 2
21+
22+
23+
_delay = 0.3 # For time/sleep
24+
25+
def _check_grid(shape: 'Shape', score: LayerTurtle) -> (bool, int):
26+
grid = shape.grid
27+
block = shape.block
28+
29+
# Check if each row is full:
30+
empty_count = 23
31+
deleted_count = 0
32+
for y in range(0,24):
33+
is_full = True
34+
is_empty = True
35+
y_erase = y
36+
for x in range(0,12):
37+
if grid.get_value(y, x) == 0:
38+
is_full = False
39+
else:
40+
is_empty = False
41+
if not is_empty and not is_full:
42+
empty_count -= 1
43+
break
44+
# Remove row and shift down
45+
if is_full:
46+
shape.score_count += 1
47+
score.clear()
48+
score.write(f'Score: {shape.score_count}', align='C')
49+
50+
for y in range(y_erase-1, -1, -1):
51+
for x in range(0,12):
52+
grid.set_value(y + 1, x, grid.get_value(y, x))
53+
54+
deleted_count += 1
55+
56+
return (empty_count == 23, deleted_count)
57+
58+
59+
class Shape:
60+
def __init__(self, pen: LayerTurtle, block_pen: LayerTurtle):
61+
self.grid = _randomize_grid(_RANDOMIZE_ROW_COUNT)
62+
self.score_count = 0
63+
self.block: Block = None
64+
self.pen = pen
65+
self.block_pen = block_pen
66+
if not self.reset_block():
67+
raise Exception("Failed to create initial block")
68+
69+
def check_grid(self, score: LayerTurtle) -> bool:
70+
(all_empty, delete_count) = _check_grid(self, score)
71+
if delete_count > 0:
72+
self.sync_image()
73+
return all_empty and self.block is None
74+
75+
def reset_block(self) -> bool:
76+
x = 5
77+
y = 0
78+
block_grid = _randomize_block_grid()
79+
x -= int((block_grid.n_cols - 1) / 2)
80+
y += 1 - block_grid.n_rows
81+
if _check_block_grid_placement(block_grid, x, y, grid=self.grid, check_boundary=False):
82+
return False
83+
self.block = Block(x, y, block_grid=block_grid, block_pen=self.block_pen)
84+
self.sync_image()
85+
return True
86+
87+
def commit_block(self):
88+
_commit_block_grid(self.block.block_grid, self.block.x, self.block.y, self.grid)
89+
#self.block.commit(self.grid)
90+
self.sync_image()
91+
self.block = None
92+
93+
def move_block_down(self) -> bool:
94+
return self.block.move_down(self.grid)
95+
96+
def move_block_right(self) -> bool:
97+
return self.block.move_right(self.grid)
98+
99+
def move_block_left(self) -> bool:
100+
return self.block.move_left(self.grid)
101+
102+
def sync_image(self):
103+
#self.block.sync_image()
104+
_draw_grid(self.grid, self.pen)
105+
106+
107+
class TetrisTwoBlockApp(DDAppBase):
108+
def __init__(self, dd: DumbDisplay = create_example_wifi_dd()):
109+
super().__init__(dd)
110+
self.score: LayerTurtle = None
111+
self.block_pen: LayerTurtle = None
112+
self.pen: LayerTurtle = None
113+
self.shape: Shape = None
114+
self.last_update_time = None
115+
116+
def initializeDD(self):
117+
118+
root = DDRootLayer(self.dd, _width, _height)
119+
root.border(5, "darkred", "round", 1)
120+
root.backgroundColor("black")
121+
122+
block_pen = LayerTurtle(self.dd, _width, _height)
123+
block_pen.penFilled()
124+
#block_pen.setTextSize(32)
125+
126+
pen = LayerTurtle(self.dd, _width, _height)
127+
pen.penFilled()
128+
pen.setTextSize(32)
129+
130+
score = LayerTurtle(self.dd, _width, _height)
131+
score.penColor('red')
132+
score.penUp()
133+
score.goTo(60, -300)
134+
score.setTextFont("Courier", 24)
135+
#score.write('Score: 0', 'C')
136+
137+
border = LayerTurtle(self.dd, _width, _height)
138+
if False:
139+
border.rectangle(260, 490, centered=True)
140+
border.penSize(10)
141+
border.penUp()
142+
border.goTo(-130, 240)
143+
border.penDown()
144+
border.penColor('linen')
145+
border.rightTurn(90)
146+
border.forward(490) # Down
147+
border.leftTurn(90)
148+
border.forward(260) # Right
149+
border.leftTurn(90)
150+
border.forward(490) # Up
151+
border.penUp()
152+
border.goTo(0,260)
153+
border.setTextFont("Courier", 36)
154+
border.write("TETRIS", "C")
155+
156+
left_button = LayerLcd(self.dd, 2, 1, char_height=28)
157+
left_button.noBackgroundColor()
158+
left_button.writeLine("⬅️")
159+
left_button.enableFeedback("f", lambda *args: self.moveBlockLeft())
160+
161+
right_button = LayerLcd(self.dd, 2, 1, char_height=28)
162+
right_button.noBackgroundColor()
163+
right_button.writeLine("➡️")
164+
right_button.enableFeedback("f", lambda *args: self.moveBlockRight())
165+
166+
AutoPin('V',
167+
AutoPin('S'),
168+
AutoPin('H', left_button, right_button)).pin(self.dd)
169+
170+
self.score = score
171+
self.block_pen = block_pen
172+
self.pen = pen
173+
174+
self.startGame()
175+
#self.shape = Shape()
176+
#self.resetBlock()
177+
178+
self.last_update_time = time.time()
179+
180+
def updateDD(self):
181+
now = time.time()
182+
need_update = (now - self.last_update_time) >= _delay
183+
if need_update:
184+
self.last_update_time = now
185+
self.update()
186+
187+
def update(self):
188+
if self.shape is None:
189+
print("... waiting to restart ...")
190+
return
191+
192+
moved_down = self.moveBlockDown()
193+
if not moved_down:
194+
self.shape.commit_block()
195+
won = self.checkGrid()
196+
if won:
197+
self.endGame(won=True)
198+
elif not moved_down:
199+
if not self.resetBlock():
200+
self.endGame(won=False)
201+
# if self.shape.block.y > 0:
202+
# #self.shape.reset_block()
203+
# self.resetBlock()
204+
# else:
205+
# self.endGame(won=False)
206+
207+
def startGame(self):
208+
self.score.clear()
209+
self.score.write('Score: 0', 'C')
210+
self.pen.clear()
211+
self.block_pen.clear()
212+
self.shape = Shape(pen=self.pen, block_pen=self.block_pen)
213+
print("... started game")
214+
215+
216+
def endGame(self, won: bool):
217+
#self.block_pen.clear()
218+
self.shape = None
219+
if won:
220+
msg = "🥳 YOU WON 🥳"
221+
color = "purple"
222+
else:
223+
msg = "GAME OVER 😔"
224+
color = "darkgray"
225+
self.pen.home(with_pen=False)
226+
self.pen.penColor("white")
227+
self.pen.oval(300, 100, centered=True)
228+
self.pen.penColor(color)
229+
self.pen.write(msg, align='C')
230+
print("... ended game")
231+
232+
233+
def checkGrid(self) -> bool:
234+
return self.shape.check_grid(score=self.score)
235+
# check_result = check_grid(shape=self.shape, score=self.score)
236+
# self.drawGrid() # should only redraw if any lines were cleared
237+
# return check_result
238+
239+
def resetBlock(self) -> bool:
240+
return self.shape.reset_block()
241+
#self.drawGrid()
242+
#self.drawBlock()
243+
244+
def moveBlockDown(self) -> bool:
245+
return self.shape.move_block_down()
246+
# if self.shape.move_block_down():
247+
# self.drawBlock()
248+
# return True
249+
# return False
250+
251+
def moveBlockLeft(self) -> bool:
252+
#print("$ move left")
253+
if self.shape is None:
254+
self.startGame()
255+
return False
256+
return self.shape.move_block_left()
257+
# if self.shape.move_block_left():
258+
# self.drawBlock()
259+
# return True
260+
# return False
261+
262+
def moveBlockRight(self) -> bool:
263+
if self.shape is None:
264+
self.startGame()
265+
return False
266+
return self.shape.move_block_right()
267+
# if self.shape.move_block_right():
268+
# self.drawBlock()
269+
# return True
270+
# return False
271+
272+
273+
if __name__ == "__main__":
274+
from dumbdisplay_examples.utils import create_example_wifi_dd, DDAppBase
275+
app = TetrisTwoBlockApp(create_example_wifi_dd())
276+
app.run()

dumbdisplay_examples/tetris/tetris_one_block.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from dumbdisplay.layer_graphical import DDRootLayer
1010
from dumbdisplay.layer_turtle import LayerTurtle
1111
from dumbdisplay.layer_lcd import LayerLcd
12-
from dumbdisplay_examples.tetris.tetris_common import Grid, _draw, _draw_grid, _width, _height, _colors, \
12+
from dumbdisplay_examples.tetris._common import Grid, _draw, _draw_grid, _width, _height, _colors, \
1313
_block_unit_width, _grid_n_rows, _grid_n_cols
1414

1515
from dumbdisplay_examples.utils import DDAppBase, create_example_wifi_dd

0 commit comments

Comments
 (0)