Sunday, October 19, 2025

Using HTML to generate random horrors from beyond...

A webpage that generates random "Elder God" names in the style of H.P. Lovecraft? Sure! This started as a Python project that would generate a list of 10 random names in the style of the infamous Elder Gods from the Lovecraft pantheon. I had so much fun with that I decided to port it over to the land of HTML.

 The page is available on my GitHub, in case anybody wants to summon an unthinkable horror with too many consonants.

https://robot-sword78634.github.io/elder-names/ 

The HTML uses the same syllable list and logic as the original Python code, but instead utilizes Javascript. It also adds some nifty apostrophes for that added Lovecraft flair.

 

Thursday, October 2, 2025

Let's create a cable TV channel!

I’ve become infatuated with Raspberry Pi single-board computers recently, and thanks to a low-grade eBay addiction, I now have several of them just sitting around, mocking me to make them useful. Recently, I read about someone who turned one into a sort of personal cable channel, and I got fired up on the idea of creating my own “cable channel” of highly curated videos—which I’m sure nobody else would want to watch.

It probably would have been easier to just follow the tutorial I found online for this type of project, but as usual, I felt it necessary to reinvent the wheel for the sake of “learning.” For me, the basic parts of getting a home cable channel working are:

  1. Figure out how to randomize/play/loop videos from a folder

  2. Determine how to “broadcast” the content (HDMI, Wi-Fi, etc.)

  3. Decide what content to use

I kept the first part simple. Since I’d be running this project on a spare Raspberry Pi 4 with Pi OS, I decided to use VLC as the media player. VLC natively does everything I needed (randomize, play, loop from a folder), and it can be controlled via terminal/bash scripts—perfect for making everything restart automatically if the system reboots.

I skipped the broadcasting question for now and focused on getting the system running. The fun part, after all, was deciding on a theme for my channel and grabbing videos! I’ve always been a movie buff and grew up watching late-night “midnight movie” flicks on TV, so it was a no-brainer to load up the Pi with movies and shows that fit that vibe.

I could have taken the easy route and gone straight to the Internet Archive, but instead, I pulled material from YouTube. A little-known fact: YouTube not only streams video content but also allows you to download files. Since I’d need a large number of videos, I wrote a quick Python script to batch-download user-curated playlists. Python makes this easy with the pytube library, which was designed for this purpose. The script asks for a YouTube URL and a save location, then pulls down the highest-quality stream available.

At first, I ran into certificate errors on macOS. Instead of troubleshooting libraries, I just ran the script on an Ubuntu machine and it worked without issues.

The flow is straightforward:

  1. Prompt for the YouTube URL and the save folder

  2. Use pytube to get the highest-resolution stream

  3. Download it to the folder

It’s a short and simple tool, but it does the job—a quick way to grab videos for offline viewing. After downloading a bunch of nostalgic movies and TV shows, I started scraping vintage 1970s commercials too. Since VLC randomizes playback, there’s a chance that after a movie or show, one or two commercials will play before the next feature. After raiding YouTube’s vaults, I had a solid library for my channel. Then came the fun part: testing and tweaking.

Long story short—it worked! It feels like watching a real TV channel from the 1970s. Videos flowed seamlessly from one to the next, with a nice balance of movies, shows, and commercials. (I might add more commercials later—it’s surprisingly fun to see a 1972 McDonald’s ad pop up.)

My startup bash script launches VLC at boot, runs everything in fullscreen, randomizes playback, and loops continuously without showing the user interface:

#!/bin/bash
vlc --fullscreen --loop --random /home/pi/Videos/

Right now, I have the Pi hooked up to a spare TV via HDMI, but I’m tempted to pick up an HDMI-to-RF modulator so I can run the channel on a CRT I keep around for playing Nintendo. Ideally, I’d love to broadcast to multiple TVs around the house—but I don’t know if I want to run 100 feet of coax cable just to watch Leonard Nimoy’s In Search Of in every room.

Or do I?



 


 

 

Wednesday, October 1, 2025

DOOM!

A LAN game of Chocolate DOOM running on the unholy trinity (Windows, Mac OS, and Ubuntu).

 That is all.


 

Sunday, September 28, 2025

Through a Glass Darkly: Building a Philip K. Dick Inspired Text Adventure in Python

As someone who's spent countless hours lost in the paranoid, twisting realities of Philip K. Dick's novels, I’ve always thought it would be fascinating to bring that sense of dislocation and uncertainty into a playable form. At the same time, I have a deep love for the classic text adventure games of the 1980s, especially Infocom’s masterpieces like Zork, where every room, every object, and every line of text contributes to an immersive narrative. It occurred to me that blending these two interests could produce something truly engaging: a text adventure where nothing is quite what it seems, and every discovery feels like piecing together fragments of a memory.

I decided to code this game in Python, keeping a few core design goals in mind. First, I wanted the game to feel like an Infocom adventure, so I structured it around a series of interconnected rooms, each with its own description, items, and NPCs. The player moves through these spaces using simple two-word commands like "go north" or "take wallet," much like the old parser systems that made classic interactive fiction so approachable and fun.

The game engine itself is data-driven. Rooms, items, and NPCs are all stored in dictionaries with unique identifiers, which makes it straightforward to expand the world later. Each room defines its exits, items present, and NPCs in place. Items can have clues associated with them, and NPCs can offer dialogue that hints at larger mysteries. Using Python’s dataclasses made it easy to encapsulate these properties while keeping the code readable and maintainable.

Player actions are handled through simple functions tied to verbs: go, take, use, talk, and so on. For instance, when the player uses the take command, the code checks whether the item is present and portable, adds it to the inventory, and collects any associated clues. Use commands allow the player to interact with objects or room features to trigger additional story events, like unlocking a door or revealing hidden information. There's also a clue and memory system that monitors the player’s discoveries; once enough clues are collected, the player recovers a key memory, which acts as a milestone in uncovering their identity.

Save and load functionality was also important, reflecting the classic adventure game experience where progress mattered. The game can save the current room, inventory, NPC states, and collected clues to a JSON file, and restore everything from that file later.

The narrative logic is built around the idea of memory recovery in a dystopian world—a theme central to Dick's work. The player starts with no memory and must piece together their identity by exploring the environment, interacting with NPCs, and collecting items. Clues are scattered across the world, and certain items or interactions trigger additional revelations. The balance between exploration, discovery, and narrative progression aims to capture the same unsettling tension found in Dick's novels, where reality is mutable and perception is unreliable.

This project was a perfect pairing for my interests: the procedural, logic-driven structure of a text adventure married to the thought-provoking themes and disorienting world-building of Philip K. Dick. It's designed to be extensible, so I can easily add more rooms, items, and puzzles in the future. For fans of either classic interactive fiction or Philip K. Dick's writing, this game represents a small but enjoyable intersection of those worlds—a place where the past, memory, and reality are constantly up for interpretation.

The code can be downloaded here if you want to try it out.

Now to see if ChatGPT can pass the Voight-Kampff test...

Sunday, March 30, 2025

"Hello Dr. Faulken. Would you like to play a game?"

I recently re-watched the classic proto-hacker 80's film "WarGames" starring Mathew Broderick and Ally Sheedy. The famous final scene, where the supercomputer Joshua blazes through game scenarios to final come to the conclusion that "the best way to win is not to play" got me thinking and inspired me to try my hand at writing a Python script that pits a computer against itself in a game of Tic-Tac-Toe, using the basic behavioral science concepts of positive and negative reinforcement, to see if I could approximate the fundamental principle of machine learning. After I got the script up and running, I added the ability to dump the results of each game played to an Excel spreadsheet, and then wrote another script using Matplotlib to visual the results. The hypthothesis is that after a certain amount of games, applying a basic machine learning algorythm the program will eventually move towards a state of optimal play, where the game registers more draws than wins. Essential the program is rewarded for making "good" moves that end in a win and penalized for making "bad" moves that result in a loss. The program will reach a state of optimal play when every game results in a draw. Essentially, when both the X and O are playing in an optimal state, the game plays to prevent a loss by achieving a draw.

Building the AI-Powered Tic-Tac-Toe

The foundation of the program is Q-learning, a reinforcement learning algorithm. The AI starts with no knowledge of the game and gradually improves by assigning values to moves based on rewards and penalties.

Here’s a quick breakdown of the main components:

  • Q-learning: The AI maintains a dictionary of board states, updating its move choices based on rewards.

  • State Representation: Each board is stored as a flattened tuple, allowing the AI to recognize patterns.

  • Exploration vs. Exploitation: Initially, the AI picks random moves to explore, but over time, it relies on learned strategies.

  • Game Logic: The program enforces Tic-Tac-Toe rules and determines wins, losses, or draws.

With this in place, I let the AI play itself continuously, logging the results to an Excel file.


 

Tracking 15,000 Games in Excel

To measure progress, I recorded each game’s outcome in an Excel file using pandas and openpyxl. The data captured:

  • Game number

  • Result (X wins, O wins, or Draw)

The AI played nonstop, generating a dataset of over 15,000 games. The expectation was clear: over time, the number of draws should increase as the AI moves toward optimal play.

Visualizing Learning with Matplotlib

Once the data was collected, I used Matplotlib to analyze how the AI improved. The key visualization was a draw percentage over time graph, calculated as:

Draw Percentage = (Total Draws / Total Games) * 100

Plotting this gave us a clear trajectory of improvement. Initially, wins and losses fluctuated wildly, but as the AI refined its strategy, the percentage of draws steadily climbed. By the end, draws accounted for over 40% of games played—a strong indication that the AI was approaching a level of optimal play.


 

Results: AI in Action

The final graph showed exactly what we hoped for: a sharp increase in draws, meaning the AI was learning to avoid losing. In Tic-Tac-Toe, perfect play from both sides should always result in a draw. The fact that the was AI approaching 100% draws proved that it was learning over time to eventually solve the game.

Final Thoughts

This project was a cool dive into reinforcement learning, data tracking, and visualization. Watching the AI evolve from random flailing to calculated mastery was incredibly rewarding. If you’re interested in AI, I highly recommend trying something similar—watching an algorithm teach itself is a fascinating experience. While 15,000 games of Tic-Tac-Toe seems like a LOT of games for a computer to begin to teach itself such a simple game, there are a few tweaks to the code that could be made to accelerate the learning. I'll probably continue to tinker with this one for a bit, as it is a surprisingly satisfying to watch the machine start to rack up draws against itself.


Saturday, February 22, 2025

Brackey's 2025.1 Game Jam

One of the coolest things to do when learning game development is to challenge yourself by participating in a game jam. Game jams are essentially online competitions where participants have a limited amount of time—ranging from several months to as short as 24 hours—to conceive and develop a working game. Most jams have "themes" that are announced when the competition begins. The themes vary with each jam, but one consistent rule is that participants must incorporate the theme into their game in some way, whether visually, mechanically, or narratively.

This past week, I had time off from work and discovered that the Brackeys 2025.1 Game Jam was happening, so I challenged myself by signing up. The jam started on Sunday and ran for seven days, with the winning theme, chosen by popular vote, being "NOTHING CAN GO WRONG."

I started brainstorming ideas for the game as soon as the theme was announced, eventually settling on a concept inspired by the Many-Worlds Interpretation in quantum mechanics. This theory posits that multiple timelines or universes are constantly being created and potentially destroyed. I'm kind of a nerd when it comes to physics, so this seemed like a cool basis for a game.

I began developing a simple game where the player controls an object on the screen that leaves a trail (representing the "timeline") while dodging enemy objects that randomly spawn from the top of the screen. To enhance the "moving through space" feel, I created a starfield background using Unity's particle system. One of the trickier mechanics involved spawning duplicate versions of the player whenever a collision occurred—these "alternative timelines" formed the core of the game's challenge. If too many spawned, the game would end. Since enemy spawns increased in intensity the longer the player survived, I realized I needed to balance the difficulty by adding a "good" object that could remove a randomly instantiated timeline. This added a risk/reward element, as players had to maneuver across the screen to collide with these objects and prevent the timeline from spiraling out of control. Fortunately, implementing this was easier than expected, thanks to Unity's prefab system and some trial and error with scripting. Everything was going great—until Day 3.

Disaster Strikes on Day 3

On Day 3, I decided the game needed a start screen. In Unity, this is done by creating a separate scene, which acts as a container for all the assets and code used in that part of the game. While working on this, I noticed that my main game scene still had the default name "SampleScene." Thinking nothing of it, I renamed it to "GameLoop" to make it more descriptive. I then returned to my newly created "StartScene" and began designing a start menu with some simple animations.

Once I was satisfied with the start menu, I saved my progress and went back to the GameLoop scene—only to realize something was very wrong. The game view screen was now completely gray, and all the game objects I had created and set up in the Unity Hierarchy window were gone.

Panic mode.

I quickly quit Unity and reloaded the project, hoping that would restore everything. It didn’t. The scene was still empty. A frantic Google search revealed the awful truth: I had inadvertently deleted my entire game scene by renaming it.

At that moment, I decided it was best to step away from the computer, grab a cup of coffee, and reconsider my options. I briefly thought about quitting the jam entirely and chalking this up as a painful lesson in Unity file management. But after a short break, I examined the empty scene again. My assets, prefabs, and, most importantly, my scripts were still intact in the Project Window.

All hope was not lost!

Rebuilding the game from scratch was still a daunting task, but I decided to give myself one hour to attempt it before making any final decisions. To my surprise, after that hour, I had restored most of the game’s core mechanics. So I kept going.

At the 3.5-hour mark, I had fully reconstructed the scene and even made a few improvements to the game's structure. Lesson learned: 

Rename your scenes BEFORE working on them!

Day 4 – Polishing the Game

Day 4 was all about refining the visuals. I replaced the placeholder geometric shapes I had been using for enemy and helper objects with actual pixel art. I also created a portrait of the player's character for the HUD, inspired by the classic DOOM face from the 1990s game. Eventually, I might even animate it to react when the player collides with an enemy, but for now, I’m quite happy with how it looks. I also fine-tuned the start menu’s timing and tested the game on multiple machines to ensure it functioned smoothly.

Day 5 – Preparing for Submission

Day 5 was spent setting up the itch.io page and adjusting the build settings to ensure the game displayed properly in WebGL. I’ve overlooked this step in past jams, and it can really impact how players experience the game. If a game doesn’t display correctly in the browser window, it can lead to a poor user experience and lower ratings. A little bit of research and testing goes a long way in making sure your hard work is properly showcased.

After a few final playtests on itch.io, I officially published the game and submitted it to the jam.

As of today, the jam ends tomorrow at 6 AM EST. After that, all participants can play and rate each other’s games based on various criteria. I’m excited to see what others have created and to receive feedback on Timeline. Every game jam is a learning experience, and this one definitely pushed me creatively.

If you're interested in playing my game, you can check out Timeline here.




The Lost Art of Tree Fishing

Now that the Northeast seems to have finally shaken off the icy grip of winter, I've taken the first reluctant steps outside of my cave ...