Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <string.h>
- #include <termios.h> //termios, TCSANOW, ECHO, ICANON
- #include <unistd.h> //STDIN_FILENO
- #include <math.h>
- #define SIZE 9
- #define LF 10
- // defines for game mode
- #define ARROW '\033'
- #define UP 'A'
- #define RIGHT 'C'
- #define DOWN 'B'
- #define LEFT 'D'
- bool init(int, char**);
- void draw(FILE*);
- void solve(int, int);
- void play();
- // helper
- bool rowOK(int, int);
- bool colOK(int, int);
- bool blockOK(int, int, int);
- bool moveCursor(int, int);
- typedef struct sudoku {
- unsigned int x;
- unsigned int y;
- unsigned int valuesSet;
- int fieldsToSolve;
- bool write;
- bool show;
- bool game;
- bool isSolved;
- bool isNumberGiven[SIZE][SIZE];
- int grid[SIZE][SIZE];
- }sudoku;
- sudoku* s;
- FILE* fp;
- int main(int argc, char* argv[]) {
- if ((argc != 2) && (argc != 3)) {
- fprintf(stderr, "Usage: ./sudoku infile [outfile | -show | -play]\n");
- return 1;
- }
- if (!init(argc, argv)) {
- return 1;
- }
- if (!s->game) {
- solve(0, 0);
- draw(stdout);
- }
- if (s->game) {
- static struct termios oldt, newt;
- tcgetattr( STDIN_FILENO, &oldt); // changes that getchar() buffers char by char read, not by pressing enter
- newt = oldt;
- newt.c_lflag &= ~(ICANON | ECHO);
- tcsetattr( STDIN_FILENO, TCSANOW, &newt);
- play();
- /*restore the old settings*/
- tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
- }
- if (s->write) {
- fprintf(fp, "\n");
- draw(fp);
- fclose(fp);
- }
- free(s);
- return 0;
- }
- bool init(int argc, char* argv[]) {
- FILE* fin = fopen(argv[1], "r");
- if (fin == NULL) {
- fprintf(stderr, "Can't read file %s.\n", argv[1]);
- return false;
- }
- s = malloc(sizeof(sudoku));
- if (s == NULL) {
- fprintf(stderr, "Can't allocate memory.\n");
- fclose(fin);
- return false;
- }
- memset(s, 0, sizeof(sudoku)); // set every value of struct to 0
- if (argc == 3) {
- if (!strcmp(argv[2], "-show")) {
- s->show = true;
- }
- else if (!strcmp(argv[2], "-play")) {
- s->game = true;
- }
- else {
- fp = fopen(argv[2], "w");
- if (fp == NULL) {
- fprintf(stderr, "Can't create file %s.\n", argv[2]);
- fclose(fin);
- return false;
- }
- s->write = true;
- }
- }
- int ch, row, col;
- row = col = 0;
- while ((ch = fgetc(fin)) != EOF) {
- switch (ch) {
- case LF: // new line
- ++row;
- col = 0;
- break;
- default:
- ch -= '0'; // ch - '0' = value of number char
- if ((col > 8) || (row > 8) || (ch < 0) || (ch > 9)) { // check file format
- fprintf(stderr, "File has wrong format (9x9 numbers from 0-9).\n");
- fclose(fin);
- return false;
- }
- if (ch > 0) {
- s->isNumberGiven[row][col] = true;
- }
- else { // 0
- ++s->fieldsToSolve;
- }
- s->grid[row][col] = ch;
- ++col;
- break;
- }
- }
- fclose(fin);
- if (s->write) draw(fp);
- draw(stdout);
- return true;
- }
- void draw(FILE* f) {
- if (s->show || s->game) {
- system("clear");
- fprintf(f, "x = %i\ny = %i\n", s->x, s->y);
- }
- if (!s->game) {
- fprintf(f, "Solved: %i\n", s->isSolved);
- fprintf(f, "Values Set: %i\n", s->valuesSet);
- }
- if (s->game) fprintf(f, "Fields left: %i\n", s->fieldsToSolve);
- for (int i = 0; i < SIZE; ++i) {
- if (!(i % 3)) {
- fprintf(f, " + ----- + ----- + ----- +\n");
- }
- for (int j = 0; j < SIZE; ++j) {
- if (!(j % 3)) {
- fprintf(f, " |");
- }
- if (s->game && ((i == s->y) && (j == s->x))) fprintf(f, " _"); // game modus cursor
- else (s->grid[i][j] == 0) ? fprintf(f, " ") : fprintf(f, "%2i", s->grid[i][j]); // display 0 as whitespace
- }
- fprintf(f, " |\n");
- }
- fprintf(f, " + ----- + ----- + ----- +\n");
- if (s->show) system("sleep 0.1");
- if (s->game) {
- fprintf(f, "<q>: Exit\t\t<Arrow-Keys>: Move cursor\t\t<Values [1-9]>: Insert value\n<c>: Clear field\t\t <a>: Auto-Solve\t\t<s>: Show Auto-Solve Backtracking %s\n", s->show ? "[x]" : "[ ]");
- }
- }
- void solve(int x, int y) {
- s->x = x;
- s->y = y;
- if (y == SIZE) { // base case, every digit is set!
- s->isSolved = true;
- return;
- }
- else if (x == SIZE) { // line is done, go to the next line (first field)
- solve(0, y + 1);
- }
- else if (s->isNumberGiven[y][x]){ // field is not changeable, go to the next field
- solve(x + 1, y);
- }
- else { // changeable field, solve
- for (int v = 1; v <= 9; ++v) {
- if (rowOK(y, v) && colOK(x, v) && blockOK(x, y, v)) {
- s->grid[y][x] = v;
- ++s->valuesSet;
- if (s->show) draw(stdout);
- solve(x + 1, y);
- }
- }
- if (!s->isSolved) {
- s->grid[y][x] = 0;
- }
- }
- }
- void play() {
- bool exit = false;
- int x;
- int y;
- draw(stdout);
- while (!exit) {
- int ch = getchar();
- switch ((ch)) {
- case 'q':
- draw(stdout);
- printf("Exit\n");
- exit = true;
- break;
- case 'c':
- if (s->grid[s->y][s->x] != 0) {
- s->grid[s->y][s->x] = 0;
- ++s->fieldsToSolve;
- draw(stdout);
- printf("Clear\n");
- }
- else {
- draw(stdout);
- printf("Field is empty!\n");
- }
- break;
- case 'a':
- // reset fields and solve
- draw(stdout);
- printf("Auto-Solver activated!\n");
- for (int i = 0; i < SIZE; ++i) {
- for (int j = 0; j < SIZE; ++j) {
- if (!s->isNumberGiven[j][i]) {
- s->grid[j][i] = 0;
- }
- }
- }
- s->game = false;
- solve(0, 0);
- exit = true;
- break;
- case 's':
- s->show = !s->show;
- draw(stdout);
- printf("%s\n", s->show ? "Show Solving-Procedure" : "Don't show Solving-Procedure");
- break;
- case ARROW:
- x = s->x;
- y = s->y;
- getchar(); // skip [
- switch (ch = getchar()) {
- case UP:
- while (!moveCursor(x, --y));
- draw(stdout);
- printf("UP\n");
- break;
- case RIGHT:
- while(!moveCursor(++x, y));
- draw(stdout);
- printf("RIGHT\n");
- break;
- case DOWN:
- while(!moveCursor(x, ++y));
- draw(stdout);
- printf("DOWN\n");
- break;
- case LEFT:
- while(!moveCursor(--x, y));
- draw(stdout);
- printf("LEFT\n");
- break;
- default:
- break;
- }
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- ch -= '0'; // change char to int
- if (rowOK(s->y, ch) && colOK(s->x, ch) && blockOK(s->x, s->y, ch)) {
- if (s->grid[s->y][s->x] == 0) --s->fieldsToSolve;
- s->grid[s->y][s->x] = ch;
- ++s->valuesSet;
- draw(stdout);
- printf("%i inserted.\n", ch);
- if (s->fieldsToSolve == 0) {
- s->isSolved = true;
- exit = true;
- }
- }
- else {
- draw(stdout);
- printf("Can't insert %i at cursor!\n", ch);
- }
- break;
- default:
- break;
- }
- }
- s->game = false;
- if (s->isSolved) {
- draw(stdout);
- printf("Well done! You have finished your sudoku!\n");
- }
- }
- // helper
- bool rowOK(int row, int val) {
- for (int i = 0; i < SIZE; ++i) {
- if (s->grid[row][i] == val) {
- return false;
- }
- }
- return true;
- }
- bool colOK(int col, int val) {
- for (int i = 0; i < SIZE; ++i) {
- if (s->grid[i][col] == val) {
- return false;
- }
- }
- return true;
- }
- bool blockOK(int x, int y, int val) {
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- if (s->grid[(y - (y % 3)) + i][(x - (x % 3)) + j] == val) { // x - (x % 3): Block x startindex; y - (y % 3): Block y startindex
- return false;
- }
- }
- }
- return true;
- }
- bool moveCursor(int x, int y) {
- // boundary jumps
- x %= SIZE;
- y %= SIZE;
- if (x < 0) x = SIZE + x;
- if (y < 0) y = SIZE + y;
- if (s->isNumberGiven[y][x]) {
- return false;
- }
- // cursor is fine, move
- s->x = x;
- s->y = y;
- return true;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement