Linha | Codigo |
001 | // Prof. Leo^nidas - http://www.matematica.br http://line.ime.usp.br |
002 | // MAC0122 - 2017/11/13 |
003 | // |
004 | // Passeio do Cavalo: encontrar um passeio em tabuleiro de xadrez para |
005 | // um cavalo de modo a visitar todas as casas uma unica vez. |
006 | // |
007 | // Descricao: definir o tamanho da tabuleiro n; definir uma posicao inicial de (0,0) ate (n-1,n-1); |
008 | // por tentativa e erro (backtracking) testar, todas as possibilidades (em busca em profundidade). |
009 | // |
010 | // Inicia em (x,y) e faz Tenta(Tab, n, lin, col, 1) |
011 | // int Tenta(Tab, n, lin, col, conta) |
012 | // if (conta==n*n) return 1; // conseguiu fazer n*n passos do cavalo => cobriu o tab. todo => sucesso! |
013 | // for "para cada movimento Mx, My (0 a 7)" |
014 | // if "Tab[Mx][My] movimento possivel" |
015 | // "registra movimento Tab[lin+Mx][col+My] <- conta" |
016 | // if (Tenta(Tab, n, lin+Mx, col+My, conta++)) // se devolver 1 => obteve sucesso! |
017 | // return 1; // "devolva sucesso" |
018 | // else "desmarcar movimento Tab[Mx][My] <- 0" |
019 | // return 0; // "devolva fracasso" |
020 | |
021 | // Fixando (0,0) para iniciar, primeiro tabuleiro factivel e' o 5x5 |
022 | |
023 | // gcc -fsanitize=address -g -o passeio_cavalo passeio_cavalo.c |
024 | |
025 | #include <stdio.h> |
026 | #include <stdlib.h> // 'atoi(...)' - string para inteiro |
027 | |
028 | // Movimentos do cavalo numerados de 0 ate 7 |
029 | // 0+1 |
030 | // 7 | 2 |
031 | // +--+--+ |
032 | // 6 | 3 |
033 | // 5+4 |
034 | signed char M[][2] = { // movimentos considerando uma matriz desde (0,0) ate' (n-1,n-1) |
035 | -2, -1, // 0 x <- x-1 e y <- y-2 |
036 | -2, 1, // 1 |
037 | -1, 2, // 2 |
038 | 1, 2, // 3 |
039 | 2, 1, // 4 |
040 | 2, -1, // 5 |
041 | 1, -2, // 6 |
042 | -1, -2 // 7 |
043 | }; |
044 | |
045 | long numeroTentativas = 0; // contabiliza numero de tentativas |
046 | |
047 | // Inicia tabuleiro. Usar 'unsigned char' para inteiros entre 0 e 256. Primeira posicao sera 1. |
048 | void iniciaTabuleiro (unsigned char *Tab, int n) { |
049 | int i, j; |
050 | for (i=0; i<n; i++) |
051 | for (j=0; j<n; j++) |
052 | *(Tab + i*n +j) = 0; // Tab[i][j] = 0; |
053 | } |
054 | |
055 | void imprimeTabuleiro (unsigned char *Tab, int n) { |
056 | int i, j; |
057 | printf("Veja a configuracao do passeio no tabuleiro de dimensao %d\n ", n); |
058 | for (i=0; i<n; i++) |
059 | printf("+----"); |
060 | printf("+\n"); |
061 | for (i=0; i<n; i++) { |
062 | printf(" |"); |
063 | for (j=0; j<n; j++) |
064 | printf("%4d|", *(Tab + i*n +j)); |
065 | printf("\n "); |
066 | for (j=0; j<n; j++) |
067 | printf("+----"); |
068 | printf("+\n"); |
069 | } |
070 | } |
071 | |
072 | int movimentoPossivel (unsigned char *Tab, int n, int lin, int col) { // movimento e' valido? |
073 | if (lin<0 || lin>=n) return 0; // fora do tabuleiro |
074 | if (col<0 || col>=n) return 0; // fora do tabuleiro |
075 | if (*(Tab + lin*n + col)>0) return 0; // posicao ja ocupada |
076 | return 1; |
077 | } |
078 | |
079 | int tentarEncontrarPasseio (unsigned char *Tab, int n, int lin, int col, int conta) { |
080 | int i, mx, my; |
081 | //D1 printf("\nconta=%d: (%d,%d)", conta-1, lin, col); // ultimo colocado na posicao (lin,col) |
082 | if (conta>n*n) { // ja' alocou todos os passeios => sucesso! |
083 | return 1; |
084 | } |
085 | for (i=0; i<8; i++) { |
086 | mx = lin+M[i][0]; |
087 | my = col+M[i][1]; |
088 | if (movimentoPossivel(Tab, n, mx, my)) { // registre o movimento "conta" na pos. (mx,my) |
089 | *(Tab + mx*n + my) = conta; |
090 | numeroTentativas++; |
091 | if (tentarEncontrarPasseio(Tab, n, mx, my, conta+1)) { // tenta completar o passeio |
092 | return 1; |
093 | } |
094 | else { // nao foi possivel completar o passeio a partir de "Tab[mx][my]==conta" => desfaz |
095 | //D1 printf("\n i=%d : desfaz (%d,%d)=%d", i, mx, my, *(Tab + mx*n + my)); |
096 | *(Tab + mx*n + my) = 0; // libere posicao |
097 | } |
098 | } // if movimento valido |
099 | } // for i |
100 | return 0; // fracasso => MAO conseguiu da posicao atual um movimento completo |
101 | } |
102 | |
103 | int main (int argc, char *argv[]) { |
104 | unsigned char *Tab; // tabuleiro - usar alocacao dinamica para nao precisar recompilar |
105 | int lin, col, n, sucesso, i, j; |
106 | if (argc!=4 && argc!=2) { |
107 | printf("Testa passeio do cavalo. Duas opcoes, supondo desejar rodar com tabuleiro 8x8:\n"); |
108 | printf(" - Para rodar tentando a partir de qualquer posicao:\n ./passeio_cavalo 8\n"); |
109 | printf(" - Para rodar iniciando na posicao (0,0), digitar:\n ./passeio_cavalo 8 0 0\n"); |
110 | return 1; |
111 | } |
112 | n = atoi(argv[1]); |
113 | |
114 | Tab = malloc(n * n * sizeof(unsigned char)); |
115 | |
116 | iniciaTabuleiro(Tab, n); |
117 | |
118 | sucesso = 0; |
119 | if (argc==2) { // Opcao 1: testar iniciando em todas os posicoes do tabuleiro |
120 | for (i=0; i<n; i++) { |
121 | if (sucesso) break; |
122 | for (j=0; j<n; j++) { |
123 | lin = i; col = j; |
124 | *(Tab + lin*n + col) = 1; // posicao inicial |
125 | if (tentarEncontrarPasseio(Tab, n, lin, col, 2)) { |
126 | printf("\n\n*** Passeio encontrado iniciando em (%d,%d)!", lin, col); |
127 | printf(" Apos tentar %ld vezes\n", numeroTentativas); |
128 | sucesso = 1; break; |
129 | } |
130 | else { |
131 | printf("Nao existe passeio iniciando na posicao (%d,%d)", lin, col); |
132 | printf(": tentei %8ld vezes!\n", numeroTentativas); |
133 | } |
134 | } |
135 | } |
136 | } // if (argc==2) |
137 | else { // Opcao 2: testar iniciando na posicao fornecida via linha de comando |
138 | lin = atoi(argv[2]); |
139 | col = atoi(argv[3]); |
140 | printf("Tabuleiro de dimensao %d, cavalo iniciando em (%d,%d)\n", n, lin, col); |
141 | *(Tab + lin*n + col) = 1; // posicao inicial |
142 | sucesso = tentarEncontrarPasseio(Tab, n, lin, col, 2); |
143 | } // else if (argc==2) |
144 | |
145 | if (sucesso) { |
146 | printf("\n*** Passeio encontrado iniciando-se em (%d,%d)! ", lin, col); |
147 | printf("Foram feitas %ld tentativas\n", numeroTentativas); |
148 | imprimeTabuleiro(Tab, n); |
149 | } |
150 | else |
151 | if (argc==4) { // Opcao 2: testar iniciando na posicao fornecida via linha de comando |
152 | printf("\nNao existe passeio iniciando na posicao (%d,%d)", lin, col); |
153 | printf("\nTentei %ld vezes!\n", numeroTentativas); |
154 | } |
155 | printf("\n"); |
156 | |
157 | free(Tab); |
158 | |
159 | return 0; |
160 | } |