示例#1
0
/*
 * Returns the maximum value from a tree.
 */
double maxVal(double alpha, double beta, struct State *state, int depth)
{
    int x;
    struct State newState;

    /* If we've reached the depth limit then evaluate this node and return its
     * value. */
    if (depth <= 0)
    {
        return evaluateBoard(state);
    }
    --depth;    /* descend one level in the tree */

    FindLegalMoves(state);

    /* Walk the move list and find the best one. */
    for (x=0; x<state->numLegalMoves; ++x)
    {
        /* Check to see if this thread has been cancelled before moving on. */
        pthread_testcancel();

        /* Copy the current board state. */
        memcpy(&newState, state, sizeof(struct State));

        /* Perform a move on the copied state. */
        PerformMove(newState.board, 
                    newState.movelist[x],
                    MoveLength(newState.movelist[x]));

        /* Toggle the current player. */
        newState.player = (newState.player == 1) ? 2 : 1;

        /* Perform a depth limited MiniMax search for the best move.
         * Uses Alpha-Beta pruning. */
        alpha = MAX(alpha, minVal(alpha, beta, &newState, depth));

        if (alpha >= beta)
        {
            return beta;
        }
    }

    return alpha;
}
示例#2
0
int alphaBeta(int depth, int alpha, int beta, bool whiteToPlay)
{
	int val, i;
	EVALUATE_INFO_t eval = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	uint32_t legalMoves = 0;
	PIECE_t pieceBackup;
	PIECE_e piece;
	
#if ENABLE_TRANSPOSITION_TABLE
	int hashFlag = ALPHA_HASH_RESULT;
	if (val = probeHash(depth, alpha, beta) != UNKNOWN_HASH_RESULT)
	{
		cacheHits++;
		return val;
	}
	else
	{
		cacheMisses++;	
	}
	
#endif // ENABLE_TRANSPOSITION_TABLE
	
	// calculate all of the moves
	MOVE_t moves[MOVE_LIST_SIZE];
	legalMoves += AddAllLegalMovesToMoveList(moves, &eval, whiteToPlay);

	if (!legalMoves && depth == currentDepth)
	{
		printf("pass");
		exit(0);
	}
	
	if (depth == 0)
	{
		numberEvaluations++;
		AddAllLegalMovesToMoveList(&moves[legalMoves-1], &eval, !whiteToPlay);
		val = evaluateBoard(&eval);
#if ENABLE_TRANSPOSITION_TABLE
		recordHash(depth, val, EXACT_HASH_RESULT);
#endif //ENABLE_TRANSPOSITION_TABLE
		if (!whiteToPlay)
			val = val * -1;
		return val;
	}

	numberNodes++;
	// for each move
	for (i = 0; i < legalMoves; i++)
	{
		// backup piece so we can undo the move later
		piece = (moves[i].move & PIECE_MASK) >> PIECE_SHIFT;
		pieceBackup.piece = pieces[piece].piece;
		
		// play the  move
		playMove(moves, i);
		
		// Check to see if this position is a win
		val = isWin();
		
		if (!whiteToPlay)
		{
			val = val*-1;
		}

		if (val > DRAW_SCORE)
		{
			val = val + depth;
		}
		else if (val < 0)
		{
			val = val - depth;
		}
		else if (val == DRAW_SCORE)
		{
			val = 0;
		}
		else 
		{
			// not a win or draw; search deeper
			//val = alphaBeta(depth - 1, alpha, beta, !whiteToPlay);
			val = -alphaBeta(depth - 1, -beta, -alpha, !whiteToPlay);	
		}
		
		// undo move
		undoMove(pieceBackup, piece);
		
		// alpha beta pruning:

		if (val >= beta)
		{
#if ENABLE_TRANSPOSITION_TABLE
			recordHash(depth, beta, BETA_HASH_RESULT);
#endif //ENABLE_TRANSPOSITION_TABLE			
			return beta;
		}
		if (val > alpha)
		{
			alpha = val;
			if (depth == currentDepth)
			{
				currMove.move = moves[i].move;				
				currentScore = val;
			}
#if ENABLE_TRANSPOSITION_TABLE
			hashFlag = EXACT_HASH_RESULT;
#endif //ENABLE_TRANSPOSITION_TABLE			
		}
	}
	

#if ENABLE_TRANSPOSITION_TABLE
		recordHash(depth, alpha, hashFlag);
#endif //ENABLE_TRANSPOSITION_TABLE		
	return alpha;
}
示例#3
0
void readInputFile(const char *fileName) {
	// Variables we'll need

	FILE *inputFile = null;

	char buffer[80];

	char fromXChar, toXChar;
	char fromYChar, toYChar;

	int got;

	int x, y;

	// Open the input file

	inputFile = fopen(fileName, "r");

	if (inputFile == null) {
		printf("Unable to open input file: '%s'", fileName);
		printf("Error number %d.\n", errno);
		exit(1);
	}

	// Get the first line

	fgets(buffer, 80, inputFile);

	got = sscanf(buffer, "%d %d %d", &me, &boardHeight, &boardWidth);	// Read in the first line

	if (got != 3) {
		printf("Error reading in first line of input.\n");
		exit(1);
	}

	if (DEBUG)
		printf("I'm player %d, board is %dx%d.\n", me, boardWidth, boardHeight);

	// Now that we know the board size, we need to allocate the board
	
	gameBoard = malloc(boardWidth * boardHeight * sizeof(int));
	memset(gameBoard, 0, boardWidth * boardHeight * sizeof(int));

	if (gameBoard == null) {
		printf("Unable to allocate game board.\n");
		exit(1);
	}

//	if (DEBUG) {	// This prints out any spaces that aren't 0 as they should be
//		for (y = 0; y < boardHeight; y++) {
//			for (x = 0; x < boardWidth; x++) {
//				if (gameBoard[xyToIndex(x, y)] != 0)
//					printf("%d, %d was %d\n", x, y, gameBoard[xyToIndex(x, y)]);
//			}
//		}
//	}

//	if (DEBUG)
//		printBoard(gameBoard);

	// Get the second line

	fgets(buffer, 80, inputFile);

	got = sscanf(buffer, "1 %d %lf", &playerOneScore, &playerOneTimeLeft);	// Read in player info

	if (got != 2) {
		printf("Error reading in second line of input.\n");
		exit(1);
	}

	if (DEBUG)
		printf("Player 1 has %d points and %lf seconds.\n", playerOneScore, playerOneTimeLeft);

	// Get the third line

	fgets(buffer, 80, inputFile);

	got = sscanf(buffer, "2 %d %lf", &playerTwoScore, &playerTwoTimeLeft);

	if (got != 2) {
		printf("Error reading in third line of input.\n");
		exit(1);
	}

	if (DEBUG)
		printf("Player 2 has %d points and %lf seconds.\n", playerTwoScore, playerTwoTimeLeft);

	// Now get the rest of the lines

	while (true) {
		int player, from_y, to_y, from_x_num, to_x_num;
		char from_x, to_x;

		if (!fgets(buffer, 80, inputFile)) {	// Get the next line
			if (feof(inputFile)) {
				break;
			} else {
				printf("Error reading line from the file: '%s'.\n", buffer);
				printf("Error number %d.\n", ferror(inputFile));
				exit(1);
			}
		}

		buffer[7] = '\0';	// Cover up the newline

		got = sscanf(buffer, "%d %c%d %c%d", &player, &from_x, &from_y, &to_x, &to_y);

		if (got != 5) {
			printf("Error reading line from the file: '%s'.\n", buffer);
			printf("Only parsed out %d things.\n", got);
			exit(1);
		}

		from_x_num = charToColumn(from_x);
		to_x_num = charToColumn(to_x);
		from_y = from_y - 1;
		to_y = to_y - 1;

		if (DEBUG) {
			printf("Player %d made a move from %d, %d to %d, %d.\n", player, from_x_num, from_y, to_x_num, to_y);
		}

		runMove(player, from_x_num, from_y, to_x_num, to_y, false, gameBoard);
//		printBoard();
	}

	if (DEBUG) {
		boardEvaluation *temp;
		
		printBoard(gameBoard);	// Show the board
		
		temp = evaluateBoard(gameBoard, null);	// Figure out the counts

		printf("Boxes with no lines:     %d\n", temp->noSides);		// Print out the counts
		printf("Boxes with one line:     %d\n", temp->oneSides);
		printf("Boxes with two lines:    %d\n", temp->twoSides);
		printf("Boxes with three lines:  %d\n", temp->threeSides);
		printf("Boxes owned by player 0: %d\n", temp->playerOtherOwned);
		printf("Boxes owned by player 1: %d\n", temp->playerOneOwned);
		printf("Boxes owned by player 2: %d\n", temp->playerTwoOwned);
		printf("Winner is: ");

		if (temp->winner == PLAYER_ONE)
			printf("Player 1\n");
		else if (temp->winner == PLAYER_TWO)
			printf("Player 2\n");
		else if (temp->winner == PLAYER_TIE)
			printf("Game was a tie\n");
		else if (temp->winner == NO_WINNER_YET)
			printf("None yet\n");
		else {
			printf("Unknown winner for board: %d\n", temp->winner);
			exit(1);
		}
		
		printf("\n");

		free(temp);									// Free the object that was given to us
	}

	// That takes care of all input, so close the file.

	fclose(inputFile);

	// Set some quick stuff up

	if (me == 1) {
		him = 2;
		ourScore = &playerOneScore;
		ourTime = &playerOneTimeLeft;
		hisScore = &playerTwoScore;
		hisTime = &playerTwoTimeLeft;
	} else {
		him = 1;
		hisScore = &playerOneScore;
		hisTime = &playerOneTimeLeft;
		ourScore = &playerTwoScore;
		ourTime = &playerTwoTimeLeft;	
	}
}
示例#4
0
void selectMove() {
	// First, the two variables we'll use

	int i;
	double bestScore;
	int bestIndex;
	int bestCount;
	int *tempBoard;
	boardEvaluation *tempEval;

	tempBoard = malloc(boardWidth * boardHeight * sizeof(int));

	if (tempBoard == null) {
		printf("Unable to allocate space for a temporary game board.\n");
		exit(1);
	}

	// A sanity check

	if (possibleMovesFound == 0) {
		printf("Error! No possible moves found!\n");
		printBoard(gameBoard);
		exit(1);
	}

	// Now the real work

	bestScore = -7.0;	// Lower than the lowest possible score
	bestIndex = -1;
	bestCount = -1;

//	i = rand() % possibleMovesFound;

	for (i = 0; i < possibleMovesFound; i++) {
		// First, get us a temporary copy of the current game board

		copyBoard(gameBoard, tempBoard);

		// Now, run the trial move on it

		runMoveWithStruct(me, possibleMoves[i], tempBoard);

		// Now, evaluate it

		tempEval = evaluateBoard(tempBoard, possibleMoves[i]);

		// Now, score it

		possibleMoves[i]->score = scoreEvaluation(tempEval);

		// Now free that evaluation

		free(tempEval);

		// Now, see if it is the best one we've found

		if (possibleMoves[i]->score == 7.0) {		// We found a winner, no need to score the rest
			bestIndex = i;
			bestCount = 1;
			break;
		} else if (possibleMoves[i]->score > bestScore) {
			bestCount = 1;
			bestScore = possibleMoves[i]->score;
			bestIndex = i;
		} else if (possibleMoves[i]->score == bestScore) {	// If the scores are the same...
			bestCount++;									// Make a random choice between them
			if ((float) rand() / RAND_MAX <= ((double) (1.0 / (double) bestCount))) {
				bestIndex = i;		// Note, this is biased towards the front
			}
		}
	}

	// Set up the move

	copyMove(possibleMoves[bestIndex], &finalMove);

	free(tempBoard);
}
示例#5
0
/// Returns the best available move for \a player according to evaluateBoard()
/// after considering a search tree of depth \a depth.
///
/// Precondition for outside callers: \a depth >= 1
std::pair<Candidate, bool> Opponent::bestMove(Board const& board, int depth, Square player, QElapsedTimer const& timer)
{
    assert(depth > 0);

    if (timer.elapsed() > timeOut) {
        return std::make_pair(Candidate{}, true);
    }

    if (player == O) {
        // try every move and use the best one
        Point move;
        Score score = -std::numeric_limits<Score>::max();

        for (int r = 0; r != board.rows(); ++r) {
            for (int c = 0; c != board.rows(); ++c) {
                if (board(r, c) == Blank) {
                    Board future{board};
                    future(r, c) = player;

                    Score futureScore;
                    if (depth == 1 || future.full()) {
                        // we're not going to look further or there's no further to look
                        futureScore = evaluateBoard(future);
                    } else {
                        std::pair<Candidate, bool> result = bestMove(future, depth - 1, switchPlayer(player), timer);
                        if (result.second == true) {
                            // time out
                            return result;
                        }
                        futureScore = result.first.score;
                    }

                    if (futureScore > score) {
                        move = Point{r, c};
                        score = futureScore;
                    } else if (futureScore == score) {
                        // prefer central squares when scores are equal
                        if (distanceToCenter(move, board.rows()) > distanceToCenter(Point{r, c}, board.rows())) {
                            move = Point{r, c};
                            score = futureScore;
                        }
                    }
                }
                // if we have won, there's no point looking for better moves
                if (score > winScore) {
                    return std::make_pair(Candidate{move, score}, false);
                }
            }
        }
        return std::make_pair(Candidate{move, score}, false);
    } else if (player == X) {
        // player is expected to pick the worst move from O's perpective
        Point move;
        Score score = std::numeric_limits<Score>::max();

        for (int r = 0; r != board.rows(); ++r) {
            for (int c = 0; c != board.rows(); ++c) {
                if (board(r, c) == Blank) {
                    Board future{board};
                    future(r, c) = player;

                    Score futureScore;
                    if (depth == 1  || future.full()) {
                        // we're not going to look further or there's no further to look
                        futureScore = evaluateBoard(future);
                    } else {
                        std::pair<Candidate, bool> result = bestMove(future, depth - 1, switchPlayer(player), timer);
                        if (result.second == true) {
                            // time out
                            return result;
                        }
                        futureScore = result.first.score;
                    }

                    if (futureScore < score) {
                        move = Point{r, c};
                        score = futureScore;
                    } else if (futureScore == score) {
                        // expect player to prefer central squares when scores are equal
                        if (distanceToCenter(move, board.rows()) > distanceToCenter(Point{r, c}, board.rows())) {
                            move = Point{r, c};
                            score = futureScore;
                        }
                    }
                    // if player has won, there's no point looking for worse moves
                    if (score < -winScore) {
                        return std::make_pair(Candidate{move, score}, false);
                    }
                }
            }
        }
        return std::make_pair(Candidate{move, score}, false);
    } else {
        assert(false);
    }
}
示例#6
0
文件: ttt.c 项目: bicepjai/mypuzzles
pair chooseMoveEvaluate (int* iboard, int player) {
    ASSERT(player == XPL || player == OPL);
    
    pair myBest = {0,-1};
    pair reply;
    int i, move;
    int moveCount=0, moveList[9];

    //default score
    if(player == US){
        myBest.score = INT_MIN;
    } else {
        myBest.score = INT_MAX;
    }

    timesCalled++;
    pair temp;
    temp.score = 0;
    temp.move = -1;    
    if(didHeWin(iboard,US)) {
        //printf("%c WON\n",US);
        //printf("=====returning{1}====================\n");
        //printboard(iboard);
        //temp.score = 10+timesCalled;
        temp.score = evaluateBoard(iboard);
        return temp;
    } else if(didHeWin(iboard,THEM)) {
        //printf("%c WON\n",THEM);
        //printf("=====returning{-1}====================\n");
        //printboard(iboard);
        //temp.score = -10-timesCalled;
        temp.score = evaluateBoard(iboard);        
        return temp;
    } else if(isBoardFull(iboard)) {
        //printf("FULL\n");
        //printf("=====returning{0}====================\n");
        //temp.score = 0;
        return temp;
    }
    
    // get legal moves
    for(i = 0; i < 9; i++) {
        if( iboard[convert9To25[cellScoreOrdered[i]]] == EMPTY) {
            moveList[moveCount++] = convert9To25[cellScoreOrdered[i]];
        }
    }

    // for(i = 0; i < 9; i++) {
    //     if( iboard[convert9To25[i]] == EMPTY) {
    //         moveList[moveCount++] = convert9To25[i];
    //     }
    // }

    // any legal move
    //myBest.move = pickValuedMove(moveList,moveCount);
    //printf("Move by %c;*********************************************\n",player);
    //for(i=0; i < moveCount; i++) {
        //printf("%d ", moveList[i]);
    //}
    //printf("\n");
    for(i=0; i < moveCount; i++) {
        move = moveList[i];
        iboard[move] = player;
        //printf("%c(to move(%d/%d) %d);best:%d ;reply:%d \n", 
        //    player,i+1,moveCount,move,myBest.score,reply.score);
        //printboard(iboard);
        reply = chooseMove(iboard, otherPlayer(player));
        iboard[move] = EMPTY;
        //printf("RESET %c(to move(%d/%d) %d);best:%d ;reply:%d \n", 
        //    player,i+1,moveCount,move,myBest.score,reply.score);
        if( // maximizinf by selecting opponents less score
            (player == US && myBest.score < reply.score) ||
            // minimizing by letting them select high score
            (player == THEM && myBest.score > reply.score)){
        //    printf("%c SCORE CHANGED (score:%d, best move:%d)!!\n",
        //        player,reply.score,move);
            myBest.score = reply.score;
            myBest.move = move;
        }
    }
    return myBest;
}
示例#7
0
/**
* Ermittelt den besten Zug aus der uebergebenen Stellung.
*
* from = Poistionsindex des Start des Zugs, to = Ziel
* bestEval = die beste ermittelte Bewertung
* bestEvalAdding = zusätzliche Bewertung die genutzt werden kann, um gleichbewertete Zuege zu priorisieren
* depth = die aktuelle Zugtiefe
*/
void aiDeepSearch(struct GameState *gameState, char *from, char *to, int *bestEval, int *bestEvalAdding, char depth) {
	short movesCounter;
	char moves[28 * 16 * 2]; // keine Initialiserung!
	struct GameState gs;

	if (depth == 0 && autoMode) printBoard((*gameState).board, 0, 0);

	// Erzeuge lokale Kopie des GameState der beliebig veraendert werden kann:
	copyGameState(gameState, &gs); 

	// Erzeuge Zuege:
	generateMoves(&gs, moves, &movesCounter);

	// Zunaechst alle Zuege auf Gueltigkeit (Schach) untersuchen.
	// Ungueltige Zuege aussortieren.
	short move;
	short found = 0; // gefundene gueltige Zuege
	int eval = 0;
	int evalAdding = 0;
	*bestEval = -valueCheckMate; // valueCheckMate bedeutet: Der bewertende Spieler ist Schachmatt/Patt
	//*bestEvalAdding = 0;
	for (move = 0; move < movesCounter; move += 2) {
		short pieceFrom = gs.board[moves[move]];
		short pieceTo = gs.board[moves[move + 1]];

		// Testzug machen:
		//printDev("Betrachte Zug %i  von %i (%i) nach %i (%i).\n", move, moves[move], pieceFrom, moves[move+1], pieceTo);
		doMovePartial(&gs, moves[move], moves[move + 1]);

		if (isCheck(&gs)) { // Eigener Koenig unter Schach?
			//printDev("Ausortierter Zug %i von %i nach %i da Schachgebot von: %i\n", move, moves[move], moves[move+1], isCheck(&gs));
			// derzeit: nichts tun
		} else {
			found++;

			if (depth >= maxDepth) {
				eval = evaluateBoard(gs.board);
				evalAdding = 0;
				if (gs.turnNumber % 2 == 1) eval *= -1; // ist der Spieler, der am Zug ist, schwarz, die Bewertung umdrehen (da sie immer aus Sicht von Weiss erfolgt)
				//printDev("Betrachte Zug %i von %i nach %i. Bewertung: %i\n", move, moves[move], moves[move+1], eval);
			} else {
				gs.turnNumber++; // Zugnummer erhoehen damit der naechste Spieler am Zug ist
				char rfrom = 0; // der Wert wird nicht benoetigt
				char rto = 0;
				aiDeepSearch(&gs, &rfrom, &rto, &eval, &evalAdding, depth + 1);		

				eval *= -1; // NegaMax-Algorithmus: Die Bewertung umdrehen. Aus der Sicht des Spielers, der in dieser Funktion gerade berechnet wird, ist der andere Spieler der Gegner und ein gutes Ergebnis von ihm fuer ihn selber schlecht.
				evalAdding *= -1;
				gs.turnNumber--;

				if (debugMode && depth == 0) {
					if (pieceTo == 0) {
						printDev("[%3.0f%%] Deep Search: Zug mit %c von %i nach %i. Bewertung: %6i\n", ((double) move / (double) movesCounter) * 100, getPieceSymbolAsChar(pieceFrom), moves[move], moves[move+1], eval);
					} else {
						printDev("[%3.0f%%] Deep Search: Zug mit %c von %i nach %i und schlaegt %c. Bewertung: %6i\n", ((double) move / (double) movesCounter) * 100, getPieceSymbolAsChar(pieceFrom), moves[move], moves[move+1], getPieceSymbolAsChar(pieceTo), eval);
					}
				}
			}

			// Schlagzuege unterhalb der tiefsten Ebene (Evaluationsebene) werden minimal vorteilhaft bewertet.
			// Der Grund dafuer ist, dass es sonst zu Situationen kommen kann, in denen die KI zwar schlagen kann,
			// was auch vorteilhat waere im Sinne der Bewertung, es aber nicht tut.
			// Warum nicht? Weil in diesen Situationen die KI sieht, dass die eine Figur sicher schlagen kann, und zwar
			// innerhalb ihres ganzen Horizonts. Es ist dann aus Sicht der KI egal, ob sie die Figur diese oder naechste Runde schlaegt.
			// Aber es kann sein, dass die KI die Situation in der naechsten Runde wiede so bewertet und das Schlagen
			// immer auf einen zukuenftigen Zeitpunkt verschiebt. Deshalb wird das schlagen minimal positiv bewertet.
			if (pieceTo != 0) evalAdding += pow(2, maxDepth + 1 - depth);

			if (eval > *bestEval || (eval == *bestEval && evalAdding > *bestEvalAdding)) {
				if (debugMode && depth == 0) printDev("Dieser Zug hat nun die beste Bewertung.\n");
				*bestEval = eval;
				*bestEvalAdding = evalAdding;
				*from = moves[move];
				*to = moves[move + 1];
			}
		}

		// Zug rueckgaengig machen:
		gs.board[moves[move]] = pieceFrom;
		gs.board[moves[move + 1]] = pieceTo;

		//if (eval > valueCheckMate) {
		//	printDev("Checkmate-Cutoff!\n");
		//	break;
		//} 
	}

	// Wenn ich keine gueltigen Zuege habe, bin ich schachmatt oder patt.
	// Daher auf Schach pruefen: Besteht kein Schach, dann bin ich patt.
	// In diesem Fall gebe ich anstatt -valueCheckMate (=Schachmatt) als Bewertung 0 zurueck.
	// Damit weiss der Spieler, der vor mir am Zug ist, zwar nicht genau, dass es ein Patt ist.
	// Das ist aber irrelevant.
	if (found == 0) {
		if (isCheck(&gs) == 0) *bestEval = 0;
	}
}
示例#8
0
/**
* Hauptmethode
*/
int main(int argc, char *argv[]) {
	hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	char o;
	char boardMode = 0; // 0/1
	char fullScreen = 1;
	char from[] = "??";
	char to[] = "??";
	char filename[255];
	char moves[28 * 16 * 2]; // keine Initialiserung!
	short movesCounter = 0;
	short board[120];
	int eval;
	int okay;
	int i;

	struct GameState gameState;
	struct GameState gameStateCopy;
	createStartBoard(board);
	setGameState(&gameState, board, 0, 3, 4);

	srand((unsigned int) time(NULL));  // Zufallsgenerator initialisieren

	if (fullScreen) system("cls");

	do {
		printf("\nSpieler: %i, Halbzug: %i\n", gameState.turnNumber % 2, gameState.turnNumber);
		printBoard(gameState.board, 0, boardMode);

		COLOR(128);
		printf("\n> Kommando:");
		COLOR(COLOR_DEFAULT);
		printf(" ");
        scanf("%c", &o); // Auf Char scannen
        fflush(stdin);

        if (fullScreen && o != 'm') system("cls");

        switch (o) {
        	case 'x':
        		// "magic" move - alles ist moeglich. Auch, Fehler zu produzieren.
        	case 'm':
        		printf("Zug von: ");
        		scanf("%s", from);
        		fflush(stdin);

        		printf("Zug nach: ");
        		scanf("%s", to);
        		fflush(stdin);

        		if (strlen(from) != 2 || strlen(to) != 2) {
        			printError("Ungueltige Koordinaten!\n");
        		} else {
        			autoSave(&gameState);
        			if (o == 'x') {
						doMovePartial(&gameState, convertCoordToIndex(from), convertCoordToIndex(to));
						doMoveFinal(&gameState, convertCoordToIndex(from), convertCoordToIndex(to));
        			} else {
        				if (doUserMove(&gameState, convertCoordToIndex(from), convertCoordToIndex(to))) system("cls");
        			}
        		}
        		break;
        	case 'n':
        		gameState.turnNumber--;
				printInfo("Zug zurueck.\n");
        		break;
        	case 'a':
        		do {
        			autoSave(&gameState);
        			okay = aiMove(&gameState, 0);
        		} while (autoMode && okay && ((gameState.turnNumber % 2 == 0 && gameState.ai0) || (gameState.turnNumber % 2 == 1 && gameState.ai1)));
        		break;
        	case 'c':
        		printInfo("Schach: %i\n", isCheck(&gameState));
        		break;
        	case 'h':
        		printHistory();
        		break;
        	case 'g':
        		generateMoves(&gameState, moves, &movesCounter);
        		printInfo("%i moegliche Zuege (ohne Beruecksichtigung von Schach).\n", movesCounter / 2);
				for (i = 0; i < movesCounter; i += 2) {
					printf("Zug mit %i von %i nach %i.\n", gameState.board[moves[i]], moves[i], moves[i + 1]);
				}
        		break;
        	case 'v':
        		eval = evaluateBoard(gameState.board);
        		printInfo("Evaluation (aus Sicht von weiss): %i\n", eval);
        		break;
        	case 't':
        		copyGameState(&gameState, &gameStateCopy);
    			okay = aiMove(&gameStateCopy, 3);
        		break;
        	case 'o':
        		okay = loadOpeningBookMove(&gameState, from, to);
        		if (okay) {
        			printInfo("Zugvorschlag aus dem Eroeffnungsbuch: mit %c von %s nach %s", getPieceSymbolAsChar(gameState.board[convertCoordToIndex(from)]), from, to);
        		} else {
        			printInfo("Das Eroeffnungsbuch enthaelt keinen passenden Zug!");
        		}
        		break;
        	case 's':
        		saveGame(&gameState, "quicksave", 1);
        		break;
        	case 'r':
				loadGame(&gameState, "quicksave");
        		break;
        	case 'l':
        		system("dir savegames\\*.sav /B");
				printf("\nLade Datei (Endung nicht angeben):\n");
				scanf("%s", filename);
				fflush(stdin);

				loadGame(&gameState, filename);
        		break;
        	case 'u':
        		loadAutoSave(&gameState);
        		break;
        	case 'b':
        		boardMode = (1 - boardMode);
        		printInfo("Brettdarstellung gewechselt auf: %i\n", boardMode);
        		break;
        	case 'd':
        		debugMode = (1 - debugMode);
        		printInfo("Debugmodus gewechselt auf: %i\n", debugMode);
        		break;
        	case '?':
        		printf("m (move)\tEinen Zug durchfuehren.\n");
        		printf("n (next)\tDen Spieler wechseln (ohne Zug, regelwidrig!)\n");
        		printf("a (ai)\t\tKI einen Zug durchfuehren lassen.\n");
        		printf("h (history)\tDen Spielverlauf anzeigen.\n");
        		printf("c (check)\tStellung auf Schach pruefen.\n");
        		printf("g (generate)\tMoegliche Zuege anzeigen lassen.\n");
        		printf("v (value)\tBewertung der Stellung anzeigen lassen.\n");
        		printf("t (tip)\t\tDie KI einen Zug-Tip anzeigen lassen.\n");
        		printf("s (save)\tQuicksave-Spielstand anlegen.\n");
        		printf("r (reload)\tQuicksave-Spielstand laden.\n");
        		printf("l (load)\tSpielstand laden (Dateiname angeben).\n");
        		printf("u (undo)\tLetzten Zug zuruecknehmen.\n");
        		printf("b (board)\tBrettdarstellung wechseln (fuer Debuggging).\n");
        		printf("d (open)\tDebugausgaben aktivieren/deaktivieren.\n");
        		printf("? (help)\tDiese Hilfe zu den Kommandos anzeigen lassen.\n");
        		printf("e (exit)\tDas Programm beenden.\n");
        		break;
        	case 'e':
        		// do nothing
        		break;
        	case '\n':
        		// do nothing
        		break;
        	default:
        		printError("Unbekannter Operator: %c\n", o);
        		break;
        }
        fflush(stdin);
	} while (o != 'e');

	return 0;
}