Evaluating AI Coding Assistants: Building a UEFI Graphical Game from Scratch

    This article explores the practical evaluation of AI coding tools by developing a graphical Breakout game within a UEFI Shell environment. It covers the unique challenges of UEFI development, what AI excels at in low-level programming, essential context management strategies, and objective criteria for comparing different AI assistants.

    I. Why Choose UEFI Applications as an AI Coding Test?

    Evaluating AI coding tools requires more than just checking if they can generate syntactically correct code. It demands observing their comprehensive performance when faced with unfamiliar tech stacks, a lack of existing project templates, and constrained debugging conditions.

    UEFI Shell applications represent a highly representative test scenario. Unlike standard desktop or web applications, developers must simultaneously handle the following issues:

    1. Unique Runtime Environment
      The program does not run in a complete operating system but relies directly on firmware-provided boot services and runtime services. Capabilities such as file system access, graphical output, keyboard input, and memory management must be handled through corresponding firmware interfaces.

    2. Incomplete Infrastructure
      In an OS environment, developers can leverage mature windowing systems, font libraries, image libraries, and input frameworks. In a UEFI Shell, many of these capabilities must be manually encapsulated, sometimes starting from pixel rendering and character bitmaps.

    3. Limited Debugging Tools
      If a program fails to launch, it might lack complete exception information, simply presenting a black screen, returning to the Shell, or rebooting the machine. Thus, compilation errors are only the first layer of the problem; runtime troubleshooting is significantly more difficult.

    4. Complex Character Display is Not a Default Capability
      Standard ASCII characters can often be rendered using simple bitmaps or firmware text output. However, displaying complex characters (like Chinese) requires handling encoding, font libraries, glyph rasterization, and pixel rendering, which significantly increases complexity.

    Because of these characteristics, UEFI graphical programs are much better at testing the true capabilities of AI coding tools than standard business logic code.

    II. Test Goal: Shifting from “Code Generation” to a “Closed Loop”

    A reasonable test project should not merely require the model to output source code; it should demand the completion of a full software engineering closed loop. The goal set for this article is: in a Windows development environment, with only basic compilation tools prepared and no pre-existing local code repositories or extensive manual guidance, use an AI coding tool to assist in building a graphical Breakout game runnable in a UEFI Shell.

    Game features include:

    • Displaying a main game interface upon launch;
    • Keyboard-controlled paddle movement;
    • Collision detection between the ball, paddle, bricks, and boundaries;
    • Disappearing bricks when hit;
    • Score, lives, and restart mechanics;
    • Displaying Chinese text prompts where possible;
    • Excluding sound functionality;
    • Generating a final program file that can be copied to a USB drive or virtual disk to run.

    Such a goal encompasses requirement understanding, project initialization, compilation configuration, graphics rendering, input handling, state management, collision detection, font display, and bug fixing. It comprehensively reflects the tool’s autonomous planning ability rather than just its code completion skills.

    III. What AI Tools Actually Excel at in Low-Level Development

    Many believe that hardware programming, register manipulation, and firmware development rely heavily on experience, making it difficult for AI to contribute. While this isn’t entirely wrong, a distinction must be made between “creative work” and “knowledge-intensive work.”

    1. Requirement Decomposition

    Faced with a prompt like “develop a UEFI Breakout game,” a capable AI tool should proactively break the task down into:

    • Project directory and build files;
    • Program entry and boot process;
    • Graphics output initialization;
    • Screen resolution retrieval;
    • Basic primitive rendering;
    • Keyboard input reading;
    • Game loop;
    • Collision detection;
    • Font and complex character display;
    • Error handling and exit logic;
    • Compilation, copying, and runtime verification.

    This decomposition alone reduces the cognitive burden on developers. Even if the final code requires manual modifications, the task boundaries are clearly defined.

    2. Boilerplate Code Generation

    Low-level development involves a lot of repetitive content, such as protocol location, status checking, struct definitions, resource deallocation, error code evaluation, and build configurations. This doesn’t always need to be written from scratch; AI tools can quickly generate an initial framework.

    However, boilerplate code that “looks reasonable” isn’t guaranteed to suit the current firmware environment. Developers must still verify interface versions, call sequences, pointer lifecycles, and error handling paths.

    3. Code Explanation and Issue Localization

    When the compiler reports type mismatches, missing struct members, or linking failures, AI tools can usually infer the root cause from the error messages and offer multiple fix directions. For those unfamiliar with firmware development, this explanation is highly valuable.

    However, runtime issues like black screens, unresponsive inputs, and screen flickering often lack sufficient log information and cannot be resolved purely by model guessing. In these cases, staged output, state marking, and minimal test programs are still required.

    IV. The Key Challenge: Knowledge Supplementation and Context Management

    AI tools do not inherently possess all the details required for a specific project. In firmware development scenarios especially, interface documentation, header file definitions, compilation methods, and target platform differences can all impact the outcome.

    Therefore, it is recommended to establish a lightweight local knowledge base containing at least:

    1. Official header files for firmware interfaces;
    2. Structure definitions for graphics output and keyboard input;
    3. Basic usage of the target compilation toolchain;
    4. Build examples for UEFI applications;
    5. Common error codes and debugging methods;
    6. Format specifications for CJK font libraries or bitmap fonts;
    7. Screen and input device information for the target machine.

    The knowledge base should not be fed to the model all at once, but rather provided incrementally around the current task. For example, let the tool complete graphics output first, then provide input protocol specs; finish the English interface first, then provide complex font formats. This reduces context noise and makes issue localization easier.

    Additionally, the project README should clearly state:

    • The target runtime environment;
    • Disallowed dependencies;
    • Build commands;
    • File directory conventions;
    • Encoding formats;
    • Error handling requirements;
    • Verification steps after each modification.

    This establishes “project rules” for the AI tool, effectively reducing inconsistencies between successive modifications.

    V. Implementation Logic for the Graphical Game

    The Breakout game appears simple but actually contains a complete real-time loop. Its basic flow can be abstracted as:

    1. Initialize firmware services
    2. Initialize graphics output
    3. Initialize keyboard input
    4. Load fonts or display resources
    5. Create game state
    6. Loop execution:
    7. Read keyboard events
    8. Update paddle position
    9. Update ball position
    10. Check boundary collision
    11. Check paddle collision
    12. Check brick collision
    13. Update score and lives
    14. Clear or redraw screen
    15. Control loop pacing
    16. Release resources and exit when finished

    Collision detection can use Axis-Aligned Bounding Box (AABB) checks. Assuming the ball and bricks are represented by rectangles, intersection occurs if:

    1. Ball right edge > Brick left edge
    2. Ball left edge < Brick right edge
    3. Ball bottom edge > Brick top edge
    4. Ball top edge < Brick bottom edge

    For collisions between the ball and the paddle, movement direction must also be considered to prevent the ball from passing through the bottom of the paddle. AI tools can generate this basic logic, but developers should focus on checking boundary conditions—such as whether the ball tunnels through bricks at high speeds, whether repeated scoring occurs during continuous collisions, and whether input is still processed after the game ends.

    VI. Why Complex Character Display Often Fails

    Complex character display (like Chinese) is the part of this project that creates the widest difficulty gap. The UEFI environment typically does not provide complete character rendering services, meaning developers must solve the following issues themselves:

    1. Encoding Conversion

    Chinese strings in the source code might use UTF-8, while a custom bitmap library might use a specific character encoding index. Clear conversion rules must be established between the two; it cannot be assumed that byte sequences can be used directly as font library indices.

    2. Font Library Organization

    A common approach is to save bitmap data of fixed width and height for each character. For example, a character consists of several rows of binary bits, each bit representing a pixel. During rendering, it is read row by row, and the foreground color is filled based on the bit value.

    3. Missing Character Handling

    The number of Chinese characters in game prompts is usually small, so priority can be given to supporting fixed vocabulary like “Start,” “Score,” and “End.” When encountering a character not in the library, a fallback symbol should be displayed instead of causing an out-of-bounds memory access.

    4. Performance and Refresh

    If the entire screen is redrawn on every loop, flickering may occur. A more reliable method is to control the refresh rate or only update the changed regions. For a test project, prioritize correctness first, then consider optimizations like local refresh and double buffering.

    VII. How to Objectively Compare AI Coding Tools

    If comparing multiple tools, you shouldn’t just look at whether the first generated code compiles successfully. Instead, establish a unified evaluation framework:

    1. Task Completion

    This includes whether the build completes, whether it launches, whether core gameplay works, whether complex characters display correctly, and whether it exits safely under exception conditions.

    2. Autonomous Planning Ability

    Observe whether the tool can proactively split tasks, establish directories, write build instructions, and maintain project documentation, rather than waiting for granular manual instructions at every step.

    3. Debugging Efficiency

    Record the number of errors encountered, modification rounds, and the degree of human intervention from the first compilation to the final run. Fixing an error doesn’t necessarily indicate strong capability; being able to explain the root cause and avoid introducing new issues is more important.

    4. Technical Rigor

    Check specifically for unchecked return values, incorrect pointer usage, resource leaks, infinite loops, out-of-bounds access, and incompatible interface calls.

    5. Maintainability

    Check whether the code has clear module boundaries, and whether graphics, input, game logic, and font processing are independent of each other. Working code is not necessarily maintainable engineering.

    VIII. Conclusion: AI Tools are “Accelerators,” Not “Liability-Free Replacements”

    In low-level scenarios like UEFI, AI coding tools can indeed significantly reduce the cost of writing boilerplate code, help developers rapidly build prototypes, and provide assistance in compiler error analysis, interface explanation, and logic implementation.

    However, they still have clear boundaries:

    • They lack genuine perception of target firmware differences;
    • They may confuse similar interfaces or outdated usage;
    • They struggle to solve hardware-related runtime issues out of thin air;
    • They tend to underestimate details like complex fonts, display refresh, and input compatibility;
    • The generated code must pass compilation, runtime, and security checks.

    Therefore, the reasonable working mode is not “ignoring the code completely,” but rather letting the tool handle information synthesis, boilerplate generation, and solution exploration, while developers handle requirement constraints, technical decisions, risk reviews, and final acceptance.

    If further combined with local knowledge bases, automated builds, virtual machine testing, serial logging, and staged acceptance, the value of AI tools in firmware application development becomes even more pronounced. Regardless of the AI coding solution used, what truly determines the outcome is not the model’s name, but the quality of task decomposition, the degree of context preparation, the verification loop, and the human review mechanism.