Advertisement
Guest User

Untitled

a guest
Jun 25th, 2019
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.34 KB | None | 0 0
  1. #ifndef _SUDOKU_H_
  2. #define _SUDOKU_H_
  3. #include <vector>
  4. #include <cstdint> // Para uint8_t em alguns compiladores
  5.  
  6. /// Classe que representa uma possivel jogada (coordenadas e valor)
  7. /// Significado dos valores:
  8. /*
  9. i | i de 0-8 | i<0 | i>8 e j>=0 |
  10. j | e | ou | ou |
  11. v | j de 0-8 | j<0 | j>8 e i>=0 |
  12. -----+----------+-----+------------+
  13. 1 a 9| JOGAR | FIM | RESOLVER |
  14. 0 | APAGAR | FIM | PREENCHER |
  15. > 9 | NOVO | FIM | VOLTAR |
  16. < 0 | FIM | FIM | FIM |
  17. */
  18.  
  19. class Jogada
  20. {
  21. protected:
  22. int i,j,v;
  23. public:
  24. /// Construtor (por default, cria Jogada que termina o jogo)
  25. Jogada(int I=-1, int J=-1, int V=-1);
  26.  
  27. /// Funcoes de acesso
  28. inline int linha() const {return i;}
  29. inline int coluna() const {return j;}
  30. inline int valor() const {return v;}
  31.  
  32. /// Testa se a jogada indica que uma casa deve ser preenchida
  33. inline bool jogada() const {return (i>=0 && i<=8 && j>=0 && j<=8 && v>=1 && v<=9);}
  34.  
  35. /// Testa se a jogada indica que uma casa deve ser apagada
  36. inline bool apagamento() const {return (i>=0 && i<=8 && j>=0 && j<=8 && v==0);}
  37.  
  38. /// Testa se a jogada indica que o uruario quer resolver o jogo automaticamente
  39. inline bool resolver_jogo() const {return ( ((i>8 && j>=0) || (i>=0 && j>8)) && v>=1 && v<=9 );}
  40.  
  41. /// Testa se a jogada indica que o uruario quer preencher as casas faceis
  42. inline bool preencher_jogo() const {return ( ((i>8 && j>=0) || (i>=0 && j>8)) && v==0 );}
  43.  
  44. /// Testa se a jogada indica que o uruario quer comecar um novo jogo
  45. inline bool novo() const {return (i>=0 && i<=8 && j>=0 && j<=8 && v>9);}
  46.  
  47. /// Testa se a jogada indica que o uruario quer recomecar (voltar ao tab inicial)
  48. inline bool voltar() const {return (((i>8 && j>=0) || (i>=0 && j>8)) && v>9);}
  49.  
  50. /// Testa se a jogada indica que o uruario quer encerrar o jogo
  51. inline bool fim_de_jogo() const {return (i<0 || j<0 || v<0);}
  52.  
  53. /// Fixa as coordenadas de uma jogada
  54. void setCell(int I, int J);
  55.  
  56. /// Fixa o valor de uma jogada
  57. void setValue(int V);
  58.  
  59. /// O METODO A SEGUIR ENVOLVE FORMATACAO.
  60. /// O codigo deve ser diferente de acordo com o modo de exibicao
  61.  
  62. /// Leh uma jogada do teclado
  63. void ler();
  64.  
  65. friend class Sudoku;
  66. };
  67.  
  68. class Sudoku
  69. {
  70. private:
  71. /// "Matriz 9x9" que contem os valores das casas do tabuleiro.
  72. /// Na realidade, a "matriz 9x9" eh um vector de 81 bytes sem sinal (uint8_t)
  73. /// O acesso aos elementos da "matriz" se dah atraves dos metodos "set" e "at",
  74. /// que transformam os indices linha e coluna da matriz no indice do vetor
  75. /// Conteudo da "matriz":
  76. /// 1 a 9 - Casa preenchida
  77. /// 0 - Casa vazia
  78. std::vector<uint8_t> tab;
  79.  
  80. /// Funcao set de alteracao de valor
  81. /// Retorna uma referencia ao i-j-esimo elemento do tabuleiro
  82. inline uint8_t& set(unsigned i, unsigned j) {return tab.at(9*i+j);}
  83.  
  84. /// Calcula o numero de possibilidades para preencher a casa (i,j)
  85. /// utilizando apenas as regras "faceis" (linha, coluna e bloco)
  86. /// Se houver uma unica possibilidade de preenchimento, retorna o valor (1 a 9)
  87. /// Se nao houver nenhuma possibilidade de preenchimento, retorna 0, o que
  88. /// indica que o tabuleiro nao tem solucao
  89. /// Se houver mais de uma possibilidade de preenchimento, retorna um numero
  90. /// negativo (<0), cujo modulo eh o numero de possibilidades
  91. int numero_possibilidades(unsigned i, unsigned j) const;
  92. public:
  93. /// Limpa o tabuleiro
  94. void limpar();
  95.  
  96. /// Gera um novo tabuleiro aleatorio
  97. void gerar();
  98.  
  99. /// Cria um tabuleiro vazio
  100. inline Sudoku(): tab(81) {limpar();}
  101.  
  102. /// Cria um tabuleiro com o conteudo do arquivo nome_arq
  103. /// Caso nao consiga ler do arquivo, retorna tabuleiro gerado
  104. /// automaticamente (caso erro ocorra logo no inicio da funcao
  105. /// de leitura) ou lido parcialmente, caso contrario
  106. Sudoku(const char *nome_arq);
  107.  
  108. /// Destrutor
  109. inline virtual ~Sudoku() {}
  110.  
  111. /// Funcao de consulta
  112. /// Retorna o i-j-esimo elemento do tabuleiro
  113. inline uint8_t at(unsigned i, unsigned j) const {return tab.at(9*i+j);}
  114.  
  115. /// Operador() de consulta - usa o metodo "at"
  116. /// Retorna o i-j-esimo elemento do tabuleiro
  117. inline uint8_t operator()(unsigned i, unsigned j) const {return at(i,j);}
  118.  
  119. /// Compara se dois tabuleiros sao iguais
  120. bool operator==(const Sudoku &S) const;
  121.  
  122. /// Testa se a jogada J eh possivel para o tabuleiro
  123. bool jogada_valida(Jogada J) const;
  124.  
  125. /// Testa se a jogada J eh um apagamento valido de uma casa para o tabuleiro,
  126. /// levando em conta o tabuleiro original (nao eh permitido apagar casas que
  127. /// estavam preenchidas no tabuleiro original)
  128. bool apagamento_valido(Jogada J, const Sudoku &Origem) const;
  129.  
  130. /// Executa uma jogada (altera o tabuleiro)
  131. inline void fazer_jogada(Jogada J) {if (jogada_valida(J)) set(J.i,J.j) = J.v;}
  132.  
  133. /// Apaga uma casa (altera o tabuleiro)
  134. inline void apagar_jogada(Jogada J, const Sudoku &O) {if (apagamento_valido(J,O)) set(J.i,J.j) = J.v;}
  135.  
  136. /// Testa se o tabuleiro estah completo (fim de jogo)
  137. bool fim_de_jogo() const;
  138.  
  139. /// Retorna o numero de casas vazias no tabuleiro
  140. unsigned num_casas_vazias() const;
  141.  
  142. /// OS 3 METODOS A SEGUIR ENVOLVEM FORMATACAO.
  143. /// O codigo deve ser diferente de acordo com o modo de exibicao
  144. /// Por isso as funcoes sao virtuais
  145.  
  146. /// Exibir o conteudo do tabuleiro (*this) na posicao de visualizacao do tabuleiro atual
  147. virtual void exibir() const;
  148.  
  149. /// Exibir o conteudo do tabuleiro (*this) na posicao de visualizacao do tabuleiro inicial
  150. virtual void exibir_origem() const;
  151.  
  152. /// Exibe os numeros de tabuleiros gerados, testados e a analisar
  153. virtual void exibir_andamento(unsigned Ntab_testados, unsigned Ntab_gerados, unsigned Ntab_analisar) const;
  154.  
  155. /// Preenche todas as casas "faceis" do tabuleiro, ou seja, aquelas que tem um
  156. /// unico valor possivel pelas regras do Sudoku
  157. /// Retorna o numero de casas adicionais preenhidas (0 ou >0) ou entao
  158. /// retorna <0 se houver alguma casa sem possibilidade de jogada (tabuleiro insoluvel)
  159. /// Quando retorna um valor negativo (ou seja, o tabuleiro eh insoluvel), o numero
  160. /// retornado serah o negativo do numero de casas preenchidas. Caso nenhuma casa
  161. /// tenha sido preeenchida e o tabuleiro seja insoluvel, serah retornado um numero
  162. /// negativo menor que -81.
  163. int resolver_casas_faceis();
  164.  
  165. /// Determina automaticamente a solucao do tabuleiro (preenche as casas vazias).
  166. ///
  167. /// O parametro com_exibicao controla se o algoritmo deve (true) ou nao (false)
  168. /// exibir os tabuleiros analisados e o numero de nohs durante o algoritmo.
  169. ///
  170. /// O parametro "basta_primeira_solucao" fixa se o algoritmo deve (true) ou nao (false)
  171. /// retornar assim que encontrar a primeira solucao, sem verificar se existe outra.
  172. ///
  173. /// Retorna 0 se nao foi encontrada solucao, 1 se foi encontrada uma solucao unica
  174. /// e >1 se existem mais de uma solucao (essa ultima possibilidade de retorno soh
  175. /// existe se o parametro basta_primeira_solucao for false.
  176. ///
  177. int resolver(bool com_exibicao=true, bool basta_primeira_solucao=true);
  178.  
  179. };
  180.  
  181. #endif // _SUDOKU_H_
  182.  
  183. int Sudoku::resolver(bool com_exibicao, bool basta_primeira_solucao) {
  184.  
  185. // Contadores do numero de tabuleiros gerados e testados
  186. int num_tab_gerados(1), num_tab_testados(1);
  187.  
  188. // Testa se jah nao estah resolvido desde o inicio
  189. if (this->fim_de_jogo()) {
  190. cout << "Ja esta resolvido!" << endl;
  191. return 1;
  192. }
  193.  
  194. // Tab. solucao
  195. Sudoku sol;
  196. // Fila com os tabuleiros.
  197. queue<Sudoku> Aberto;
  198. Aberto.push(*this);
  199.  
  200. bool encontrou_solucao = false;
  201.  
  202. int i, j, k;
  203.  
  204. do {
  205. // Extrai tabuleiro da fila.
  206. sol = Aberto.front();
  207. Aberto.pop();
  208. num_tab_testados++;
  209.  
  210. if (sol.fim_de_jogo()) {
  211. encontrou_solucao = true;
  212. } else {
  213. // Escolhe a primeira casa vaga
  214. i = 0;
  215. j = 0;
  216. while (i < 9 && sol(i, j) != 0) {
  217. j++;
  218. if (j >= 9) {
  219. j = 0;
  220. i++;
  221. }
  222. }
  223.  
  224. // Testa jogadas possiveis em sol(i,j)
  225. // Escolhe o primeiro valor de jogada para a casa.
  226. // Se soh houver um valor possivel joga esse valor.
  227. Jogada J(i, j);
  228.  
  229. // Calcula a(s) possibilidades de jogada na casa (i,j)
  230. k = sol.numero_possibilidades(i, j);
  231. if (k == 0) {
  232. // Tabuleiro S nao tem solucao
  233. J.setValue(-1); // Jogada invalida
  234. break; // Sai do laço pois o tabuleiro nao tem solucao
  235. } else if (k < 0) {
  236. // Existe mais de uma possibilidade de jogada
  237. // Verifica os valores possiveis para jogada e cria tab. sucessores (1~9).
  238. for (int z = 1; z < 10; z++) {
  239. J.setValue(z);
  240. // Se a jogada for valida gera novo tabuleiro: sucessor
  241. // de tab com a jogada.
  242. if (sol.jogada_valida(J)) {
  243. Sudoku suc = sol;
  244. suc.fazer_jogada(J);
  245. Aberto.push(suc);
  246. num_tab_gerados++;
  247. }
  248. }
  249. } else {
  250. // Soh existe uma possibilidade de jogada
  251. J.setValue(k);
  252. // Se a jogada for valida gera novo tabuleiro: sucessor
  253. // de tab com a jogada.
  254. if (sol.jogada_valida(J)) {
  255. Sudoku suc = sol;
  256. suc.fazer_jogada(J);
  257. Aberto.push(suc);
  258. num_tab_gerados++;
  259. }
  260. }
  261. }
  262.  
  263. if (com_exibicao /*&& (num_tab_testados % 10000 == 0)*/) {
  264. sol.exibir();
  265. exibir_andamento(num_tab_testados, num_tab_gerados, Aberto.size());
  266. //cout << "Ignorados: " << num_tab_ignorados << endl;
  267. }
  268. //cout << num_tab_gerados << endl;
  269.  
  270. } while ((!encontrou_solucao && !Aberto.empty()) && num_tab_testados < 1000000);
  271.  
  272. // Pode ter terminado porque
  273. // encontrou a solução ou porque
  274. // não há mais tabuleiros a testar
  275. if (!encontrou_solucao) {
  276. cout << "Sudoku sem solucao!" << endl;
  277. exibir_andamento(num_tab_testados, num_tab_gerados, Aberto.size());
  278. return 0;
  279. } else {
  280. cout << "Solucao:" << endl;
  281. if (com_exibicao) {
  282. sol.exibir();
  283. }
  284. exibir_andamento(num_tab_testados, num_tab_gerados, Aberto.size());
  285. return 1;
  286. }
  287. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement