feat: add initial project scaffolding with Makefile, C sources, web UI, and documentation
Add Makefile with build targets for sudoku solver, generator, and coverage reporting. Include NOTES.md explaining sudoku difficulty factors and solving techniques. Add README.md with puzzle examples and generator output. Implement app.js with Grid and Grid2 classes for rendering puzzle data in the browser. Add box.c with functions for box indexing, grid-to-array conversion, and box value extraction. Include footer.h with terminal size detection, cursor positioning, and footer display utilities. Add index.html with CSS grid layout and script loading for the web interface. Include rlib.h as a large utility header library.
This commit is contained in:
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"sudoku.h": "c"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
all: build run
|
||||
|
||||
build:
|
||||
gcc sudoku3.c -o sudoku3 -Ofast -Werror -Wall -Wextra
|
||||
|
||||
run:
|
||||
./sudoku3
|
||||
Executable
BIN
Binary file not shown.
+8450
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
#ifndef SUDOKU_H
|
||||
#define SUDOKU_H
|
||||
typedef struct field_t {
|
||||
unsigned int value;
|
||||
unsigned int selected;
|
||||
unsigned int initial;
|
||||
unsigned int column;
|
||||
unsigned int row;
|
||||
unsigned int index;
|
||||
unsigned char box;
|
||||
} field_t;
|
||||
|
||||
field_t * new_field(){
|
||||
field_t * field = (field_t *)calloc(1,sizeof(field_t));
|
||||
return field;
|
||||
}
|
||||
|
||||
typedef struct row_t {
|
||||
unsigned int index;
|
||||
field_t * columns;
|
||||
unsigned int column_count;
|
||||
} row_t;
|
||||
|
||||
row_t * new_row(unsigned int size) {
|
||||
row_t * row = (row_t *)calloc(1, sizeof(row));
|
||||
row->columns = calloc(size,sizeof(field_t));
|
||||
row->index = 0;
|
||||
return row;
|
||||
}
|
||||
|
||||
typedef struct grid_t {
|
||||
unsigned int size;
|
||||
unsigned int row_count;
|
||||
unsigned int field_count;
|
||||
row_t * rows;
|
||||
field_t * fields;
|
||||
field_t * (*get)(struct grid_t * grid, unsigned int row, unsigned int col);
|
||||
field_t * (*get_empty_field)(struct grid_t * grid);
|
||||
} grid_t;
|
||||
|
||||
field_t * grid_get(grid_t * grid, unsigned int row, unsigned int col){
|
||||
return &grid->rows[row].columns[col];
|
||||
}
|
||||
field_t * grid_get_empty_field(grid_t * grid){
|
||||
for(int i = 0; i < grid->size * grid->size; i++){
|
||||
printf("AT:%d\n",i);
|
||||
printf("V:%d\n",grid->fields[i].value);
|
||||
printf("V2:%d\n",grid->rows[i].columns[i].value);
|
||||
printf("V2:%d\n",grid->get(grid,i,i)->value);
|
||||
if(grid->fields[i].value == 0)
|
||||
return &grid->fields[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char get_box_letter(grid_t * grid, unsigned int row, unsigned int col){
|
||||
//char box_letter = 65 + (row)*grid->size / grid->size / 3 + row; // (row*grid->size+col)+(grid->size / 3);// + grid->size % (grid->size / 3));
|
||||
char box_letter = 65 + ((row % (grid->size / 3))) + grid->size % (grid->size / 3);// (row-1)*grid->size+(col-1)+(row-1)+(col-1);
|
||||
//(65 + row * (grid->size / 3) % (grid->size / 3)+col); /// (grid->size / 3));
|
||||
return box_letter;
|
||||
}
|
||||
|
||||
|
||||
grid_t * new_grid(unsigned int size){
|
||||
grid_t * grid = (grid_t *)calloc(1,sizeof(grid_t));
|
||||
grid->get = grid_get;
|
||||
grid->get_empty_field = grid_get_empty_field;
|
||||
grid->size = size;
|
||||
grid->row_count = 0;
|
||||
grid->rows = (row_t *)calloc(size, sizeof(row_t));
|
||||
grid->fields = (field_t *)calloc(size*size, sizeof(field_t));
|
||||
for(unsigned int irow = 0; irow < size; irow++){
|
||||
row_t * row = new_row(size);
|
||||
row->index = grid->row_count;
|
||||
row->column_count = size;
|
||||
grid->row_count++;
|
||||
grid->rows[row->index] = *row;
|
||||
for(unsigned int icol = 0; icol < size; icol++){
|
||||
unsigned int field_index = irow * size + icol;
|
||||
field_t * field = new_field();
|
||||
field->column = icol;
|
||||
field->row = irow;
|
||||
field->index = field_index;
|
||||
field->box = get_box_letter(grid, irow, icol);
|
||||
row->columns[icol] = *field;
|
||||
grid->fields[field_index] = *field;
|
||||
grid->field_count++;
|
||||
}
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef SUDOKU_H
|
||||
#define SUDOKU_H
|
||||
#include "sudoku_header.h"
|
||||
#include "sudoku_format.h"
|
||||
#include "sudoku_generate.h"
|
||||
#endif
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,31 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sudoku.h"
|
||||
|
||||
int main(){
|
||||
|
||||
grid_t * grid = new_grid(48);
|
||||
printf("%d \n",grid->rows[3].index);
|
||||
printf("%d \n",grid->fields[30].index);
|
||||
printf("%d \n",grid->rows[6].columns[6].index);
|
||||
field_t * f = grid->get(grid, 0,3);
|
||||
printf("%d \n", f->index);
|
||||
//for(int i = 0; i < grid->size*grid->size;i++){
|
||||
// printf("%c",grid->fields[i].box);
|
||||
// }
|
||||
grid->get(grid,5,5)->value = 3;
|
||||
grid->get(grid,0,0)->value = 1;
|
||||
grid->fields[0].value = 4;
|
||||
printf("**%d**\n",grid->get(grid,5,5)->index);
|
||||
printf("^^%d^^\n",grid->get(grid,0,0)->index);
|
||||
printf("!!%d!!\n", grid->get_empty_field(grid)->index);
|
||||
printf("Computer format:\n%s\n",grid_to_string(grid,row_to_string,field_to_string));
|
||||
printf("Human format:\n%s\n",grid_to_string_human(grid));
|
||||
printf("C format:\n%s\n",grid_to_string_c(grid));
|
||||
grid = generate_sudoku(48);
|
||||
printf("C format:\n%s\n",grid_to_string_c(grid));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef SUDOKU_ALGORITHM_H
|
||||
#define SUDOKU_ALGORITHM_H
|
||||
#include "sudoku.h"
|
||||
#include "rlib.h"
|
||||
#include <stdint.h>
|
||||
#define uin unsigned int
|
||||
unsigned int rand_int(int min, int max){
|
||||
return rand() % (max - min + 1) + min;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
double count_neighbors(grid_t * grid, uint row, uint col) {
|
||||
double count = 0.0;
|
||||
for(uint i = 0; i < row; i++){
|
||||
for(uint j = 0; j < grid->size; j++){
|
||||
if(grid->get(grid,row,j)->value != 0 && j != col)
|
||||
count += 1; //grid[row][j].initial ? 1.1 : 1.0;
|
||||
}
|
||||
for(uint j = 0; j < grid->size; j++){
|
||||
if(grid->get(grid,j,col)->value!= 0 && j != row)
|
||||
count += 1; //grid[j][col].initial ? 1.1 : 1.0;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
#ifndef SUDOKU_FORMAT_H
|
||||
#define SUDOKU_FORMAT_H
|
||||
#include "sudoku_header.h"
|
||||
#include <string.h>
|
||||
#include "rlib.h"
|
||||
#define SUDOKU_FORMAT_BUFFER_SIZE 90000
|
||||
|
||||
char * field_to_string_human(field_t * field){
|
||||
static char result[SUDOKU_FORMAT_BUFFER_SIZE] = {0};
|
||||
result[0] = 0;
|
||||
sprintf(result,"%d ",field->value);
|
||||
return sbuf(result);
|
||||
}
|
||||
|
||||
char * field_to_string_comma(field_t * field){
|
||||
static char result[SUDOKU_FORMAT_BUFFER_SIZE] = {0};
|
||||
result[0] = 0;
|
||||
sprintf(result,"%d, ",field->value);
|
||||
return sbuf(result);
|
||||
}
|
||||
|
||||
char * field_to_string(field_t * field){
|
||||
static char result[SUDOKU_FORMAT_BUFFER_SIZE] = {0};
|
||||
result[0] = 0;
|
||||
sprintf(result,"%d",field->value);
|
||||
return sbuf(result);
|
||||
}
|
||||
char * row_to_string(row_t * row,char * field_string_fn(field_t * field)){
|
||||
static char result[SUDOKU_FORMAT_BUFFER_SIZE] = {0};
|
||||
result[0] = 0;
|
||||
for(uint i = 0; i < row->column_count; i++){
|
||||
strcat(result, field_string_fn(&row->columns[i]));
|
||||
}
|
||||
return sbuf(result);
|
||||
}
|
||||
char * row_to_string_human(row_t * row,char * field_string_fn(field_t * field)){
|
||||
static char result[SUDOKU_FORMAT_BUFFER_SIZE] = {0};
|
||||
result[0] = 0;
|
||||
for(uint i = 0; i < row->column_count; i++){
|
||||
strcat(result, field_string_fn(&row->columns[i]));
|
||||
}
|
||||
result[strlen(result)-2] = 0;
|
||||
strcat(result, "\n");
|
||||
return sbuf(result);
|
||||
}
|
||||
char * row_to_string_c(row_t * row){
|
||||
static char result[SUDOKU_FORMAT_BUFFER_SIZE] = {0};
|
||||
result[0] = 0;
|
||||
strcat(result,"{");
|
||||
for(uint i = 0; i < row->column_count; i++){
|
||||
strcat(result, field_to_string_comma(&row->columns[i]));
|
||||
}
|
||||
result[strlen(result)-2] = 0;
|
||||
strcat(result,"},\n");
|
||||
return sbuf(result);
|
||||
}
|
||||
|
||||
char * grid_to_string(grid_t * grid, char * row_to_string_fn(row_t * row,char * (field_t *)), char * field_string_fn(field_t * field)){
|
||||
static char result[SUDOKU_FORMAT_BUFFER_SIZE] = {0};
|
||||
result[0] = 0;
|
||||
for(uint irow = 0; irow < grid->size; irow++){
|
||||
row_t row = grid->rows[irow];
|
||||
row.column_count++;
|
||||
strcat(result,row_to_string_fn(&row,field_string_fn));
|
||||
}
|
||||
result[strlen(result)-1] = 0;
|
||||
return sbuf(result);
|
||||
}
|
||||
char * grid_to_string_c(grid_t * grid){
|
||||
char result[SUDOKU_FORMAT_BUFFER_SIZE] = {0};
|
||||
result[0] = 0;
|
||||
strcat(result,"{\n");
|
||||
for(uint i = 0; i < grid->size; i++){
|
||||
strcat(result," ");
|
||||
strcat(result,row_to_string_c(&grid->rows[i]));
|
||||
|
||||
}
|
||||
result[strlen(result)-2] = 0;
|
||||
strcat(result,"\n}");
|
||||
return sbuf(result);
|
||||
}
|
||||
char * grid_to_string_human(grid_t * grid){
|
||||
return grid_to_string(grid, row_to_string_human, field_to_string_human);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef SUDOKU_GENERATE_H
|
||||
#define SUDOKU_GENERATE_H
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include "sudoku_header.h"
|
||||
#include "sudoku_algorithm.h"
|
||||
|
||||
|
||||
field_t * grid_get_random_empty_field(grid_t * grid){
|
||||
while(true){
|
||||
unsigned int row = rand_int(0,grid->size-1);
|
||||
unsigned int col = rand_int(0,grid->size-1);
|
||||
field_t * found = grid_get(grid,row,col);
|
||||
if(found->value == 0)
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
void grid_set_random_field(grid_t * grid){
|
||||
field_t * field = grid_get_random_empty_field(grid);
|
||||
field->value = rand_int(1,grid->size);
|
||||
field->initial = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
grid_t * generate_sudoku(unsigned int size){
|
||||
srand(time(NULL));
|
||||
grid_t * grid = new_grid(size);
|
||||
|
||||
for(unsigned int i = 0; i < rand_int(17,20); i++){
|
||||
grid_set_random_field(grid);
|
||||
}
|
||||
return grid;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
#ifndef SUDOKU_HEADER_H
|
||||
#define SUDOKU_HEADER_H
|
||||
#include "rlib.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
typedef struct field_t {
|
||||
unsigned int value;
|
||||
unsigned int selected;
|
||||
unsigned int initial;
|
||||
unsigned int column;
|
||||
unsigned int row;
|
||||
unsigned int index;
|
||||
unsigned char box;
|
||||
} field_t;
|
||||
|
||||
field_t * new_field(){
|
||||
field_t * field = (field_t *)calloc(1,sizeof(field_t));
|
||||
return field;
|
||||
}
|
||||
|
||||
typedef struct row_t {
|
||||
unsigned int index;
|
||||
field_t * columns;
|
||||
unsigned int column_count;
|
||||
} row_t;
|
||||
|
||||
row_t * new_row(unsigned int size) {
|
||||
row_t * row = (row_t *)calloc(sizeof(row_t),1);
|
||||
row->columns = calloc(size,sizeof(field_t));
|
||||
row->index = 0;
|
||||
return row;
|
||||
}
|
||||
|
||||
typedef struct grid_t {
|
||||
unsigned int size;
|
||||
unsigned int row_count;
|
||||
unsigned int field_count;
|
||||
row_t * rows;
|
||||
field_t * fields;
|
||||
field_t * (*get)(struct grid_t * grid, unsigned int row, unsigned int col);
|
||||
field_t * (*get_empty_field)(struct grid_t * grid);
|
||||
} grid_t;
|
||||
|
||||
field_t * grid_get(grid_t * grid, unsigned int row, unsigned int col){
|
||||
return &grid->rows[row].columns[col];
|
||||
}
|
||||
field_t * grid_get_empty_field(grid_t * grid){
|
||||
for(uint i = 0; i < grid->size * grid->size; i++){
|
||||
if(grid->fields[i].value == 0)
|
||||
return &grid->fields[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
char get_box_letter(grid_t * grid, unsigned int row, unsigned int col){
|
||||
//char box_letter = 65 + (row)*grid->size / grid->size / 3 + row; // (row*grid->size+col)+(grid->size / 3);// + grid->size % (grid->size / 3));
|
||||
char box_letter = 65 + ((row % (grid->size / 3))) + grid->size % (grid->size / 3);// (row-1)*grid->size+(col-1)+(row-1)+(col-1);
|
||||
//(65 + row * (grid->size / 3) % (grid->size / 3)+col); /// (grid->size / 3));
|
||||
return box_letter;
|
||||
}*/
|
||||
|
||||
|
||||
grid_t * new_grid(unsigned int size){
|
||||
grid_t * grid = (grid_t *)calloc(1,sizeof(grid_t));
|
||||
grid->get = grid_get;
|
||||
grid->get_empty_field = grid_get_empty_field;
|
||||
grid->size = size;
|
||||
grid->row_count = 0;
|
||||
grid->rows = (row_t *)calloc(size, sizeof(row_t));
|
||||
grid->fields = (field_t *)calloc(size*size, sizeof(field_t));
|
||||
unsigned int field_index = 0;
|
||||
for(unsigned int irow = 0; irow < size; irow++){
|
||||
row_t * row = new_row(size);
|
||||
row->index = grid->row_count;
|
||||
row->column_count = size;
|
||||
grid->row_count++;
|
||||
grid->rows[row->index] = *row;
|
||||
for(unsigned int icol = 0; icol < size; icol++){
|
||||
field_t * field = new_field();
|
||||
field->column = icol;
|
||||
field->row = irow;
|
||||
field->index = field_index;
|
||||
//field->box = get_box_letter(grid, irow, icol);
|
||||
row->columns[icol] = *field;
|
||||
grid->fields[field_index] = *field;
|
||||
grid->field_count++;
|
||||
field_index++;
|
||||
}
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "rlib.h"
|
||||
#include "sudoku.h"
|
||||
|
||||
#include <pthread.h>
|
||||
char * xx = "aa";
|
||||
|
||||
void * thread_worker(){
|
||||
tick();
|
||||
|
||||
|
||||
for(uint i = 0; i< 1000; i++){
|
||||
|
||||
grid_t * grid = new_grid(18);
|
||||
grid_to_string_c(grid);
|
||||
// printf("%d\n",i);
|
||||
sbuf(xx);
|
||||
//strcpy(xx,"AAA");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bench_rtemp_c(){
|
||||
grid_t * grid = new_grid(18);
|
||||
char * to_copy = sbuf(grid_to_string_c(grid));
|
||||
|
||||
uint times_bench = 10;
|
||||
uint times_function = 10000000;
|
||||
printf("Benchmark %d*%d with/without thread lock.\n",times_bench,times_function);
|
||||
RBENCH(times_bench,{
|
||||
printf("with: ");
|
||||
RBENCH(times_function,{
|
||||
sbuf(sbuf(sbuf(to_copy)));
|
||||
});
|
||||
|
||||
rtempc_use_mutex = false;
|
||||
printf("witout: ");
|
||||
RBENCH(10000000,{
|
||||
sbuf(sbuf(sbuf(to_copy)));
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
int main(){
|
||||
//rtempc_use_mutex = false;
|
||||
bench_rtemp_c();
|
||||
rtempc_use_mutex = true;
|
||||
uint worker_count = 4;
|
||||
pthread_t workers[worker_count];
|
||||
printf("Threading: \n");
|
||||
RBENCH(1,{
|
||||
for(uint i = 0; i < worker_count; i++){
|
||||
pthread_create(&workers[i],0,thread_worker,NULL);
|
||||
}
|
||||
for(uint i = 0; i < worker_count; i++){
|
||||
pthread_join(workers[i],NULL);
|
||||
}
|
||||
});
|
||||
printf("Without threading: \n");
|
||||
RBENCH(1,{
|
||||
for(uint i = 0; i < worker_count; i++){
|
||||
thread_worker();
|
||||
}
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user