/
main.py
215 lines (162 loc) · 5.52 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
"""main.py
Controller + interface for playing snake
"""
# external dependencies
import curses
import serial
from curses import KEY_RIGHT, KEY_LEFT, KEY_UP, KEY_DOWN
from curses import wrapper
from random import randint
import time
import os
import sys
# internal dependencies
from render_text import render_text
def update_board_state(snake, food, ser):
"""updates board state using serial output
Args:
snake (List(List)): list of lists representing (x,y) snake pos coordinates
food (List): (x,y) position representing food location
"""
# for debugging purposes, return if we can't write to Serial monitor
if ser is None:
return
# initialize empty grid
grid = [['0' for i in range(10)] for j in range(10)]
# highlight grid entries with snake
for part in snake:
grid[part[0]][part[1]] = '1'
# add food to grid
grid[food[0]][food[0]] = '1'
# reshape grid into 1D, convert to string, add linebreak
grid_str = "".join(["".join(row[1:-1]) for row in grid[1:-1]]) + "\n"
# write Serial output
ser.write(grid_str.encode())
return
def display_score_state(win, ser, score):
"""display_score_state
Args:
win (curses window): window for curses, used for debugging dispaly simulation
ser (serial monitor object): used for communicating with the board through serial output
score (int): score obtained through playing snake
Function used to display the score state after you've died in snake :)
Uses function in board_letters.py to retrieve the grid state for each letter in the target message
"""
# produce message, display
message = "Your score: " + str(score)
render_text(message, ser)
# Display score only a couple of extra times for extra spice
time.sleep(1)
render_text(str(score), ser)
time.sleep(1)
def curses_main(ser):
"""runs the snake program
"""
# initialize curses display
curses.initscr()
win = curses.newwin(10, 10, 0, 0)
win.keypad(1)
curses.noecho()
curses.curs_set(0)
win.border(0)
win.nodelay(1)
key = KEY_RIGHT
score = 0
snake = [[3,5], [3,4]]
food = [5,5]
win.addch(food[0], food[1], '*')
update_board_state(snake, food, ser)
# While Esc key is not pressed
while key != 27:
win.timeout(300 - (len(snake)//5 + len(snake)//10)%120)
prevKey = key
event = win.getch()
key = key if event == -1 else event
# If SPACE BAR is pressed, wait for another
if key == ord(' '):
key = -1
while key != ord(' '):
key = win.getch()
key = prevKey
continue
# If an invalid key is pressed
if key not in [KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, 27]:
key = prevKey
# Calculates the new coordinates of the head of the snake. NOTE: len(snake) increases.
snake.insert(0, [snake[0][0] + (key == KEY_DOWN and 1) + (key == KEY_UP and -1), snake[0][1] + (key == KEY_LEFT and -1) + (key == KEY_RIGHT and 1)])
# If snake crosses the boundaries, make it enter from the other side
# note that snake[0] gives [x,y] list of snake head
# snake[0][0] is x coord
# snake[0][1] is y coord
if snake[0][0] == 0: # check if snake is at top row; if so, move head to bottom row
snake[0][0] = 8
if snake[0][0] == 9:
snake[0][0] = 1
if snake[0][1] == 0: # check if snake is at right column; if so, move head to left column
snake[0][1] = 8
if snake[0][1] == 9:
snake[0][1] = 1
# If snake runs over itself
if snake[0] in snake[1:]:
break
# at each iteration, check if we've gotten the food
# if we have gotten the food:
# produce new food, don't change snake
# otherwise:
# leave food alone, take off the end of the snake to simulate crawling motion
if snake[0] == food:
food = []
score += 1
while food == []:
# next food position
food = [randint(2, 7), randint(2, 7)]
if food in snake:
food = []
win.addch(food[0], food[1], '*')
else:
last = snake.pop()
win.addch(last[0], last[1], ' ')
# update the head of the snake
win.addch(snake[0][0], snake[0][1], '#')
# write to the board
update_board_state(snake, food, ser)
display_score_state(win, ser, score)
curses.nocbreak()
win.keypad(False)
curses.echo()
curses.endwin()
print("\nScore - " + str(score))
def key(event):
if event.keysym == 'Escape':
root.destroy()
if event.char == event.keysym:
# normal number and letter characters
print( 'Normal Key %r' % event.char )
elif len(event.char) == 1:
# charcters like []/.,><#$ also Return and ctrl/key
print( 'Punctuation Key %r (%r)' % (event.keysym, event.char) )
else:
# f1 to f12, shift keys, caps lock, Home, End, Delete ...
print( 'Special Key %r' % event.keysym )
if __name__ == "__main__":
# initialize Serial monitor
ser = serial.Serial(
port='\\\\.\\COM6',
baudrate=115200,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
# for debugging:
# ser = None
# update_board_state([[3,5], [3,4], [3,3]] , [5,5])
# welcome message
render_text("Welcome To Snake!", ser)
# game main
try:
wrapper(curses_main(ser))
except:
render_text("Come back again!", ser)
pass
# exit message
render_text("Come back again!", ser)