Skip to content

Instantly share code, notes, and snippets.

@bromaster912791
Created March 4, 2025 14:52
Show Gist options
  • Save bromaster912791/8230e42ed957b08ceb7e46c9917e8dc3 to your computer and use it in GitHub Desktop.
Save bromaster912791/8230e42ed957b08ceb7e46c9917e8dc3 to your computer and use it in GitHub Desktop.
c sharp donut translated to python
import math
import os
import sys
import time
# Constants for better viewing
WIDTH = 80
HEIGHT = 22
RENDER_DELAY = 0.05 # Slow down the rendering a bit
# Clear the screen completely before starting
os.system('cls' if os.name == 'nt' else 'clear')
A = 0
B = 0
print("\nDonut animation starting. Press Ctrl+C to exit.")
print("Try expanding your console to full screen for best viewing.")
time.sleep(2) # Give time to read the message
# Clear again before the animation starts
os.system('cls' if os.name == 'nt' else 'clear')
try:
while True:
# Reset the buffers for each frame
b = [' ' for _ in range(WIDTH * HEIGHT)]
z = [0.0 for _ in range(WIDTH * HEIGHT)]
# Pre-compute sin/cos values
sin_A, cos_A = math.sin(A), math.cos(A)
sin_B, cos_B = math.sin(B), math.cos(B)
# Spin the donut
for j in range(0, 628, 7): # 0 to 2π in small increments
j = j / 100.0
for i in range(0, 628, 2): # 0 to 2π in small increments
i = i / 100.0
sin_i, cos_i = math.sin(i), math.cos(i)
sin_j, cos_j = math.sin(j), math.cos(j)
h = cos_j + 2 # R1 + R2*cos(θ)
D = 1 / (sin_i * h * sin_A + sin_j * cos_A + 5) # 1/z
# 3D (x,y) projection
t = sin_i * h * cos_A - sin_j * sin_A
x = int(WIDTH/2 + 30 * D * (cos_i * h * cos_B - t * sin_B))
y = int(HEIGHT/2 + 15 * D * (cos_i * h * sin_B + t * cos_B))
# Calculate the index in the buffer
o = x + WIDTH * y
# Calculate luminance
N = int(8 * ((sin_j * sin_A - sin_i * cos_j * cos_A) * cos_B -
sin_i * cos_j * sin_A - sin_j * cos_A -
cos_i * cos_j * sin_B))
# Only render pixels that are within bounds and closer to viewer
if 0 < y < HEIGHT and 0 < x < WIDTH and D > z[o]:
z[o] = D
# Higher luminance values get brighter characters
b[o] = ".,-~:;=!*#$@"[max(N, 0)]
# Clear the screen before each frame (more reliable than cursor positioning)
os.system('cls' if os.name == 'nt' else 'clear')
# Render the frame
frame = ""
for k in range(HEIGHT):
frame += ''.join(b[k * WIDTH:(k + 1) * WIDTH]) + '\n'
# Print the frame
print(frame, end='')
sys.stdout.flush()
# Increment angles for animation
A += 0.04
B += 0.02
# Slow down the animation
time.sleep(RENDER_DELAY)
except KeyboardInterrupt:
# Clean exit on Ctrl+C
os.system('cls' if os.name == 'nt' else 'clear')
print("\nDonut animation stopped.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment