Building a Guess-the-Number Game in C Without Using the Standard Library
If you're up for a programming challenge, creating a C program without relying on the standard library is a great way to explore how low-level programming works. In this post, we’ll build a Guess-the-Number game that uses only Windows system calls for input, output, and random number generation.
Why Avoid the Standard Library?
The C standard library provides functions like printf
, scanf
, and rand
, which make programming easier. However, these are high-level abstractions built on lower-level system calls. By avoiding them, you:
- Learn how to work directly with the operating system.
- Gain a deeper understanding of how common functions are implemented under the hood.
- Explore efficient ways to handle tasks like random number generation, string manipulation, and I/O.
Overview of the Game
The game is simple:
- The program generates a random number between 1 and 100.
- The player guesses the number.
- The program provides hints like "Too low" or "Too high" until the player guesses correctly.
The Code: A Fully Standard Library-Free Implementation
Here's the complete implementation:
#include <windows.h> // Windows system calls ke liye
// Global seed for random number generation
unsigned int seed = 0;
// Seed initialization using system time
void initialize_seed() {
SYSTEMTIME st;
GetSystemTime(&st);
seed = (unsigned int)(st.wMilliseconds + st.wSecond * 1000);
}
// Custom pseudo-random number generator
int custom_rand() {
seed = (214013 * seed + 2531011); // Linear Congruential Generator (LCG) formula
return (seed >> 16) & 0x7FFF; // Extracting a smaller range
}
// Custom function to calculate string length
int custom_strlen(const char *str) {
int length = 0;
while (str[length] != '\0') {
length++;
}
return length;
}
// Custom function to print a string
void custom_print(const char *str) {
DWORD written;
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsole(hOut, str, custom_strlen(str), &written, NULL);
}
// Custom function to read input as a string
int custom_read_input() {
char buffer[16] = {0}; // Fixed size buffer
DWORD read;
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
ReadConsole(hIn, buffer, sizeof(buffer) - 1, &read, NULL);
// Convert string to integer manually
int num = 0;
for (int i = 0; buffer[i] != '\0' && buffer[i] != '\n'; i++) {
if (buffer[i] >= '0' && buffer[i] <= '9') {
num = num * 10 + (buffer[i] - '0');
}
}
return num;
}
// Main Game Logic
int main() {
initialize_seed(); // Initialize random seed
int number_to_guess = custom_rand() % 100 + 1; // Random number between 1 and 100
int guess;
custom_print("Welcome to Guess the Number Game!\n");
custom_print("I have chosen a number between 1 and 100. Try to guess it!\n");
while (1) {
custom_print("Enter your guess: ");
guess = custom_read_input();
if (guess < number_to_guess) {
custom_print("Too low! Try again.\n");
} else if (guess > number_to_guess) {
custom_print("Too high! Try again.\n");
} else {
custom_print("Congratulations! You guessed the number!\n");
break;
}
}
return 0;
}
Key Features of the Code
1. Custom Random Number Generator
Instead of rand()
, we implemented a Linear Congruential Generator (LCG):
int custom_rand() {
seed = (214013 * seed + 2531011); // LCG formula
return (seed >> 16) & 0x7FFF; // Extract a smaller range
}
This simple formula generates a pseudo-random sequence based on a global seed
, initialized using system time.
2. Custom String Length Function
Without strlen
, we wrote our own function:
This manually calculates the length of a string by iterating through it.
3. Custom Print Function
To replace printf
, we use Windows system calls (WriteConsole
):
void custom_print(const char *str) {
DWORD written;
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsole(hOut, str, custom_strlen(str), &written, NULL);
}
This function calculates the string length and writes it to the console.
4. Custom Input Reader
Instead of scanf
, we use ReadConsole
to read user input:
int custom_read_input() {
char buffer[16] = {0};
DWORD read;
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
ReadConsole(hIn, buffer, sizeof(buffer) - 1, &read, NULL);
// Convert the string to an integer manually
int num = 0;
for (int i = 0; buffer[i] != '\0' && buffer[i] != '\n'; i++) {
if (buffer[i] >= '0' && buffer[i] <= '9') {
num = num * 10 + (buffer[i] - '0');
}
}
return num;
}
Step-by-Step Execution
- The program initializes the random number generator with the current system time.
- A random number between 1 and 100 is generated.
- The user is prompted to guess the number, with hints provided until they guess correctly.
- The game uses only Windows API functions for printing and reading input.
Compiling and Running the Code
You’ll need a Windows compiler like MinGW or Visual Studio. To compile the code:
Run it in a Windows terminal, and enjoy the game.
Why This Approach is Interesting
- Deeper Understanding: By removing the standard library, you interact directly with the operating system.
- Learning Opportunity: This approach teaches how common C functions like
printf
andscanf
work under the hood. - Portability Awareness: This game is Windows-specific due to its reliance on
windows.h
. Building a cross-platform version would require different system calls.
Conclusion
Building a game without the standard library is a rewarding experience that sharpens your programming skills and deepens your understanding of system-level operations. Try this project, and take your C programming knowledge to the next level!
Ready to take the challenge? Copy the code, compile it, and start guessing! 😊