Reply 20 of 22, by Peter Swinkels
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
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
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//
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 3typedef struct {int board[GRID_SIZE][GRID_SIZE];int mask[GRID_SIZE][GRID_SIZE]; // 1 for visible, 0 for hiddenint 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]);elseprintf(". ");}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 validbool 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 visiblefor(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).