Pretty sure nobody is saying the time complexity is feasible, so let's not argue about that. But RoundTower and I are saying that if you gave the search algorithm an unlimited amount of time to run, it would eventually find the optimal move from any given position. And furthermore it could be implemented to run in a modest amount of memory. That's the part that might be surprising so I'll try to explain how depth first search works.
From the opening position, white has 20 possible moves. A depth first search completes its evaluation for each move before moving on to the next candidate. So once it evaluates 1. a3 as either a win, a loss, or a draw, it no longer needs to store the 1. a3 subtree in memory. It then moves on to 1. a4.
You might say, ok fine so it only has to store 1/20th of the game tree in memory at a time. That's still ridiculously huge and it won't fit in memory. But depth first search is recursive, and the space savings apply at every level of the game tree, not just the top level. A depth first evaluation of any non-terminal position involves performing a depth first search on each possible move from that position, and returns the most favorable of those evaluations for the side to move. So when evaluating the 1. a3 subtree, a depth first search will be applied to each of black's 20 responses. Once 1. a3 a6 has been evaluated, that subtree is no longer stored in memory and the search moves on to 1. a3 a5.
Time complexity increases exponentially with each ply of lookahead. But due to the way memory is freed up after each subtree's evaluation, memory usage only increases linearly as search depth increases. Only one subtree from any given node is ever expanded. I've included skeleton code for depth first search in Java (no I haven't compiled and run it, it's skeleton code because it would rely on the existence of other functions and data structures that I haven't actually written, but I think the names make clear what those would be).
A few obvious ways this could be improved, like it doesn't use alpha/beta pruning which any real chess program would. And as written it wouldn't prefer a mate in 3 over a mate in 50, as long as there's a forced mate. It also doesn't return which move is the best move from a given position, only the position's evaluation. So if you want to know the best move, you'd call depthFirst on the position resulting from each possible move and compare the evaluations.
Code:
int depthFirst(boolean whiteToMove) {
if (isMate()) {
if (whiteToMove) return -1; // black won
return 1; // white won
}
if (isDraw()) return 0;
// otherwise not a terminal position
int bestScore;
// initialize bestScore to unfavorable value for side to move
if (whiteToMove)
bestScore = -1000;
else
bestScore = 1000;
for (int i = 0; i < moveList.length; i++) {
doMove(moveList[i]);
int score = depthFirst(!whiteToMove);
if ((whiteToMove && score > bestScore) || (!whiteToMove && score < bestScore))
bestScore = score;
undoMove();
}
return bestScore;
}