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/modules/__pycache__
|
||||
saves
|
||||
tetris
|
Binary file not shown.
|
@ -26,7 +26,7 @@ with open("credentials.pickle", "rb") as f:
|
|||
if d["credtype"] == "mysql":
|
||||
MYSQL_USERNAME = d["user"]
|
||||
MYSQL_PASSWORD = d["pass"]
|
||||
except EOFError:
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -5,3 +5,6 @@ from maze.modules.maze import main
|
|||
|
||||
def bruh():
|
||||
curses.wrapper(main)
|
||||
curses.nocbreak()
|
||||
curses.echo()
|
||||
curses.endwin()
|
||||
|
|
|
@ -141,7 +141,7 @@ class Maze:
|
|||
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])
|
||||
nodes_to_explore = [start]
|
||||
explored_nodes = set()
|
||||
|
@ -174,7 +174,9 @@ def path(maze, start, finish): # Not used
|
|||
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:
|
||||
head = ("█", curses.color_pair(2))
|
||||
if not trail:
|
||||
|
@ -221,11 +223,14 @@ def construction_demo(maze, screen):
|
|||
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 = []
|
||||
finish = []
|
||||
solution = None
|
||||
old_solution = None
|
||||
|
||||
def reset(start_or_finish, cell, colour):
|
||||
nonlocal solution, old_solution
|
||||
if start_or_finish:
|
||||
|
@ -238,6 +243,7 @@ def pathfinding_demo(maze, screen, start_ts, won_coords, loadedcoords=None, load
|
|||
if start and finish:
|
||||
solution, old_solution = tee(path(maze, start[0], finish[0]))
|
||||
draw_path(solution, screen, calledby="reset")
|
||||
|
||||
maxy, maxx = screen.getmaxyx()
|
||||
|
||||
if loadedcoords:
|
||||
|
@ -266,7 +272,9 @@ def pathfinding_demo(maze, screen, start_ts, won_coords, loadedcoords=None, load
|
|||
PAUSED = False
|
||||
break
|
||||
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.refresh()
|
||||
key = screen.getch()
|
||||
|
@ -531,9 +539,9 @@ def play(screen, loadedmaze=None, loadedcoords=None, loadedtime=0):
|
|||
|
||||
|
||||
def main(screen):
|
||||
screen.nodelay(True)
|
||||
curses.curs_set(False)
|
||||
curses.mousemask(curses.ALL_MOUSE_EVENTS)
|
||||
screen.nodelay(True)
|
||||
curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLACK)
|
||||
curses.init_pair(2, curses.COLOR_GREEN, 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)
|
|
@ -16,7 +16,7 @@ with open("credentials.pickle", "rb") as f:
|
|||
user = d["user"]
|
||||
password = d["pass"]
|
||||
break
|
||||
except EOFError:
|
||||
except:
|
||||
user = password = None
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ Run 'python starter.py initsql' to initialise credentials of your choice. """
|
|||
d["pass"] = ""
|
||||
f.seek(pos)
|
||||
pickle.dump(d, f)
|
||||
except EOFError:
|
||||
except:
|
||||
pass
|
||||
return None, None
|
||||
|
||||
|
@ -71,6 +71,6 @@ else:
|
|||
d["pass"] = password
|
||||
f.seek(pos)
|
||||
pickle.dump(d, f)
|
||||
except EOFError:
|
||||
except:
|
||||
pass
|
||||
print("Successfully set.")
|
||||
|
|
Loading…
Reference in a new issue