-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
227 lines (174 loc) · 6.44 KB
/
main.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
import pygame
import random
import tkinter
from tkinter import messagebox
pygame.init()
class Cube(object):
def __init__(self, start_pos, dir_x=1, dir_y=0, color=(0, 255, 0)):
self.pos = start_pos
self.dir_x = 1
self.dir_y = 0
self.color = color
def move(self, dir_x, dir_y):
self.dir_x = dir_x
self.dir_y = dir_y
self.pos = (self.pos[0] + self.dir_x, self.pos[1] + self.dir_y)
def draw(self):
dis = 500 // 20
i = self.pos[0] # Current row
j = self.pos[1] # Current column
pygame.draw.rect(win, self.color, (i * dis + 1, j * dis + 1, dis - 2, dis - 2)) # Drawing the rectangle
# Minus 2 just so it doesn't fill up the whole rectangle
class Snake(object):
body = [] # List containing multiple cube objects which represent the body
# This is an dictionary which stores the point of turn so the snake won't turn as a whole,
# rather cube by cube
turns = {}
def __init__(self, color, pos):
self.color = color
self.pos = pos
self.head = Cube(pos) # The head will be the first cube object
self.body.append(self.head) # Adding the head to the body list
# Initial directions
self.dir_x = 1
self.dir_y = 0
def move(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
keys = pygame.key.get_pressed() # Get multiple key presses
for key in keys:
if keys[pygame.K_LEFT]:
self.dir_x = -1
self.dir_y = 0
self.turns[self.head.pos[:]] = [self.dir_x, self.dir_y] # Remembering the direction
elif keys[pygame.K_RIGHT]:
self.dir_x = 1
self.dir_y = 0
self.turns[self.head.pos[:]] = [self.dir_x, self.dir_y]
elif keys[pygame.K_UP]:
self.dir_x = 0
self.dir_y = -1
self.turns[self.head.pos[:]] = [self.dir_x, self.dir_y]
elif keys[pygame.K_DOWN]:
self.dir_x = 0
self.dir_y = 1
self.turns[self.head.pos[:]] = [self.dir_x, self.dir_y]
for i, c in enumerate(self.body): # Loop through every cube in the body list
p = c.pos[:] # Cube position in the grid
if p in self.turns:
turn = self.turns[p] # Direction for the next turn
c.move(turn[0], turn[1])
if i == len(self.body) - 1: # If it's the last cube
self.turns.pop(p) # It removes the turn
else:
# This code just makes the snake appear on the other side if it goes past the screen boundaries
if c.dir_x == -1 and c.pos[0] <= 0:
c.pos = (19, c.pos[1])
elif c.dir_x == 1 and c.pos[0] >= 19:
c.pos = (0, c.pos[1])
elif c.dir_y == 1 and c.pos[1] >= 19:
c.pos = (c.pos[0], 0)
elif c.dir_y == -1 and c.pos[1] <= 0:
c.pos = (c.pos[0], 19)
else:
c.move(c.dir_x, c.dir_y)
def reset(self, pos):
self.head = Cube(pos)
self.body = []
self.body.append(self.head)
self.dir_x = 1
self.dir_y = 0
self.turns = {}
def add_cube(self):
tail = self.body[-1]
dx, dy = tail.dir_x, tail.dir_y
# We need to check to which side of the snake to add the cube to
if dx == 1 and dy == 0:
self.body.append(Cube((tail.pos[0] - 1, tail.pos[1])))
elif dx == -1 and dy == 0:
self.body.append(Cube((tail.pos[0] + 1, tail.pos[1])))
elif dx == 0 and dy == 1:
self.body.append(Cube((tail.pos[0], tail.pos[1] - 1)))
elif dx == 0 and dy == -1:
self.body.append(Cube((tail.pos[0], tail.pos[1] + 1)))
# We then set the cubes direction to the direction of the snake.
self.body[-1].dir_x = dx
self.body[-1].dir_y = dy
def draw(self):
for i, c in enumerate(self.body):
c.draw()
# Screen
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("Snake")
# Colors
WHITE = (255, 255, 255)
GRAY = (226, 226, 226)
# Clock
clock = pygame.time.Clock()
FPS = 10
# Fonts
SCORE_FONT = pygame.font.SysFont('helvetica', 30)
def draw_grid(w, rows):
gap = w // rows
# Initial x and y
x = 0
y = 0
for i in range(rows):
x = x + gap
y = y + gap
pygame.draw.line(win, GRAY, (x, 0), (x, w))
pygame.draw.line(win, GRAY, (0, y), (w, y))
def render():
global s, snack
score_text = SCORE_FONT.render("Score: {}".format(str(len(s.body))), 1, (0, 0, 0))
win.fill(WHITE)
s.draw()
snack.draw()
draw_grid(500, 20)
win.blit(score_text, (10, 10))
pygame.display.update()
def random_snack(rows, item):
positions = item.body # Get the positions of cubes in the snake
while True:
# Random snack position
x = random.randrange(rows)
y = random.randrange(rows)
# Setting the snack so it can't be on the same position as the snake
if len(list(filter(lambda z: z.pos == (x, y), positions))) > 0:
continue
else:
break
# Returns the position of the snack
return x, y
def message_box(subject, content):
root = tkinter.Tk()
root.attributes("-topmost", True)
root.withdraw()
messagebox.showinfo(subject, content)
try:
root.destroy()
except:
pass
def main():
global s, snack
run = True
s = Snake((255, 0, 0), (10, 10))
snack = Cube(random_snack(20, s), color=(255, 0, 0))
while run:
clock.tick(FPS)
pygame.time.delay(50)
s.move()
if snack.pos == s.body[0].pos: # Checks if the head collides with the snack
print("Gje")
s.add_cube() # Adds a new cube to the snake
snack = Cube(random_snack(20, s), color=(255, 0, 0))
for x in range(len(s.body)):
# This will check if any of the positions in our body list overlap
if s.body[x].pos in list(map(lambda z: z.pos, s.body[x + 1:])):
message_box('You Lost!', 'Play again...')
s.reset((10, 10))
break
render()
if __name__ == '__main__':
main()