-
Notifications
You must be signed in to change notification settings - Fork 1
/
game.py
137 lines (109 loc) · 4.53 KB
/
game.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
from asyncio.queues import Queue
import logging
import random
import asyncio
from common import Dimensions
from copy import deepcopy
from shape import SHAPES
from collections import Counter
logger = logging.getLogger("Game")
logger.setLevel(logging.DEBUG)
GAME_SPEED = 10
SPEED_STEP = 10 # points
class Game:
def __init__(self, x=10, y=30) -> None:
logger.info("Game")
self.dimensions = Dimensions(x, y)
self.current_piece = None
self.next_pieces = [deepcopy(random.choice(SHAPES)) for _ in range(3)]
self._bottom = [(i, y) for i in range(x)] # bottom
self._lateral = [(0, i) for i in range(y)] # left
self._lateral.extend([(x - 1, i) for i in range(y)]) # right
self.grid = self._bottom + self._lateral
self.game = []
self.score = 0
self.speed = 1
self.game_speed = 10
self._lastkeypress = None
self.running = True
def info(self):
return {
"dimensions": self.dimensions,
"grid": self.grid,
"game_speed": self.game_speed,
"score": self.score
}
def clear_rows(self):
lines = 0
for item, count in sorted(Counter(y for _, y in self.game).most_common()):
if count == len(self._bottom) - 2:
self.game = [
(x, y + 1) if y < item else (x, y)
for (x, y) in self.game
if y != item
] # remove row and drop lines
lines += 1
logger.debug("Clear line %s", item)
self.score += lines ** 2
self.game_speed = GAME_SPEED + self.score // SPEED_STEP
most_common = Counter(y for _, y in self.game).most_common(1)
if most_common != []:
(_, count) = most_common[0]
assert count != len(self._bottom) - 2, f"please create an issue https://github.com/dgomes/ia-tetris/issues sharing:\n {self.game}"
def keypress(self, key):
"""Update locally last key pressed."""
self._lastkeypress = key
async def loop(self):
logger.info("Loop - score: %s - speed: %s", self.score, self.game_speed)
await asyncio.sleep(1.0 / self.game_speed)
if self.current_piece is None:
self.current_piece = self.next_pieces.pop(0)
self.next_pieces.append(deepcopy(random.choice(SHAPES)))
logger.debug("New piece: %s", self.current_piece)
self.current_piece.set_pos(
(self.dimensions.x - self.current_piece.dimensions.x) / 2, 0
)
if not self.valid(self.current_piece):
logger.info("GAME OVER")
self.running = False
self.current_piece.y += 1
if self.valid(self.current_piece):
if self._lastkeypress == "s":
while self.valid(self.current_piece):
self.current_piece.y += 1
self.current_piece.y -= 1
elif self._lastkeypress == "w":
self.current_piece.rotate()
if not self.valid(self.current_piece):
self.current_piece.rotate(-1)
elif self._lastkeypress == "a":
shift = -1
elif self._lastkeypress == "d":
shift = +1
if self._lastkeypress in ["a", "d"]:
self.current_piece.translate(shift, 0)
if self.collide_lateral(self.current_piece):
logger.debug("Hitting the wall")
self.current_piece.translate(-shift, 0)
elif not self.valid(self.current_piece):
self.current_piece.translate(-shift, 0)
else:
self.current_piece.y -= 1
self.game.extend(self.current_piece.positions)
self.clear_rows()
self.current_piece = None
self._lastkeypress = None
logger.debug("Current piece: %s", self.current_piece)
return {
"game": self.game,
"piece": self.current_piece.positions if self.current_piece else None,
"next_pieces": [n.positions for n in self.next_pieces],
"game_speed": self.game_speed,
"score": self.score,
}
def valid(self, piece):
return not any(
[piece_part in self.grid for piece_part in piece.positions]
) and not any([piece_part in self.game for piece_part in piece.positions])
def collide_lateral(self, piece):
return any([piece_part in self._lateral for piece_part in piece.positions])