Welcome to Code Forum!

Join a community that supports you and your coding journey from day one. We strive to be a friendly, supportive community that empowers everyone to be better developers. By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

Sudoku Puzzle in C

user_232

New Coder
# Sudoku
This is a basic beginner Sudoku project made with the C language using Windows API.

# Features
  • Custom levels according to your capability
  • click an empty cell then use keyboard or buttons on the screen to enter the number.
  • The game features 3 hints for you to use when you get stuck.
  • the GUI is super clean and modern with live score/mistakes/click tracking and cell highlighting.


# Notes
- What can I improve? What can I make more efficient and less time-consuming as am I am a rookie programmer and any extra suggestion you want to give me feel free?

GitHub repo: GitHub - reewdgh/sudoku


Include Directory
\
sudoku_game.h
Code:
#pragma once
#include <stdlib.h>
#include <stdbool.h>
int *shuffle();
int checkValidPlacement(int (*grid)[9], int num, int row, int col);
int solveSudoku(int (*grid)[9], int row, int col);
int copyMatrix(int (*grid1)[9], int (*grid2)[9]);
int countSolutions(int (*grid)[9]);
int checkRows(int (*grid)[9], int number, int row, int col);
int checkCols(int (*grid)[9], int number, int row, int col);
int checkSubGrid(int (*grid)[9], int number, int row, int col);
int generateValidSudoku(int (*grid)[9], int row, int col);
void fillWithZero(int (*grid1)[9], int (*grid2)[9], int level);

sudoku_gui.c


Code:
#pragma once
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include "../src/config.h"

extern int i;
#define X 0
#define Y 1
#define I 2
#define J 3
extern int START_POINT;
extern int POINT_GAP;
typedef struct
{
    int boardInfo[100][4];
    int emptyCells;
    int isEmptyCellClicked;
    int userGrid[9][9];
    int sudokuGrid[9][9];
    int score;
    int mistakes;
    int isStart;
    int unsolvedGrid[9][9];
    int prevIndex;
    int centerX;
    int centerY;
    int hintUsed;
} Sudoku;

#define CELL_I(index, ctx) ctx->boardInfo[index][I]
#define CELL_J(index, ctx) ctx->boardInfo[index][J]
#define CELL_X(index, ctx) ctx->boardInfo[index][X]
#define CELL_Y(index, ctx) ctx->boardInfo[index][Y]

void createNumberButtons(HWND hwnd);
void drawSudokuGrid(HDC hdc, Sudoku *ctx);
int fillEmptyCell(Sudoku *ctx, HWND hwnd);
void displayUserStats(HDC hdc, Sudoku *ctx);
int checkEmptyBoxClick(HWND hwnd, Sudoku *ctx);
void checkUserInput(HWND hwnd, int number, Sudoku *ctx);
void colorLevelButtons(int buttonID, LPDRAWITEMSTRUCT draw);
void drawImage(HDC hdc, char *imagePath, int x, int y, int width, int height);
int DeleteLevelButtons(HWND hwnd);
int createLevelButtons(Sudoku *ctx, HWND hwnd);
void colorNumberButtons(LPDRAWITEMSTRUCT draw, int buttonID);
void createHintButton(HWND hwnd);
void createStartScreen(HDC hdc, Sudoku *ctx);
void HandleKeyBoardInput(WPARAM wparm, Sudoku *ctx, HWND hwnd);
void isPointerNull(void *ptr);

Source Directory

sudoku_game.c

Code:
 #include "../include/sudoku_game.h"

void fillWithZero(int (*grid1)[9], int (*grid2)[9], int level)
{
    copyMatrix(grid1, grid2);
    for (int i = 0; i < 9; i++)
    {
        int *numbers = shuffle();
        for (int j = 0; j < level; j++)
        {
            grid1[i][numbers[j]] = 0;
            if (countSolutions(grid1) == 0)
            {
                grid1[i][numbers[j]] = grid2[i][numbers[j]];
            }
        }
    }
}

int countSolutions(int (*grid)[9])
{
    int solveGrid1[9][9] = {0}, solvedGrid2[9][9] = {0};
    copyMatrix(solveGrid1, grid);
    solveSudoku(solveGrid1, 0, 0);
    srand(4);
    for (int i = 0; i < 9; i++)
    {
        copyMatrix(solvedGrid2, grid);
        solveSudoku(solvedGrid2, 0, 0);
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                if (solvedGrid2[i][j] != solveGrid1[i][j])
                {
                    return 0;
                }
            }
        }
    }
    return 1;
}

int solveSudoku(int (*grid)[9], int row, int col)
{
    if (row == 9)
    {
        return 1;
    }
    if (col == 9)
    {
        return solveSudoku(grid, row + 1, 0);
    }
    if (grid[row][col] != 0)
    {
        return solveSudoku(grid, row, col + 1);
    }
    int numbers[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (int i = 8; i > 0; i--)
    {
        int random = rand() % (i + 1);
        int temp = numbers[i];
        numbers[i] = numbers[random];
        numbers[random] = temp;
    }
    for (int i = 0; i < 9; i++)
    {
        if (checkValidPlacement(grid, numbers[i], row, col))
        {
            grid[row][col] = numbers[i];
            if (solveSudoku(grid, row, col + 1))
            {
                return 1;
            }
            grid[row][col] = 0;
        }
    }
    return 0;
}

int copyMatrix(int (*grid1)[9], int (*grid2)[9])
{
    for (int i = 0; i < 9; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            grid1[i][j] = grid2[i][j];
        }
    }
    return 0;
}

int *shuffle()
{
    static int numbers[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (int i = 0; i < 9; i++)
    {
        int random = rand() % 9;
        int temp = numbers[i];
        numbers[i] = numbers[random];
        numbers[random] = temp;
    }
    return numbers;
}

int checkValidPlacement(int (*grid)[9], int num, int row, int col)
{
    return checkRows(grid, num, row, col) &&
           checkCols(grid, num, row, col) &&
           checkSubGrid(grid, num, row, col);
}

int generateValidSudoku(int (*grid)[9], int row, int col)
{
    if (row == 9)
    {
        return 1;
    }
    if (col == 9)
    {
        return generateValidSudoku(grid, row + 1, 0);
    }
    int *numbers = shuffle();

    for (int i = 0; i < 9; i++)
    {
        int num = numbers[i];

        if (checkValidPlacement(grid, num, row, col))
        {
            grid[row][col] = num;
            if (generateValidSudoku(grid, row, col + 1))
            {
                return 1;
            }
            grid[row][col] = 0;
        }
    }
    return 0;
}

int checkRows(int (*grid)[9], int number, int row, int col)
{
    for (int i = 0; i < 9; i++)
    {
        if (i != col && grid[row][i] == number)
        {
            return false;
        }
    }
    return true;
}

int checkCols(int (*grid)[9], int number, int row, int col)
{
    for (int i = 0; i < 9; i++)
    {
        if (i != row && grid[i][col] == number)
        {
            return false;
        }
    }
    return true;
}

int checkSubGrid(int (*grid)[9], int number, int row, int col)
{
    int first = (row / 3) * 3;
    int second = (col / 3) * 3;

    for (int i = first; i < first + 3; i++)
    {
        for (int j = second; j < second + 3; j++)
        {
            if ((i != row || j != col) && grid[i][j] == number)
            {
                return false;
            }
        }
    }
    return true;
}
Code:
#include "../include/sudoku_gui.h"
int i = 0;
#define X 0
#define Y 1
#define I 2
#define J 3
int START_POINT;

// Sudoku s1 = {};

void drawSudokuGrid(HDC hdc, Sudoku *ctx)
{
    isPointerNull(ctx);
    int y = START_POINT, x = START_POINT;
    HPEN defaultPen = CreatePen(PS_SOLID, 1, BLACK);
    HPEN boldPen = CreatePen(PS_SOLID, 2, BLACK);
    for (int i = 0; i < LINES_TO_DRAW; i++)
    {
        if (i % 3 == 0)
        {
            SelectObject(hdc, boldPen);
        }
        MoveToEx(hdc, y, START_POINT, 0);
        LineTo(hdc, y, END_POINT);
        SelectObject(hdc, defaultPen);
        y += START_POINT;
    }
    for (int j = 0; j < LINES_TO_DRAW; j++)
    {
        if (j % 3 == 0)
        {
            SelectObject(hdc, boldPen);
        }
        MoveToEx(hdc, START_POINT, x, 0);
        LineTo(hdc, END_POINT, x);
        SelectObject(hdc, defaultPen);
        x += START_POINT;
    }
    DeleteObject(defaultPen);
    DeleteObject(boldPen);
    HFONT font = CreateFont(START_POINT - 10, 0, 0, 0, FW_MEDIUM, 0, 0, 0, 0, 0, 0, 0, 0, MAIN_FONT);
    SelectObject(hdc, font);

    int a = 0;
    ctx->emptyCells = 0;
    SetBkMode(hdc, TRANSPARENT);

    for (int i = 0; i < 9; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            ctx->boardInfo[a][X] = (START_POINT * (j + 1));
            ctx->boardInfo[a][Y] = (START_POINT * (i + 1));
            ctx->boardInfo[a][I] = i;
            ctx->boardInfo[a][J] = j;
            a++;
            if (ctx->userGrid[i][j] == 0)
            {
                ctx->emptyCells++;
                continue;
            }
            if (ctx->unsolvedGrid[i][j] == 0)
            {
                SetTextColor(hdc, BLUE);
            }
            char s[2];
            sprintf(s, "%d", ctx->userGrid[i][j]);

            RECT cellRect;
            cellRect.left = START_POINT + (START_POINT * j);
            cellRect.top = START_POINT + (START_POINT * i);
            cellRect.right = cellRect.left + START_POINT;
            cellRect.bottom = cellRect.top + START_POINT;

            DrawText(hdc, s, 1, &cellRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
            SetTextColor(hdc, BLACK);
        }
    }
    DeleteObject(font);
}

void createNumberButtons(HWND hwnd)
{
    HDC hdc = GetDC(hwnd);
    HFONT font = CreateFont(START_POINT, 0, 0, 0, FW_MEDIUM, 0, 0, 0, 0, 0, 0, 0, 0, MAIN_FONT);
    SelectObject(hdc, font);

    int y = (START_POINT * 4), x = START_POINT * 11, j = 0, z = 0;

    for (int i = 0; i < 9; i++)
    {
        if (i % 3 == 0 && i != 0)
        {
            y = y + START_POINT * 2;
            z = 0;
            x = START_POINT * (z + 11);
        }
        char s[10];
        sprintf(s, "%d ", j + 1);
        HWND button = CreateWindow("button", s, WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, x, y,
                                   START_POINT * 3 / 2, START_POINT * 3 / 2, hwnd, (HMENU)(INT_PTR)(j + 1), 0, 0);
        SendMessage(button, WM_SETFONT, (WPARAM)font, TRUE);
        x = (START_POINT * ((z + 1) + 11)) + START_POINT * (z + 1);
        j++;
        z++;
    }
    ReleaseDC(hwnd, hdc);
}

void checkUserInput(HWND hwnd, int number, Sudoku *ctx)
{
    isPointerNull(ctx);

    if (ctx->sudokuGrid[CELL_I(i, ctx)][CELL_J(i, ctx)] == number)
    {
        ctx->userGrid[CELL_I(i, ctx)][CELL_J(i, ctx)] = number;
        ctx->score += MAX_INCREMENT_SCORE;
        ctx->emptyCells--;
        ctx->isEmptyCellClicked = 0;
    }
    else
    {
        PlaySound("fah.wav", NULL, SND_ASYNC);
        MessageBox(hwnd, "Invalid placement, Try another number", "Error!", MB_OK | MB_ICONQUESTION);
        ctx->mistakes++;
        if (ctx->mistakes == 5)
        {
            MessageBox(hwnd, "Max limit of Mistakes Reached(5)!", "msg", MB_OK | MB_ICONASTERISK);
            PostQuitMessage(0);
        }
    }

    drawSudokuGrid(GetDC(hwnd), ctx);
    displayUserStats(GetDC(hwnd), ctx);

    if (!ctx->emptyCells)
    {
        MessageBox(hwnd, "Congratulations, You solved the Sudoku puzzle!", "Message ", MB_OK | MB_ICONINFORMATION);
        PostQuitMessage(0);
    }
}

int checkEmptyBoxClick(HWND hwnd, Sudoku *ctx)
{
    isPointerNull(ctx);

    POINT p = {.x = 0, .y = 0};
    GetCursorPos(&p);
    ScreenToClient(hwnd, &p);

    if (p.x <= END_POINT && p.x >= START_POINT && p.y <= END_POINT && p.y >= START_POINT)
    {
        for (i = 0; i < 81; i++)
        {
            if ((p.x <= CELL_X(i, ctx) + START_POINT &&
                 p.y <= CELL_Y(i, ctx) + START_POINT) &&
                (p.x >= CELL_X(i, ctx) &&
                 p.y >= CELL_Y(i, ctx)))
            {
                if (ctx->userGrid[CELL_I(i, ctx)][CELL_J(i, ctx)] == 0)
                {
                    ctx->isEmptyCellClicked = 1;
                    return 1;
                }
                return 2;
            }
        }
    }
    ctx->isEmptyCellClicked = 0;
    return 0;
}

int fillEmptyCell(Sudoku *ctx, HWND hwnd)
{
    isPointerNull(ctx);

    HBRUSH hBrush2 = CreateSolidBrush(RGB(176, 209, 232));
    ctx->prevIndex = i;
    HDC hdc = GetDC(hwnd);

    if (checkEmptyBoxClick(hwnd, ctx) == 1)
    {
        RECT rect = {.left = CELL_X(i, ctx) + 1, .top = CELL_Y(i, ctx) + 1, .right = CELL_X(i, ctx) + START_POINT, .bottom = CELL_Y(i, ctx) + START_POINT};
        FillRect(hdc, &rect, hBrush2);
        ctx->isEmptyCellClicked = 1;
        ReleaseDC(hwnd, hdc);
        DeleteObject(hBrush2);
        return 0;
    }

    if (checkEmptyBoxClick(hwnd, ctx) == 2)
    {
        for (int j = 0; j < 81; j++)
        {
            if (ctx->userGrid[CELL_I(j, ctx)][CELL_J(j, ctx)] == 0)
            {
                continue;
            }
            if (ctx->sudokuGrid[CELL_I(j, ctx)][CELL_J(j, ctx)] == ctx->sudokuGrid[CELL_I(i, ctx)][CELL_J(i, ctx)])
            {
                RECT rect1 = {.left = CELL_X(j, ctx) + 1, .top = CELL_Y(j, ctx) + 1, .right = CELL_X(j, ctx) + START_POINT, .bottom = CELL_Y(j, ctx) + START_POINT};
                FillRect(hdc, &rect1, hBrush2);
            }
        }
        drawSudokuGrid(hdc, ctx);
    }

    ctx->isEmptyCellClicked = 0;
    DeleteObject(hBrush2);

    return 0;
}

void displayUserStats(HDC hdc, Sudoku *ctx)
{
    isPointerNull(ctx);

    HFONT font = CreateFont(START_POINT / 2, 0, 0, 0, FW_SEMIBOLD, 0, 0, 0, 0, 0, 0, 0, 0, MAIN_FONT);
    SelectObject(hdc, font);
    char scoreMsg[20], mistakeMsg[20];
    sprintf(scoreMsg, "Score : %d", ctx->score);
    sprintf(mistakeMsg, "Mistakes: %d", ctx->mistakes);
    SetTextColor(hdc, OFF_WHITE);
    TextOut(hdc, END_POINT + START_POINT, END_POINT / 4, scoreMsg, strlen(scoreMsg));
    TextOut(hdc, END_POINT + END_POINT / 2, END_POINT / 4, mistakeMsg, strlen(mistakeMsg));
    DeleteObject(font);
}

void colorLevelButtons(int buttonID, LPDRAWITEMSTRUCT draw)
{
    FillRect(draw->hDC, &draw->rcItem, CreateSolidBrush(DARK_BLUE));
    SetBkMode(draw->hDC, TRANSPARENT);
    SetTextColor(draw->hDC, WHITE);
    HFONT font = CreateFont(START_POINT - 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MAIN_FONT);
    SelectObject(draw->hDC, font);
    char *levels[3] = LEVELS;
    int level[3] = LEVEL_IDS;
    for (int i = 0; i < 3; i++)
    {
        if (buttonID == level[i])
        {
            DrawText(draw->hDC, levels[i], -1, &draw->rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
            break;
        }
    }
}

void drawImage(HDC hdc, char *imagePath, int x, int y, int width, int height)
{

    HBITMAP hbitmap = (HBITMAP)LoadImage(
        NULL,
        imagePath,
        IMAGE_BITMAP,
        0,
        0,
        LR_LOADFROMFILE);

    if (hbitmap == NULL)
    {
        OutputDebugString("FILE NOT FOUND");
        return;
    }
    BITMAP bmp;
    GetObject(hbitmap, sizeof(bmp), &bmp);
    HDC newHDC = CreateCompatibleDC(hdc);

    HBITMAP oldbmp = SelectObject(newHDC, (HBITMAP)hbitmap);
    StretchBlt(hdc, x, y, width, height, newHDC, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
    SelectObject(newHDC, oldbmp);
    DeleteDC(newHDC);
    DeleteObject(&bmp);
}

int DeleteLevelButtons(HWND hwnd)
{
    int id[3] = LEVEL_IDS;
    for (int i = 0; i < 3; i++)
    {
        DestroyWindow(GetDlgItem(hwnd, id[i]));
    }
    InvalidateRect(hwnd, NULL, TRUE);
    return 0;
}

int createLevelButtons(Sudoku *ctx, HWND hwnd)
{
    isPointerNull(ctx);

    int step = 5;
    int id[] = LEVEL_IDS;
    for (int i = 0; i < 3; i++)
    {
        CreateWindow("BUTTON", "", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_OWNERDRAW, ctx->centerY + START_POINT * 2, START_POINT * step, START_POINT * 5, START_POINT, hwnd, (HMENU)(INT_PTR)id[i], 0, NULL);
        step = step + 2;
    }
    return 0;
}

void colorNumberButtons(LPDRAWITEMSTRUCT draw, int buttonID)
{
    char s[2];
    sprintf(s, "%d", buttonID);
    FillRect(draw->hDC, &draw->rcItem, CreateSolidBrush(LIGHT_BLUE));
    SetTextColor(draw->hDC, BLUE);
    SetBkColor(draw->hDC, LIGHT_BLUE);
    DrawText(draw->hDC, s, -1, &draw->rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}

void createHintButton(HWND hwnd)
{
    CreateWindowEx(0, "button", "Hint", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_OWNERDRAW, END_POINT + END_POINT / 3, START_POINT * 2,
                   START_POINT, START_POINT, hwnd, (HMENU)(INT_PTR)HINT_ID, 0, 0);
}

void createStartScreen(HDC hdc, Sudoku *ctx)
{

    HFONT font = CreateFont(START_POINT - 10, 0, 0, 0, FW_MEDIUM, 0, 0, 0, 0, 0, 0, 0, 0, MAIN_FONT);
    SelectObject(hdc, font);
    SetTextAlign(hdc, TA_CENTER | TA_RIGHT);
    TextOut(hdc, ctx->centerX - SUDOKU_DIMENSIONS * 2, ctx->centerY - START_POINT * 2, "Sudoku", strlen("Sudoku"));
    drawImage(hdc, SUDOKU_BMP_PATH, ctx->centerX - START_POINT * 1.75, START_POINT / 4, START_POINT * 3, START_POINT * 3);
}

void HandleKeyBoardInput(WPARAM wparm, Sudoku *ctx, HWND hwnd)
{
    isPointerNull(ctx);

    int press = (int)wparm - '0';
    if (press >= 1 && press <= 9)
    {
        if (ctx->isEmptyCellClicked)
        {
            checkUserInput(hwnd, press, ctx);
        }
    }
}

void isPointerNull(void *ptr)
{
    if (ptr == NULL)
    {
        MessageBox(0, "Data passed is Null, Kindly check", "message", MB_OK | MB_ICONERROR);
        PostQuitMessage(0);
    }
}

Code:
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include "../include/sudoku_gui.h"
#include "../include/sudoku_game.h"
LRESULT CALLBACK cb(HWND hwnd, UINT msg, WPARAM wparm, LPARAM lparm)
{
    Sudoku *ctx = (Sudoku *)GetWindowLongPtr(hwnd, GWLP_USERDATA);

    int number_id[] = NUMBER_BUTTONS_ID;
    int level_id[] = LEVEL_IDS;
    switch (msg)
    {
    case WM_CLOSE:
    {
        PostQuitMessage(0);
        return 0;
    }
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        if (ctx->isStart)
        {
            createStartScreen(hdc, ctx);
            break;
        }
        drawSudokuGrid(hdc, ctx);
        displayUserStats(hdc, ctx);
        EndPaint(hwnd, &ps);
        break;
    }

    case WM_CREATE:
    {
        CREATESTRUCT *cs = (CREATESTRUCT *)lparm;
        ctx = (Sudoku *)cs->lpCreateParams;
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)ctx);
        HICON hicon;
        hicon = (HICON)LoadImage(NULL, SUDOKU_ICON_PATH, IMAGE_ICON, 500, 500, LR_LOADFROMFILE);
        SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
        if (ctx->isStart)
        {
            RECT rect;
            GetClientRect(hwnd, &rect);
            ctx->centerX = (rect.left + rect.right) / 2;
            ctx->centerY = (rect.bottom + rect.top) / 2;
            createLevelButtons(ctx, hwnd);
        }
        break;
    }
    case WM_DRAWITEM:
    {
        LPDRAWITEMSTRUCT draw = (LPDRAWITEMSTRUCT)lparm;
        int buttonID = LOWORD(wparm);
        if (buttonID == HINT_ID)
        {
            drawImage(draw->hDC, HINT_BMP_PATH, 0, 0, START_POINT, START_POINT);
        }
        else if (buttonID >= number_id[0] && buttonID <= number_id[SUDOKU_DIMENSIONS - 1])
        {
            colorNumberButtons(draw, buttonID);
        }
        else if (buttonID >= level_id[0] && buttonID <= level_id[LEVEL_COUNT - 1])
        {
            colorLevelButtons(buttonID, draw);
        }
        break;
    }

    case WM_COMMAND:
    {
        int buttonID = LOWORD(wparm);
        if (ctx->isStart == 1 && buttonID >= level_id[0] && buttonID <= level_id[LEVEL_COUNT - 1])
        {
            DeleteLevelButtons(hwnd);
            ctx->isStart = 0;
            fillWithZero(ctx->userGrid, ctx->sudokuGrid, (buttonID - (level_id[0] - 1)) * 2);
            copyMatrix(ctx->unsolvedGrid, ctx->userGrid);
            createNumberButtons(hwnd);
            createHintButton(hwnd);
            break;
        }
        if (buttonID >= number_id[0] && buttonID <= number_id[SUDOKU_DIMENSIONS - 1] && ctx->isEmptyCellClicked)
        {
            checkUserInput(hwnd, buttonID, ctx);
        }
        if (buttonID == HINT_ID && ctx->isEmptyCellClicked)
        {
            if (ctx->hintUsed != MAX_HINT)
            {
                checkUserInput(hwnd, ctx->sudokuGrid[ctx->boardInfo[i][I]][ctx->boardInfo[i][J]], ctx);
                ctx->hintUsed++;
            }
            else
            {
                MessageBox(hwnd, "Max Limit of Hint Used(3)", "Message", MB_OK | MB_ICONQUESTION);
            }
        }
        SetFocus(hwnd);
        break;
    }

    case WM_LBUTTONDOWN:
    {
        int check = checkEmptyBoxClick(hwnd, ctx);
        if (check != 0)
        {
            if (i == ctx->prevIndex)
            {
                break;
            }
            for (int j = 0; j < 81; j++)
            {
                if (ctx->sudokuGrid[CELL_I(j, ctx)][CELL_J(j, ctx)] == ctx->sudokuGrid[CELL_I(ctx->prevIndex, ctx)][CELL_J(ctx->prevIndex, ctx)])
                {
                    RECT rect = {.left = CELL_X(j, ctx) + 1, .top = CELL_Y(j, ctx) + 1, .right = CELL_X(j, ctx) + START_POINT, .bottom = CELL_Y(j, ctx) + START_POINT};
                    HRGN rgn = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
                    InvalidateRgn(hwnd, rgn, TRUE);
                    UpdateWindow(hwnd);
                }
            }
        }

        fillEmptyCell(ctx, hwnd);
        break;
    }

    case WM_KEYDOWN:
    {
        if (ctx->isStart == 0)
        {
            HandleKeyBoardInput(wparm, ctx, hwnd);
        }
        break;
    }
    default:
        return DefWindowProc(hwnd, msg, wparm, lparm);
    }
    return 0;
}

int main()
{
    srand((unsigned int)time(NULL));
    Sudoku ctx = {};
    ctx.isStart = 1;
    generateValidSudoku(ctx.sudokuGrid, 0, 0);
    solveSudoku(ctx.sudokuGrid, 0, 0);

    HINSTANCE hInstance = GetModuleHandle(0);
    WNDCLASS class = {};

    char classTitle[] = "my class";
    class.lpszClassName = classTitle;
    class.lpfnWndProc = cb;
    class.hInstance = hInstance;
    class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    class.hCursor = LoadCursor(NULL, IDC_ARROW);
    int width = GetSystemMetrics(SM_CXSCREEN);
    float cal = ((float)100 / DEFAULT_WIDTH) * width;
    START_POINT = (int)cal;
    RegisterClass(&class);
    HWND hwnd = CreateWindowEx(0, classTitle, "Sudoku",
                               WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 0, 0, 1000, 1000, NULL,
                               NULL, hInstance, &ctx);
    if (hwnd == NULL)
    {
        MessageBox(NULL, "Something Went worng", "Error", MB_OK);
        return 0;
    }
    ShowWindow(hwnd, SHOW_FULLSCREEN);
    MSG msg;
    RECT rect;
    GetClientRect(hwnd, &rect);
    ctx.centerX = (rect.left + rect.right) / 2;
    ctx.centerY = (rect.bottom + rect.top) / 2;
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {

        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}
config.c
Code:
 // config define
#define SUDOKU_DIMENSIONS 9
#define LINES_TO_DRAW 10
#define END_POINT (LINES_TO_DRAW * START_POINT)
#define DEFAULT_WIDTH 1920
#define DEFAULT_HEIGHT 1200
#define LEVEL_IDS {10, 11, 12}
#define NUMBER_BUTTONS_ID {1, 2, 3, 4, 5, 6, 7, 8, 9}
#define HINT_ID 40
#define BLACK RGB(0, 0, 0)
#define BLUE RGB(0, 102, 190)
#define MAIN_FONT "Segoe UI"
#define MAX_INCREMENT_SCORE 70
#define LEVEL_COUNT 3
#define LEVELS {"Easy", "Medium", "Hard"}
#define WHITE RGB(255, 255, 255)
#define DARK_BLUE RGB(71, 112, 202)
#define OFF_WHITE RGB(197, 203, 209)
#define LIGHT_BLUE RGB(234, 238, 244)
#define MAX_MISTAKES 5
#define MAX_HINT 3
#define SUDOKU_ICON_PATH "images/icon.ico"
#define SUDOKU_BMP_PATH "images/icon.bmp"
#define HINT_BMP_PATH "images/hint.bmp"
 
Looks okay. I won't tear you a new one, but it does seem a bit long (that's Windows for ya).

There are other things you can do with sudoku.

In my version I didn't use all the 9 numbers, my grid was a 5 by 5 square made up of a random tiling of 5 pentominoes.

Initially blank, the hint feature would reveal 1 number, and the objective was to solve the grid using the fewest hints.

Personally I find sudoku a chore, but the 5 by 5 grid hit the spot when I wanted a distraction.

To be honest, writing the program to search all pentomino tilings was more interesting than playing it.
 

Latest posts

Buy us a coffee!

Buy me a coffee.
Back
Top Bottom