/***********************************************************************************************************
 * su.bot.checkers.javascript.Referee
 * Location: http://www.bot.su/library/su/bot/checkers/javascript/Referee.js
 * Index Version Location: http://www.bot.su/library/su/bot/checkers/javascript/referee/index.html
 * © Bot.Su (http://www.bot.su/)
***********************************************************************************************************/

if (typeof su == "undefined") {su = {};};
if (typeof su.bot == "undefined") {su.bot = {};};
if (typeof su.bot.checkers == "undefined") {su.bot.checkers = {};};
if (typeof su.bot.checkers.javascript == "undefined") {su.bot.checkers.javascript = {};};

if (typeof su.bot.checkers.javascript.Referee == "undefined") {
 su.bot.checkers.javascript.Referee = function() {}; 
 su.bot.checkers.javascript.Referee.prototype = new com.oclib.javascript.lang.Root();

 su.bot.checkers.javascript.Referee.prototype.className = "Referee"; 
 su.bot.checkers.javascript.Referee.prototype.classNamespace = "su.bot.checkers.javascript.Referee"; 
 su.bot.checkers.javascript.Referee.prototype.classCreated = "20070403"; 
 su.bot.checkers.javascript.Referee.prototype.classCreator = "http://www.bot.su/"; 
 su.bot.checkers.javascript.Referee.prototype.classLocation = "http://www.bot.su/library/su/bot/checkers/javascript/Referee.js"; 
 su.bot.checkers.javascript.Referee.prototype.classIndexLocation = "http://www.bot.su/library/su/bot/checkers/javascript/referee/index.html"; 
 su.bot.checkers.javascript.Referee.prototype.classVersion = "20070528"; 
 su.bot.checkers.javascript.Referee.prototype.classVersionLocation = "http://www.bot.su/library/su/bot/checkers/javascript/referee/builds/20070528/Referee.js"; 
 su.bot.checkers.javascript.Referee.prototype.classVersionIndexLocation = "http://www.bot.su/library/su/bot/checkers/javascript/referee/index.html"; 
 
 su.bot.checkers.javascript.Referee.prototype.currentGameNodes = new Array(); // Array of Nodes
  su.bot.checkers.javascript.Referee.prototype.addNodeToCurrentGameNodes = function (node) {this.currentGameNodes[this.currentGameNodes.length] = node;};
  su.bot.checkers.javascript.Referee.prototype.getCurrentGameNodes = function () {return this.currentGameNodes;};
  su.bot.checkers.javascript.Referee.prototype.setCurrentGameNodes = function (currentGameNodes) {this.currentGameNodes = currentGameNodes;}; 
 su.bot.checkers.javascript.Referee.prototype.environment = null;  // Environment
  su.bot.checkers.javascript.Referee.prototype.getEnvironment = function () {return this.environment;};
  su.bot.checkers.javascript.Referee.prototype.setEnvironment = function (environment) {this.environment = environment;}; 
 su.bot.checkers.javascript.Referee.prototype.gameDoRun = false; // Boolean
  su.bot.checkers.javascript.Referee.prototype.getGameDoRun = function () {return this.gameDoRun;};
  su.bot.checkers.javascript.Referee.prototype.setGameDoRun = function (gameDoRun) {this.gameDoRun = gameDoRun;}; 
 su.bot.checkers.javascript.Referee.prototype.lastNode = null; // Node
  su.bot.checkers.javascript.Referee.prototype.getLastNode = function () {return this.lastNode;};
  su.bot.checkers.javascript.Referee.prototype.setLastNode = function (lastNode) {this.lastNode = lastNode; this.addNodeToCurrentGameNodes(lastNode.getCopy())}; 
 su.bot.checkers.javascript.Referee.prototype.maxScore = 0; // Integer
  su.bot.checkers.javascript.Referee.prototype.getMaxScore = function () {return this.maxScore;};
  su.bot.checkers.javascript.Referee.prototype.setMaxScore = function (maxScore) {this.maxScore = maxScore;}; 
 su.bot.checkers.javascript.Referee.prototype.minScore = 0; // Integer
  su.bot.checkers.javascript.Referee.prototype.getMinScore = function () {return this.minScore;};
  su.bot.checkers.javascript.Referee.prototype.setMinScore = function (minScore) {this.minScore = minScore;}; 
 su.bot.checkers.javascript.Referee.prototype.numberMove = 0; // Integer
  su.bot.checkers.javascript.Referee.prototype.getNumberMove = function () {return this.numberMove;};
  su.bot.checkers.javascript.Referee.prototype.setNumberMove = function (numberMove) {this.numberMove = numberMove;}; 
 su.bot.checkers.javascript.Referee.prototype.whoseMove = "empty"; /*"empty", "max", "min"*/
  su.bot.checkers.javascript.Referee.prototype.getWhoseMove = function () {return this.whoseMove;};
  su.bot.checkers.javascript.Referee.prototype.setWhoseMove = function (whoseMove) {this.whoseMove = whoseMove;}; 
 
 su.bot.checkers.javascript.Referee.prototype.createLegalNodes = function(node) {
  //if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.createLegalNodes is runing...");};
  if(!node.processed) {
   var checkersLocation = node.board.getCheckersLocation(node.whoseMove);
   if(checkersLocation.length == 0) {
    this.surrender(node.whoseMove); 
   } else {
    var nodes = this.createLegalNodesForTake(node, checkersLocation);
    if(nodes.length == 0) {nodes = this.createLegalNodesForMove(node, checkersLocation);};
    if(nodes.length == 0) {this.surrender(node.whoseMove);} else {node.setNodes(nodes);};
   };
   node.setProcessed(true);
  };
 };
 
 su.bot.checkers.javascript.Referee.prototype.createLegalNodesForMove = function(node, checkersLocation) {
  //if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.createLegalNodesForMove is runing...");};
  var nodes = new Array();
  var board = node.getBoard();
  for(var i = 0; i < checkersLocation.length; i++) {
   var fromSquare = checkersLocation[i];
   var fromI = fromSquare.i; var fromJ = fromSquare.j;
   var checker = node.getBoard().getChecker(fromI, fromJ);
   var toWhoseMove = (node.getWhoseMove() == "min") ? "max" : "min";
   var moves = checker.isChecker() ? this.getLegalMovesForChecker(node, fromSquare) : this.getLegalMovesForKing(node, fromSquare);
   for(var j = 0; j < moves.length; j++) {
    var toNode = new su.bot.checkers.javascript.Node();
	toNode.setMove(moves[j]);
	toNode.setParentNode(node);
	toNode.setWhoseMove(toWhoseMove);
	var toBoard = board.getCopy();
	toBoard.move(moves[j]);
	toNode.setBoard(toBoard);
    nodes[nodes.length] = toNode;
   };
  };
  return nodes;
 };
 
 su.bot.checkers.javascript.Referee.prototype.createLegalNodesForTake = function(node, checkersLocation) {
  //if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.createLegalNodesForTake is runing...");};
  var nodes = new Array();
  var whoseMove = node.whoseMove;
  var board = node.board;
  var maxDepthTake = 0;
  for(var i = 0; i < checkersLocation.length; i++) {
   var fromSquare = checkersLocation[i];
   var fromI = fromSquare.i; var fromJ = fromSquare.j;
   var checker = board.getChecker(fromI, fromJ);
   var moves = checker.isChecker() ? this.getLegalTakesForChecker(node, fromSquare) : this.getLegalTakesForKing(node, fromSquare);
   for(var j = 0; j < moves.length; j++) {
    var toNode = new su.bot.checkers.javascript.Node();
	toNode.setMove(moves[j]);
	toNode.setParentNode(node);
	toNode.setWhoseMove(whoseMove);
	var toBoard = board.getCopy();
	toBoard.move(moves[j]);
	toNode.setBoard(toBoard);
	var cL = new Array();
	cL[0] = moves[j].to;
	var nodesArray = this.createLegalNodesForTake(toNode, cL);
    if(nodesArray.length == 0) {
     toNode.setWhoseMove((whoseMove == "min") ? "max" : "min");
	} else {
     toNode.setNodes(nodesArray);
	 var toDepthTake = nodesArray[0].getMaxDepthTake()+1;
     toNode.setMaxDepthTake(toDepthTake);
	 toNode.setProcessed(true);
	 if(toDepthTake > maxDepthTake) {maxDepthTake = toDepthTake;};
	};
    nodes[nodes.length] = toNode;
   };
  };
  if(maxDepthTake == 0) {
   return nodes;
  } else {
   var selectedNodes = new Array();   
   for(var i = 0; i < nodes.length; i++) {if(nodes[i].getMaxDepthTake() == maxDepthTake) {selectedNodes[selectedNodes.length] = nodes[i];};};
   return selectedNodes;
  };
 };
  
 su.bot.checkers.javascript.Referee.prototype.doMove = function(name, move) {
  if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.doMove is runing for name="+name+"; move="+move);};
  if((name == this.getWhoseMove())) {
   var nodes = this.getLastNode().getNodes();
   var node = null;
   for(var i = 0; i < nodes.length &&  node == null; i++) {if(move.similarTo(nodes[i].move)) {node = nodes[i].getCopy();};};
   if(node != null) {
    this.getEnvironment().getClock().change("empty");
    this.setNumberMove(this.getNumberMove()+1);
    this.getEnvironment().getMainBoard().move(move.clone());
    this.getEnvironment().getVisualBoard().move(move);
    this.getEnvironment().getVisualGamePanel().move(move);
    this.createLegalNodes(node);
	if(node.nodes.length != 0) {
     this.setLastNode(node);
     if(this.getGameDoRun()) {
      this.setWhoseMove(node.getWhoseMove());
      this.getEnvironment().getVisualGamePanel().showNodes(node);
      var the = this;
      var f = function() {if(the.getEnvironment().getProperties().getDoPause()) {the.getEnvironment().getVisualGamePanel().toPause();} else {the.inviteDoMove();};};
      setTimeout(f, 300);
	 };
    } else {
     //if(this.mustDebug()) {this.getLog().println("su.bot.checkers.javascript.Referee.doMove INTERNAL ERROR!");};
	};
   } else {
    //if(this.mustDebug()) {this.getLog().println("su.bot.checkers.javascript.Referee.doMove ISN'T LEGAL MOVE!");};
   };
  } else {
   //if(this.mustDebug()) {this.getLog().println("su.bot.checkers.javascript.Referee.doMove ISN'T LEGAL NAME!");};
  };
 };
  
 su.bot.checkers.javascript.Referee.prototype.end = function() {
  if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.end is runing...");};
  this.setGameDoRun(false);
  this.setWhoseMove("");
  this.getEnvironment().getVisualGamePanel().showNodes(new su.bot.checkers.javascript.Node());
  this.getEnvironment().getClock().end();
  this.getEnvironment().getMaxGamer().end();
  this.getEnvironment().getMinGamer().end();
  if(this.getEnvironment().getProperties().getAutoplay()) {
   this.getEnvironment().getVisualGamePanel().changeScore();
   var the = this; this.moveTimer = setTimeout(function(){the.getEnvironment().getVisualGamePanel().doStartAutoplay();}, 3000);
  } else {
   this.getEnvironment().getVisualGamePanel().toStop();
  };
 };
  
 su.bot.checkers.javascript.Referee.prototype.getLegalMovesForChecker = function(node, fromSquare) {
  //if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.getLegalMovesForChecker is runing...");};
  var moves = new Array();
  var board = node.getBoard();
  var fromI = fromSquare.i;
  var properties = this.environment.properties;
  var whoseTopPosition = properties.whoseTopPosition;
  var toI = (node.whoseMove == whoseTopPosition) ? fromI+1 : fromI-1;
  if(board.containI(toI)) {
   var fromJ = fromSquare.j;
   for(var toJ = fromJ-1; toJ < fromJ+2; toJ = toJ+2) {
    if(board.containJ(toJ)) {
     if(board.getChecker(toI, toJ).isEmpty()) {
      var toSquare = new su.bot.checkers.javascript.Square();
      toSquare.i = toI; toSquare.j = toJ;
      var move = new su.bot.checkers.javascript.Move();
      move.from = fromSquare; move.to = toSquare; move.checker = board.getChecker(fromI, fromJ).clone();
      if( ( (toI == (properties.getNumberSquaresVertical()-1)) && (node.whoseMove == whoseTopPosition) ) || ( (toI == 0) && (node.whoseMove != whoseTopPosition) )) {
        move.setComeKing(true);
	   };
	  moves[moves.length] = move;
     };
    };
   };
  };
  return moves;
 };
  
 su.bot.checkers.javascript.Referee.prototype.getLegalMovesForKing = function(node, fromSquare) {
  //if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.getLegalMovesForKing is runing...");};
  var moves = new Array();
  var board = node.getBoard();
  var fromI = fromSquare.i; var fromJ = fromSquare.j;
  var kingMoveLength = this.getEnvironment().getProperties().getKingMoveLength();
  for(var offset=1; offset < kingMoveLength; offset=offset+1) {
   for(var offsetI=-1*offset; offsetI < offset*2; offsetI += offset*2) {
    for(var offsetJ=-1*offset; offsetJ < offset*2; offsetJ += offset*2) {
     var toI = fromI+offsetI; var toJ = fromJ+offsetJ;
     var toSquare = new su.bot.checkers.javascript.Square();
     toSquare.i = toI; toSquare.j = toJ; 
     if(board.isFree(fromSquare, toSquare)) {
	  var move = new su.bot.checkers.javascript.Move();
      move.from = fromSquare; move.to = toSquare; move.checker = board.getChecker(fromI, fromJ).clone();
	  moves[moves.length] = move;
	 };
	};
   };
  };
  return moves;
 };
  
 su.bot.checkers.javascript.Referee.prototype.getLegalTakesForChecker = function(node, fromSquare) {
  //if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.getLegalTakesForChecker is runing...");};
  var moves = new Array();
  var fromI = fromSquare.getI(); var fromJ = fromSquare.getJ();
  var board = node.getBoard();
  var firstOffsetI = 1;
  var properties = this.environment.getProperties();
  var whoseTopPosition = properties.getWhoseTopPosition();
  if(properties.getTakeBack()) {firstOffsetI = -1;};
  for(var offsetI = firstOffsetI; offsetI < 2; offsetI = offsetI+2) {
   var toI;
   if(node.getWhoseMove() == whoseTopPosition) {
    takeI = fromI+offsetI;
    toI = fromI+2*offsetI;
   } else {
    takeI = fromI-offsetI;
    toI = fromI-2*offsetI; 
   };
   if(board.containI(takeI) && board.containI(toI)) {
    for(var offsetJ = -1; offsetJ < 2; offsetJ = offsetJ+2) {
     var takeJ = fromJ+offsetJ;
     var toJ = fromJ+2*offsetJ;
     if(board.containJ(takeJ) && board.containJ(toJ)) {
      if(board.getChecker(toI, toJ).isEmpty() 
         && !board.getChecker(takeI, takeJ).isEmpty()
         && board.getChecker(takeI, takeJ).getOwner() != board.getChecker(fromI, fromJ).getOwner()) {
       var toSquare = new su.bot.checkers.javascript.Square();
	   toSquare.setI(toI); toSquare.setJ(toJ);
       var takeSquare = new su.bot.checkers.javascript.Square();
	   takeSquare.setI(takeI); takeSquare.setJ(takeJ);
	   var move = new su.bot.checkers.javascript.Move();
	   move.setChecker(board.getChecker(fromI, fromJ).clone()); move.setTakedChecker(board.getChecker(takeI, takeJ).clone());
	   move.setFrom(fromSquare); move.setTake(takeSquare); move.setTo(toSquare); 
	   if( ( (toI == (this.getEnvironment().getProperties().getNumberSquaresVertical()-1)) && (node.getWhoseMove() == this.getEnvironment().getProperties().getWhoseTopPosition()) )
          || ( (toI == 0) && (node.getWhoseMove() != this.getEnvironment().getProperties().getWhoseTopPosition()) )) {
        move.setComeKing(true);
	   };moves[moves.length] = move;
      };
     };
    };
   };
  };
  return moves;
 };
  
 su.bot.checkers.javascript.Referee.prototype.getLegalTakesForKing = function(node, fromSquare) {
  //if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.getLegalTakesForKing is runing...");};
  var moves = new Array();
  var fromI = fromSquare.getI(); var fromJ = fromSquare.getJ();
  if(!node) {node = this.getLastNode();};
  var board = node.getBoard();
  var kingMoveLength = this.getEnvironment().getProperties().getKingMoveLength();
  for(var offsetI = -1; offsetI <= 1; offsetI=offsetI+2) {
   for(var offsetJ = -1; offsetJ <= 1; offsetJ=offsetJ+2) {
    var takeI = fromI+offsetI; var takeJ = fromJ+offsetJ;
	var i;
	for(i = 2; board.containI(takeI) && board.containJ(takeJ) && board.getChecker(takeI, takeJ).isEmpty() && (Math.abs(i*offsetI) <= kingMoveLength) && (Math.abs(i*offsetJ) <= kingMoveLength); i++) {
     takeI = fromI + i*offsetI; takeJ = fromJ + i*offsetJ;
	};
	if(board.containI(takeI) && board.containJ(takeJ) 
	   && (Math.abs(i*offsetI) <= kingMoveLength) && (Math.abs(i*offsetJ) <= kingMoveLength)
	   && board.getChecker(takeI, takeJ).getOwner() != board.getChecker(fromI, fromJ).getOwner()) {
	 var toI = takeI+offsetI; var toJ = takeJ+offsetJ;
	 for(var j = 1; board.containI(toI) && board.containJ(toJ) && board.getChecker(toI, toJ).isEmpty(); j++) {
      var toSquare = new su.bot.checkers.javascript.Square();
      toSquare.setI(toI); toSquare.setJ(toJ);
      var takeSquare = new su.bot.checkers.javascript.Square();
      takeSquare.setI(takeI); takeSquare.setJ(takeJ);
      var move = new su.bot.checkers.javascript.Move();
      move.setChecker(board.getChecker(fromI, fromJ).clone()); move.setTakedChecker(board.getChecker(takeI, takeJ).clone());
      move.setFrom(fromSquare); move.setTake(takeSquare); move.setTo(toSquare); 
      moves[moves.length] = move;
      toI = takeI+(j+1)*offsetI; toJ = takeJ+(j+1)*offsetJ;	  
	 };
	}
   };
  };
  return moves;
 };
 
 su.bot.checkers.javascript.Referee.prototype.init = function() {
  if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.init is runing...");};
  if(this.getGameDoRun()) {return -1;};
  this.setNumberMove(1);
  this.setCurrentGameNodes(new Array());
  this.getEnvironment().getVisualClock().update();
  this.getEnvironment().getClock().run();
  try {clearTimeout(this.getEnvironment().getVisualBoard().getMoveTimer());} catch (e) {};
  var mainBoard = new su.bot.checkers.javascript.Board();
  this.getEnvironment().setMainBoard(mainBoard); 
  this.getEnvironment().getMainBoard().create();
  var visualBoard = new su.bot.checkers.javascript.VisualBoard();
  visualBoard.setDebugging(this.getDebugging()); visualBoard.setTracing(this.getTracing()); visualBoard.setLog(this.getLog());
  this.getEnvironment().setVisualBoard(visualBoard); 
  this.getEnvironment().getVisualBoard().display();
  this.setWhoseMove(this.getEnvironment().getProperties().getWhoseMove());
  this.getEnvironment().getMaxGamer().init();
  this.getEnvironment().getMinGamer().init();
  var node = new su.bot.checkers.javascript.Node;
  node.setBoard(this.getEnvironment().getMainBoard());
  node.setWhoseMove(this.getWhoseMove());
  this.setLastNode(node);
 };
 
 su.bot.checkers.javascript.Referee.prototype.inviteDoMove = function() {
  if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.inviteDoMove is runing for this.getWhoseMove()="+this.getWhoseMove());};
  this.getEnvironment().getClock().change(this.getWhoseMove());
  if(this.getWhoseMove() == "min") {this.getEnvironment().getMinGamer().doMove();} else {this.getEnvironment().getMaxGamer().doMove();};
 };
 
 su.bot.checkers.javascript.Referee.prototype.isLegalMove = function(move) {
  if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.isLegalMove is runing...");};
  var nodes = this.getLastNode().getNodes();
  for(var i = 0; i < nodes.length; i++) {if(move.similarTo(nodes[i].getMove())) {return true;};};
  return false;
 };
  
 su.bot.checkers.javascript.Referee.prototype.run = function() {
  if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.run is runing...");};
  this.setGameDoRun(true);
  this.getEnvironment().getMaxGamer().run();
  this.getEnvironment().getMinGamer().run();
  this.createLegalNodes(this.getLastNode());
  this.getEnvironment().getVisualGamePanel().showNodes(this.getLastNode());
  this.inviteDoMove();
 };
  
 su.bot.checkers.javascript.Referee.prototype.surrender = function(who) {
  if(this.mustTrace()) {this.getLog().println("su.bot.checkers.javascript.Referee.surrender is runing...");};
  if(who == "max") {
   this.setMinScore(this.getMinScore()+2);
  } else {
   this.setMaxScore(this.getMaxScore()+2);
  };
  this.end();
 };
};
