展会信息港展会大全

Java中国象棋博弈程序探秘之搜索算法
来源:互联网   发布日期:2011-09-16 09:21:47   浏览:13383次  

导读:搜索是电脑棋手AI的核心,有效的搜索算法很关键。本文给出了一些常用的搜索算法代码,以及这些算法的改进。例如配合置换表,历史启发...

搜索是电脑棋手AI的核心,有效的搜索算法很关键。本文给出了一些常用的搜索算法代码,以及这些算法的改进。例如配合置换表,历史启发表,开局库。算法的深入学习可以参考注释里给出的地址 : )

view plaincopy to clipboardprint? /*

* @(#)SearchEngine.java

* Author: 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* Created on May 24, 2008, 10:51:52 AM

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.chinesechess.infrastructure.search;

import cn.edu.ynu.sei.chinesechess.infrastructure.common.Motion;

import cn.edu.ynu.sei.chinesechess.infrastructure.common.Situation;

import cn.edu.ynu.sei.chinesechess.infrastructure.search.TranspositionTable.NodeType;

import java.util.Collections;

import java.util.List;

/**

* This class descripts some search algorithms of game tree.

* @author 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* @version 1.1.2.6, Jun 7, 2008

*/

public class SearchEngine {

/**

* value while win a game

*/

public static final int WIN = 54;

/**

* chessboard situation

*/

public Situation situation;

/**

* the best move

*/

public Motion bestMotion;

/**

* situation libaray

*/

private Book book = new Book();

/**

* default search depth

*/

public static int SEARCH_DEPTH = 5;

/**

* For Performance Test.

* @param args should be <codenull</code

*/

public static void main(String[] args) {

SearchEngine instance;

instance = new SearchEngine(new Situation());

System.out.println("Getting start search!");

long startTime = System.nanoTime();

//instance.basicAlphaBetaSearch(SEARCH_DEPTH, -WIN, WIN);

//instance.alphaBetaWithHistoryHeuristicSearch(SEARCH_DEPTH, -WIN, WIN);

//instance.alphaBetaWithTranspositonSearch(SEARCH_DEPTH, -WIN, WIN);

//instance.principalVariationSearch(SEARCH_DEPTH, -WIN, WIN);

//instance.principalVariationWithHHSearch(SEARCH_DEPTH, -WIN, WIN);

instance.negaScoutWithHHTTSearch(SEARCH_DEPTH, -WIN, WIN);

[8][9]

long estimatedTime = System.nanoTime, otherwise, returns bound(

* determined by cut-off)

*/

final int principalVariationSearch(int depth, int alpha, int beta) {

if (situation.gameOver() != 0) {

return -WIN;

}

if (depth <= 0) {

return situation.evaluate();

}

List<Motion motions = situation.generatePossibleMoves();

situation.makeMove(motions.get(0).fromX, motions.get(0).fromY,

motions.get(0).toX, motions.get(0).toY);

int best = -principalVariationSearch(depth - 1, -beta, -alpha);

situation.unMove();

if (depth == SEARCH_DEPTH) {

bestMotion = motions.get(0);

}

for (int i = 1; i < motions.size(); i++) {

if (best < beta) {

if (bestalpha) {

alpha = best;

}

[8][9]

Motion motion = motions.get(i);

situation.makeMove(motion.fromX, motion.fromY, motion.toX, motion.toY);

int score = -principalVariationSearch(depth - 1, -alpha - 1, -alpha);

if (scorealpha && score < beta) {

// fail high, re-search

best = -principalVariationSearch(depth - 1, -beta, -score);

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

} else if (scorebest) {

best = score;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

}

situation.unMove();

}

}

return best;

}

/**

* Principal Variation with History Heuristic SearchEngine method(fail-soft version).

* @param depth depth search

* @param alpha min value to max value, the "floor"

* @param beta max value to min value, the "ceiling"

* @return if game is over, returns <code-WIN</code, if depth arrived,

* returns evaluat value(leaf node value), otherwise, returns bound(

* determined by cut-off)

*/

@SuppressWarnings("unchecked")

final int principalVariationWithHHSearch(int depth, int alpha, int beta) {

if (situation.gameOver() != 0) {

return -WIN;

}

if (depth <= 0) {

return situation.evaluate();

}

List<Motion motions = situation.generatePossibleMoves();

// History heuristic

if (depth < SEARCH_DEPTH) {

for (Motion motion : motions) {

motion.value = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX, motion.toY);

}

Collections.sort(motions);

}

Motion motion = motions.get(0);

situation.makeMove(motion.fromX, motion.fromY,

motion.toX, motion.toY);

int best = -principalVariationWithHHSearch(depth - 1, -beta, -alpha);

situation.unMove();

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

int oldValue = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY);

HistoryHeuristicTable.setValue(motions.get(0).fromX,

motions.get(0).fromY,

motions.get(0).toX,

motions.get(0).toY,

(oldValue + 2 << depth));

}

for (int i = 1; i < motions.size(); i++) {

if (best < beta) {

if (bestalpha) {

alpha = best;

}

motion = motions.get(i);

situation.makeMove(motion.fromX, motion.fromY, motion.toX, motion.toY);

int score = -principalVariationWithHHSearch(depth - 1, -alpha - 1,

-alpha);

if (scorealpha && score < beta) {

best = -principalVariationWithHHSearch(depth - 1, -beta, -score);

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

} else if (scorebest) {

int oldValue = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY);

HistoryHeuristicTable.setValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY,

(oldValue + 2 << depth));

best = score;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

}

situation.unMove();

}

}

return best;

}

/**

* Alpha-Beta with Transposition Table search method.

* @param depth depth search

* @param alpha min value to max value, the "floor"

* @param beta max value to min value, the "ceiling"

* @return if game is over, returns <code-WIN</code, if depth arrived,

* returns evaluat value(leaf node value), otherwise, returns bound(

* determined by cut-off)

*/

final int alphaBetaWithTranspositonSearch(int depth, int alpha, int beta) {

if (situation.gameOver() != 0) {

return -WIN;

}

// lookup transposition table

int score = TranspositionTable.lookup(depth, alpha, beta);

if (score != 88250) {

// hit the target!

return score;

}

if (depth <= 0) {

score = situation.evaluate();

// save the node

TranspositionTable.save(NodeType.exact, depth, score);

return score;

}

NodeType hashItemType = NodeType.unknown;

List<Motion motions = situation.generatePossibleMoves();

for (Motion motion : motions) {

int toId = situation.makeMove(motion.fromX, motion.fromY, motion.toX,

motion.toY);

score = -alphaBetaWithTranspositonSearch(depth - 1, -beta, -alpha);

situation.unMove();

if (scorealpha) {

alpha = score;

hashItemType = NodeType.exact;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

if (alpha = beta) {

TranspositionTable.save(NodeType.lowerBound, depth, alpha);

return beta;

}

}

}

if (hashItemType != NodeType.unknown) {

TranspositionTable.save(NodeType.exact, depth, alpha);

} else {

TranspositionTable.save(NodeType.upperBound, depth, alpha);

}

return alpha;

}

/**

* NegaScout with History Heuristic and Transposition Table search.

* @param depth depth search

* @param alpha min value to max value, the "floor"

* @param beta max value to min value, the "ceiling"

* @return if game is over, returns <code-WIN</code, if depth arrived,

* returns evaluat value(leaf node value), otherwise, returns bound(

* determined by cut-off)

*/

@SuppressWarnings("unchecked")

final int negaScoutWithHHTTSearch(int depth, int alpha, int beta) {

if (situation.gameOver() != 0) {

return -WIN;

}

// lookup transpositiont table

int score = TranspositionTable.lookup(depth, alpha, beta);

if (score != 88250) {

// hit the target!

return score;

}

if (depth <= 0) {

score = situation.evaluate();

[8][9]

TranspositionTable.save(NodeType.exact, depth, score);

return score;

}

List<Motion motions = situation.generatePossibleMoves();

// History heuristic

if (depth < SEARCH_DEPTH) {

for (Motion motion : motions) {

motion.value = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX, motion.toY);

}

Collections.sort(motions);

}

int bestmove = 0;

int a = alpha;

int b = beta;

int t;

int oldValue;

NodeType hashItemType = NodeType.unknown;

for (int i = 0; i < motions.size(); i++) {

Motion motion = motions.get(i);

int toId = situation.makeMove(motion.fromX, motion.fromY, motion.toX,

motion.toY);

t = -negaScoutWithHHTTSearch(depth - 1, -b, -a);

if (ta && t < beta && i0) {

a = -negaScoutWithHHTTSearch(depth - 1, -beta, -t);

hashItemType = NodeType.exact;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

bestmove = i;

}

situation.unMove();

if (a < t) {

hashItemType = NodeType.exact;

a = t;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

}

if (a = beta) {

TranspositionTable.save(NodeType.lowerBound, depth, a);

oldValue = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY);

HistoryHeuristicTable.setValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY,

(oldValue + 2 << depth));

return a;

}

b = a + 1; // set a new numm window

}

oldValue = HistoryHeuristicTable.getValue(motions.get(bestmove).fromX,

motions.get(bestmove).fromY,

motions.get(bestmove).toX,

motions.get(bestmove).toY);

HistoryHeuristicTable.setValue(motions.get(bestmove).fromX,

motions.get(bestmove).fromY,

motions.get(bestmove).toX,

motions.get(bestmove).toY,

(oldValue + 2 << depth));

if (hashItemType != NodeType.unknown) {

TranspositionTable.save(NodeType.exact, depth, alpha);

} else {

TranspositionTable.save(NodeType.upperBound, depth, alpha);

}

return a;

}

/**

* Constructor with parameters.

* @param situation the specified situation

*/

public SearchEngine(Situation situation) {

this.situation = situation;

}

}

/*

* @(#)SearchEngine.java

* Author: 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* Created on May 24, 2008, 10:51:52 AM

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.chinesechess.infrastructure.search;

import cn.edu.ynu.sei.chinesechess.infrastructure.common.Motion;

import cn.edu.ynu.sei.chinesechess.infrastructure.common.Situation;

import cn.edu.ynu.sei.chinesechess.infrastructure.search.TranspositionTable.NodeType;

import java.util.Collections;

import java.util.List;

/**

* This class descripts some search algorithms of game tree.

* @author 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* @version 1.1.2.6, Jun 7, 2008

*/

public class SearchEngine {

/**

* value while win a game

*/

public static final int WIN = 54;

/**

* chessboard situation

*/

public Situation situation;

/**

* the best move

*/

public Motion bestMotion;

/**

* situation libaray

*/

private Book book = new Book();

/**

* default search depth

*/

public static int SEARCH_DEPTH = 5;

/**

* For Performance Test.

* @param args should be <codenull</code

*/

public static void main(String[] args) {

SearchEngine instance;

instance = new SearchEngine(new Situation());

System.out.println("Getting start search!");

long startTime = System.nanoTime();

//instance.basicAlphaBetaSearch(SEARCH_DEPTH, -WIN, WIN);

[8][9]

//instance.alphaBetaWithHistoryHeuristicSearch, otherwise, returns bound(

* determined by cut-off)

*/

final int principalVariationSearch(int depth, int alpha, int beta) {

if (situation.gameOver() != 0) {

return -WIN;

}

if (depth <= 0) {

return situation.evaluate();

}

List<Motion motions = situation.generatePossibleMoves();

situation.makeMove(motions.get(0).fromX, motions.get(0).fromY,

motions.get(0).toX, motions.get(0).toY);

int best = -principalVariationSearch(depth - 1, -beta, -alpha);

situation.unMove();

if (depth == SEARCH_DEPTH) {

bestMotion = motions.get(0);

}

for (int i = 1; i < motions.size(); i++) {

if (best < beta) {

if (bestalpha) {

alpha = best;

}

Motion motion = motions.get(i);

situation.makeMove(motion.fromX, motion.fromY, motion.toX, motion.toY);

int score = -principalVariationSearch(depth - 1, -alpha - 1, -alpha);

if (scorealpha && score < beta) {

// fail high, re-search

best = -principalVariationSearch(depth - 1, -beta, -score);

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

} else if (scorebest) {

best = score;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

}

situation.unMove();

}

}

return best;

}

/**

* Principal Variation with History Heuristic SearchEngine method(fail-soft version).

* @param depth depth search

* @param alpha min value to max value, the "floor"

* @param beta max value to min value, the "ceiling"

* @return if game is over, returns <code-WIN</code, if depth arrived,

* returns evaluat value(leaf node value), otherwise, returns bound(

* determined by cut-off)

*/

@SuppressWarnings("unchecked")

final int principalVariationWithHHSearch(int depth, int alpha, int beta) {

if (situation.gameOver() != 0) {

return -WIN;

}

if (depth <= 0) {

return situation.evaluate();

}

List<Motion motions = situation.generatePossibleMoves();

// History heuristic

if (depth < SEARCH_DEPTH) {

for (Motion motion : motions) {

motion.value = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX, motion.toY);

}

Collections.sort(motions);

}

Motion motion = motions.get(0);

situation.makeMove(motion.fromX, motion.fromY,

motion.toX, motion.toY);

int best = -principalVariationWithHHSearch(depth - 1, -beta, -alpha);

situation.unMove();

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

int oldValue = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY);

HistoryHeuristicTable.setValue(motions.get(0).fromX,

motions.get(0).fromY,

motions.get(0).toX,

motions.get(0).toY,

(oldValue + 2 << depth));

}

for (int i = 1; i < motions.size(); i++) {

if (best < beta) {

if (bestalpha) {

alpha = best;

}

motion = motions.get(i);

[8][9]

situation.makeMove(motion.fromX, motion.fromY, motion.toX, motion.toY);

int score = -principalVariationWithHHSearch(depth - 1, -alpha - 1,

-alpha);

if (scorealpha && score < beta) {

best = -principalVariationWithHHSearch(depth - 1, -beta, -score);

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

} else if (scorebest) {

int oldValue = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY);

HistoryHeuristicTable.setValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY,

(oldValue + 2 << depth));

best = score;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

}

situation.unMove();

}

}

return best;

}

/**

* Alpha-Beta with Transposition Table search method.

* @param depth depth search

* @param alpha min value to max value, the "floor"

* @param beta max value to min value, the "ceiling"

* @return if game is over, returns <code-WIN</code, if depth arrived,

* returns evaluat value(leaf node value), otherwise, returns bound(

* determined by cut-off)

*/

final int alphaBetaWithTranspositonSearch(int depth, int alpha, int beta) {

if (situation.gameOver() != 0) {

return -WIN;

}

// lookup transposition table

int score = TranspositionTable.lookup(depth, alpha, beta);

if (score != 88250) {

// hit the target!

return score;

}

if (depth <= 0) {

score = situation.evaluate();

// save the node

TranspositionTable.save(NodeType.exact, depth, score);

return score;

}

NodeType hashItemType = NodeType.unknown;

List<Motion motions = situation.generatePossibleMoves();

for (Motion motion : motions) {

int toId = situation.makeMove(motion.fromX, motion.fromY, motion.toX,

motion.toY);

score = -alphaBetaWithTranspositonSearch(depth - 1, -beta, -alpha);

situation.unMove();

if (scorealpha) {

alpha = score;

hashItemType = NodeType.exact;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

if (alpha = beta) {

TranspositionTable.save(NodeType.lowerBound, depth, alpha);

return beta;

}

}

}

if (hashItemType != NodeType.unknown) {

TranspositionTable.save(NodeType.exact, depth, alpha);

} else {

TranspositionTable.save(NodeType.upperBound, depth, alpha);

}

return alpha;

}

/**

* NegaScout with History Heuristic and Transposition Table search.

* @param depth depth search

* @param alpha min value to max value, the "floor"

* @param beta max value to min value, the "ceiling"

* @return if game is over, returns <code-WIN</code, if depth arrived,

* returns evaluat value(leaf node value), otherwise, returns bound(

* determined by cut-off)

*/

@SuppressWarnings("unchecked")

final int negaScoutWithHHTTSearch(int depth, int alpha, int beta) {

if (situation.gameOver() != 0) {

return -WIN;

}

// lookup transpositiont table

int score = TranspositionTable.lookup(depth, alpha, beta);

if (score != 88250) {

// hit the target!

return score;

}

if (depth <= 0) {

score = situation.evaluate();

TranspositionTable.save(NodeType.exact, depth, score);

return score;

}

List<Motion motions = situation.generatePossibleMoves();

// History heuristic

if (depth < SEARCH_DEPTH) {

for (Motion motion : motions) {

motion.value = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX, motion.toY);

}

Collections.sort(motions);

}

int bestmove = 0;

int a = alpha;

int b = beta;

int t;

int oldValue;

NodeType hashItemType = NodeType.unknown;

for (int i = 0; i < motions.size(); i++) {

Motion motion = motions.get(i);

int toId = situation.makeMove(motion.fromX, motion.fromY, motion.toX,

motion.toY);

t = -negaScoutWithHHTTSearch(depth - 1, -b, -a);

if (ta && t < beta && i0) {

a = -negaScoutWithHHTTSearch(depth - 1, -beta, -t);

hashItemType = NodeType.exact;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

bestmove = i;

}

situation.unMove();

if (a < t) {

hashItemType = NodeType.exact;

a = t;

if (depth == SEARCH_DEPTH) {

bestMotion = motion;

}

}

if (a = beta) {

TranspositionTable.save(NodeType.lowerBound, depth, a);

oldValue = HistoryHeuristicTable.getValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY);

HistoryHeuristicTable.setValue(motion.fromX,

motion.fromY,

motion.toX,

motion.toY,

(oldValue + 2 << depth));

return a;

}

b = a + 1; // set a new numm window

}

oldValue = HistoryHeuristicTable.getValue(motions.get(bestmove).fromX,

motions.get(bestmove).fromY,

motions.get(bestmove).toX,

motions.get(bestmove).toY);

HistoryHeuristicTable.setValue(motions.get(bestmove).fromX,

motions.get(bestmove).fromY,

motions.get(bestmove).toX,

motions.get(bestmove).toY,

(oldValue + 2 << depth));

if (hashItemType != NodeType.unknown) {

TranspositionTable.save(NodeType.exact, depth, alpha);

} else {

TranspositionTable.save(NodeType.upperBound, depth, alpha);

}

return a;

}

/**

* Constructor with parameters.

* @param situation the specified situation

*/

public SearchEngine(Situation situation) {

this.situation = situation;

}

}

view plaincopy to clipboardprint? /*

* @(#)Book.java

* Author: 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* Created on Jun 5, 2008, 4:45:31 PM

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

[8][9]

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.chinesechess.infrastructure.search;

import cn.edu.ynu.sei.chinesechess.infrastructure.common.Situation;

import cn.edu.ynu.sei.chinesechess.infrastructure.fen.FEN;

import cn.edu.ynu.sei.chinesechess.infrastructure.fen.FENAccessor;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

/**

* Opening book, endgame book, or any chessboard situation book.

* Currently, this class ONLY can read FEN file.

* @author 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* @version 1.0.0.0, Jun 5, 2008

*/

final public class Book {

/**

* book situation hash map

*/

public Map<Integer, FEN hashMap = new HashMap<Integer, FEN();

/**

* Packaged default constructor.

*/

Book() {

List<FEN fens = FENAccessor.readFile("book_final");

Integer hashCode = 0;

for (FEN fen : fens) {

hashCode = TranspositionTable.calcCurHashCode(fen.chessboard);

hashMap.put(hashCode, fen);

}

}

/**

* This book exists the specified chessboard situation?

* @param chessboard the specified chessboard

* @return if exists, returns <codetrue</code, otherwise,

* returns <codefalse</code

*/

final public boolean exists(int[][] chessboard) {

FEN f = hashMap.get(TranspositionTable.calcCurHashCode(chessboard));

if (f != null && f.isBlackDone == false) {

return true;

}

return false;

}

}

/*

* @(#)Book.java

* Author: 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* Created on Jun 5, 2008, 4:45:31 PM

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.chinesechess.infrastructure.search;

import cn.edu.ynu.sei.chinesechess.infrastructure.common.Situation;

import cn.edu.ynu.sei.chinesechess.infrastructure.fen.FEN;

import cn.edu.ynu.sei.chinesechess.infrastructure.fen.FENAccessor;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

/**

* Opening book, endgame book, or any chessboard situation book.

* Currently, this class ONLY can read FEN file.

* @author 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* @version 1.0.0.0, Jun 5, 2008

*/

final public class Book {

/**

* book situation hash map

*/

public Map<Integer, FEN hashMap = new HashMap<Integer, FEN();

/**

* Packaged default constructor.

*/

Book() {

List<FEN fens = FENAccessor.readFile("book_final");

Integer hashCode = 0;

for (FEN fen : fens) {

hashCode = TranspositionTable.calcCurHashCode(fen.chessboard);

hashMap.put(hashCode, fen);

}

}

/**

* This book exists the specified chessboard situation?

* @param chessboard the specified chessboard

* @return if exists, returns <codetrue</code, otherwise,

* returns <codefalse</code

*/

final public boolean exists(int[][] chessboard) {

FEN f = hashMap.get(TranspositionTable.calcCurHashCode(chessboard));

if (f != null && f.isBlackDone == false) {

return true;

}

return false;

}

}

view plaincopy to clipboardprint? /*

* @(#)HistoryHeuristicTable.java

* Author: 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* Created on May 29, 2008, 11:51:10 PM

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.chinesechess.infrastructure.search;

/**

* A <emHistory Heuristic Table</em maintains all best motion in

* the past.

* ({@link cn.edu.ynu.sei.chinesechess.common.Motion#value})

* @author 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* @version 1.0.1.4, Jun 7, 2008

*/

final class HistoryHeuristicTable {

/**

* hold all best moves

*/

static int[][][][] holds = new int[9][10][9][10];

/**

* singleton

*/

private static HistoryHeuristicTable instance = new HistoryHeuristicTable();

/**

* Gets the single instance of the class.

* @return history heuristic instance

*/

final public static HistoryHeuristicTable getInstance() {

if (instance == null) {

instance = new HistoryHeuristicTable();

}

return instance;

}

/**

* Private default constructor.

*/

private HistoryHeuristicTable() {

}

/**

* Returns the history motion.

* @param fromX x coordinate of which chessman do this move

* @param fromY y coordinate of which chessman do this move

* @param toX x coordinate of which chessman‘s destination

* @param toY y coordinate of which chessman‘s destination

* @return this move‘s value

*/

final static int getValue(int fromX, int fromY, int toX, int toY) {

return holds[fromX][fromY][toX][toY];

}

/**

* Sets the history motion.

* @param fromX x coordinate of which chessman do this move

* @param fromY y coordinate of which chessman do this move

* @param toX x coordinate of which chessman‘s destination

* @param toY y coordinate of which chessman‘s destination

* @param newValue the new value

*/

[8][9]

final static void setValue(int fromX, int fromY, int toX, int toY, int newValue) {

holds[fromX][fromY][toX][toY] = newValue;

}

}

/*

* @(#)TranspositionTable.java

* Author: 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* Created on Jun 1, 2008, 11:04:57 AM

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 3 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU Library General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

package cn.edu.ynu.sei.chinesechess.infrastructure.search;

import java.util.Random;

/**

* A <emTranspositon Table</em maintains a mass of node had evaluated.

* In the table, we use <codeHashTable</code to store each game tree node.

* @author 88250 <DL88250@gmail.com, http://blog.csdn.net/DL88250

* @version 1.0.0.5, Jun 7, 2008

*/

final public class TranspositionTable {

// XXX currently, using 32-bits hash code

/**

* transposition table‘s size

*/

final static int SIZE = 1024 * 32 * 8;

/**

* holds the chessboard condition<br

* <ul

* <li15: 14 kinds of chessman, from 1 to 14</li

* </li9, 10: 9 * 10 matrics form chessboard

* </ul

* @see cn.edu.ynu.sei.chinesechess.infrastructure.common.Constants

* @see cn.edu.ynu.sei.chinesechess.infrastructure.common.Situation#chessboard

*/

static int[][][] hashCodes = new int[15][9][10];

/**

* the holds, [0, 1] for min value and max value

*/

static HashNode[][] items = new HashNode[SIZE];

/**

* a 32-bits integer, acts for current hash code

*/

static int curHashCode;

/**

* Transposition table hit count

*/

public static int hashHitCount = 0;

/**

* singleton

*/

private static TranspositionTable instance = new TranspositionTable();

/**

* Gets the single instance.

* @return transposition table single instance

*/

public static TranspositionTable getInstance() {

if (instance == null) {

instance = new TranspositionTable();

}

return instance;

}

/**

* Initializes the hash code of the specified chessboard situation.

* @param chessboard the specified chessboard situation

*/

final static void initHashCode(int[][] chessboard) {

curHashCode = calcCurHashCode(chessboard);

}

/**

* Private default constructor.

*/

private TranspositionTable() {

Random random = new Random();

for (int i = 0; i < 15; i++) {

for (int j = 0; j < 9; j++) {

for (int k = 0; k < 10; k++) {

hashCodes[i][j][k] = Math.abs(random.nextInt());

}

}

}

for (int i = 0; i < 2; i++) {

for (int j = 0; j < SIZE; j++) {

items[i][j] = new HashNode();

}

}

}

/**

* Calculates the hash code for the specified chessboard situation.

* @param chessboard the specified chessboar situation

* @return 32-bits hash code

*/

final public static int calcCurHashCode(int[][] chessboard) {

int ret = 0;

for (int i = 0; i < 9; i++) {

for (int j = 0; j < 10; j++) {

ret ^= hashCodes[chessboard[i][j]][i][j];

}

}

return ret;

}

/**

* Save a chessboard situation into transposition table.

* @param type type of this hash item

* @param depth depth depth of search

* @param value value of this hash value

*/

final public static void save(NodeType type, int depth, int value) {

// depth % 2: 0 for max, 1 for min

HashNode item = items[depth % 2][curHashCode % SIZE];

item.depth = depth;

item.hashCode = curHashCode;

item.type = type;

item.value = value;

}

/**

* Lookup a chessboard situation in transposition table.

* @param depth depth of search

* @param alpha min value to max value, the "floor"

* @param beta max value to min value, the "ceiling"

* @return if find the result, returns value, otherwise,

* returns <code88250</code

*/

final public static int lookup(int depth, int alpha, int beta) {

// depth % 2: 0 for max, 1 for min

HashNode item = items[depth % 2][curHashCode % SIZE];

if (item.depth == depth && item.hashCode == curHashCode) {

hashHitCount++;

switch (item.type) {

case exact:

return item.value;

case lowerBound:

if (item.value = beta) {

return item.value;

} else {

break;

}

case upperBound:

if (item.value <= alpha) {

return item.value;

} else {

break;

}

}

}

// doesn‘t hit the target

[8][9]

作者:88250

Blog:http:/blog.csdn.net/DL88250

MSN & Gmail & QQ:DL88250@gmail.com

[8][9]

赞助本站

人工智能实验室
AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港