Background

Bad Apple is a song from the Japanese video game franchise Touhou. In 2009, a fan-made video for the song was posted online. The video is entirely in black and white, and the simplicity of the two colors has allowed people to play Bad Apple in creative ways. One notable example is Bad Apple being played on Minecraft sheep.

So I was looking at my university's course planner, NUSMods, and I thought to myself...

Can you play Bad Apple with NUSMods?

How it works

The timetable for NUSMods consists of 5 days from Monday to Friday, and 8 hours from 10 am to 6 pm. We can then treat the table as a grid with 5 rows and 8 columns. If a timeslot is occupied by a class, then it represents the color white, and black otherwise.

The challenge, then, is to select the right combination of classes so that the resulting grid resembles a frame from the Bad Apple video. By doing this for all frames, the result is the entire video from start to finish.

Also, NUSMods has a share feature, which means you can share frames of Bad Apple for your friends to enjoy!

How it was made

First, I scraped all possible classes using the NUSMods API. Then, using some "clever" algorithm (which we'll get to in a moment), I would find a valid combination of classes. Now I can use a tool like Selenium to open the requested timetable in a new window and take a screenshot of it. Repeat this process many, many times and we're done!

To concatenate the frames together, I used ffmpeg. Other features of the final video (such as the text) were added using the Python Imaging Library.

Challenges

The first challenge I encountered was finding a valid combination of classes. If we treat each class and video frame as a set of time slots, then what we really want is to find a collection of sets that exactly equals some other, bigger set. This is known as the exact cover problem, which is NP-complete. Luckily, real-life data is forgiving, and a simple backtracking solution (with some heuristics) works here. That being said, some frames literally do not have a solution, and I fixed this issue by simply using the most recent frame with a solution.

The real difficulty was rendering the timetables. Initially, I wanted to have only one timetable playing the video, but I decided that the resolution wasn't high enough, meaning I had to scale up to 4 timetables instead. Given that there are about 6-and-a-half thousand frames, I would have to render about 26 thousand timetables. So it's crucial that each timetable takes as little time to render as possible if I wanted to finish this project.

Whenever a timetable is imported to NUSMods, several annoying pop-ups appear. Instead of closing them with a click, I used Selenium to directly delete the HTML elements. And instead of waiting a fixed amount of time between deletions, I repeatedly try to perform a deletion until I am allowed to. Even with this speedy setup, it still took a painful amount of time (~5-6h) to render everything.

Reflection

Despite having to face the near-impossible task of waiting patiently, this project was very fun. It's always satisfying to see the final product after many hours of work.

I think Bad Apple is a great example of hacker culture, and I'm happy to have contributed to it!

What's next?

Now that we've shown how NUSMods can double as a video player, the next logical step is to see if it can be a video game engine as well. In other words, can NUSMods run Doom?

I leave that as an exercise for the reader.

Built With

Share this project:

Updates