Skip to content

Instantly share code, notes, and snippets.

@justinledwards
Created February 19, 2025 15:14
Show Gist options
  • Save justinledwards/02f3f46eafea234952ce4fa3368c0912 to your computer and use it in GitHub Desktop.
Save justinledwards/02f3f46eafea234952ce4fa3368c0912 to your computer and use it in GitHub Desktop.
Matrix python
#!/usr/bin/env python3
import os
import sys
import time
import random
import curses
# ANSI escape codes for text formatting
LIGHT_GREEN = '\033[92m'
DARK_GREEN = "\033[0;32m"
BOLDON = '\033[1m'
CURSORON = '\x1b[?25h'
CURSOROFF = '\x1b[?25l'
END = '\033[0m'
def clear_terminal():
"""Clear the terminal screen (compatible with Windows and Unix)."""
os.system('cls' if os.name != 'posix' else 'clear')
def live_type(text, delay, remain, prefix=""):
"""
Prints text one character at a time with a delay between characters.
:param text: The string to display.
:param delay: Time delay between characters.
:param remain: Time to wait after printing the text.
:param prefix: A string printed before the text (for positioning).
"""
print(prefix, end='')
for char in text:
print(char, end='', flush=True)
time.sleep(delay)
time.sleep(remain)
def show_message(message, delays, delay_factor, remain, prefix=""):
"""
Prints a message with a pre-defined per-character delay list.
:param message: The message to print.
:param delays: A list of delay multipliers for each character.
:param delay_factor: A global multiplier for the delays.
:param remain: Time to pause after the message is printed.
:param prefix: A string printed before the message (for positioning).
"""
print(prefix, end='')
for char, d in zip(message, delays):
time.sleep(d * delay_factor)
print(char, end='', flush=True)
time.sleep(remain)
def matrix_rain_effect(duration):
"""
Displays a Matrix rain effect for a given duration using curses.
This function sets up the curses window, then in a loop randomly
updates each column with a falling random ASCII character.
:param duration: How many seconds to run the effect.
"""
def run_matrix(stdscr):
curses.curs_set(0)
stdscr.nodelay(True)
sh, sw = stdscr.getmaxyx()
curses.start_color()
curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK)
# Initialize drop positions for each column
columns = [0] * sw
start_time = time.time()
while time.time() - start_time < duration:
stdscr.erase()
for x in range(sw):
# Occasionally reset the drop to create a staggered look.
if random.random() > 0.975:
columns[x] = 0
else:
columns[x] = (columns[x] + 1) % sh
char = chr(random.randint(33, 126))
try:
stdscr.addstr(columns[x], x, char, curses.color_pair(1))
except curses.error:
pass # Ignore errors when drawing outside the window
stdscr.refresh()
time.sleep(0.05)
stdscr.erase()
stdscr.refresh()
time.sleep(0.1)
curses.wrapper(run_matrix)
def handle_interrupt(prefix, delay_factor, remain_factor, exit_msg, exit_msg2):
"""
Handles KeyboardInterrupt by displaying an alternate sequence.
"""
clear_terminal()
print(prefix, end='')
print(END + LIGHT_GREEN + "Switch!")
time.sleep(0.6 * remain_factor)
clear_terminal()
print(prefix, end='')
print("Switch!\n\t\tApoc!")
time.sleep(1.2 * remain_factor)
clear_terminal()
print(prefix, end='\n\n\n ')
print(exit_msg, flush=True)
time.sleep(0.9 * remain_factor)
clear_terminal()
print(prefix, end='\n ')
print(exit_msg2, flush=True)
time.sleep(0.6 * remain_factor)
clear_terminal()
print(prefix, end='')
live_type(exit_msg, 0.045 * delay_factor, 3.5 * remain_factor)
print(CURSORON + END)
clear_terminal()
sys.exit()
def main():
# Configuration factors (you can adjust these to change the pace)
remain_factor = 0.2 # Affects how long messages remain on screen.
delay_factor = 0.7 # Affects typing speed.
# Positioning prefix for messages
prefix = "\n\n\n "
# Message definitions
ur_name = "Neo"
msg1 = f"Wake up, {ur_name}..."
msg2 = "The Matrix has you..."
msg3 = "Follow the white rabbit."
msg4 = f"Knock, knock, {ur_name}."
exit_msg = " 671tcH iN Th3 M4tr1x\n"
exit_msg2 = " gLiTCh In tH€ WaTriX\n"
# Delay arrays measured from the film (ensure these match the message lengths)
secs1 = [0, 0.1500, 0.1625, 0.1500, 0.1625, 0.1500,
0.1625, 0.1500, 0.1200, 0.1250, 0.1200,
0.1250, 0.0625, 0.0875, 0.0625]
secs2 = [0, 0.7325, 0.6700, 0.6000, 0.7800, 0.0950,
0.1350, 0.1075, 0.5275, 0.6225, 0.0080,
0.1200, 0.1475, 0.4500, 0.0080, 0.4275,
0.1275, 0.1425, 0.3550, 0.2275, 0.1450]
try:
clear_terminal()
# Pre-sequence Matrix rain (3 seconds)
matrix_rain_effect(duration=3)
# Set text formatting: bold, light green, and hide the cursor.
print(BOLDON + LIGHT_GREEN + CURSOROFF, end='')
# Display each message with its timing and then clear the screen.
show_message(msg1, secs1, delay_factor, 16.03 * remain_factor, prefix=prefix)
clear_terminal()
show_message(msg2, secs2, delay_factor, 7.54 * remain_factor, prefix=prefix)
clear_terminal()
live_type(msg3, 0.1167 * delay_factor, 8.515 * remain_factor, prefix=prefix)
clear_terminal()
# Print the final message without per-character delays.
print(prefix, end='')
print(msg4, end='')
print(prefix * 2, end='')
time.sleep(4)
clear_terminal()
# Post-sequence Matrix rain (3 seconds)
matrix_rain_effect(duration=3)
except KeyboardInterrupt:
handle_interrupt(prefix, delay_factor, remain_factor, exit_msg, exit_msg2)
# Restore cursor and default text formatting
print(CURSORON + END, end='')
clear_terminal()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment