Skip to content

Instantly share code, notes, and snippets.

@sppmacd
Last active February 6, 2024 11:20
Show Gist options
  • Save sppmacd/0a806c65ce634b2825c4016c88b73c73 to your computer and use it in GitHub Desktop.
Save sppmacd/0a806c65ce634b2825c4016c88b73c73 to your computer and use it in GitHub Desktop.
Bad Apple!! in C++ template errors

How to run

  1. Install GCC (tested on 12.2.0) and pyvideoreader (pip3 install pyvideoreader)
  2. Enter target terminal size to terminal_size.txt
  3. Replace line 7 of preprocess.py with:
    video = VideoReader('<path to your video>')

and line 10 of generate_cpp.py with:

        '<path to your video>').number_of_frames)()

(thanks @56independent for a comment!)

  1. Run:
python preprocess.py
python generate_cpp.py
  1. Run with buffering so that animation plays with original 30fps
g++ sources/badapple_*.cpp |& python buffer.py
  1. Or just play (this doesn't keep up speed and passes very fast)
g++ sources/badapple_*.cpp
import os
import sys
import time
terminal_size = (lambda: [int(i) for i in open("terminal_size.txt").read().split()])()
FRAME_TIME = 1/30
while True:
start_time = time.time()
out = ""
for i in range(7):
out += (sys.stdin.readline() or exit())
sys.stdout.write(out or exit())
time.sleep(FRAME_TIME - (time.time() - start_time))
from io import StringIO
import numpy as np
import os
import random
import sys
import time
from videoreader import VideoReader
frame_count = (lambda: VideoReader(
'/home/sppmacd/Videos/badapple.webm').number_of_frames)()
terminal_size = (lambda: [int(i) for i in open("terminal_size.txt").read().split()])()
FUNCTION_NAMES = [
"i",
"up",
"get",
"load",
"parse",
"format"
]
lead_size = len(" 10 | frame< >(\"")
os.makedirs("sources", exist_ok=True)
def rand_op():
chars = "+-*/%"
return chars[random.randrange(len(chars))]
FRAMES_PER_FILE = 200
FRAME_REPETITIONS = 1
for i in range(int(frame_count / FRAMES_PER_FILE) + 1):
with open(f"sources/badapple_{i:03}.txt", "w") as ascii_file:
for j in range(FRAMES_PER_FILE):
frame = i * FRAMES_PER_FILE + j
print(f"Generating: Frame {frame}/{frame_count} ({frame*100/frame_count:.1f}%)")
try:
with open(f"frames/{frame}", "rb") as frame_file:
frame_data = frame_file.read()
except FileNotFoundError:
break
# FANCY
data = StringIO()
offset = 0
while offset < len(frame_data) - 2:
if frame_data[offset] < 10:
data.write(" ")
offset += 1
else:
longest_white_sequence = 0
offset2 = offset
while offset2 < len(frame_data) - 2 and frame_data[offset2] >= 10:
longest_white_sequence += 1
offset2 += 1
trailing_length = len("() + ")
while longest_white_sequence > 0:
required_function_name_length = longest_white_sequence - trailing_length
if required_function_name_length <= 0:
data.write(f" " * longest_white_sequence)
break
elif required_function_name_length < len(FUNCTION_NAMES):
data.write(f"{FUNCTION_NAMES[required_function_name_length - 1]}() {rand_op()} ")
break
else:
length = random.randrange(1, len(FUNCTION_NAMES) + 1)
data.write(f"{FUNCTION_NAMES[length - 1]}() {rand_op()} ")
longest_white_sequence -= length + trailing_length
offset = offset2
for _ in range(FRAME_REPETITIONS):
ascii_file.write(f" frame<{frame:5}>(")
ascii_file.write(" "*(terminal_size[0] - lead_size))
ascii_file.write(data.getvalue())
ascii_file.write("2);\n")
# PLAIN
# ascii_file.write(f" frame<{i:5.0f}>(")
# ascii_file.write(" "*(terminal_size[0] - lead_size))
# for pixel in frame_data:
# ascii_file.write("#" if pixel > 10 else " ")
# ascii_file.write(");\n")
for i in range(int(frame_count / FRAMES_PER_FILE) + 1):
with open(f"sources/badapple_{i:03}.cpp", "w") as source_file:
template = open("template.cpp").read()
template = template.replace("|FRAMES|", open(f"sources/badapple_{i:03}.txt").read())
source_file.write(template)
import numpy as np
import os
import sys
import time
from videoreader import VideoReader
video = VideoReader('/home/sppmacd/Videos/badapple.webm')
frame_count = video.number_of_frames
terminal_size = (lambda: [int(i) for i in open("terminal_size.txt").read().split()])()
x_step = video.frame_width / (terminal_size[0])
y_step = video.frame_height / (terminal_size[1] - 8)
os.makedirs("frames", exist_ok=True)
for frame in video:
print(f"Preprocessing: Frame {video.current_frame_pos}/{frame_count} ({video.current_frame_pos*100/frame_count:.1f}%)")
with open(f"frames/{int(video.current_frame_pos - 1)}", "wb") as image:
# TODO: Interpolate
for scanline_idx in np.arange(0, video.frame_height, y_step):
scanline = frame[int(scanline_idx)]
for pixel_idx in np.arange(0, video.frame_width, x_step):
pixel = scanline[int(pixel_idx)]
image.write(bytes([pixel[0]]))
template<int I>
struct Idx { };
int i();
int up();
int get();
int load();
int parse();
int format();
struct Foo {};
template<class T>
struct InvokeResult { using Type = int; };
template<>
struct InvokeResult<int> {};
template<class T>
using InvokeResultT = typename InvokeResult<T>::Type;
template<int IDX, class T>
auto frame(T) -> InvokeResultT<T> {
}
void bad_apple()
{
|FRAMES|
}
int main()
{
bad_apple();
}
@notMONGCHAW
Copy link

I did everything but it was the rolling text that was the issue on standard terminal
but konsole somehow has a fix for that

@sppmacd
Copy link
Author

sppmacd commented Feb 24, 2023

hmm, strange

@LuxOrions
Copy link

The buffer wont work unless I remove the terminal_size. And I have to re-adjust the terminal_size.txt to my current terminal width x length.

Anyway it works like a charm!!

@notMONGCHAW
Copy link

notMONGCHAW commented Apr 17, 2023

The buffer wont work unless I remove the terminal_size. And I have to re-adjust the terminal_size.txt to my current terminal width x length.
Anyway it works like a charm!!

Yeah the terminal_size.txt had the default width and height of konsole app for Linux
if you are going to use any other app you have to change the size in there with your sizes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment