SETTINGS
Appearance
Language
About

Settings

Select a category to the left.

Appearance

Theme

Choose an overall theme for the entire blog. Each can have their own colours.

Colourscheme

Light or dark? Choose how the site looks to you by clicking an image below.

Light Dark
AMOLED

Language

Preferred Language

All content on blog.claranguyen.me is originally in UK English. However, if content exists in your preferred language, it will display as that instead. Feel free to choose that below. This will require a page refresh to take effect.

About

"blog.claranguyen.me" details

Domain Name: claranguyen.me
Site Version: 2.0.0
Last Updated: 2025/03/09
Block Block: The Semi-Optimised Run
Friday, June 19, 2026

Introduction

My childhood consisted of a lot of arcade games. My Dad introduced me and my brother to MAME back in around 1999 with a bunch of ROMs he managed to get. Me and my brother would use MAME32 (or MAMEUI32) as a frontend to select games and play them. It was the first experience with emulation I ever had.

One of the games that me and my brother played a bunch was Block Block. As kids, we never really finished the game. But now, 27 years later, we kind of went back to playing games like this and it became a weekly tradition to beat them. I set up a custom arcade "machine" that auto-records demo files so we can go back and upload videos to the DERPG YouTube channel for archival's sake. Here's a tweet about it, actually:

So yeah, we take our arcade games decently seriously. But we played so much of Block Block that I began to wonder what an optimal run would look like. Given it's one of the very few arcade games we play that doesn't run at a fixed pace, surely it's possible to have an optimal playthrough. That's where a TAS would come in. But we aren't doing that here. I want to take all of the runs of Block Block that we have, find the fastest runs of each level, and slap them all together into a single video, automatically. How do I do that? Well, let's get into it.

How Block Block works

Block Block is very simple. One or two players take down 50 fixed levels of blocks Arkanoid-style. I get the feeling Block Block is Capcom's attempt at an Arkanoid game. There are powerups. The player's "mallet" can expand in size. The ball can pierce through targets. There are multiple opportunities for extra lives. However, you are also penalised for the ball hitting the mallet too much.

Given the style of the game, each level can have an optimal path that clears out blocks more efficiently than other paths. Obviously, two players will clear out levels twice as fast. Occasionally, an "EXIT" will pop up which, when hit, will auto-complete a level for you. This is purely RNG-based. A truly optimal play would involve getting as many "EXIT"s as possible.

The Spreadsheet

I am going for a video where the fastest runs of each level, based on all runs, is shown. For instance, we played the game 20 times between 2024-2025. That is 20 runs of all 50 levels. Take the fastest run of level 1 and put it into the video. Take the fastest run of level 2 and do the same. And so on for all 50 levels.

Obviously, this requires a spreadsheet. I decided to use Google Sheets for convenience. After that, I painstakingly went through every single video and got the exact timestamps for the beginning and ending of each level. You can do this on YouTube via:

JavaScript
document.querySelector("video").currentTime

The spreadsheet looks like this:

As you can see, there are two pages to the spreadsheet. The first page is where the times are punched in. The second page is for export as CSV. Because we are going to write up a Bash script to comb through the data and encode video. More on that later. The spreadsheet auto-computes the fastest runs of each level and gives the date. It is also expandable, so I can make future iterations of this compilation video for 2026 runs, 2027 runs, and so on.

CSV Export

As mentioned up above, I export the second page of the spreadsheet to CSV. This has all of the auto-computed values for optimal plays, as well as the dates of the recordings where it happened. This is more than enough information to jump to a video file, seek to the moment the level starts, and extract the level clip. Here is what part of the CSV looks like:

CSV File Sample
File,Start,Delta
2025/11/16,46.035054,25.800285
2024/12/15,67.239091,32.622161
2024/12/01,138.326376,27.72129
2024/12/08,165.559408,31.066394
2025/06/29,222.330936,20.272769

This is the first 5 levels out of 50. To see the full file, check this out: data.csv.

Preparing Replay files and videos

At DERPG, there is no such thing as a delete button. We keep all footage. The format that these arcade demo files are stored is in a replay format. These files are very small. Though I also store separate audio tracks for me and my brother's microphones as an MKA file. I package everything up into a TAR.XZ and archive that. We can always go back to those replays and generate video to upload to YouTube or use for projects like this. This is what we call a "Master".

I am not going to get into the technical details of how the archive works. Just know we take the replay file, as well as backed up NVRAM, play back the gameplay, and tell MAME to export a video. Then we magically have a video file to work with. That gives us this:

Now we have the CSV, as well as all videos to comb through. Let's move on to the next step.

Automating Video Splicing and Concatenation

I am an automation person. I refuse to use a video editor to do things. Sure, we could technically read the spreadsheet, import all 20 videos into a video editor, and cut at the appropriate spots. Join them together, export, and upload. But that is just not how I do things. We are going to do this the FFmpeg way. In other words, I am going to write up a way to automatically cut the videos at the correct spots, and then join them all together.

The Basics

Let's start with the CSV file. Here's the first 5 levels again for reference:

CSV File Sample
File,Start,Delta
2025/11/16,46.035054,25.800285
2024/12/15,67.239091,32.622161
2024/12/01,138.326376,27.72129
2024/12/08,165.559408,31.066394
2025/06/29,222.330936,20.272769

Given the video files are named with the date and timestamp baked in, we can extract the date from the CSV file and use auto-completion to find the correct video file. Here is an example where I take a line from the CSV and "convert" it to the appropriate video file:

Bash
UNIX> ls -1 *"$(echo "2025/11/16,46.035054,25.800285" | sed 's/^\(.*\)\/\(.*\)\/\(.*\),.*,.*$/\1-\2-\3/')"*".mkv"
[2025-11-16 - 21 24 59] blockr1.mkv

Alternatively, sed 's/^\(.*\),.*,.*$/\1/;s/\//-/g' also works. Either way, we got our video file. Now we need to hack up a script to comb through all of the videos. In FFmpeg, you can cut videos precisely via:

Bash
ffmpeg -i "VIDEO.MKV" -ss TIME_START -t TIME_DELTA ...

So the first level in that spreadsheet would be...

Bash
ffmpeg -i "[2025-11-16 - 21 24 59] blockr1.mkv" -ss 46.035054 -t 25.800285 ...

For encoding settings, as per "Frame jumping on a YouTube video", uploading a YouTube video encoded via libx265 results in frame skipping. So we will resort to libx264. Other settings include CRF 17, slow preset, and yuv420p10le pixel format, as 10-bit encodes on 8-bit content somehow compresses better.

The Script

Here is my script which will take a data.csv, as well as the 20 videos in the same directory and make the final video for upload:

Bash
#!/bin/bash

mkdir level_clips
rm -f "level_clips/concat.txt"

# Read all lines into array
lines=()
{
	while IFS= read -r line; do
		lines+=("$line")
	done
} < data.csv

# Go through every line and process
for ((i=1; i<${#lines[@]}; i++)); do
	line="${lines[$i]}"

	# Extract CSV information
	date="$(echo "$line" | sed 's/^\(.*\)\/\(.*\)\/\(.*\),.*,.*$/\1-\2-\3/')"
	time_start="$(echo "$line" | sed 's/^.*,\(.*\),.*$/\1/')"
	time_delta="$(echo "$line" | sed 's/^.*,.*,\(.*\)$/\1/')"

	# Grab the video file based on the date
	F="$(ls -1 *"$date"*".mkv" | head -n 1)"

	# Process via FFmpeg
	ffmpeg \
		-i "$F" \
		-ss "$time_start" \
		-filter_complex "[0:v]scale=-2:4320:flags=neighbor[out]" \
		-map '[out]' -map 0:a \
		-c:v libx264 -crf 17 -preset slow -pix_fmt yuv420p10le \
		-c:a flac -compression_level 12 -sample_fmt s16 \
		-t "$time_delta" \
		"level_clips/segment_level${i}.mkv"

	# Add to FFmpeg concat file
	echo "file 'segment_level${i}.mkv'" >> "level_clips/concat.txt"
done

# Stitch all videos together
ffmpeg \
	-f concat -safe 0 -i "level_clips/concat.txt" \
	-map 0 -c copy \
	"final.mkv"

I do need to explain. I read all lines into an array intentionally. For some reason, variables were being tampered with when I streamed the lines in. It was skipping videos and I didn't feel like debugging it. Anyway, I feel like the script is fairly straight-forward. It goes through every line in the CSV, finds the video, extracts the specific moment. Finally, it joins all 50 segments at the last step via FFmepg's concat mode.

Conclusion

This was a rather short blog post. And a very simple "production procedure". I plan to release "semi-optimal" playthrough videos of Block Block yearly from now on. Just to see how much we improve over the years. This'll go until we eventually stop playing Block Block, I guess. I hope you learned something about Bash or FFmpeg through this post as well. Though I didn't make this as educational as I probably could have.

To close out the post, here is the final video:

In a normal, average run of Block Block, we would spend 50-60 minutes playing. This optimal run is 28:05. Makes you wonder if it's possible to legitimately do this without segmentation. But until I see a TAS, I'm satisfied with this for now.




Clara Nguyễn
Hi! I am a Vietnamese/Italian mix with a Master's Degree in Computer Science from UTK. I have been programming since I was 6 and love to write apps and tools to make people's lives easier. I also love to do photography and media production. Nice to meet you!


Blog Links
Post Archive