Skip to content

Commit 25d6c64

Browse files
committed
feat: Snake game functional
1 parent 042c4d2 commit 25d6c64

11 files changed

+1397
-0
lines changed

Controller.py

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import curses
2+
from Snake import Directions
3+
P1 = {ord("w"): Directions.up, ord("s"):Directions.down, ord("d"):Directions.right, ord("a"):Directions.left}
4+
P2 = {curses.KEY_UP: Directions.up, curses.KEY_DOWN:Directions.down, curses.KEY_RIGHT:Directions.right, curses.KEY_LEFT:Directions.left}
5+
P3 = {ord("u"): Directions.up, ord("j"):Directions.down, ord("k"):Directions.right, ord("h"):Directions.left}
6+
P4 = {ord("8"): Directions.up, ord("5"):Directions.down, ord("6"):Directions.right, ord("4"):Directions.left} #Num Block must be off to use the numPad
7+
8+
class Controller(object):
9+
maxPlayers = 4
10+
def __init__(self, players = 1):
11+
if players > Controller.maxPlayers:
12+
raise Exception("Too many players")
13+
self.players = players
14+
15+
def changePlayerNum(self, players):
16+
self.players = players
17+
def keypressed(self, key):
18+
if key in P1:
19+
return [1, P1[key]]
20+
21+
if key in P2:
22+
return [2 if self.players > 1 else 1, P2[key]]
23+
24+
if key in P3:
25+
if self.players > 2:
26+
return [3, P3[key]]
27+
elif self.players > 1 and self.players < 3:
28+
return -1
29+
else:
30+
return [1, P3[key]]
31+
if key in P4:
32+
if self.players > 3:
33+
return [4, P4[key]]
34+
else:
35+
return -1
36+
37+
38+
return -1

Helper.py

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import curses
2+
#-- Define the appearance of some interface elements
3+
hotkey_attr = curses.A_BOLD | curses.A_UNDERLINE
4+
menu_attr = curses.A_NORMAL
5+
6+
heightStatScreen=7
7+
8+
9+
MINIMUM_HEIGHT=34
10+
MINIMUM_WIDTH=52
11+
12+
def createMenu(screen, menus, startX, startY):
13+
for menu in menus:
14+
menu_name = menu[0]
15+
menu_hotkey = menu_name[0]
16+
menu_no_hot = menu_name[1:]
17+
screen.addstr(startY, startX, menu_hotkey, hotkey_attr)
18+
screen.addstr(startY, startX+1, menu_no_hot, menu_attr)
19+
startY+=1
20+
# Add key handlers for this hotkey
21+
menu_handler(screen, (str.upper(menu_hotkey), menu[1]))
22+
menu_handler(screen, (str.lower(menu_hotkey), menu[1]))
23+
24+
screen.refresh()
25+
26+
#-- Magic key handler both loads and processes keys strokes
27+
def menu_handler(screen, key_assign=None, key_dict={}):
28+
if key_assign:
29+
key_dict[ord(key_assign[0])] = key_assign[1]
30+
else:
31+
c = screen.getch()
32+
if c in (curses.KEY_END, ord('!')):
33+
return 0
34+
elif c not in key_dict.keys():
35+
curses.beep()
36+
return 1
37+
else:
38+
return key_dict[c]()
39+
40+
def checkIfEnoughSpaceForGame(stdscr, gameScreen = None):
41+
42+
maxY, maxX = stdscr.getmaxyx()
43+
44+
if (maxX < MINIMUM_WIDTH or maxY < MINIMUM_HEIGHT):
45+
return True
46+
47+
if gameScreen==None:
48+
return False
49+
50+
return maxY <= (gameScreen.sizeY + heightStatScreen + 1) or maxX <= (gameScreen.sizeX)
51+
52+
53+
class NotEnoughSpace(Exception):
54+
pass
55+
56+
class ExitTotal(Exception):
57+
pass
58+
59+
class GoBackToMainScreen(Exception):
60+
pass

KeyboardInput.py

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
global isWindows
2+
isWindows = False
3+
4+
try:
5+
from win32api import STD_INPUT_HANDLE
6+
from win32console import GetStdHandle, KEY_EVENT, ENABLE_ECHO_INPUT, ENABLE_LINE_INPUT, ENABLE_PROCESSED_INPUT
7+
isWindows = True
8+
except ImportError as e:
9+
import sys, select, termios
10+
11+
class KeyPoller(object):
12+
def __enter__(self):
13+
global isWindows
14+
if(isWindows):
15+
self.readHandle = GetStdHandle(STD_INPUT_HANDLE)
16+
self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT)
17+
18+
self.currEventLength = 0
19+
self.currKeysLength = 0
20+
21+
self.capturedChars = []
22+
else:
23+
#Save terminal settings
24+
self.fd = sys.stdin.fileno()
25+
self.newTerm = termios.tcgetattr(self.fd)
26+
self.oldTerm = termios.tcgetattr(self.fd)
27+
28+
#New terminal setting unbuffered
29+
self.newTerm[3] = (self.newTerm[3] & ~termios.ICANON & ~termios.ECHO)
30+
termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.newTerm)
31+
return self
32+
def __exit__(self, exc_type, exc_val, exc_tb):
33+
if isWindows:
34+
pass
35+
else:
36+
termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.oldTerm)
37+
def poll(self):
38+
if(isWindows):
39+
if(not len(self.capturedChars) == 0):
40+
return self.capturedChars.pop(0)
41+
eventsPeek = self.readHandle.PeekConsoleInput(10000)
42+
if len(eventsPeek) == 0:
43+
return None
44+
45+
if not len(eventsPeek) == self.currEventLength:
46+
for curEvent in eventsPeek[self.currEventLength]:
47+
if(curEvent.EventType == KEY_EVENT):
48+
if(ord(curEvent.Char) == 0 or not curEvent.KeyDown):
49+
pass
50+
else:
51+
curChar = str(curEvent.Char)
52+
self.capturedChars.append(curChar)
53+
self.currEventLength = len(eventsPeek)
54+
if(not len(self.capturedChars) == 0):
55+
return self.capturedChars.pop(0)
56+
else:
57+
return None
58+
else:
59+
dr,dw,de = select.select([sys.stdin], [], [], 0)
60+
if(not dr == []):
61+
return sys.stdin.read(1)
62+
return None
63+
64+
if __name__ == "__main__":
65+
#Simle use case
66+
with KeyPoller() as keyPoler:
67+
while True:
68+
c = keyPoler.poll()
69+
if(not c is None):
70+
if c == "c":
71+
break
72+
print(c)

0 commit comments

Comments
 (0)