def draw(canvas: curses.window): canvas.border() canvas.nodelay(True) # https://docs.python.org/3/library/curses.html#curses.window.getmaxyx window_height, window_width = canvas.getmaxyx() # rows and columns greater by one then real window size max_y, max_x = window_height - 1, window_width - 1 curses.curs_set(False) # Reducing max dimensions by 2 allows to avoid "curses.error" stars_max_y = window_height - 2 stars_max_x = window_width - 2 coroutines = [ blink( canvas, random.randint(1, stars_max_y), # stars mustn't appear on border random.randint(0, stars_max_x), delay=random.randint(1, 20), ) for _ in range(random.randint(100, 200)) ] coroutines.append(animate_rocket_flight(canvas, max_y, max_x)) while coroutines: for coro in coroutines.copy(): try: coro.send(None) except StopIteration: coroutines.remove(coro) canvas.refresh() time.sleep(TIC_TIMEOUT)
def show_msg(screen: curses.window, screen_height: int, screen_width: int, message: str): """Generic routine to generate an error message""" screen.addstr(screen_height // 2, screen_width // 2 - len(message) // 2, message) screen.nodelay(0) screen.getch() sys.exit(0)
def run_game(scr: curses.window): curses.curs_set(0) scr.nodelay(True) game_state = "" status_w: int = 25 maxy = scr.getmaxyx()[0] - 1 maxx = scr.getmaxyx()[1] midy = int(maxy / 2) midx = int(maxx / 2) snake: list = [] for i in range(SNAKE_LEN): snake.append((midy, status_w + midx + i)) direction = WEST apples: list = [] score = 0 while True: scr.erase() draw_statusbar(scr, (maxy - 1, maxx), status_w, score) draw_snek(scr, snake, direction) draw_apples(scr, apples) # ++ Tick ++ key = scr.getch() direction, game_state = process_key(key, direction) snake = move_snake(snake, direction) snake = portals(snake, direction, status_w + 2, (maxy - 1, maxx)) snake, apples, nscore = eat_apples(snake, apples) apples = create_apples(snake, apples, MAX_APPLES - len(apples), status_w, (maxy, maxx)) score += nscore if game_state != "": return game_state, 0 # -- Tick -- scr.refresh() if check_loss(snake): curses.napms(1000) return "end", score curses.napms(100)
def main(scr: curses.window): # Remove blinking cursor curses.curs_set(0) # Get screen's height and width & check if the screen is big enough sh, sw = scr.getmaxyx() if sh < SCR_H + 2 or sw < SCR_W + 2: show_msg(scr, sh, sw, MSG_SCR_SMALL) # Get args mode, ip, port, plname = get_args(scr, sh, sw) # Start socket for host/join mode skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM) skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if mode == 'host': try: skt.bind((ip, port)) skt.listen(1) except: show_msg(scr, sh, sw, MSG_CANT_HOST) else: try: skt.connect((ip, port)) except: show_msg(scr, sh, sw, MSG_CANT_JOIN) # Setup keys up_key = set((curses.KEY_UP, ord('k'), ord('K'), ord('w'), ord('W'))) down_key = set((curses.KEY_DOWN, ord('j'), ord('J'), ord('s'), ord('S'))) quit_key = set((ord('q'), ord('Q'))) keys = {'up_key': up_key, 'down_key': down_key, 'quit_key': quit_key} # Activate nodelay (so getch won't interrupt the execution) scr.nodelay(1) scr.timeout(33) # Create arena arena = Arena(0, 1, SCR_W, SCR_H) # Create players player1 = Player('left', arena) player2 = Player('right', arena) # Create the ball ball = Ball(arena.bound_x // 2, arena.bound_y // 2, choice((-1, 1)), choice((-1, 0, 1))) # Connection accepted accepted = False # Waiting connection message scr.addstr(sh // 2, sw // 2 - len(MSG_WAITING) // 2, MSG_WAITING) scr.refresh() scr.addstr(sh // 2, 0, " " * sw) # Draw the arena arena.draw(scr) # Game loop while True: # Start networking if mode == 'host': if not accepted: # Accept client try: clskt, claddr = skt.accept() except: sys.exit() # Write host name on the screen and send it scr.addstr(0, 0, plname) clskt.send(plname.encode().ljust(16)) # Receive client name and add to screen try: clname = clskt.recv(16).strip().decode()[:16] except: show_msg(scr, 0, SCR_W, MSG_DISCONN) scr.addstr(0, SCR_W + 1 - len(clname), clname) # Mark client as accpeted accepted = True else: if not accepted: # Receive host name and add to screen try: scr.addstr(0, 0, skt.recv(16).strip().decode()[:16]) except: show_msg(scr, 0, SCR_W, MSG_DISCONN) # Write client name on the screen and send it scr.addstr(0, SCR_W + 1 - len(plname), plname) skt.send(plname.encode().ljust(16)) accepted = True # Draw the game score scr.addstr(0, SCR_W // 2 - 6, str(player1.score)) scr.addstr(0, SCR_W // 2 + 6, str(player2.score)) # Draw players player1.draw(scr, arena) player2.draw(scr, arena) # Draw ball (host) and check goals if mode == 'host': ball.move(player1, player2, arena) ball.draw(scr) # Get button press, perform action and send over the network if mode == 'host': action = get_action(scr, arena, player1, keys, plname == 'AI', { 'p1': player1.y, 'p2': player2.y, 'ball': ball.upload() }) if action == 'up' and player1.y > arena.y + 3: player1.move('up') elif action == 'down' and player1.y < arena.bound_y - 3: player1.move('down') elif action == 'quit': clskt.close() sys.exit(0) else: action = None # Send ball and host's action try: clskt.send(pickle.dumps((str(action), ball.upload()))) player2_action = clskt.recv(16).strip().decode() if player2_action == 'up' and player2.y > arena.y + 3: player2.move('up') elif player2_action == 'down' and player2.y < arena.bound_y - 3: player2.move('down') except: show_msg(scr, 0, SCR_W, MSG_DISCONN) else: action = get_action(scr, arena, player2, keys, plname == 'AI', { 'p1': player1.y, 'p2': player2.y, 'ball': ball.upload() }) if action == 'up' and player2.y > arena.y + 3: player2.move('up') elif action == 'down' and player2.y < arena.bound_y - 3: player2.move('down') elif action == 'quit': skt.close() sys.exit(0) else: action = None # Send client's action, then get ball and host's position try: skt.send(str(action).encode().ljust(16)) player1_action, ball_info = pickle.loads( skt.recv(sys.getsizeof(('down', ball.upload())) * 3)) if player1_action == 'up' and player1.y > arena.y + 3: player1.move('up') elif player1_action == 'down' and player1.y < arena.bound_y - 3: player1.move('down') ball.download(ball_info) except: show_msg(scr, 0, SCR_W, MSG_DISCONN) # Draw ball (join) and check goals ball.move(player1, player2, arena) ball.draw(scr) scr.refresh()
def main(screen: curses.window): curses.mousemask(1) screen.nodelay(1) curses.curs_set(0) start(screen) chat_page(screen)