public virtual int AlphaBeta(Position p, int depth, int alpha, int beta, double extension, MoveList pv, long Zkey, int move) { if (nodecount[1] + nodecount[0] > NODELIMIT) //wenn Knotenlimit überschritten, gehe zu Exception { throw new TooManyNodesException(); } if (depth < maxDepth) { maxDepth = depth; } p.makeMove(move); nodecount[0] += 1; int hashflag = HASHALPHA; //letzte Bits des Keys in Index umwandeln int index = (int)Zkey & (HASHSIZE - 1); //Hash Tables hvalue = -1; bestMove = -1; newbeta = beta; newalpha = alpha; if (HashTable2[index].key == Zkey) { if (HashTable2[index].depth >= (depth + extension)) { if (HashTable2[index].flag == HASHEXACT) { hvalue = HashTable2[index].value_Renamed; } if (HashTable2[index].flag == HASHALPHA && HashTable2[index].value_Renamed <= alpha) { hvalue = alpha; } if (HashTable2[index].flag == HASHALPHA && HashTable2[index].value_Renamed < beta) { newbeta = HashTable2[index].value_Renamed; } if (HashTable2[index].flag == HASHBETA && HashTable2[index].value_Renamed >= beta) { hvalue = beta; } if (HashTable2[index].flag == HASHBETA && HashTable2[index].value_Renamed > alpha) { newalpha = HashTable2[index].value_Renamed; } } bestMove = HashTable2[index].move; } if (HashTable1[index].key == Zkey) { if (HashTable1[index].depth >= (depth + extension)) { if (HashTable1[index].flag == HASHEXACT) { hvalue = HashTable1[index].value_Renamed; } if (HashTable1[index].flag == HASHALPHA && HashTable1[index].value_Renamed <= alpha) { hvalue = alpha; } if (HashTable1[index].flag == HASHALPHA && HashTable1[index].value_Renamed < beta) { newbeta = HashTable1[index].value_Renamed; } if (HashTable1[index].flag == HASHBETA && HashTable1[index].value_Renamed >= beta) { hvalue = beta; } if (HashTable1[index].flag == HASHBETA && HashTable1[index].value_Renamed > alpha) { newalpha = HashTable1[index].value_Renamed; } } bestMove = HashTable1[index].move; } if (HashTable3[index].key == Zkey) { hvalue = HashTable3[index].value_Renamed; } beta = newbeta; alpha = newalpha; if (hvalue != -1) { pv.length = 0; return hvalue; } MoveList mypv = new MoveList(); //entschiedene Positionen if (p.isWon(!p.toMove, move)) { pv.length = 0; addHashEntries(Zkey, index, depth + extension, -1000 + p.numberOfDiscs(), HASHEXACT, -1); return -1000 + p.numberOfDiscs(); } if (p.Draw) { pv.length = 0; addHashEntries(Zkey, index, depth + extension, 0, HASHEXACT, -1); return 0; } //Eröffnungsbuchzugriff if (opening) { if (p.numberOfDiscs() <= 8) { value_Renamed = searchBook(p); if (value_Renamed != -1) { pv.length = 0; addHashEntries(Zkey, index, depth + extension, value_Renamed, HASHEXACT, -1); return value_Renamed; } } } //Interior Node Recognition firstFreeColumn = -1; secondFreeColumn = -1; freeColumns = 0; for (int i = 0; i < 7; i++) { if (p.height[i] != 6) { freeColumns += 1; if (freeColumns == 3) break; if (freeColumns == 1) firstFreeColumn = i; if (freeColumns == 2) secondFreeColumn = i; } } //Wenn nur mehr wenige Spalten frei sind (Ende des Spieles) if (freeColumns == 1 || (freeColumns == 2 && (secondFreeColumn - firstFreeColumn >= 4))) { if (acuteThreat(p, p.toMove) == -1 && acuteThreat(p, !p.toMove) == -1) { value_Renamed = evaluate(p, true); pv.length = 0; addHashEntries(Zkey, index, depth + extension, value_Renamed, HASHEXACT, -1); return value_Renamed; } } if (depth <= (0 - extension)) { int akut2 = acuteThreat(p, p.toMove); if (akut2 != -1) { pv.length = 0; addHashEntries(Zkey, index, depth + extension, 1000 - p.numberOfDiscs() - 1, HASHEXACT, -1); return 1000 - p.numberOfDiscs() - 1; } int akut = acuteThreat(p, !p.toMove); if (akut == -1) { pv.length = 0; int val = evaluate(p, false); addHashEntries(Zkey, index, depth + extension, val, HASHEXACT, -1); return val; } extension += 2; Zkey = Zkey ^ (p.toMove ? zobristKeys[akut][0] : zobristKeys[akut][1]); int value_Renamed = -AlphaBeta(p, depth - 1, -beta, -alpha, extension, mypv, Zkey, akut); p.undoMove(akut); Zkey = Zkey ^ (p.toMove ? zobristKeys[akut][0] : zobristKeys[akut][1]); if (value_Renamed >= beta) { addHashEntries(Zkey, index, depth + extension - 2, beta, HASHBETA, -1); return beta; } if (value_Renamed > alpha) { hashflag = HASHEXACT; alpha = value_Renamed; pv.First = new MoveListElement(akut); if (mypv.length != 0) { pv.Rest = mypv; } pv.length = mypv.length + 1; } addHashEntries(Zkey, index, depth + extension - 2, alpha, hashflag, -1); return alpha; } int[] moves = generateMoves(p, searchDepth - depth); sort(moves, p); //Sortiert Züge nach Feldgewichten und nach dem besten Zug aus den Hash Tables //Suchvertiefung for (int i = 0; i < moves[7]; i++) { Zkey = Zkey ^ (p.toMove ? zobristKeys[moves[i]][0] : zobristKeys[moves[i]][1]); value_Renamed = -AlphaBeta(p, depth - 1, -beta, -alpha, extension, mypv, Zkey, moves[i]); p.undoMove(moves[i]); Zkey = Zkey ^ (p.toMove ? zobristKeys[moves[i]][0] : zobristKeys[moves[i]][1]); if (value_Renamed >= beta) { addHashEntries(Zkey, index, depth + extension, value_Renamed, HASHBETA, moves[i]); return beta; } if (value_Renamed > alpha) { hashflag = HASHEXACT; alpha = value_Renamed; pv.First = new MoveListElement(moves[i]); if (mypv.length != 0) { pv.Rest = mypv; } pv.length = mypv.length + 1; } } addHashEntries(Zkey, index, depth + extension, alpha, hashflag, (hashflag == HASHEXACT ? pv.pop() : -1)); return alpha; }
/* * Für den initialen Aufruf von AlphaBeta gibt es eine spezielle Funktion. * a) Hier wird kein Wert aus den Hash Tables, aus dem Eröffnungsbuch oder aus einer Form von Evaluation übernommen, * da man sonst 0 Level im Suchbaum und demzufolge keine PV, also auch keinen besten Zug erhält. * b) Hier muß nicht auf gewonnene oder unentschiedene Positionen getestet werden, da playGame() solche Stellungen abfängt. * c) Hier wird kein Zug-Argument übergeben. Diese Methode stellt stets den Wurzelknoten dar. */ public virtual int StartAlphaBeta(Position p, int depth, int alpha, int beta, double extension, MoveList pv, long Zkey) { nodecount[0] += 1; int hashflag = HASHALPHA; //letzte Bits des Keys in Index umwandeln int index = (int)Zkey & (HASHSIZE - 1); //Hashtables zugriff bestMove = -1; if (HashTable1[index].key == Zkey) //HashTable 1 suchen { bestMove = HashTable1[index].move; } if (HashTable2[index].key == Zkey) //in HashTable 2 suchen { bestMove = HashTable2[index].move; } MoveList mypv = new MoveList(); int[] moves = generateMoves(p, searchDepth - depth); //mögliche Züge generieren sort(moves, p); //Sortiert Züge nach Feldgewichten und nach dem besten Zug aus den Hash Tables for (int i = 0; i < moves[7]; i++) //moves[7] = Anzahl der möglichen Züge { Zkey = Zkey ^ (p.toMove == Position.WHITE ? zobristKeys[moves[i]][0] : zobristKeys[moves[i]][1]); value_Renamed = -AlphaBeta(p, depth - 1, -beta, -alpha, extension, mypv, Zkey, moves[i]); p.undoMove(moves[i]); Zkey = Zkey ^ (p.toMove == Position.WHITE ? zobristKeys[moves[i]][0] : zobristKeys[moves[i]][1]); if (value_Renamed >= beta) { addHashEntries(Zkey, index, depth + extension, value_Renamed, HASHBETA, moves[i]); return beta; } if (value_Renamed > alpha) { hashflag = HASHEXACT; alpha = value_Renamed; pv.First = new MoveListElement(moves[i]); if (mypv.length != 0) { pv.Rest = mypv; } pv.length = mypv.length + 1; } } addHashEntries(Zkey, index, depth + extension, alpha, hashflag, (hashflag == HASHEXACT ? pv.pop() : -1)); return alpha; }