Introduction
In our last lesson, you learned to use the <string.h> library, particularly strcmp, to create a basic command handler with a chain of if-else if statements. While functional, you may have sensed this approach could become unwieldy in a real game with dozens of commands. It's not scalable, efficient, or easy to maintain. Your intuition would be correct.
This lesson introduces a superior, more professional technique: the lookup table (LUT). We will explore how to replace cumbersome conditional logic with an elegant data structure that maps command strings to their meanings. This is a fundamental pattern in game development and embedded systems, prized for its speed and clarity. By the end of this lesson, you will be able to implement a clean, maintainable command structure for your text-based game, moving one step closer to your capstone project.

The Problem: Why if-else Chains Don't Scale
Before diving into the solution, let's solidify our understanding of the problem. A long series of if-else checks for string comparisons forces the program to perform multiple sequential operations. In the worst case, to find the last command in a list of 50, the CPU must execute 49 strcmp calls that fail before finding the one that succeeds. This is computationally wasteful and makes the code long, repetitive, and difficult to manage.
The following video introduces the concept of lookup tables by first highlighting the exact issue with this if-else approach.
How Look Up Tables (LUTs) make your code Smaller, Faster, and Better (example in C)
This video, "How Look Up Tables (LUTs) make your code Smaller, Faster, and Better" from Jacob Sorber's channel, provides excellent C examples.
First, watch the segment from this timestamp. The presenter demonstrates a function that uses a long if-else if chain to map numbers to messages. He then outlines its three main drawbacks: it's ugly, error-prone to update, and computationally slow. This is the exact scenario we want to avoid with our game's command parser.
The Solution: Replacing Computation with a Lookup
The core idea of a lookup table is to pre-compute or store results in a data structure (usually an array) and then access them directly. This trades a small amount of memory for a significant gain in speed and code readability. Instead of performing a series of comparisons, we perform a single lookup operation.
The fundamental principle is mapping a key to a value.

Let's see how the if-else mess from the video is transformed into a clean lookup table.
How Look Up Tables (LUTs) make your code Smaller, Faster, and Better (example in C)
Now, let's look at the elegant solution using a LUT.
First, get a formal definition of a lookup table by watching from this brief introduction. Next, see how the if-else logic is replaced by a simple array of strings (char* messages[]) in the segment from this timestamp. Here, the integer people is used as an index to directly look up the correct message. Finally, watch how this simplifies the function from this section. The long if-else chain is reduced to a single bounds check and one line of code to access the array. The video even shows the dramatic reduction in generated machine code, confirming the performance gain.
This first example maps an integer to a string. For our game, however, we need to solve a slightly different problem: mapping a string (the player's command) to some data.
Building a Command Lookup Table
In our text adventure, the player won't type a number; they'll type "north", "get", or "look". How do we use a string as a "key"? The most straightforward way is to create a structure that pairs the command string with its corresponding data, and then store these structures in an array. We can then loop through this small array, using strcmp to find a match.
This might sound like we're back to looping and comparing, but we are now doing so over a clean, separate, and easily expandable data structure, not a hardcoded if-else monstrosity. This separates our game data (the commands) from our game logic (the parser).
The following article provides a perfect example of this exact technique, which is often called a table-driven approach.
Table-driven approach - strchr.com
This article by Peter Kankowski is a concise and powerful demonstration of refactoring game logic.
Read the entire article. First, study the "before" code, a classic if-else if chain for handling movement commands like "north" and "south". Then, carefully analyze the "shorter equivalent". Notice the key components of the new approach: An enum to create symbolic constants for the directions (SIDE_NORTH, SIDE_EAST, etc.). A struct COMMAND that pairs a command string (name) with its corresponding enum value (side). A static const array of these COMMAND structs, which forms our lookup table. A simple for loop that iterates through the commands array to find a match. This structure is vastly superior. To add a new command, you simply add one more entry to the commands array. You don't need to touch the core parsing logic at all. This is a critical principle for writing maintainable code.
The use of struct here is a small preview of what we'll cover in detail in the next module. For now, you can think of a struct as a custom data type that lets you bundle different variables together under one name—in this case, packaging a command's text with its internal game ID.
Advanced Technique: Designated Initializers
The table-driven approach is excellent. C offers an even more expressive syntax for initializing arrays and structs called designated initializers (a feature from the C99 standard). This syntax allows you to explicitly label the indices or members you are initializing, making the code even more readable and less prone to ordering errors.
This is especially useful for mapping single-character commands ('n', 's', 'e', 'w') which is common in roguelike games. The ASCII value of the character serves as the index into the array.
The video "Advanced C 6: Lookup Tables" by Charles Cabergs demonstrates this modern C feature.
Watch the introduction from the beginning, where the presenter introduces the lookup table pattern and shows the [index] = value syntax for designated initializers. Continue through the next segment from this timestamp, which shows how this can be used to map char values. Pay close attention to the important caveat he mentions: if your keys are sparse (e.g., indices 5 and 1024), the compiler will allocate a very large array, which can be inefficient. This is a key engineering trade-off to remember. Finally, watch the "real-world" example from the sed utility. This demonstrates mapping a command character to a struct containing a function pointer and other data—a very powerful and common pattern in C.
While we won't be using function pointers just yet, this gives you a glimpse into the power and flexibility of lookup tables. For your game, you can start by mapping command strings to enums, and later evolve this to map commands to functions that execute the desired action.
Conclusion
You've now learned one of the most important refactoring techniques in a C programmer's toolkit. Moving from hardcoded conditional logic to a data-driven lookup table is a significant step toward writing professional-quality code. Your game's command parser will now be faster, cleaner, and far easier to extend.
Key Takeaways:
- The Anti-Pattern: Long
if-else iforswitchstatements for command parsing are inefficient, hard to read, and difficult to maintain. - The Solution: A lookup table replaces this logic with a data structure, trading a small amount of memory for significant gains in performance and clarity.
- Game Command LUTs: For mapping string-based commands, an array of
structsis an excellent approach. Eachstructpairs the command text (e.g.,"north") with an internal identifier (e.g., anenum). - Maintainability: This table-driven approach separates your game's data (the commands) from its logic (the parser), allowing you to add, remove, or change commands by only modifying the data array.
- Modern C: Designated initializers provide a highly readable and robust syntax for creating lookup tables.
In the next lesson, we will build upon this foundation. Now that you have a way to look up a command, we need a robust way to extract that command from player input like "go north" or "take brass key". We'll explore how to properly tokenize user input using strtok_r, a thread-safe and more robust version of the strtok function you saw previously.