-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsnake_lesson_8.py
254 lines (194 loc) · 7.73 KB
/
snake_lesson_8.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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
################################################################################
# 'SNAKEY' GAME
## Adapted by George Deeks from https://gist.github.com/sanchitgangwar/2158089
## Use ARROW KEYS to play, SPACE BAR to pause/resume and Esc Key to exit
################################################################################
# Import helper libraries
import curses
from curses import KEY_RIGHT, KEY_LEFT, KEY_UP, KEY_DOWN
from random import randint
# Initialise cursor and window properties
curses.initscr()
# game window will be 20 units top to bottom, and 60 units left to right
win = curses.newwin(20, 60, 0, 0)
win.keypad(1)
curses.noecho()
curses.curs_set(0)
# draw a border for our window
win.border(0)
win.nodelay(1)
# Escape key reference number for the computer system
KEY_ESC = 27
################################################################################
# INITIALISING VALUES BEFORE THE GAME STARTS
################################################################################
# Initial snake co-ordinates
# Co-ordinates are y-coordinate, then x-coordinate.
# Snake is being placed here approximately in the middle left of our window
snake = [[4,10], [4,9], [4,8]]
# Initial snake direction
# Snake will move in direction of last arrow key pressed, but initially we will
# set this to right arrow key (so snake starts moving left to right)
key = KEY_RIGHT
# First food co-ordinates (Lesson 4)
food = [10,20]
# Display the food
# 'win' represents where we are playing our game.
# 'addch' will add a single character based on co-ordinates it receives
win.addch(food[0], food[1], '*')
# Print the game title on the top border
win.addstr(0, 27, " SNAKEY ")
# Initial score (Lesson 7)
score = 0
################################################################################
# THE MAIN GAME LOOP (Lesson 1)
################################################################################
# A 'while' loop will repeatedly execute until its stated condition is met, OR
# a 'break' statement is executed inside of it. Each loop iteration will execute
# one movement of the snake and update the game display accordingly. The
# condition that breaks this while loop is the user pressing the Esc key. which
# will end the game.
while key != KEY_ESC:
# Print current 'Score' string
win.addstr(0, 2, ' Score : ' + str(score) + ' ')
###
# SET THE SPEED 'LEVEL' OF THE GAME (Lesson 8)
###
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
# TODO Lesson #8
win.timeout(150)
###
# HANDLE USER KEY INPUT
###
# Store the previous key selection for future reference
prevKey = key
# Determine if a valid new key has been pressed.
event = win.getch()
# If the new key press is invalid, the program will return -1, otherwise
# we will update our active key pressed selection:
if event != -1:
key = event
# Pause/Resume game (Lesson 6)
# If SPACE BAR is pressed, then wait for another SPACE BAR to be pressed to
# resume game.
if key == ord(' '):
# update display to show game is paused
win.addstr(0, 27, " *PAUSED* ")
# reset key to invalid value, then keep reading new key presses until
# SPACE BAR has been pressed
key = -1
while key != ord(' '):
key = win.getch()
# Game is now resumed, so let's update display:
win.addstr(0, 27, " SNAKEY ")
# replace SPACE BAR with previous key selection, as if no SPACE BARs had
# ever been pressed!
key = prevKey
# Ignore useless key selections
# Ignore the latest key press if it is not an arrow key (or Esc key)
if key not in [KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_ESC]:
key = prevKey
###
# CALCULATE NEW SNAKEHEAD POSITION (Lesson 2)
###
# Current key selection should now be an arrow key. This arrow key, plus
# the snakehead's current position, can be used to calculate the new
# co-ordinates for the snakehead as it moves one 'square'.
# The snake is an array of 2-length arrays, e.g. = [[4,10], [4,9], [4,8]] -
# this is also known as a 3D array.
# snake[0][0] accesses the snakehead's y-coordinate (e.g., '4')
# snake[0][1] accesses the snakehead's x-coordinate (e.g., '10')
newY = snake[0][0]
if key == KEY_DOWN:
newY += 1
elif key == KEY_UP:
newY -= 1
newX = snake[0][1]
if key == KEY_RIGHT:
newX += 1
elif key == KEY_LEFT:
newX -= 1
# Put new snakehead co-ordinates into start of snake array (position 0)
snake.insert(0, [newY, newX])
# ...Snake is now longer than it should be - unless we're about to eat a
# piece of fruit (Lesson 5). If we decide later on that we're not eating a
# piece of fruit, we must remember to reduce the snake length by cutting off
# its tail. See [1].
###
# IF SNAKE REACHES BORDER, MAKE IT ENTER FROM OTHER SIDE (Lesson 3)
###
# For our window, the Y-axis runs from 0 to 19, the X-axis from 0 to 59. (We
# defined this earlier at the top of this file.) However, we have also drawn
# a border (again, see earlier), so actually the snake can move 1 to 18 in
# the Y-axis, and from 1 to 58 in the X-axis. If the snake breaches these
# limits, reposition snakehead so it continues from the other side:
if snake[0][0] == 0:
snake[0][0] = 18
if snake[0][1] == 0:
snake[0][1] = 58
if snake[0][0] == 19:
snake[0][0] = 1
if snake[0][1] == 59:
snake[0][1] = 1
###
# IF SNAKE CROSSES ITSELF (Lesson 2)
###
# [1:] refers to position 1 (i.e., the 2nd element in the array, as we
# count from 0) and onwards.
if snake[0] in snake[1:]:
break
###
# CHECK IF SNAKE HAS EATEN FOOD (Lessons 2 + 3)
###
# If the snakehead co-ordinates match the current food's co-ordinates, then
# the snake will have eaten the food!
if snake[0] == food:
# remove the previous food coordinates
food = []
# Add 1 to the score
score += 1
# calculate new food position
while food == []:
food = [randint(1, 18), randint(1, 58)]
# reset food if it's been randomly assigned a co-ordinate that the
# snake is currently occupying
if food in snake:
food = []
# update display with new food
win.addch(food[0], food[1], '*')
else:
# [1] If snake does not eat food, remember to decrease its length
# remove last snake co-ordinate (its 'tail') from snake array
last = snake.pop()
# update display where snaketail has just been removed
win.addch(last[0], last[1], ' ')
###
# DRAW THE SNAKE (Lesson 1)
###
# We can write the head with a '@' character, and ensure those parts that
# are (no longer) the head are drawn as body ('#')
win.addch(snake[1][0], snake[1][1], '#')
win.addch(snake[0][0], snake[0][1], '@')
#### End of main game loop ###
################################################################################
# END OF GAME
################################################################################
# Close window
curses.endwin()
# Print out score and thank you message
# Each print command will print its message to a new line
print("Final score - " + str(score))
print("Thank you for playing!")
################################################################################
### THANKS FOR PLAYING #########################################################
################################################################################