Package nl.zoidberg.calculon.engine

Source Code of nl.zoidberg.calculon.engine.ChessEngine$ScoredMove

/**
* Calculon - A Java chess-engine.
*
* Copyright (C) 2008-2009 Barry Smith
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package nl.zoidberg.calculon.engine;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import nl.zoidberg.calculon.analyzer.GameScorer;
import nl.zoidberg.calculon.engine.BitBoard.BitBoardMove;

public class ChessEngine {
  private static final int DEPTH = 3;
  private static final int Q_DEPTH = 4;
 
//  private static final Logger log = Logger.getLogger(ChessEngine.class.getName());
 
  private GameScorer gameScorer;
  private int searchDepth = DEPTH;
  private int scoreMargin = 1000;
  private int maxDeepMoves = 5;
  private boolean quiesce = false;
 
  public ChessEngine() {
    this.gameScorer = GameScorer.getDefaultScorer();
  }
 
  public ChessEngine(GameScorer gameScorer) {
    this.gameScorer = gameScorer;
  }
 
  public void setQuiesce(boolean quiesce) {
    // this.quiesce = quiesce;
  }

  public String getPreferredMove(BitBoard bitBoard) {
//    String bookMove = OpeningBook.getDefaultBook() == null ? null : OpeningBook.getDefaultBook().getBookMove(board);
//    if(bookMove != null) {
//      log.fine("Using book move: " + bookMove);
//      return PGNUtils.toPgnMoveMap(board).get(bookMove);
//    }

    List<ScoredMove> allMoves = getScoredMoves(bitBoard);
//    System.out.println(allMoves);
//    ChessEngine.selectBestMoves(allMoves, scoreMargin, maxDeepMoves);
//    searchDepth++;
//    for(ScoredMove move: allMoves) {
//      List<ScoredMove> nextDepth = getScoredMoves(board.clone().applyMove(move.getMove()));
//      System.out.println(nextDepth);
//    }
    String rv = ChessEngine.selectBestMove(allMoves);
   
    return rv;
  }
 
  public List<ScoredMove> getScoredMoves(BitBoard bitBoard) {
    List<ScoredMove> rv = new ArrayList<ScoredMove>();

//    BitBoardMove bbm = bitBoard.getMove("G1G2");
//    bitBoard.makeMove(bbm);
//    int score = alphaBetaMax(Integer.MIN_VALUE, Integer.MAX_VALUE, searchDepth, bitBoard);
//    rv.add(new ScoredMove("G1G2", score));
//    bitBoard.unmakeMove();
   
    for(Iterator<BitBoardMove> moveItr = new MoveGenerator(bitBoard); moveItr.hasNext(); ) {
      BitBoardMove move = moveItr.next();

      bitBoard.makeMove(move);
      int score = alphaBetaMax(Integer.MIN_VALUE, Integer.MAX_VALUE, searchDepth, bitBoard);
     
      bitBoard.unmakeMove();

      rv.add(new ScoredMove(move.getAlgebraic(), score));
    }
   
    return rv;
  }
 
  public int getScoreMargin() {
    return scoreMargin;
  }

  public void setScoreMargin(int scoreMargin) {
    this.scoreMargin = scoreMargin;
  }

  public int getMaxDeepMoves() {
    return maxDeepMoves;
  }

  public void setMaxDeepMoves(int maxDeepMoves) {
    this.maxDeepMoves = maxDeepMoves;
  }

  public final int getDepth() {
    return searchDepth;
  }

  public final void setDepth(int depth) {
    this.searchDepth = depth;
  }
 
  private int alphaBetaMaxQ(int alpha, int beta, int depth, BitBoard bitBoard) {
    List<BitBoardMove> qmoves = new MoveGenerator(bitBoard).getThreateningMoves();
 
    if(depth >= Q_DEPTH || qmoves.size() == 0) {
      return gameScorer.score(bitBoard, false, alpha, beta);
    }
   
    for(BitBoardMove move: qmoves) {
      bitBoard.makeMove(move);
      int score = alphaBetaMinQ(alpha, beta, depth + 1, bitBoard);
      bitBoard.unmakeMove();

      if(score >= beta) {
        return beta;
      }
            alpha = Math.max(alpha, score);
    }
    return alpha;
  }
 
  private int alphaBetaMinQ(int alpha, int beta, int depth, BitBoard bitBoard) {
    List<BitBoardMove> qmoves = new MoveGenerator(bitBoard).getThreateningMoves();

    if(depth >= Q_DEPTH || qmoves.size() == 0) {
      return -gameScorer.score(bitBoard, false, alpha, beta);
    }

    for(BitBoardMove move: qmoves) {
      bitBoard.makeMove(move);
      int score = alphaBetaMaxQ(alpha, beta, depth + 1, bitBoard);
      bitBoard.unmakeMove();
     
      if(score <= alpha) {
        return alpha;
      }
            beta = Math.min(beta, score);
    }
    return beta;
  }

  private int alphaBetaMax(int alpha, int beta, int depthLeft, BitBoard bitBoard) {
    Iterator<BitBoardMove> moveItr = new MoveGenerator(bitBoard);
    if(depthLeft == 0 || ! moveItr.hasNext()) {
      int rv;
      if(quiesce) {
        if(! moveItr.hasNext()) {
          rv = gameScorer.score(bitBoard, false, alpha, beta);
        } else {
          rv = alphaBetaMinQ(alpha, beta, 0, bitBoard);
        }
      } else {
        rv = gameScorer.score(bitBoard, false, alpha, beta);
      }
      if(rv == GameScorer.MATE_SCORE) {
        rv *= (depthLeft+1);
      }
      return rv;
    }
   
    while(moveItr.hasNext()) {
      BitBoardMove move = moveItr.next();
     
      bitBoard.makeMove(move);
      int score = alphaBetaMin(alpha, beta, depthLeft - 1, bitBoard);
      bitBoard.unmakeMove();

      if(score >= beta) {
        return beta;
      }
            alpha = Math.max(alpha, score);
    }
   
    return alpha;
  }

  private int alphaBetaMin(int alpha, int beta, int depthLeft, BitBoard bitBoard) {
    Iterator<BitBoardMove> moveItr = new MoveGenerator(bitBoard);
    if(depthLeft == 0 || ! moveItr.hasNext()) {
      int rv;
      if(quiesce) {
        if(! moveItr.hasNext()) {
          rv = gameScorer.score(bitBoard, false, alpha, beta);
        } else {
          rv = alphaBetaMaxQ(alpha, beta, 0, bitBoard);
        }
      } else {
        rv = gameScorer.score(bitBoard, false, alpha, beta);
      }
      if(rv == GameScorer.MATE_SCORE) {
        rv *= (depthLeft+1);
      }
      return -rv;
    }

    while(moveItr.hasNext()) {
      BitBoardMove move = moveItr.next();
     
      bitBoard.makeMove(move);
      int score = alphaBetaMax(alpha, beta, depthLeft - 1, bitBoard);
      bitBoard.unmakeMove();
     
      if(score <= alpha) {
        return alpha;
      }
            beta = Math.min(beta, score);
    }
   
    return beta;
  }
 
  private static List<ScoredMove> selectBestMoves(List<ScoredMove> allMoves) {
    return selectBestMoves(allMoves, 0, 5);
  }
 
  /**
   * Selects all moves sharing the lowest (i.e. best) score.
   *
   * @param allMoves
   * @return
   */
  private static List<ScoredMove> selectBestMoves(List<ScoredMove> allMoves, int margin, int maxMoves) {
    if(allMoves.size() == 0) {
      return allMoves;
    }
   
    Collections.sort(allMoves);
    int bestScore = allMoves.get(0).getScore();
    while(allMoves.size() > maxMoves || allMoves.get(allMoves.size()-1).getScore() > bestScore+margin) {
      allMoves.remove(allMoves.size()-1);
    }
    return allMoves;
  }

  private static String selectBestMove(List<ScoredMove> allMoves) {
    List<ScoredMove> bestMoves = selectBestMoves(allMoves);
    if(bestMoves.size() == 0) {
      return null;
    }
    return allMoves.get((int) (Math.random() * allMoves.size())).getMove();
  }
 
  private static class ScoredMove implements Comparable<ScoredMove> {
    private String move;
    private int score;
   
    public ScoredMove(String move, int score) {
      super();
      this.move = move;
      this.score = score;
    }
    public String getMove() {
      return move;
    }
    public void setMove(String move) {
      this.move = move;
    }
    public int getScore() {
      return score;
    }
    public void setScore(int score) {
      this.score = score;
    }
   
    @Override
    public String toString() {
      return move + "=" + score;
    }
   
    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((move == null) ? 0 : move.hashCode());
      result = prime * result + score;
      return result;
    }
   
    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (getClass() != obj.getClass())
        return false;
      ScoredMove other = (ScoredMove) obj;
      if (move == null) {
        if (other.move != null)
          return false;
      } else if (!move.equals(other.move))
        return false;
      if (score != other.score)
        return false;
      return true;
    }
   
    public int compareTo(ScoredMove o) {
      return new Integer(score).compareTo(o.getScore());
    }
  }
}
TOP

Related Classes of nl.zoidberg.calculon.engine.ChessEngine$ScoredMove

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.