Advertisement

Transposition table problems

Started by April 03, 2008 07:29 AM
12 comments, last by kluster 16 years, 10 months ago
Quote:
Original post by alvaro
Quote:
Original post by kluster
Yes you are right about the position/move thing, but in gomoku they are almost the same.

I don't think so. "Place a black stone on E6" is a move, not a position. A position is the whole configuration on the board. Looking at your code, it looks like you are making many copies of the board when you generate children. Instead, you could just generate the moves, and then you can just do and undo each move on the existing board, without any copies. This saves a lot of time and is not too hard to implement.

Quote:
Now Im calculation the Zobrist keys when Im generation the child-moves by XOR'ing the last
value with the new position.

I guess you mean "with the new move".
Quote:
Unfortunately, the TT-AI still playes different comparing to the AI without a TT. But the TT-part seems ok? that makes it even more confusing. Im pretty sure that the TT implementation works and all that stuff.

It looks reasonable to me. You may still have a bug somewhere that I haven't seen (or is in a part of the code that you haven't posted).

Even if you get rid of all the bugs, you shouldn't expect the program with the transposition table to play the exact same moves as the program without it. Transposition tables introduce a well-known nightmare called "search instability", which makes search results less reproducible and your program harder to understand in general. Well, this is true at least for chess and checkers; I haven't thought carefully about how this would affect a gomoku program.

You can (should) store the best move from this position in the transposition table, so even if later on you can't use the score you stored, you can still search that move first, which will improve your move ordering and therefore the efficiency of your alpha-beta search.

In general, you should pay attention to move ordering. It is not obvious from looking at your code if you have made any efforts in that direction.


I have made some drastic changes, and now the AI can't play at all.
I implemented negamax to make/undo moves instead of copy the whole board and
apply the new move the it. Perhaps I did't understand what you ment, can you spot
any errors directly by looking at this part of the code?

[SOURCE]int negamax(Position* pos, Move* bestMove, char player, int depth, int alpha, int beta) {	/* pos->value was generated for the other player, reversing the value. */	if (depth == 0 || pos->value == MAXSCORE) {			return -pos->value; 	} 	/* generate possible moves and evaluate them */	vector<Move*> *childs = getChilds(pos, player);		if (childs->empty()) {		return 0;	}	for (unsigned int i = 0; i < childs->size(); i++) {		int x = childs->at(i)->x;		int y = childs->at(i)->y;		int val = pos->value;		/* update value and set a new move */		pos->makeMove(childs->at(i));		int value = -negamax(pos, bestMove, player == RING ? CROSS: RING, depth-1, -beta, -alpha);		/* reset the value of the move to val, and make the position x,y free */ 		pos->undoMove(val, x, y);		if(value > alpha) {			if(value >= beta) {				bestMove->setInfo(x, y, pos->value, size);				return beta;			}			bestMove->setInfo(x, y, pos->value, size);			alpha = value;		}	}	return alpha;}[/SOURCE]



There are two things that confuse me in your code (and that might be wrong):
1) The way you are using bestMove.
2) What is "size"?

If you are using bestMove to try to collect the best move at the root, you are doing it all wrong. You are passing the same pointer around throughout the tree and any sub-search can set the value of bestMove, not just the root.

I recommend writing a separate function to search the root. This one can return the best move, it can perform iterative deepening, it can inform the user of the progress of the search...
Advertisement
Quote:
Original post by alvaro
There are two things that confuse me in your code (and that might be wrong):
1) The way you are using bestMove.
2) What is "size"?

If you are using bestMove to try to collect the best move at the root, you are doing it all wrong. You are passing the same pointer around throughout the tree and any sub-search can set the value of bestMove, not just the root./* update value and set a new move */
pos->makeMove(childs->at(i));


I recommend writing a separate function to search the root. This one can return the best move, it can perform iterative deepening, it can inform the user of the progress of the search...


Weee :)
thanks again for the support :)
I solved the problem by adding the the code:

[SOURCE]if(depth == maxDepth) {    bestMove->setInfo(x, y, pos->value, size);}[/SOURCE]


Size is the size of the board, i.e 15*15 for example.
I know it's unnecessary, I removed it.
Quote:
Original post by kluster
Quote:
Original post by alvaro
There are two things that confuse me in your code (and that might be wrong):
1) The way you are using bestMove.
2) What is "size"?

If you are using bestMove to try to collect the best move at the root, you are doing it all wrong. You are passing the same pointer around throughout the tree and any sub-search can set the value of bestMove, not just the root./* update value and set a new move */
pos->makeMove(childs->at(i));


I recommend writing a separate function to search the root. This one can return the best move, it can perform iterative deepening, it can inform the user of the progress of the search...


Weee :)
thanks again for the support :)
I solved the problem by adding the the code:

*** Source Snippet Removed ***[/source]

Size is the size of the board, i.e 15*15 for example.
I know it's unnecessary, I removed it.


I was wrong :(
AI does not want me to win. AI does not want to win either.
He blocks me from winning but nothing more.
What could be wrong?

This topic is closed to new replies.

Advertisement