import curses import random import time def main(stdscr, start_length, speed): # Setup curses curses.curs_set(0) # Hide cursor stdscr.nodelay(1) # Non-blocking getch w = 100 if speed == 1: w = 250 if speed == 2: w = 225 if speed == 3: w = 200 if speed == 4: w = 175 if speed == 5: w = 150 if speed == 6: w = 125 if speed == 7: w = 100 if speed == 8: w = 75 if speed == 9: w = 50 if speed == 10: w = 25 stdscr.timeout(w) # Wait 100ms for input # if speed = 50 then timeout = 100 # if speed = 100 then timeout = 50 # if speed = 0 then timeout = 1000 # Snake and food characters head_char = '█' #head_char = '■' #head_char = '0' #head_char_up = '▄' #head_char_down = '▀' head_char_up = head_char_down = head_char body_char = '▓' #body_char = 'Φ' #body_char = '■' #body_char = 'O' #body_char = '░' #body_char = '■' #food_char = '💗' food_char = '█' #food_char = '▓' #food_char = '▒' # Setup colors curses.start_color() curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK) # Snake curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK) # Food curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_BLACK) # Score/Text stdscr.bkgd(' ', curses.color_pair(3)) # Game constants h, w = stdscr.getmaxyx() # Ensure window is large enough if h < 10 or w < 20: stdscr.addstr(0, 0, "Terminal window too small!") stdscr.refresh() time.sleep(2) return # Initial snake: list of [y, x] # Check if snake fits horizontally if start_length > w - 2: stdscr.addstr(h // 2, (w - len(f"Length {start_length} too long for width {w}!")) // 2, f"Length {start_length} too long for width {w}!", curses.color_pair(3)) stdscr.refresh() time.sleep(2) return # Start the head at x=start_length so the tail ends at x=1 snake = [[h // 2, start_length - i] for i in range(start_length)] # Initial food def get_new_food(): while True: nf = [random.randint(1, h - 2), random.randint(1, w - 2)] if nf not in snake: return nf food = get_new_food() # Initial direction key = curses.KEY_RIGHT score = start_len hc = head_char while True: next_key = stdscr.getch() # If no key is pressed, next_key is -1 # Update direction if it's a valid arrow key and not opposite to current if next_key != -1: if next_key == curses.KEY_DOWN and key != curses.KEY_UP: key = next_key hc = head_char_down elif next_key == curses.KEY_UP and key != curses.KEY_DOWN: key = next_key hc = head_char_up elif next_key == curses.KEY_LEFT and key != curses.KEY_RIGHT: key = next_key hc = head_char elif next_key == curses.KEY_RIGHT and key != curses.KEY_LEFT: key = next_key hc = head_char elif next_key == ord('q'): # Allow quit break # Calculate new head head = snake[0] if key == curses.KEY_DOWN: new_head = [head[0] + 1, head[1]] elif key == curses.KEY_UP: new_head = [head[0] - 1, head[1]] elif key == curses.KEY_LEFT: new_head = [head[0], head[1] - 1] elif key == curses.KEY_RIGHT: new_head = [head[0], head[1] + 1] else: # Should not happen new_head = head # Check collisions if (new_head[0] in [0, h - 1] or new_head[1] in [0, w - 1] or new_head in snake): key = stdscr.getch() break snake.insert(0, new_head) # Check if snake ate food if snake[0] == food: score += 1 food = get_new_food() else: snake.pop() # Remove tail # Draw everything stdscr.clear() stdscr.attron(curses.color_pair(3)) stdscr.border(0) stdscr.attroff(curses.color_pair(3)) # Draw snake for i, (y, x) in enumerate(snake): char = hc if i == 0 else body_char stdscr.addch(y, x, char, curses.color_pair(1)) # Draw food stdscr.addch(food[0], food[1], food_char, curses.color_pair(2)) # Draw score stdscr.addstr(0, 2, f' Length: {score} @ {speed}MPH ({w}x{h}) ', curses.color_pair(3)) stdscr.refresh() # Game Over screen #stdscr.clear() msg = f"GAME OVER! SCORE: {score}" stdscr.addstr(h // 2, (w - len(msg)) // 2, msg, curses.color_pair(3)) stdscr.addstr(h // 2 + 1, (w - 18) // 2, "Press Q to exit", curses.color_pair(3)) stdscr.nodelay(0) key = stdscr.getch() while key != ord('q'): key = stdscr.getch() exit('bye') if __name__ == "__main__": try: start_len = input("Enter starting snake length (default 3): ") start_len = int(start_len) if start_len.strip() else 3 if start_len < 1: start_len = 3 except ValueError: start_len = 3 try: speed = input("Enter snake speed (1 to 10, default 7): ") speed = int(speed) if speed.strip() else 7 if speed > 10: speed = 10 if speed < 1: speed = 1 except ValueError: speed = 7 curses.wrapper(main, start_len, speed)