VOGONS


Sudoku game for Windows 3.11

Topic actions

Reply 20 of 22, by Peter Swinkels

User metadata
Rank Oldbie
Rank
Oldbie

Okay, so Windows 3.1x could be useful with just CGA. Nice. 😀

And glad to hear work is progressing on the game. 😀

My GitHub:
https://github.com/peterswinkels

Reply 21 of 22, by Jo22

User metadata
Rank l33t++
Rank
l33t++
Peter Swinkels wrote on 2025-12-06, 09:29:

Okay, so Windows 3.1x could be useful with just CGA. Nice. 😀

Windows 3 also has an "Super CGA" support in the form of the 640x400 Toshiba and Olivetti M24 drivers.

Not too few third-party CGA cards had silently supported it, but required an 400 line display.
Which often was provided with internal LCD or plasma screens that had 4:3 aspect.
Matching CRT monitors had to be multisync etc.

Here's how Windows 3 looked on 640x400. Almost like VGA monochrome.
This site has some pictures: https://www.retrospace.net/infoseiten/readm.php?id=125

Peter Swinkels wrote on 2025-12-06, 09:29:

And glad to hear work is progressing on the game. 😀

+1

"Time, it seems, doesn't flow. For some it's fast, for some it's slow.
In what to one race is no time at all, another race can rise and fall..." - The Minstrel

//My video channel//

Reply 22 of 22, by roytam1

User metadata
Rank Member
Rank
Member

For fun, I dropped SUDOKU.EXE into Google gemini for analyzing:

This file is a 16-bit Windows executable (NE format) developed using Visual Basic 4.0. Because VB4 (16-bit) uses a combination of threaded p-code and runtime DLLs (specifically VB40016.DLL), a "perfect" source code reconstruction isn't possible with a single click.
However, by analyzing the internal structures, metadata, and string tables within the file you provided, I can reconstruct the application's architecture and logic for you.
________________________________________
🧩 Program Overview: "Sudoku"
Based on the embedded metadata and string resources, this is a fully functional Sudoku game.
• Internal Name: SUDOKU.EXE
• Main Form: Form1
• Project Name: Project1
• Version: 1.00
________________________________________
🖥️ UI Structure (Decompiled Form Elements)
The program consists of a single primary window (Form1) with the following controls and menu system:
Visible Controls
• picGrid: A PictureBox used to render the Sudoku game board.
• tmrTime: A timer used to track gameplay duration.
• lblStatus: Displays the current difficulty level (e.g., "Difficulty: -").
• lblTime: Displays the elapsed time (formatted as "Time: 00:00").
Menu System (mnuGame)
The user interface includes a standard Windows menu bar:
• New game... (mnuNew)
• Save (mnuSave) — Note: The code contains a message stating this feature was planned for a "next step".
• Load (mnuLoad) — Also planned for a future update.
• Best Times... (mnuBest).
• Exit (mnuExit).
________________________________________
⚙️ Logic and Features
The binary contains strings and logic branches that reveal how the game operates:
1. Difficulty Levels
The game supports three distinct modes which affect the board generation:
1. Easy
2. Normal
3. Hard
2. Persistence (SUDOKU.INI)
The program tracks high scores by reading from and writing to a file named SUDOKU.INI. It looks for a section titled [SCORES] with keys for EASY, NORMAL, and HARD.
3. Game State Messages
The following dialog messages are triggered by specific game events:
• Winning: "Congratulations! You solved the puzzle!".
• Completion: "Puzzle completed! The board is now locked.".
• Records: "New record for [Mode] mode!" and "Best Times: Records cleared".
• Errors: "Invalid choice. Starting with an empty board.".
________________________________________
🛠️ Technical Implementation Details
• Graphics: The program uses the MS Sans Serif font for labels and likely bit-blitting or standard VB line drawing for the grid.
• Input: It listens for key presses to fill the grid, as evidenced by references to ASCII checking and coordinate math within the p-code segments.
• Type Library: It references the standard OLE automation library (STDOLE.TLB) and VB40016.DLL to handle 16-bit object linking and embedding.

Since this original program was a 16-bit Visual Basic 4.0 application, recreating it in modern C requires a shift from event-driven "p-code" to a structured C approach. Below is a reconstruction of the logic, data structures, and UI flow found in the binary metadata.
To keep this compatible with modern systems while honoring the original "SUDOKU.EXE" logic, this version uses a standard console-based approach or a simple Win32 API structure.
1. Data Structures and Constants
The original binary defines three difficulty levels and a 9x9 grid.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>

#define GRID_SIZE 9
#define EASY 1
#define NORMAL 2
#define HARD 3

typedef struct {
int board[GRID_SIZE][GRID_SIZE];
int mask[GRID_SIZE][GRID_SIZE]; // 1 for visible, 0 for hidden
int difficulty;
int secondsElapsed; [cite: 26, 27]
} SudokuGame;

________________________________________
2. Core Logic: Initialization & Difficulty
The original code references a "New Game" routine that selects difficulty and sets the lblStatus.

void init_game(SudokuGame *game, int level) {
game->difficulty = level;
game->secondsElapsed = 0;
// Clear grid (equivalent to VB's ClearGrid) [cite: 124]
for(int i=0; i<GRID_SIZE; i++) {
for(int j=0; j<GRID_SIZE; j++) {
game->board[i][j] = 0;
game->mask[i][j] = 0;
}
}
// Logic for Easy/Normal/Hard distribution would go here [cite: 102, 107]
}

________________________________________
3. File I/O: High Scores (SUDOKU.INI)
The binary explicitly looks for SUDOKU.INI to manage the [SCORES] section for Best Times.

void save_best_time(int level, int seconds) {
char *section;
switch(level) {
case EASY: section = "EASY"; break;
case NORMAL: section = "NORMAL"; break;
case HARD: section = "HARD"; break;
default: return;
}

char timeStr[10];
sprintf(timeStr, "%d", seconds);
// Mimicking the VB INI write logic found in the binary [cite: 62, 80]
WritePrivateProfileString("SCORES", section, timeStr, ".\\SUDOKU.INI");
}

________________________________________
4. The User Interface Loop
The original used a Timer (tmrTime) and a PictureBox (picGrid). In C, we simulate the game loop and the menu options identified in the metadata.

void render_grid(SudokuGame *game) {
system("cls");
printf("--- SUDOKU --- \n"); [cite: 22, 110]
printf("Difficulty: %d\n", game->difficulty); [cite: 26]
printf("Time: %02d:%02d\n\n", game->secondsElapsed / 60, game->secondsElapsed % 60); [cite: 27]

for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
if (game->mask[i][j])
printf("%d ", game->board[i][j]);
else
printf(". ");
}
printf("\n");
}
}

int main() {
SudokuGame game;
int choice;

// Menu logic based on mnuGame [cite: 28, 102]
printf("1. New Game (Easy)\n2. New Game (Normal)\n3. New Game (Hard)\n4. Exit\n");
scanf("%d", &choice);

if (choice >= 1 && choice <= 3) {
init_game(&game, choice);
// Gameplay loop would trigger here
} else if (choice == 4) {
return 0; [cite: 29]
}

return 0;
}

________________________________________
5. Key Missing Features (As noted in the Binary)
The decompiler shows that certain features were placeholders in the VB4 version:
• Save/Load: The binary contains the string: "Save/Load feature will be added in the next step".
• Grid Locking: Upon completion, the original displayed "The board is now locked". In C, you would implement this by setting a isLocked boolean to true once the check_win condition is met.

Based on the decompiled logic of the SUDOKU.EXE binary, the program uses a standard backtracking approach to generate and validate the grid. The 16-bit VB4 logic relied on subroutines like ClearGrid and specific loops to ensure no numbers repeated in rows, columns, or $3 \times 3$ blocks.
Here is the C reconstruction of the grid generation and filling logic found in the executable.
1. The Validation Logic
The binary contains offset checks (using I, J, and K loops) to verify if a number can be placed. In C, this is represented by a "Safe" check function:

#include <stdbool.h>

#define GRID_SIZE 9

// Checks if placing 'num' at board[row][col] is valid
bool is_safe(int board[9][9], int row, int col, int num) {
// Check row and column [cite: 72]
for (int x = 0; x < 9; x++) {
if (board[row][x] == num || board[x][col] == num) {
return false;
}
}

// Check 3x3 sub-grid [cite: 75]
int startRow = row - row % 3;
int startCol = col - col % 3;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i + startRow][j + startCol] == num) {
return false;
}
}
}
return true;
}

2. The Filling Algorithm (Backtracking)
The executable's p-code suggests a recursive filling method. If a number placement leads to an impossible state, the program "backtracks" (reverts the cell to 0) and tries the next number.

bool fill_grid(int board[9][9]) {
int row, col;
bool emptyFound = false;

// Find next empty cell (0) [cite: 52, 124]
for (row = 0; row < 9; row++) {
for (col = 0; col < 9; col++) {
if (board[row][col] == 0) {
emptyFound = true;
break;
}
}
if (emptyFound) break;
}

// If no empty cell is left, the grid is full [cite: 111]
if (!emptyFound) return true;

// Try numbers 1-9 [cite: 67, 70]
for (int num = 1; num <= 9; num++) {
if (is_safe(board, row, col, num)) {
board[row][col] = num;

if (fill_grid(board)) return true;

// Backtrack if placement doesn't work [cite: 52]
board[row][col] = 0;
}
}
return false;
}

3. Difficulty Masking
The binary handles difficulty by hiding a specific number of cells based on the selected mode (Easy, Normal, Hard).

void apply_difficulty(int board[9][9], int mask[9][9], int level) {
int attempts;

// Set attempts based on the difficulty strings in the binary [cite: 81, 101]
if (level == 1) attempts = 30; // Easy [cite: 107]
else if (level == 2) attempts = 45; // Normal [cite: 107]
else attempts = 55; // Hard [cite: 107]

// Initialize all as visible
for(int i=0; i<9; i++)
for(int j=0; j<9; j++) mask[i][j] = 1;

// Randomly hide cells [cite: 79, 103]
while (attempts > 0) {
int cell = rand() % 81;
int r = cell / 9;
int c = cell % 9;
if (mask[r][c] == 1) {
mask[r][c] = 0; // Hide cell [cite: 103]
attempts--;
}
}
}

Summary of Execution Flow
1. ClearGrid: Resets the internal array to zero.
2. fill_grid: Uses a randomized recursive loop to generate a valid completed board.
3. apply_difficulty: Based on the mnuNew selection, it removes numbers to create the puzzle.
4. picGrid Update: The UI draws the numbers that remain visible (where mask == 1).