Advertisement
algore87

sudoku game and solver

Sep 25th, 2017
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.99 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <string.h>
  5. #include <termios.h>            //termios, TCSANOW, ECHO, ICANON
  6. #include <unistd.h>             //STDIN_FILENO
  7. #include <math.h>
  8.  
  9. #define SIZE 9
  10. #define LF 10
  11.  
  12. // defines for game mode
  13. #define ARROW '\033'
  14. #define UP 'A'
  15. #define RIGHT 'C'
  16. #define DOWN 'B'
  17. #define LEFT 'D'
  18.  
  19. bool init(int, char**);
  20. void draw(FILE*);
  21. void solve(int, int);
  22. void play();
  23. // helper
  24. bool rowOK(int, int);
  25. bool colOK(int, int);
  26. bool blockOK(int, int, int);
  27. bool moveCursor(int, int);
  28.  
  29. typedef struct sudoku {
  30.     unsigned int x;
  31.     unsigned int y;
  32.     unsigned int valuesSet;
  33.     int fieldsToSolve;
  34.     bool write;
  35.     bool show;
  36.     bool game;
  37.     bool isSolved;
  38.     bool isNumberGiven[SIZE][SIZE];
  39.     int grid[SIZE][SIZE];
  40. }sudoku;
  41.  
  42. sudoku* s;
  43. FILE* fp;
  44.  
  45. int main(int argc, char* argv[]) {
  46.     if ((argc != 2) && (argc != 3)) {
  47.         fprintf(stderr, "Usage: ./sudoku infile [outfile | -show | -play]\n");
  48.         return 1;
  49.     }
  50.  
  51.     if (!init(argc, argv)) {
  52.         return 1;
  53.     }
  54.  
  55.  
  56.     if (!s->game) {
  57.         solve(0, 0);
  58.         draw(stdout);
  59.     }
  60.  
  61.     if (s->game) {
  62.         static struct termios oldt, newt;
  63.         tcgetattr( STDIN_FILENO, &oldt); // changes that getchar() buffers char by char read, not by pressing enter
  64.         newt = oldt;
  65.         newt.c_lflag &= ~(ICANON | ECHO);
  66.         tcsetattr( STDIN_FILENO, TCSANOW, &newt);
  67.  
  68.         play();
  69.  
  70.         /*restore the old settings*/
  71.         tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
  72.     }
  73.  
  74.  
  75.     if (s->write) {
  76.         fprintf(fp, "\n");
  77.         draw(fp);
  78.         fclose(fp);
  79.     }
  80.  
  81.     free(s);
  82.     return 0;
  83. }
  84.  
  85. bool init(int argc, char* argv[]) {
  86.     FILE* fin = fopen(argv[1], "r");
  87.     if (fin == NULL) {
  88.         fprintf(stderr, "Can't read file %s.\n", argv[1]);
  89.         return false;
  90.     }
  91.  
  92.     s = malloc(sizeof(sudoku));
  93.     if (s == NULL) {
  94.         fprintf(stderr, "Can't allocate memory.\n");
  95.         fclose(fin);
  96.         return false;
  97.     }
  98.     memset(s, 0, sizeof(sudoku)); // set every value of struct to 0
  99.  
  100.  
  101.     if (argc == 3) {
  102.         if (!strcmp(argv[2], "-show")) {
  103.             s->show = true;
  104.         }
  105.         else if (!strcmp(argv[2], "-play")) {
  106.             s->game = true;
  107.         }
  108.         else {
  109.             fp = fopen(argv[2], "w");
  110.             if (fp == NULL) {
  111.                 fprintf(stderr, "Can't create file %s.\n", argv[2]);
  112.                 fclose(fin);
  113.                 return false;
  114.             }
  115.             s->write = true;
  116.         }
  117.     }
  118.  
  119.  
  120.     int ch, row, col;
  121.     row = col = 0;
  122.     while ((ch = fgetc(fin)) != EOF) {
  123.         switch (ch) {
  124.             case LF: // new line
  125.                 ++row;
  126.                 col = 0;
  127.                 break;
  128.             default:
  129.                 ch -= '0'; // ch - '0' = value of number char
  130.                 if ((col > 8) || (row > 8) || (ch < 0) || (ch > 9)) { // check file format
  131.                     fprintf(stderr, "File has wrong format (9x9 numbers from 0-9).\n");
  132.                     fclose(fin);
  133.                     return false;
  134.                 }
  135.                 if (ch > 0) {
  136.                     s->isNumberGiven[row][col] = true;
  137.                 }
  138.                 else { // 0
  139.                     ++s->fieldsToSolve;
  140.                 }
  141.                 s->grid[row][col] = ch;
  142.                 ++col;
  143.                 break;
  144.         }
  145.     }
  146.  
  147.     fclose(fin);
  148.     if (s->write) draw(fp);
  149.     draw(stdout);
  150.     return true;
  151. }
  152.  
  153. void draw(FILE* f) {
  154.     if (s->show || s->game) {
  155.         system("clear");
  156.         fprintf(f, "x = %i\ny = %i\n", s->x, s->y);
  157.     }
  158.     if (!s->game) {
  159.         fprintf(f, "Solved: %i\n", s->isSolved);
  160.         fprintf(f, "Values Set: %i\n", s->valuesSet);
  161.     }
  162.     if (s->game) fprintf(f, "Fields left: %i\n", s->fieldsToSolve);
  163.     for (int i = 0; i < SIZE; ++i) {
  164.         if (!(i % 3)) {
  165.             fprintf(f, " + ----- + ----- + ----- +\n");
  166.         }
  167.         for (int j = 0; j < SIZE; ++j) {
  168.             if (!(j % 3)) {
  169.                 fprintf(f, " |");
  170.             }
  171.             if (s->game && ((i == s->y) && (j == s->x))) fprintf(f, " _"); // game modus cursor
  172.             else (s->grid[i][j] == 0) ? fprintf(f, "  ") : fprintf(f, "%2i", s->grid[i][j]); // display 0 as whitespace
  173.         }
  174.         fprintf(f, " |\n");
  175.     }
  176.     fprintf(f, " + ----- + ----- + ----- +\n");
  177.     if (s->show) system("sleep 0.1");
  178.     if (s->game) {
  179.         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]" : "[ ]");
  180.     }
  181. }
  182.  
  183. void solve(int x, int y) {
  184.     s->x = x;
  185.     s->y = y;
  186.     if (y == SIZE) { // base case, every digit is set!
  187.         s->isSolved = true;
  188.         return;
  189.     }
  190.     else if (x == SIZE) { // line is done, go to the next line (first field)
  191.         solve(0, y + 1);
  192.     }
  193.     else if (s->isNumberGiven[y][x]){ // field is not changeable, go to the next field
  194.         solve(x + 1, y);
  195.     }
  196.     else { // changeable field, solve
  197.         for (int v = 1; v <= 9; ++v) {
  198.             if (rowOK(y, v) && colOK(x, v) && blockOK(x, y, v)) {
  199.                  s->grid[y][x] = v;
  200.                  ++s->valuesSet;
  201.                  if (s->show) draw(stdout);
  202.                  solve(x + 1, y);
  203.             }
  204.         }
  205.         if (!s->isSolved) {
  206.             s->grid[y][x] = 0;
  207.         }
  208.     }
  209. }
  210.  
  211. void play() {
  212.     bool exit = false;
  213.     int x;
  214.     int y;
  215.     draw(stdout);
  216.     while (!exit) {
  217.         int ch = getchar();
  218.         switch ((ch)) {
  219.             case 'q':
  220.                 draw(stdout);
  221.                 printf("Exit\n");
  222.                 exit = true;
  223.                 break;
  224.             case 'c':
  225.                 if (s->grid[s->y][s->x] != 0) {
  226.                     s->grid[s->y][s->x] = 0;
  227.                     ++s->fieldsToSolve;
  228.                     draw(stdout);
  229.                     printf("Clear\n");
  230.                 }
  231.                 else {
  232.                     draw(stdout);
  233.                     printf("Field is empty!\n");
  234.                 }
  235.                 break;
  236.             case 'a':
  237.                 // reset fields and solve
  238.                 draw(stdout);
  239.                 printf("Auto-Solver activated!\n");
  240.                 for (int i = 0; i < SIZE; ++i) {
  241.                     for (int j = 0; j < SIZE; ++j) {
  242.                         if (!s->isNumberGiven[j][i]) {
  243.                             s->grid[j][i] = 0;
  244.                         }
  245.                     }
  246.                 }
  247.                 s->game = false;
  248.                 solve(0, 0);
  249.                 exit = true;
  250.                 break;
  251.             case 's':
  252.                 s->show = !s->show;
  253.                 draw(stdout);
  254.                 printf("%s\n", s->show ? "Show Solving-Procedure" : "Don't show Solving-Procedure");
  255.                 break;
  256.             case ARROW:
  257.                 x = s->x;
  258.                 y = s->y;
  259.                 getchar(); // skip [
  260.                 switch (ch = getchar()) {
  261.                     case UP:
  262.                         while (!moveCursor(x, --y));
  263.                         draw(stdout);
  264.                         printf("UP\n");
  265.                         break;
  266.                     case RIGHT:
  267.                         while(!moveCursor(++x, y));
  268.                         draw(stdout);
  269.                         printf("RIGHT\n");
  270.                         break;
  271.                     case DOWN:
  272.                         while(!moveCursor(x, ++y));
  273.                         draw(stdout);
  274.                         printf("DOWN\n");
  275.                         break;
  276.                     case LEFT:
  277.                         while(!moveCursor(--x, y));
  278.                         draw(stdout);
  279.                         printf("LEFT\n");
  280.                         break;
  281.                     default:
  282.                         break;
  283.                 }
  284.                 break;
  285.             case '1':
  286.             case '2':
  287.             case '3':
  288.             case '4':
  289.             case '5':
  290.             case '6':
  291.             case '7':
  292.             case '8':
  293.             case '9':
  294.                 ch -= '0'; // change char to int
  295.                 if (rowOK(s->y, ch) && colOK(s->x, ch) && blockOK(s->x, s->y, ch)) {
  296.                     if (s->grid[s->y][s->x] == 0) --s->fieldsToSolve;
  297.                     s->grid[s->y][s->x] = ch;
  298.                     ++s->valuesSet;
  299.                     draw(stdout);
  300.                     printf("%i inserted.\n", ch);
  301.                     if (s->fieldsToSolve == 0) {
  302.                         s->isSolved = true;
  303.                         exit = true;
  304.                     }
  305.                 }
  306.                 else {
  307.                     draw(stdout);
  308.                     printf("Can't insert %i at cursor!\n", ch);
  309.                 }
  310.                 break;
  311.             default:
  312.                 break;
  313.         }
  314.     }
  315.     s->game = false;
  316.     if (s->isSolved) {
  317.         draw(stdout);
  318.         printf("Well done! You have finished your sudoku!\n");
  319.     }
  320. }
  321.  
  322. // helper
  323. bool rowOK(int row, int val) {
  324.     for (int i = 0; i < SIZE; ++i) {
  325.         if (s->grid[row][i] == val) {
  326.             return false;
  327.         }
  328.     }
  329.     return true;
  330. }
  331.  
  332. bool colOK(int col, int val) {
  333.     for (int i = 0; i < SIZE; ++i) {
  334.         if (s->grid[i][col] == val) {
  335.             return false;
  336.         }
  337.     }
  338.     return true;
  339. }
  340.  
  341. bool blockOK(int x, int y, int val) {
  342.     for (int i = 0; i < 3; ++i) {
  343.         for (int j = 0; j < 3; ++j) {
  344.             if (s->grid[(y - (y % 3)) + i][(x - (x % 3)) + j] == val) { // x - (x % 3): Block x startindex;  y - (y % 3): Block y startindex
  345.                 return false;
  346.             }
  347.         }
  348.     }
  349.     return true;
  350. }
  351.  
  352. bool moveCursor(int x, int y) {
  353.     // boundary jumps
  354.     x %= SIZE;
  355.     y %= SIZE;
  356.     if (x < 0) x = SIZE + x;
  357.     if (y < 0) y = SIZE + y;
  358.     if (s->isNumberGiven[y][x]) {
  359.         return false;
  360.     }
  361.     // cursor is fine, move
  362.     s->x = x;
  363.     s->y = y;
  364.     return true;
  365. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement