project-euler

https://projecteuler.net/
Log | Files | Refs | README

Euler_96.cpp (6527B)


      1 #include <array>
      2 #include <fstream>
      3 #include <sstream>
      4 #include <unordered_set>
      5 
      6 #include "Euler.h"
      7 
      8 typedef std::array<std::array<int, 9>, 9> sudoku;
      9 typedef std::unordered_set<int> set;
     10 
     11 bool check(sudoku& bifurcation) {
     12     for (int i = 0; i < 9; ++i) {
     13         set h, v;
     14 
     15         for (int j = 0; j < 9; ++j) {
     16              h.insert(bifurcation[i][j]);
     17              v.insert(bifurcation[j][i]);
     18         }
     19 
     20         if (h.size() < 9 || v.size() < 9) {
     21             return false;
     22         }
     23     }
     24 
     25     for (int l = 0; l < 3; ++l) {
     26         for (int k = 0; k < 3; ++k) {
     27             set subgroup;
     28 
     29             for (int i = l * 3; i < (l * 3) + 3; ++i) {
     30                 for (int j = k * 3; j < (k * 3) + 3; ++j) {
     31                     subgroup.insert(bifurcation[i][j]);
     32                 }
     33             }
     34 
     35             if (subgroup.size() < 9) {
     36                 return false;
     37             }
     38         }
     39     }
     40 
     41     return true;
     42 }
     43 
     44 void reset_hv(sudoku& puzzle, std::array<set, 9>& h, std::array<set, 9>& v) {
     45     for (int i = 0; i < 9; ++i) {
     46         h[i].clear(); v[i].clear();
     47 
     48         for (int j = 0; j < 9; ++j) {
     49              h[i].insert(puzzle[i][j]);
     50              v[i].insert(puzzle[j][i]);
     51         }
     52     }
     53 }
     54 
     55 void reset_subgroup(sudoku& puzzle, set& subgroup, set& missing, int l, int k) {
     56     subgroup.clear(); missing.clear();
     57 
     58     for (int i = l * 3; i < (l * 3) + 3; ++i) {
     59         for (int j = k * 3; j < (k * 3) + 3; ++j) {
     60             subgroup.insert(puzzle[i][j]);
     61         }
     62     }
     63 
     64     for (int i = 1; i <= 9; ++i) {
     65         if (subgroup.find(i) == subgroup.end()) {
     66             missing.insert(i);
     67         }
     68     }
     69 }
     70 
     71 void found(sudoku& puzzle, int x, int i, int j, int k, int l, bool& r, std::array<set, 9>& h, std::array<set, 9>& v, set& s, set& m) {
     72     puzzle[i][j] = x;
     73     r = true;
     74 
     75     reset_hv(puzzle, h, v);
     76     reset_subgroup(puzzle, s, m, l, k);
     77 }
     78 
     79 sudoku reduce(sudoku& puzzle) {
     80     bool reduced;
     81     do {
     82         reduced = false;
     83 
     84         std::array<set, 9> h, v;
     85 
     86         reset_hv(puzzle, h, v);
     87 
     88         for (int l = 0; l < 3; ++l) {
     89             for (int k = 0; k < 3; ++k) {
     90                 set missing, subgroup;
     91                 reset_subgroup(puzzle, subgroup, missing, l, k);
     92 
     93                 for (int i = l * 3; i < (l * 3) + 3; ++i) {
     94                     for (int j = k * 3; j < (k * 3) + 3; ++j) {
     95                         if (puzzle[i][j] <= 0) {
     96                             if (missing.size() == 1) {
     97                                 found(puzzle, *missing.begin(), i, j, k, l, reduced, h, v, subgroup, missing);
     98                                 continue;
     99                             }
    100 
    101                             set matches;
    102 
    103                             for (int x : missing) {
    104                                 if (h[i].find(x) == h[i].end() && v[j].find(x) == v[j].end()) {
    105                                     matches.insert(x);
    106                                 }
    107 
    108                                 if (subgroup.find(x) == subgroup.end()) {
    109                                     int li1 = (l * 3) + ((i + 1) % 3), li2 = (l * 3) + ((i + 2) % 3),
    110                                         kj1 = (k * 3) + ((j + 1) % 3), kj2 = (k * 3) + ((j + 2) % 3);
    111 
    112                                     if (((h[li1].find(x) != h[li1].end()) && (h[li2].find(x) != h[li2].end())
    113                                       && ((puzzle[i][kj1] > 0) || v[kj1].find(x) != v[kj1].end())
    114                                       && ((puzzle[i][kj2] > 0) || v[kj2].find(x) != v[kj2].end())) || (
    115                                          (v[kj1].find(x) != v[kj1].end()) && (v[kj2].find(x) != v[kj2].end())
    116                                       && ((puzzle[li1][j] > 0) || h[li1].find(x) != h[li1].end())
    117                                       && ((puzzle[li2][j] > 0) || h[li2].find(x) != h[li2].end()))) {
    118                                         found(puzzle, x, i, j, k, l, reduced, h, v, subgroup, missing);
    119                                         break;
    120                                     }
    121                                 }
    122                             }
    123 
    124                             if (matches.size() == 1) {
    125                                 found(puzzle, *matches.begin(), i, j, k, l, reduced, h, v, subgroup, missing);
    126                                 continue;
    127                             }
    128                         }
    129                     }
    130                 }
    131             }
    132         }
    133     } while (reduced);
    134 
    135     return puzzle;
    136 }
    137 
    138 //need to modify bifurcation to start with lowest branching factor rather than sequentially.
    139 sudoku bifurcate(sudoku bifurcation) {
    140     if (!check(bifurcation)) {
    141         return {};
    142     }
    143 
    144     for (int i = 0; i < 9; ++i) {
    145         for (int j = 0; j < 9; ++j) {
    146             if (bifurcation[i][j] <= 0) {
    147                 for (int k = 1; k <= 9; ++k) {
    148                     bifurcation[i][j] = k;
    149 
    150                     sudoku candidate = bifurcate(bifurcation);
    151 
    152                     if (check(candidate)) {
    153                         return candidate;
    154                     }
    155                 }
    156             }
    157         }
    158     }
    159 
    160     return bifurcation;
    161 }
    162 
    163 void print(sudoku puzzle) {
    164     for (int i = 0; i < 9; ++i) {
    165         if (i % 3 == 0) {
    166             std::cout << "-------------------" << std::endl;
    167         }
    168         for (int j = 0; j < 9; ++j) {
    169             std::cout << ((j % 3 == 0) ? "|" : " ") << ((puzzle[i][j] < 0) ? 0 : puzzle[i][j]);
    170         }
    171         std::cout << "|" << std::endl;
    172     }
    173     std::cout << "-------------------" << std::endl << std::endl;
    174 }
    175 
    176 int Euler::Sudoku()
    177 {
    178     std::array<sudoku, 50> sudokus;
    179     std::ifstream file;
    180     std::string temp;
    181     int i = -1, j = 0, empty = 0, sum = 0;
    182 
    183     file.open("files/p096_sudoku.txt");
    184 
    185     while(std::getline(file, temp)) {
    186         if (temp[0] == 'G') {
    187             i++; j = 0; empty = 0; continue;
    188         }
    189 
    190         for (int k = 0; k < 9; ++k) {
    191             sudokus[i][j][k] = ((temp[k] - 48) != 0) ? temp[k] - 48 : empty--;
    192         }
    193 
    194         j++;
    195     }
    196 
    197     file.close();
    198 
    199     for (int j = 0; j < 5; ++j) {
    200         sudoku puzzle = sudokus[j];
    201         std::cout << "next puzzle " << j << ":" << std::endl;
    202         print(puzzle);
    203         sudoku reduced = reduce(puzzle);
    204         std::cout << "reduced:" << std::endl;
    205         print(reduced);
    206         sudoku solution = bifurcate(reduced);
    207         std::cout << "solution:" << std::endl;
    208         print(solution);
    209         std::stringstream ss;
    210         ss << solution[0][0] << solution[0][1] << solution[0][2];
    211         int temp;
    212         ss >> temp;
    213         sum += temp;
    214 
    215     }
    216 
    217     return sum;
    218 }