15 #define rep(i, n) repb(i, 0, n)
16 #define repb(i, b, n) repbc(i, b, n, <)
17 #define repbc(i, b, n, c) for(int i = b; i c n; i++)
18 #define repe(i, n) repbe(i, 0, n)
19 #define repbe(i, b, n) repbc(i, b, n, <=)
20 #define reps(i, n) for(unsigned int i = 0; i < n.size(); i++)
22 #define getch do{ if(0)scanf("%*c"); }while(0)
24 #define INDEX(i, j) (((i) << 3) + (j))
25 #define DIAG0(i, j) ((i) + (j))
26 #define DIAG1(i, j) ((i) - (j) + 7)
30 char dx
[] = {0, 1, 1, 1}, dy
[] = {1, 0, 1, -1}; //direções de movimento: vertical, horizontal e duas diagonais
32 typedef bitset
<64> Imp
; //representação das peças de um dos jogadores
34 Imp both
, adj
; // both armazena o tabuleiro com a peças de um ou de outro jogador
35 // adj é utiliada para detectar quando algum jogador está em situação de vitória
36 // podem (vão) se tornar membros estáticos da classe Tab em vez de globais
38 char horiz
[8], vert
[8], diag
[2][15]; //quantidade de peças na horizontal, vertical e nas duas diagonais
40 /* converte um bitset correspondente a um tabuleiro para long long,
41 para facilitar comparação entre tabuleiros */
42 inline unsigned __int64
to_longlong(const Imp
&t
)
44 unsigned __int64 res
= 0;
47 res
|= ((unsigned __int64
) 1) << i
;
52 typedef pair
<unsigned __int64
, unsigned __int64
> TabComp
;
54 /* comparação para o set */
55 inline bool compareTabComp(const TabComp
& l
, const TabComp
& r
)
57 return l
.first
< r
.first
|| (l
.first
== r
.first
&& l
.second
< r
.second
);
60 /* Classe que representa um tabuleiro do jogo */
63 typedef bitset
<64> Imp
; //representação das peças de um dos jogadores
64 typedef pair
<char, char> Move
; //representação dos movimentos (origem, destino) em coordenadas absolutas [0,63]
66 typedef vector
<Move
> MoveList
; //Lista de movimentos
67 //OTI: Move[4 * 12] em vez de vector<Move> -- talvez não seja bom quando há poucas peças
71 inline Tab(const Tab
& tab
) { t
[0] = tab
.t
[0]; t
[1] = tab
.t
[1]; }
72 inline const Tab
& operator=(const Tab
& tab
) { t
[0] = tab
.t
[0]; t
[1] = tab
.t
[1]; return *this; }
74 /* há duas formas possíveis para os metodos set, reset e get:
75 uma que utiliza [] e outra que utiliza a função correspondente
76 estão aqui para testarmos qual é mais eficiente
77 [] não testa se o índice é válido, mas retorna uma referência para o valor
78 () teste se o índice é válido, mas retorna apenas um bool
81 inline void set(bool player
, char i
, char j
, bool val
= true) {
82 //t[player].set(INDEX(i, j), val);
83 t
[player
][INDEX(i
, j
)] = val
;
86 inline void reset(bool player
, char i
, char j
) {
87 //t[player].reset(INDEX(i, j));
88 t
[player
][INDEX(i
, j
)] = false;
91 inline bool get(bool player
, char i
, char j
) {
92 return t
[player
].test(INDEX(i
, j
)); //profiling
93 //return t[player][INDEX(i, j)];
101 /* print bonito do tabuleiro
102 pode receber o próximo movimento a ser feito
104 inline void print(Move move
= Move(-1, -1)) {
108 printf("p: %i\n", p);
111 printf("%i ", get(p, i, j));
118 Imp temp = t[0] | t[1];
121 printf("%i ", (bool) temp[INDEX(i, j)]);
127 char rep
[] = ".pb?PBxXX";
130 printf("%c", rep
[(get(0, i
, j
) ? 1 : get(1, i
, j
) ? 2 : 0) + 3 * (move
.first
== INDEX(i
, j
)) + 6 * (move
.second
== INDEX(i
, j
))]);
136 cout
<< "[0]: " << to_longlong(t
[0]) << "\n[1]: " << to_longlong(t
[1]) << endl
;
142 printf("%i ", horiz
[i
]);
147 printf("%i ", vert
[i
]);
152 printf("%i ", diag
[0][i
]);
157 printf("%i ", diag
[1][i
]);
163 /* coloca o tabuleiro na posição inicial */
164 void initial_position() {
172 /* retorna a quantidade de casas que a peça na posição (i, j) pode andar na direção d */
173 inline char count(int d
, char i
, char j
) {
174 //OTI: contar uma vez para cada linha, coluna e diagonal (8 + 8 + 15 + 15) em vez de 4 * 8 * 8
178 return vert
[(int) j
];
180 return horiz
[(int) i
];
182 return diag
[1][DIAG1(i
, j
)];
184 return diag
[0][DIAG0(i
, j
)];
196 //res += both[INDEX(x, y)];
197 res += both.test(INDEX(x, y)); //profiling
205 //res += both[INDEX(x, y)];
206 res += both.test(INDEX(x, y)); //profiling
208 //return res - both[INDEX(i, j)];
209 return res - both.test(INDEX(i, j));//*/
212 /* coloca em moves as jogadas possíveis na posição atual pelo jogador player */
213 void valid_moves(bool player
, MoveList
&moves
) {
216 horiz
[i
] = vert
[i
] = 0;
218 diag
[0][i
] = diag
[1][i
] = 0;
223 if(both
.test(INDEX(i
, j
))) {
226 diag
[0][DIAG0(i
, j
)]++;
227 diag
[1][DIAG1(i
, j
)]++;
237 if(get(player
, i
, j
)) {
240 //printf("\n(k, d, i, j) = (%i, %i, %i, %i)\n", k, d, i, j);
248 //printf("(x, y) = (%i, %i) out of tab!\n", x, y);
252 if(get(!player
, x
, y
)) {
253 //printf("(x, y) = (%i, %i) enemy!\n", x, y);
263 //printf("(x, y) = (%i, %i) out of tab!\n", x, y);
264 } else if(get(player
, x
, y
)) {
265 //printf("(x, y) = (%i, %i) over own piece!\n", x, y);
267 //printf("(x, y) = (%i, %i) valid move!\n", x, y);
268 moves
.push_back(Move(INDEX(i
, j
), INDEX(x
, y
)));
278 //printf("(x, y) = (%i, %i) out of tab!\n", x, y);
282 if(get(!player
, x
, y
)) {
283 //printf("(x, y) = (%i, %i) enemy!\n", x, y);
293 //printf("(x, y) = (%i, %i) out of tab!\n", x, y);
294 } else if(get(player
, x
, y
)) {
295 //printf("(x, y) = (%i, %i) over own piece!\n", x, y);
297 //printf("(x, y) = (%i, %i) valid move!\n", x, y);
298 moves
.push_back(Move(INDEX(i
, j
), INDEX(x
, y
)));
305 /* efetua o movimento move pelo jogador player */
306 inline void move(bool player
, Move move
) {
307 t
[player
][move
.first
] = t
[!player
][move
.second
] = 0;
308 t
[player
][move
.second
] = 1;
311 /* testa se o jogo terminou */
314 return t
[0].count() < 2 || t
[1].count() < 2 ||
318 /* test se o jogador player está com todas as suas peças adjacentes */
319 inline bool win(bool player
) {
323 if(get(player
, i
, j
)) {
325 bool res = adjacent(player, i, j) == t[player].count();
327 //printf("win(%i)!!\n", player);
329 //printf("win(%i)!!\n", player);
334 return adjacent(player
, i
, j
) == t
[player
].count();
340 /* função para determinar se as peças do jogador player estão adjacentes, partindo
341 da peça na posição (i, j) */
342 inline unsigned char adjacent(bool player
, char i
, char j
) {
343 static int adjdx
[] = {-1, -1, -1, 0, 0, 1, 1, 1},
344 adjdy
[] = {-1, 0, 1, -1, 1, -1, 0, 1};
347 adj
.set(INDEX(i
, j
));
352 if(x
> 7 || x
< 0 || y
> 7 || y
< 0) continue;
353 if(adj
.test(INDEX(x
, y
)) || !get(player
, x
, y
)) continue;
354 res
+= adjacent(player
, x
, y
);
361 Imp t
[2]; //t[i] representa o tabuleiro somente com as peças do jogador i
364 /* conjunto dos tabuleiros que já foram visitados
365 utilizado para determinar quando estamos no mesmo tabuleiro pela segunda vez
366 colocar os unsigned _int64 correspondentes aos tabuleiros facilita a comparação
368 set
<TabComp
, bool(*)(const TabComp
&, const TabComp
&)> tabSet
[13][13];
370 /* número de tabuleiros pesquisados */
373 /* efetua todos as jogadas possíveis pelo jogador player no tabuleiro tab,
374 chamando-se recursivamente, até uma certa profundidade */
375 void search(bool player
, Tab tab
, int depth
= 0) {
383 if(depth
> MAX_DEPTH
) return;
388 moves
.reserve((tab
.t
[0].count() + tab
.t
[1].count()) * 2); //reserva o dobro do numero de peças vivas
389 tab
.valid_moves(player
, moves
);
393 for(unsigned int i = 0; i < moves.size(); i++)
394 printf("(%i, %i) ", moves[i].first, moves[i].second);
397 unsigned char end
= moves
.size();
398 for(unsigned char i
= 0; i
< end
; i
++) {
401 rep(j
, depth
) printf(".");
402 printf("%2i / %2i\n", i
, end
);
403 //if(!depth) system("pause");
405 //printf("%4i:%4i\n", depth, i);
409 //temp.print(moves[i]);
411 temp
.move(player
, moves
[i
]);
412 pair
<set
<TabComp
>::iterator
, bool> res
= tabSet
[temp
.t
[0].count()][temp
.t
[1].count()].insert(
413 TabComp(to_longlong(temp
.t
[0]),
414 to_longlong(temp
.t
[1])));
416 //printf("!!!!!!!!!!!!!!!!!!!!!!!!!!");
421 search(!player
, temp
, depth
+ 1);
428 printf("size tab: %i\n", sizeof(tab
));
432 tabSet
[i
][j
] = set
<TabComp
, bool(*)(const TabComp
&, const TabComp
&)>(compareTabComp
);
434 tab
.initial_position();
440 tab.set(1, 0, 0);//*/
441 tabSet
[tab
.t
[0].count()][tab
.t
[1].count()].insert(
442 TabComp(to_longlong(tab
.t
[0]), //.to_string<char, char_traits<char>, allocator<char> >()
443 to_longlong(tab
.t
[1])));
448 printf("nSearch: %i; tabSet.size(): %i\n", nSearch
, tabSet
[12][12].size());
449 printf("clock(): %li", clock());
450 printf("rand: %i\n", RAND_MAX
);
458 http://en.wikipedia.org/wiki/Killer_heuristic
459 http://en.wikipedia.org/wiki/Negascout
460 http://en.wikipedia.org/wiki/MTD-f
461 http://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search
462 http://en.wikipedia.org/wiki/Best_first_search
463 http://en.wikipedia.org/wiki/Branch_and_bound
464 http://en.wikipedia.org/wiki/Transposition_table
465 http://en.wikipedia.org/wiki/Zobrist_hashing
466 https://www.cs.wisc.edu/techreports/1970/TR88.pdf
467 http://www.personeel.unimaas.nl/m-winands/loa/
471 * funcao de avaliação
473 * n peças adjacentes -> n!
474 * distância para o centro do tabuleiro
475 * ordenação (best first)
476 * tabela de transposicao
480 * pensar na vez do adversário