Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
ee49b1f637 |
6
Makefile
6
Makefile
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
.POSIX:
|
.POSIX:
|
||||||
|
|
||||||
CFLAGS += -std=c89 -pedantic -Wall -Wextra
|
CFLAGS += -std=c11 -pedantic -Wall -Wextra
|
||||||
CFLAGS += -O3 -flto
|
CFLAGS += -O3 -flto
|
||||||
CFLAGS += -D_XOPEN_SOURCE=700
|
CFLAGS += -D_XOPEN_SOURCE=700
|
||||||
CFLAGS += -march=native
|
CFLAGS += -march=native
|
||||||
@ -32,13 +32,15 @@ default: sudoku eval
|
|||||||
sudoku: $(OBJ)
|
sudoku: $(OBJ)
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $@
|
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $@
|
||||||
|
|
||||||
|
eval: eval.c ds.h
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) eval.c -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f sudoku eval genlut *.o lut.c
|
rm -f sudoku eval genlut *.o lut.c
|
||||||
|
|
||||||
lut.c: genlut
|
lut.c: genlut
|
||||||
./genlut > $@
|
./genlut > $@
|
||||||
|
|
||||||
eval.o: ds.h
|
|
||||||
main.o: sud.h solve.h ds.h
|
main.o: sud.h solve.h ds.h
|
||||||
sud.o: sud.h lut.h
|
sud.o: sud.h lut.h
|
||||||
solve.o: solve.h lut.h
|
solve.o: solve.h lut.h
|
||||||
|
22
eval.c
22
eval.c
@ -28,25 +28,21 @@
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
FILE *rfp, *sfp;
|
FILE *rfp = fopen(RESNAME, "rb");
|
||||||
unsigned solved = 0, errors = 0, i, j;
|
|
||||||
char res[NCELLS], sol[NCELLS];
|
|
||||||
int allcells;
|
|
||||||
double pc;
|
|
||||||
|
|
||||||
rfp = fopen(RESNAME, "rb");
|
|
||||||
if (!rfp) {
|
if (!rfp) {
|
||||||
fputs("Failed to open results file\n", stderr);
|
fputs("Failed to open results file\n", stderr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
sfp = fopen(SOLNAME, "rb");
|
FILE *sfp = fopen(SOLNAME, "rb");
|
||||||
if (!sfp) {
|
if (!sfp) {
|
||||||
fputs("Failed to open solutions file\n", stderr);
|
fputs("Failed to open solutions file\n", stderr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NPUZZ; ++i) {
|
unsigned solved = 0, errors = 0;
|
||||||
|
char res[NCELLS], sol[NCELLS];
|
||||||
|
for (unsigned i = 0; i < NPUZZ; ++i) {
|
||||||
if (fread(&res, sizeof(char), NCELLS, rfp) != NCELLS) {
|
if (fread(&res, sizeof(char), NCELLS, rfp) != NCELLS) {
|
||||||
fprintf(stderr, "Failed to read result #%u\n", i);
|
fprintf(stderr, "Failed to read result #%u\n", i);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -56,10 +52,10 @@ int main(void)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
allcells = 1;
|
bool allcells = true;
|
||||||
for (j = 0; j < NCELLS; ++j) {
|
for (unsigned j = 0; j < NCELLS; ++j) {
|
||||||
if (res[j] != sol[j]) {
|
if (res[j] != sol[j]) {
|
||||||
allcells = 0;
|
allcells = false;
|
||||||
if (res[j] != '0')
|
if (res[j] != '0')
|
||||||
++errors;
|
++errors;
|
||||||
}
|
}
|
||||||
@ -68,7 +64,7 @@ int main(void)
|
|||||||
++solved;
|
++solved;
|
||||||
}
|
}
|
||||||
|
|
||||||
pc = 1e2 * (double)solved / (double)NPUZZ;
|
double pc = 1e2 * (double)solved / (double)NPUZZ;
|
||||||
printf("%u/%u (%.2f%%) solved, %u errors\n", solved, NPUZZ, pc, errors);
|
printf("%u/%u (%.2f%%) solved, %u errors\n", solved, NPUZZ, pc, errors);
|
||||||
|
|
||||||
fclose(rfp);
|
fclose(rfp);
|
||||||
|
23
genlut.c
23
genlut.c
@ -25,11 +25,10 @@
|
|||||||
|
|
||||||
static void prlut(const char *name, unsigned lut[NCELLS][NDIGITS - 1])
|
static void prlut(const char *name, unsigned lut[NCELLS][NDIGITS - 1])
|
||||||
{
|
{
|
||||||
unsigned i, j;
|
|
||||||
printf("const unsigned %s[NCELLS][NDIGITS - 1] = {\n", name);
|
printf("const unsigned %s[NCELLS][NDIGITS - 1] = {\n", name);
|
||||||
for (i = 0; i < NCELLS; ++i) {
|
for (unsigned i = 0; i < NCELLS; ++i) {
|
||||||
fputs("\t{ ", stdout);
|
printf("\t[%2u] = { ", i);
|
||||||
for (j = 0; j < NDIGITS - 1; ++j) {
|
for (unsigned j = 0; j < NDIGITS - 1; ++j) {
|
||||||
printf("%2u", lut[i][j]);
|
printf("%2u", lut[i][j]);
|
||||||
if (j != NDIGITS - 2)
|
if (j != NDIGITS - 2)
|
||||||
putchar(',');
|
putchar(',');
|
||||||
@ -45,14 +44,14 @@ int main(void)
|
|||||||
unsigned rowidx_lut[NCELLS][NDIGITS - 1];
|
unsigned rowidx_lut[NCELLS][NDIGITS - 1];
|
||||||
unsigned colidx_lut[NCELLS][NDIGITS - 1];
|
unsigned colidx_lut[NCELLS][NDIGITS - 1];
|
||||||
unsigned segidx_lut[NCELLS][NDIGITS - 1];
|
unsigned segidx_lut[NCELLS][NDIGITS - 1];
|
||||||
unsigned rowi, coli, segi, r, c, i, j, sr, sc;
|
|
||||||
|
|
||||||
/* Populate tables. */
|
/* Populate tables. */
|
||||||
for (r = 0; r < NDIGITS; ++r) {
|
unsigned rowi, coli, segi;
|
||||||
for (c = 0; c < NDIGITS; ++c) {
|
for (unsigned r = 0; r < NDIGITS; ++r) {
|
||||||
|
for (unsigned c = 0; c < NDIGITS; ++c) {
|
||||||
/* Calculate row and column indices. */
|
/* Calculate row and column indices. */
|
||||||
rowi = coli = 0;
|
rowi = coli = 0;
|
||||||
for (i = 0; i < NDIGITS; ++i) {
|
for (unsigned i = 0; i < NDIGITS; ++i) {
|
||||||
if (i != c)
|
if (i != c)
|
||||||
rowidx_lut[r * NDIGITS + c][rowi++] = r * NDIGITS + i;
|
rowidx_lut[r * NDIGITS + c][rowi++] = r * NDIGITS + i;
|
||||||
if (i != r)
|
if (i != r)
|
||||||
@ -61,10 +60,10 @@ int main(void)
|
|||||||
|
|
||||||
/* Calculate segment indices. */
|
/* Calculate segment indices. */
|
||||||
segi = 0;
|
segi = 0;
|
||||||
sr = SEGLEN * (r / SEGLEN);
|
const unsigned sr = SEGLEN * (r / SEGLEN);
|
||||||
sc = SEGLEN * (c / SEGLEN);
|
const unsigned sc = SEGLEN * (c / SEGLEN);
|
||||||
for (i = sr; i < sr + SEGLEN; ++i) {
|
for (unsigned i = sr; i < sr + SEGLEN; ++i) {
|
||||||
for (j = sc; j < sc + SEGLEN; ++j) {
|
for (unsigned j = sc; j < sc + SEGLEN; ++j) {
|
||||||
if (i == r && j == c)
|
if (i == r && j == c)
|
||||||
continue;
|
continue;
|
||||||
segidx_lut[r * NDIGITS + c][segi++] = i * NDIGITS + j;
|
segidx_lut[r * NDIGITS + c][segi++] = i * NDIGITS + j;
|
||||||
|
10
main.c
10
main.c
@ -41,12 +41,12 @@ static char *obuf;
|
|||||||
|
|
||||||
void *threadproc(void *arg)
|
void *threadproc(void *arg)
|
||||||
{
|
{
|
||||||
unsigned start = CELLPT * (uintptr_t)arg, o;
|
unsigned start = CELLPT * (uintptr_t)arg;
|
||||||
const char *libuf = ibuf + start;
|
const char *libuf = ibuf + start;
|
||||||
char *lobuf = obuf + start;
|
char *lobuf = obuf + start;
|
||||||
struct sudoku sud;
|
|
||||||
|
|
||||||
for (o = 0; o < CELLPT; o += NCELLS) {
|
struct sudoku sud;
|
||||||
|
for (unsigned o = 0; o < CELLPT; o += NCELLS) {
|
||||||
load(&sud, libuf + o);
|
load(&sud, libuf + o);
|
||||||
solve(&sud);
|
solve(&sud);
|
||||||
save(&sud, lobuf + o);
|
save(&sud, lobuf + o);
|
||||||
@ -58,8 +58,6 @@ void *threadproc(void *arg)
|
|||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
pthread_t pool[NTHREADS];
|
|
||||||
uintptr_t i;
|
|
||||||
|
|
||||||
fd = open(IFNAME, O_RDONLY);
|
fd = open(IFNAME, O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
@ -85,6 +83,8 @@ int main(void)
|
|||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
pthread_t pool[NTHREADS];
|
||||||
|
uintptr_t i;
|
||||||
for (i = 0; i < NTHREADS; ++i) {
|
for (i = 0; i < NTHREADS; ++i) {
|
||||||
if (pthread_create(&pool[i], NULL, threadproc, (void *)i) != 0)
|
if (pthread_create(&pool[i], NULL, threadproc, (void *)i) != 0)
|
||||||
fprintf(stderr, "Failed to create thread #%lu\n", i);
|
fprintf(stderr, "Failed to create thread #%lu\n", i);
|
||||||
|
15
solve.c
15
solve.c
@ -23,8 +23,7 @@
|
|||||||
|
|
||||||
static void setpval(struct sudoku *sud, unsigned i, uint16_t pval)
|
static void setpval(struct sudoku *sud, unsigned i, uint16_t pval)
|
||||||
{
|
{
|
||||||
unsigned val;
|
for (unsigned val = 0; val < NDIGITS; ++val) {
|
||||||
for (val = 0; val < NDIGITS; ++val) {
|
|
||||||
if (pval & 1) {
|
if (pval & 1) {
|
||||||
update(sud, i, val);
|
update(sud, i, val);
|
||||||
return;
|
return;
|
||||||
@ -36,11 +35,11 @@ static void setpval(struct sudoku *sud, unsigned i, uint16_t pval)
|
|||||||
int solve(struct sudoku *sud)
|
int solve(struct sudoku *sud)
|
||||||
{
|
{
|
||||||
unsigned n, i, j, val;
|
unsigned n, i, j, val;
|
||||||
int match;
|
bool match;
|
||||||
uint16_t valmask, pvals;
|
uint16_t valmask, pvals;
|
||||||
|
|
||||||
for (n = 0;; ++n) {
|
for (n = 0;; ++n) {
|
||||||
match = 0;
|
match = false;
|
||||||
|
|
||||||
for (i = 0; i < NCELLS; ++i) {
|
for (i = 0; i < NCELLS; ++i) {
|
||||||
if (DET(sud->cells[i]))
|
if (DET(sud->cells[i]))
|
||||||
@ -55,7 +54,7 @@ int solve(struct sudoku *sud)
|
|||||||
if (pvals & 1) {
|
if (pvals & 1) {
|
||||||
if (pvals == 1) {
|
if (pvals == 1) {
|
||||||
update(sud, i, val);
|
update(sud, i, val);
|
||||||
match = 1;
|
match = true;
|
||||||
goto next_cell;
|
goto next_cell;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -72,7 +71,7 @@ int solve(struct sudoku *sud)
|
|||||||
valmask |= sud->cells[rowidx_lut[i][j]];
|
valmask |= sud->cells[rowidx_lut[i][j]];
|
||||||
if ((pvals = sud->cells[i] & ~valmask)) {
|
if ((pvals = sud->cells[i] & ~valmask)) {
|
||||||
setpval(sud, i, pvals);
|
setpval(sud, i, pvals);
|
||||||
match = 1;
|
match = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +84,7 @@ int solve(struct sudoku *sud)
|
|||||||
valmask |= sud->cells[colidx_lut[i][j]];
|
valmask |= sud->cells[colidx_lut[i][j]];
|
||||||
if ((pvals = sud->cells[i] & ~valmask)) {
|
if ((pvals = sud->cells[i] & ~valmask)) {
|
||||||
setpval(sud, i, pvals);
|
setpval(sud, i, pvals);
|
||||||
match = 1;
|
match = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +97,7 @@ int solve(struct sudoku *sud)
|
|||||||
valmask |= sud->cells[segidx_lut[i][j]];
|
valmask |= sud->cells[segidx_lut[i][j]];
|
||||||
if ((pvals = sud->cells[i] & ~valmask)) {
|
if ((pvals = sud->cells[i] & ~valmask)) {
|
||||||
setpval(sud, i, pvals);
|
setpval(sud, i, pvals);
|
||||||
match = 1;
|
match = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
49
sud.c
49
sud.c
@ -16,8 +16,8 @@
|
|||||||
* <https://www.gnu.org/licenses/>.
|
* <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sud.h"
|
|
||||||
#include "lut.h"
|
#include "lut.h"
|
||||||
|
#include "sud.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -28,31 +28,28 @@
|
|||||||
|
|
||||||
static void init(struct sudoku *sud)
|
static void init(struct sudoku *sud)
|
||||||
{
|
{
|
||||||
unsigned i;
|
for (unsigned i = 0; i < NCELLS; ++i)
|
||||||
for (i = 0; i < NCELLS; ++i)
|
|
||||||
sud->cells[i] = CELLINIT;
|
sud->cells[i] = CELLINIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load(struct sudoku *sud, const char *ptr)
|
bool load(struct sudoku *sud, const char *ptr)
|
||||||
{
|
{
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
init(sud);
|
init(sud);
|
||||||
|
|
||||||
for (i = 0; i < NCELLS; ++i) {
|
for (unsigned i = 0; i < NCELLS; ++i) {
|
||||||
if (ptr[i] == '0')
|
if (ptr[i] == '0')
|
||||||
continue;
|
continue;
|
||||||
if (update(sud, i, ptr[i] - '1') != OK)
|
if (update(sud, i, ptr[i] - '1') != OK)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save(struct sudoku *sud, char *ptr)
|
void save(struct sudoku *sud, char *ptr)
|
||||||
{
|
{
|
||||||
unsigned i;
|
for (unsigned i = 0; i < NCELLS; ++i) {
|
||||||
for (i = 0; i < NCELLS; ++i) {
|
|
||||||
if (DET(sud->cells[i]))
|
if (DET(sud->cells[i]))
|
||||||
*ptr++ = '1' + VAL(sud->cells[i]);
|
*ptr++ = '1' + VAL(sud->cells[i]);
|
||||||
else
|
else
|
||||||
@ -63,11 +60,10 @@ void save(struct sudoku *sud, char *ptr)
|
|||||||
enum update_res update(struct sudoku *sud, unsigned i, unsigned val)
|
enum update_res update(struct sudoku *sud, unsigned i, unsigned val)
|
||||||
{
|
{
|
||||||
const uint16_t clearmask = ~(1 << val);
|
const uint16_t clearmask = ~(1 << val);
|
||||||
unsigned j;
|
|
||||||
|
|
||||||
/* Update possible values of cells in same row, column and
|
/* Update possible values of cells in same row, column and
|
||||||
* segment. */
|
* segment. */
|
||||||
for (j = 0; j < NGROUP; ++j) {
|
for (unsigned j = 0; j < NGROUP; ++j) {
|
||||||
sud->cells[rowidx_lut[i][j]] &= clearmask;
|
sud->cells[rowidx_lut[i][j]] &= clearmask;
|
||||||
sud->cells[colidx_lut[i][j]] &= clearmask;
|
sud->cells[colidx_lut[i][j]] &= clearmask;
|
||||||
sud->cells[segidx_lut[i][j]] &= clearmask;
|
sud->cells[segidx_lut[i][j]] &= clearmask;
|
||||||
@ -83,9 +79,7 @@ enum update_res update(struct sudoku *sud, unsigned i, unsigned val)
|
|||||||
|
|
||||||
void print(const struct sudoku *sud)
|
void print(const struct sudoku *sud)
|
||||||
{
|
{
|
||||||
unsigned r, c;
|
for (unsigned r = 0; r < NDIGITS; ++r) {
|
||||||
|
|
||||||
for (r = 0; r < NDIGITS; ++r) {
|
|
||||||
/*
|
/*
|
||||||
* Print horizontal divider if on a segment boundary (but not
|
* Print horizontal divider if on a segment boundary (but not
|
||||||
* at the start).
|
* at the start).
|
||||||
@ -93,7 +87,7 @@ void print(const struct sudoku *sud)
|
|||||||
if (r != 0 && r % SEGLEN == 0)
|
if (r != 0 && r % SEGLEN == 0)
|
||||||
puts("------+-------+------");
|
puts("------+-------+------");
|
||||||
|
|
||||||
for (c = 0; c < NDIGITS; ++c) {
|
for (unsigned c = 0; c < NDIGITS; ++c) {
|
||||||
/*
|
/*
|
||||||
* Print vertical divider if on a segment boundary (but
|
* Print vertical divider if on a segment boundary (but
|
||||||
* not at the start).
|
* not at the start).
|
||||||
@ -112,19 +106,17 @@ void print(const struct sudoku *sud)
|
|||||||
|
|
||||||
static void zerocounts(unsigned counts[NDIGITS])
|
static void zerocounts(unsigned counts[NDIGITS])
|
||||||
{
|
{
|
||||||
unsigned i;
|
for (unsigned i = 0; i < NDIGITS; ++i)
|
||||||
for (i = 0; i < NDIGITS; ++i)
|
|
||||||
counts[i] = 0;
|
counts[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checkcounts(unsigned counts[NDIGITS])
|
static bool checkcounts(unsigned counts[NDIGITS])
|
||||||
{
|
{
|
||||||
unsigned i;
|
for (unsigned i = 0; i < NDIGITS; ++i) {
|
||||||
for (i = 0; i < NDIGITS; ++i) {
|
|
||||||
if (counts[i] != 1)
|
if (counts[i] != 1)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum check_res check(const struct sudoku *sud)
|
enum check_res check(const struct sudoku *sud)
|
||||||
@ -173,14 +165,13 @@ enum check_res check(const struct sudoku *sud)
|
|||||||
return SOLVED;
|
return SOLVED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int filled(const struct sudoku *sud)
|
bool filled(const struct sudoku *sud)
|
||||||
{
|
{
|
||||||
unsigned r, c;
|
for (unsigned r = 0; r < NDIGITS; ++r) {
|
||||||
for (r = 0; r < NDIGITS; ++r) {
|
for (unsigned c = 0; c < NDIGITS; ++c) {
|
||||||
for (c = 0; c < NDIGITS; ++c) {
|
|
||||||
if (!(DET(sud->cells[IDX(r, c)])))
|
if (!(DET(sud->cells[IDX(r, c)])))
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
5
sud.h
5
sud.h
@ -19,6 +19,7 @@
|
|||||||
#ifndef SUD_H
|
#ifndef SUD_H
|
||||||
#define SUD_H
|
#define SUD_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define SEGLEN 3
|
#define SEGLEN 3
|
||||||
@ -47,7 +48,7 @@ enum check_res { INCOMPLETE, INCORRECT, SOLVED };
|
|||||||
* Read `NCELLS` values from the given pointer and load them into the
|
* Read `NCELLS` values from the given pointer and load them into the
|
||||||
* sudoku.
|
* sudoku.
|
||||||
*/
|
*/
|
||||||
int load(struct sudoku *sud, const char *ptr);
|
bool load(struct sudoku *sud, const char *ptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the sudoku to the given pointer (`NCELLS` bytes).
|
* Write the sudoku to the given pointer (`NCELLS` bytes).
|
||||||
@ -74,6 +75,6 @@ enum check_res check(const struct sudoku *sud);
|
|||||||
/**
|
/**
|
||||||
* Determine whether all the sudoku's cells have been determined.
|
* Determine whether all the sudoku's cells have been determined.
|
||||||
*/
|
*/
|
||||||
int filled(const struct sudoku *sud);
|
bool filled(const struct sudoku *sud);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user