Introducing pong and snake
This commit is contained in:
parent
640dbd9e8a
commit
149819fdd4
8 changed files with 334 additions and 17 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,3 +5,4 @@ __pycache__
|
||||||
maze/__pycache__
|
maze/__pycache__
|
||||||
maze/modules/__pycache__
|
maze/modules/__pycache__
|
||||||
saves
|
saves
|
||||||
|
tetris
|
Binary file not shown.
|
@ -26,7 +26,7 @@ with open("credentials.pickle", "rb") as f:
|
||||||
if d["credtype"] == "mysql":
|
if d["credtype"] == "mysql":
|
||||||
MYSQL_USERNAME = d["user"]
|
MYSQL_USERNAME = d["user"]
|
||||||
MYSQL_PASSWORD = d["pass"]
|
MYSQL_PASSWORD = d["pass"]
|
||||||
except EOFError:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,3 +5,6 @@ from maze.modules.maze import main
|
||||||
|
|
||||||
def bruh():
|
def bruh():
|
||||||
curses.wrapper(main)
|
curses.wrapper(main)
|
||||||
|
curses.nocbreak()
|
||||||
|
curses.echo()
|
||||||
|
curses.endwin()
|
||||||
|
|
|
@ -141,7 +141,7 @@ class Maze:
|
||||||
return finalstr
|
return finalstr
|
||||||
|
|
||||||
|
|
||||||
def path(maze, start, finish): # Not used
|
def path(maze, start, finish):
|
||||||
heuristic = lambda node: abs(node[0] - finish[0]) + abs(node[1] - finish[1])
|
heuristic = lambda node: abs(node[0] - finish[0]) + abs(node[1] - finish[1])
|
||||||
nodes_to_explore = [start]
|
nodes_to_explore = [start]
|
||||||
explored_nodes = set()
|
explored_nodes = set()
|
||||||
|
@ -174,7 +174,9 @@ def path(maze, start, finish): # Not used
|
||||||
nodes_to_explore.append(neighbour)
|
nodes_to_explore.append(neighbour)
|
||||||
|
|
||||||
|
|
||||||
def draw_path(path, screen, delay=0, head=None, trail=None, skip_first=True, calledby=None):
|
def draw_path(
|
||||||
|
path, screen, delay=0, head=None, trail=None, skip_first=True, calledby=None
|
||||||
|
):
|
||||||
if not head:
|
if not head:
|
||||||
head = ("█", curses.color_pair(2))
|
head = ("█", curses.color_pair(2))
|
||||||
if not trail:
|
if not trail:
|
||||||
|
@ -221,11 +223,14 @@ def construction_demo(maze, screen):
|
||||||
screen.nodelay(False)
|
screen.nodelay(False)
|
||||||
|
|
||||||
|
|
||||||
def pathfinding_demo(maze, screen, start_ts, won_coords, loadedcoords=None, loadedtime=0):
|
def pathfinding_demo(
|
||||||
|
maze, screen, start_ts, won_coords, loadedcoords=None, loadedtime=0
|
||||||
|
):
|
||||||
start = []
|
start = []
|
||||||
finish = []
|
finish = []
|
||||||
solution = None
|
solution = None
|
||||||
old_solution = None
|
old_solution = None
|
||||||
|
|
||||||
def reset(start_or_finish, cell, colour):
|
def reset(start_or_finish, cell, colour):
|
||||||
nonlocal solution, old_solution
|
nonlocal solution, old_solution
|
||||||
if start_or_finish:
|
if start_or_finish:
|
||||||
|
@ -238,15 +243,16 @@ def pathfinding_demo(maze, screen, start_ts, won_coords, loadedcoords=None, load
|
||||||
if start and finish:
|
if start and finish:
|
||||||
solution, old_solution = tee(path(maze, start[0], finish[0]))
|
solution, old_solution = tee(path(maze, start[0], finish[0]))
|
||||||
draw_path(solution, screen, calledby="reset")
|
draw_path(solution, screen, calledby="reset")
|
||||||
|
|
||||||
maxy, maxx = screen.getmaxyx()
|
maxy, maxx = screen.getmaxyx()
|
||||||
|
|
||||||
if loadedcoords:
|
if loadedcoords:
|
||||||
current_coords = list(loadedcoords)
|
current_coords = list(loadedcoords)
|
||||||
cell = (int(current_coords[0] / 2), int(current_coords[1] / 2))
|
cell = (int(current_coords[0] / 2), int(current_coords[1] / 2))
|
||||||
reset(finish, cell, curses.color_pair(2))
|
reset(finish, cell, curses.color_pair(2))
|
||||||
reset(start, (0,0), curses.color_pair(2))
|
reset(start, (0, 0), curses.color_pair(2))
|
||||||
else:
|
else:
|
||||||
#current_coords = [maxy - 5, maxx - 27]
|
# current_coords = [maxy - 5, maxx - 27]
|
||||||
current_coords = [1, 1]
|
current_coords = [1, 1]
|
||||||
screen.addstr(current_coords[0], current_coords[1], "█", curses.color_pair(2))
|
screen.addstr(current_coords[0], current_coords[1], "█", curses.color_pair(2))
|
||||||
WALL = ["═", "║", "╗", "╚", "╝", "╔", "╠", "╣", "╦", "╩", "╬", "═", "═", "║", "║"]
|
WALL = ["═", "║", "╗", "╚", "╝", "╔", "╠", "╣", "╦", "╩", "╬", "═", "═", "║", "║"]
|
||||||
|
@ -266,7 +272,9 @@ def pathfinding_demo(maze, screen, start_ts, won_coords, loadedcoords=None, load
|
||||||
PAUSED = False
|
PAUSED = False
|
||||||
break
|
break
|
||||||
pause_elapsed += int(end_paused_ts - start_paused_ts)
|
pause_elapsed += int(end_paused_ts - start_paused_ts)
|
||||||
actual_elapsed = str(int(time.time() - start_ts - -1*loadedtime) - pause_elapsed)
|
actual_elapsed = str(
|
||||||
|
int(time.time() - start_ts - -1 * loadedtime) - pause_elapsed
|
||||||
|
)
|
||||||
screen.addstr(5, maxx - 17, actual_elapsed + " sec")
|
screen.addstr(5, maxx - 17, actual_elapsed + " sec")
|
||||||
screen.refresh()
|
screen.refresh()
|
||||||
key = screen.getch()
|
key = screen.getch()
|
||||||
|
@ -531,9 +539,9 @@ def play(screen, loadedmaze=None, loadedcoords=None, loadedtime=0):
|
||||||
|
|
||||||
|
|
||||||
def main(screen):
|
def main(screen):
|
||||||
|
screen.nodelay(True)
|
||||||
curses.curs_set(False)
|
curses.curs_set(False)
|
||||||
curses.mousemask(curses.ALL_MOUSE_EVENTS)
|
curses.mousemask(curses.ALL_MOUSE_EVENTS)
|
||||||
screen.nodelay(True)
|
|
||||||
curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLACK)
|
curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLACK)
|
||||||
curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK)
|
curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK)
|
||||||
curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK)
|
curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK)
|
||||||
|
|
193
pong.py
Normal file
193
pong.py
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
import curses
|
||||||
|
import random
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
from math import fabs
|
||||||
|
|
||||||
|
quit = threading.Event()
|
||||||
|
|
||||||
|
|
||||||
|
class Scores:
|
||||||
|
def __init__(self):
|
||||||
|
self.score = 0
|
||||||
|
self.collision_count = 0
|
||||||
|
self.speed_multiplier = 0.20
|
||||||
|
self.speed_calc = lambda speed: speed - 0.02 if self.score % 30 == 0 else speed
|
||||||
|
|
||||||
|
def scoreupdate(self):
|
||||||
|
self.score += 10
|
||||||
|
self.collision_count += 1
|
||||||
|
self.speed_multiplier = self.speed_calc(self.speed_multiplier)
|
||||||
|
return self.speed_multiplier
|
||||||
|
|
||||||
|
|
||||||
|
class Ball:
|
||||||
|
def __init__(self, y, x, screen):
|
||||||
|
self.ball_dx = 1
|
||||||
|
self.ball_dy = 1
|
||||||
|
self.speed_multipliery = random.choice([1, 2])
|
||||||
|
self.speed_multiplierx = random.choice([1, 2])
|
||||||
|
self.ball_dy *= self.speed_multipliery
|
||||||
|
self.ball_dx *= self.speed_multiplierx
|
||||||
|
self.ball_coords = [y // 2, x // 2]
|
||||||
|
self.y = y
|
||||||
|
self.x = x
|
||||||
|
self.y_border = [0, y]
|
||||||
|
self.x_border = [0, x]
|
||||||
|
self.screen = screen
|
||||||
|
|
||||||
|
def move(self):
|
||||||
|
raw_calc_to_movey = lambda y: y + self.ball_dy
|
||||||
|
raw_calc_to_movex = lambda x: x + self.ball_dx
|
||||||
|
raw_movey = raw_calc_to_movey(
|
||||||
|
self.ball_coords[0]
|
||||||
|
) # Gives raw about to move coords without speed alter
|
||||||
|
raw_movex = raw_calc_to_movex(self.ball_coords[1])
|
||||||
|
|
||||||
|
speed_altery = lambda y: int(y / fabs(y)) # Gives unit speed in the current dir
|
||||||
|
speed_alterx = lambda x: int(x / fabs(x))
|
||||||
|
calc_to_movey = (
|
||||||
|
lambda y: y + speed_altery(self.ball_dy)
|
||||||
|
if checky(raw_movey)
|
||||||
|
else y + self.ball_dy
|
||||||
|
) # assign same dir movement coords
|
||||||
|
calc_to_movex = (
|
||||||
|
lambda x: x + speed_alterx(self.ball_dx)
|
||||||
|
if checkx(raw_movex)
|
||||||
|
else x + self.ball_dx
|
||||||
|
)
|
||||||
|
checky = (
|
||||||
|
lambda y: True
|
||||||
|
if (y in self.y_border)
|
||||||
|
or (y >= self.y_border[1])
|
||||||
|
or (y <= self.y_border[0] + 1)
|
||||||
|
else False
|
||||||
|
) # Gives True if out of bound coords
|
||||||
|
checkx = (
|
||||||
|
lambda x: True
|
||||||
|
if (x in self.x_border)
|
||||||
|
or (x >= self.x_border[1] - 1)
|
||||||
|
or (x <= self.x_border[0] + 1)
|
||||||
|
else False
|
||||||
|
)
|
||||||
|
|
||||||
|
actual_game_checky = (
|
||||||
|
lambda y: True if (y <= self.y_border[0]) else False
|
||||||
|
) # Gives true if ball at top
|
||||||
|
|
||||||
|
to_movey = calc_to_movey(self.ball_coords[0]) # Moving here after speed alter
|
||||||
|
to_movex = calc_to_movex(self.ball_coords[1])
|
||||||
|
old_ball = self.ball_coords.copy()
|
||||||
|
collision = False
|
||||||
|
pos = self.screen.instr(to_movey, to_movex, 1).decode("utf-8")
|
||||||
|
if pos == "=" or pos == "[" or pos == "]":
|
||||||
|
collision = True
|
||||||
|
if (
|
||||||
|
actual_game_checky(to_movey) or collision
|
||||||
|
): # Deflect ball if top border/collision
|
||||||
|
self.ball_dy *= -1
|
||||||
|
elif to_movey >= self.y_border[1] and not collision:
|
||||||
|
return [None, None], [None, None], "OVER"
|
||||||
|
if checkx(to_movex):
|
||||||
|
self.ball_dx *= -1
|
||||||
|
self.ball_coords[0] += self.ball_dy
|
||||||
|
self.ball_coords[1] += self.ball_dx
|
||||||
|
if collision:
|
||||||
|
return self.ball_coords, old_ball, "collision"
|
||||||
|
return self.ball_coords, old_ball, "nocollision"
|
||||||
|
|
||||||
|
|
||||||
|
class Player:
|
||||||
|
def __init__(self, y, x):
|
||||||
|
self.y = y
|
||||||
|
self.x = x
|
||||||
|
self.paddle = "[=======]"
|
||||||
|
self.paddle_posx = x // 2
|
||||||
|
self.paddle_posy = y - 1 # Top of paddle
|
||||||
|
|
||||||
|
def player_move(self, dir):
|
||||||
|
if dir == "LEFT" and self.paddle_posx > 1:
|
||||||
|
self.paddle_posx -= 1
|
||||||
|
if dir == "RIGHT" and self.paddle_posx + 10 < self.x:
|
||||||
|
self.paddle_posx += 1
|
||||||
|
return self.paddle_posy, self.paddle_posx
|
||||||
|
|
||||||
|
|
||||||
|
def player_movement(screen, player):
|
||||||
|
global quit
|
||||||
|
screen.keypad(True)
|
||||||
|
while 1:
|
||||||
|
# f.write("player running\n")
|
||||||
|
if quit.is_set():
|
||||||
|
break
|
||||||
|
old_player_coordsy = player_coordsy = player.paddle_posy
|
||||||
|
old_player_coordsx = player_coordsx = player.paddle_posx
|
||||||
|
key = screen.getch()
|
||||||
|
if key == 27:
|
||||||
|
quit.set()
|
||||||
|
elif key == curses.KEY_LEFT:
|
||||||
|
player_coordsy, player_coordsx = player.player_move("LEFT")
|
||||||
|
elif key == curses.KEY_RIGHT:
|
||||||
|
player_coordsy, player_coordsx = player.player_move("RIGHT")
|
||||||
|
screen.addstr(old_player_coordsy, old_player_coordsx, " ")
|
||||||
|
screen.addstr(player_coordsy, player_coordsx, player.paddle)
|
||||||
|
|
||||||
|
|
||||||
|
def ball_movement(screen, ball, score):
|
||||||
|
y, x = screen.getmaxyx()
|
||||||
|
while 1:
|
||||||
|
# f.write("ball running\n")
|
||||||
|
if quit.is_set():
|
||||||
|
break
|
||||||
|
speed_multi = score.speed_multiplier
|
||||||
|
time.sleep(speed_multi)
|
||||||
|
ball_coords = ball.move()
|
||||||
|
old_ball_posy, old_ball_posx = ball_coords[1]
|
||||||
|
ball_posy, ball_posx = ball_coords[0]
|
||||||
|
collision = ball_coords[2]
|
||||||
|
if collision == "OVER":
|
||||||
|
finalscore = score.score
|
||||||
|
screen.addstr(y // 2 - 1, x // 2 - 4, "GAME OVER!")
|
||||||
|
screen.addstr(y // 2, x // 2 - 5, "The Score is: " + str(finalscore))
|
||||||
|
time.sleep(5)
|
||||||
|
quit.set()
|
||||||
|
break
|
||||||
|
elif collision == "collision":
|
||||||
|
score.scoreupdate()
|
||||||
|
screen.addch(old_ball_posy, old_ball_posx, " ")
|
||||||
|
screen.addch(ball_posy, ball_posx, "*")
|
||||||
|
screen.refresh()
|
||||||
|
|
||||||
|
|
||||||
|
def main(screen):
|
||||||
|
screen.clear()
|
||||||
|
screen.refresh()
|
||||||
|
screen.nodelay(True)
|
||||||
|
curses.curs_set(False)
|
||||||
|
screen.keypad(True)
|
||||||
|
y, x = screen.getmaxyx()
|
||||||
|
ball = Ball(y, x, screen)
|
||||||
|
score = Scores()
|
||||||
|
player = Player(y, x)
|
||||||
|
ball_thread = threading.Thread(
|
||||||
|
target=ball_movement,
|
||||||
|
args=(
|
||||||
|
screen,
|
||||||
|
ball,
|
||||||
|
score,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
player_thread = threading.Thread(
|
||||||
|
target=player_movement,
|
||||||
|
args=(
|
||||||
|
screen,
|
||||||
|
player,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ball_thread.start()
|
||||||
|
player_thread.run()
|
||||||
|
# player_movement(screen, player)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
curses.wrapper(main)
|
112
snake.py
Normal file
112
snake.py
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
import curses
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
from curses import textpad
|
||||||
|
|
||||||
|
OPPOSITE_DIRECTION_DICT = {
|
||||||
|
curses.KEY_UP: curses.KEY_DOWN,
|
||||||
|
curses.KEY_DOWN: curses.KEY_UP,
|
||||||
|
curses.KEY_RIGHT: curses.KEY_LEFT,
|
||||||
|
curses.KEY_LEFT: curses.KEY_RIGHT,
|
||||||
|
}
|
||||||
|
|
||||||
|
DIRECTIONS_LIST = [curses.KEY_RIGHT, curses.KEY_LEFT, curses.KEY_DOWN, curses.KEY_UP]
|
||||||
|
|
||||||
|
|
||||||
|
def create_food(snake, box):
|
||||||
|
"""Simple function to find coordinates of food which is inside box and not on snake body"""
|
||||||
|
food = None
|
||||||
|
while food is None:
|
||||||
|
food = [
|
||||||
|
random.randint(box[0][0] + 1, box[1][0] - 1),
|
||||||
|
random.randint(box[0][1] + 1, box[1][1] - 1),
|
||||||
|
]
|
||||||
|
if food in snake:
|
||||||
|
food = None
|
||||||
|
return food
|
||||||
|
|
||||||
|
|
||||||
|
def main(stdscr):
|
||||||
|
# initial settings
|
||||||
|
curses.curs_set(0)
|
||||||
|
stdscr.nodelay(1)
|
||||||
|
stdscr.timeout(100)
|
||||||
|
|
||||||
|
# create a game box
|
||||||
|
sh, sw = stdscr.getmaxyx()
|
||||||
|
box = [[3, 3], [sh - 3, sw - 3]] # [[ul_y, ul_x], [dr_y, dr_x]]
|
||||||
|
textpad.rectangle(stdscr, box[0][0], box[0][1], box[1][0], box[1][1])
|
||||||
|
|
||||||
|
# create snake and set initial direction
|
||||||
|
snake = [[sh // 2, sw // 2 + 1], [sh // 2, sw // 2], [sh // 2, sw // 2 - 1]]
|
||||||
|
direction = curses.KEY_RIGHT
|
||||||
|
|
||||||
|
# draw snake
|
||||||
|
for y, x in snake:
|
||||||
|
stdscr.addstr(y, x, "#")
|
||||||
|
|
||||||
|
# create food
|
||||||
|
food = create_food(snake, box)
|
||||||
|
stdscr.addstr(food[0], food[1], "*")
|
||||||
|
|
||||||
|
# print score
|
||||||
|
score = 0
|
||||||
|
score_text = "Score: {}".format(score)
|
||||||
|
stdscr.addstr(1, sw // 2 - len(score_text) // 2, score_text)
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
# non-blocking input
|
||||||
|
key = stdscr.getch()
|
||||||
|
|
||||||
|
# set direction if user pressed any arrow key and that key is not opposite of current direction
|
||||||
|
if key in DIRECTIONS_LIST and key != OPPOSITE_DIRECTION_DICT[direction]:
|
||||||
|
direction = key
|
||||||
|
|
||||||
|
# find next position of snake head
|
||||||
|
head = snake[0]
|
||||||
|
if direction == curses.KEY_RIGHT:
|
||||||
|
new_head = [head[0], head[1] + 1]
|
||||||
|
elif direction == curses.KEY_LEFT:
|
||||||
|
new_head = [head[0], head[1] - 1]
|
||||||
|
elif direction == curses.KEY_DOWN:
|
||||||
|
new_head = [head[0] + 1, head[1]]
|
||||||
|
elif direction == curses.KEY_UP:
|
||||||
|
new_head = [head[0] - 1, head[1]]
|
||||||
|
|
||||||
|
# insert and print new head
|
||||||
|
stdscr.addstr(new_head[0], new_head[1], "#")
|
||||||
|
snake.insert(0, new_head)
|
||||||
|
|
||||||
|
# if sanke head is on food
|
||||||
|
if snake[0] == food:
|
||||||
|
# update score
|
||||||
|
score += 1
|
||||||
|
score_text = "Score: {}".format(score)
|
||||||
|
stdscr.addstr(1, sw // 2 - len(score_text) // 2, score_text)
|
||||||
|
|
||||||
|
# create new food
|
||||||
|
food = create_food(snake, box)
|
||||||
|
stdscr.addstr(food[0], food[1], "*")
|
||||||
|
|
||||||
|
# increase speed of game
|
||||||
|
stdscr.timeout(100 - (len(snake) // 3) % 90)
|
||||||
|
else:
|
||||||
|
# shift snake's tail
|
||||||
|
stdscr.addstr(snake[-1][0], snake[-1][1], " ")
|
||||||
|
snake.pop()
|
||||||
|
|
||||||
|
# conditions for game over
|
||||||
|
if (
|
||||||
|
snake[0][0] in [box[0][0], box[1][0]]
|
||||||
|
or snake[0][1] in [box[0][1], box[1][1]]
|
||||||
|
or snake[0] in snake[1:]
|
||||||
|
):
|
||||||
|
msg = "Game Over!"
|
||||||
|
stdscr.addstr(sh // 2, sw // 2 - len(msg) // 2, msg)
|
||||||
|
stdscr.nodelay(0)
|
||||||
|
stdscr.getch()
|
||||||
|
time.sleep(5)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
curses.wrapper(main)
|
12
starter.py
12
starter.py
|
@ -16,7 +16,7 @@ with open("credentials.pickle", "rb") as f:
|
||||||
user = d["user"]
|
user = d["user"]
|
||||||
password = d["pass"]
|
password = d["pass"]
|
||||||
break
|
break
|
||||||
except EOFError:
|
except:
|
||||||
user = password = None
|
user = password = None
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ Run 'python starter.py initsql' to initialise credentials of your choice. """
|
||||||
d["pass"] = ""
|
d["pass"] = ""
|
||||||
f.seek(pos)
|
f.seek(pos)
|
||||||
pickle.dump(d, f)
|
pickle.dump(d, f)
|
||||||
except EOFError:
|
except:
|
||||||
pass
|
pass
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
@ -53,9 +53,9 @@ else:
|
||||||
databaseinit()
|
databaseinit()
|
||||||
subprocess.call(
|
subprocess.call(
|
||||||
f"mysql -u {user} --password={password} -D labyrinth < {os.path.abspath('dbdump.sql')}",
|
f"mysql -u {user} --password={password} -D labyrinth < {os.path.abspath('dbdump.sql')}",
|
||||||
shell=True#,
|
shell=True # ,
|
||||||
#stdout=subprocess.DEVNULL,
|
# stdout=subprocess.DEVNULL,
|
||||||
#stderr=subprocess.DEVNULL,
|
# stderr=subprocess.DEVNULL,
|
||||||
)
|
)
|
||||||
print("Successfully dumped sample data")
|
print("Successfully dumped sample data")
|
||||||
elif sys.argv[1] == "initsql":
|
elif sys.argv[1] == "initsql":
|
||||||
|
@ -71,6 +71,6 @@ else:
|
||||||
d["pass"] = password
|
d["pass"] = password
|
||||||
f.seek(pos)
|
f.seek(pos)
|
||||||
pickle.dump(d, f)
|
pickle.dump(d, f)
|
||||||
except EOFError:
|
except:
|
||||||
pass
|
pass
|
||||||
print("Successfully set.")
|
print("Successfully set.")
|
||||||
|
|
Loading…
Reference in a new issue