/* * Evaluate function to evaluate the nodes of my tree. I added a variable to keep track of how many turns players got. * if each player got equal number of turns then the number is 0, if top got more is <0 and opposite for bottom * Note: my Max is for the bottom because I could visualize it better that way. * */ public int evaluate(Board b, int playsinarow) { int score = b.stonesAt(6) - b.stonesAt(13); int stones = 0; int distributedstones = 0; for (int i = 0; i < 6; i++) { stones = stones + (b.stonesAt(i) - b.stonesAt(12 - i));//who has controll of more stones } if (b.gameOver()) { score += stones; //if game is over add the extra stones to the scores } int goagains = 0; //figure out how many go agains may be possible at the begininng of the next turn if (b.whoseMove() == Position.Top) { for (int i = 12; i >= 7; i--) { // try first go-again if (b.stonesAt(i) == 13 - i) { goagains--; } distributedstones = i - 13 + b.stonesAt(i); //find the distribution of the stones } } else { for (int i = 5; i >= 0; i--) { if (b.stonesAt(i) == 6 - i) { goagains++; } distributedstones = 6 - i - b.stonesAt(i); } } //note that plays and go agains are raised to the power of three to conserve signs and help promote sprees. return(40 * score + 2 * Convert.ToInt32(Math.Pow((playsinarow + goagains), 3)) + 30 * distributedstones);//weights were found be tweeking to find the most defensive and offensive bot. }
/* * Evaluate: return a number saying how much we like this board. * TOP is MAX, so positive scores should be better for TOP. * This default just counts the score so far. Override to improve! */ public virtual int evaluate(Board b) { int score = 0; bool allZeros = true; int endCaptures = 0; int stonesAt = 0; score += (b.stonesAt(13) - b.stonesAt(6)) * 100; for (int i = 12; i >= 7; i--) { stonesAt = b.stonesAt(i); if (b.stonesAt(12 - i) > 0) { allZeros = false; } //if (stonesAt == 0) // score += 2 * b.stonesAt(12 - i); endCaptures += stonesAt; } if (allZeros) { score += endCaptures * 100; } allZeros = true; endCaptures = 0; for (int i = 5; i >= 0; i--) { stonesAt = b.stonesAt(i); if (b.stonesAt(12 - i) > 0) { allZeros = false; } //if (stonesAt == 0) // score -= 2 * b.stonesAt(12 - i); endCaptures += stonesAt; } if (allZeros) { score -= endCaptures * 100; } return(score); }
/* * Evaluate: return a number saying how much we like this board. * h1 = the difference in score * h2 = stones in my home * h3 = stones in opponent's home * h4 = whether or not to go again * h5 = whether or not to capture opponent's pieces */ public override int evaluate(Board b) { int h1; int h2; int h3; int h4 = 0; int h5 = 0; int target; int captureTarget; int score; if (me == Position.Top) { h2 = b.stonesAt(13); // stones in my home h3 = b.stonesAt(6); // stones in opponent's home h1 = h2 - b.scoreBot(); // my margin of winning/losing for (int i = 7; i < 13; i++) { target = (i + b.stonesAt(i)) % 12; captureTarget = ((target - 12) + (2 * (12 - target))); // lookup the spot on the opposite of the board for a potential capture if (target == 13 && b.whoseMove() == me) // if the move will end in my home -- a go-again { h4 = 1; } else if (b.stonesAt(target) == 0 && target > 6 && b.whoseMove() == me) // if it is possible to get a capture { if (b.stonesAt(captureTarget) > 2) // see if capture is worth it { h5 = 50; } } } } else { // if I'm on the bottom, do the same thing but changed for the bottom half of the board h2 = b.stonesAt(6); h3 = b.stonesAt(13); h1 = h2 - b.scoreTop(); for (int i = 0; i < 6; i++) { target = (i + b.stonesAt(i)) % 12; captureTarget = ((target + 12) - (2 * target)); if (target == 6 && b.whoseMove() == me) { h4 = 1; } else if (b.stonesAt(target) == 0 && target < 6 && b.whoseMove() == me) // if it is possible to get a capture { if (b.stonesAt(captureTarget) > 2) // see if capture is worth it { h5 = 50; } } } } score = h1 + h2 + h5 + h4; score = (me == Position.Top) ? score : -1 * score; if (h2 > 24) // if we've won -- really want this { score += 500; } else if (h3 > 24) // if opponent has won -- really don't want this { score -= 500; } return(score); }
/* Evaluate: override --> consider at least 3 more factors * The University of Kansas researched that there are 7 * factors that play an important role for winning in Mancala * for the sake of time, I will focus on 3 of them. * total stones, go agains, and captures total */ public override int evaluate(Board b) // ---> change this { int score = b.stonesAt(13) - b.stonesAt(6); //followed from example of player class // score = (b.whoseMove() == Position.Top) ? score : -1 * score; int totalStones = 0; int goAgainTotal = 0; int capturesTotal = 0; if (b.whoseMove() == Position.Top) { for (int i = 7; i <= 12; i++) //position == TOP { totalStones += b.stonesAt(i); //add all of the stones in the top row if (b.stonesAt(i) - (13 - i) == 0) //add the times you can go again { goAgainTotal += 1; } int target = i + b.stonesAt(i); if (target < 13) { int tStones = b.stonesAt(target); if (b.whoseMove() == Position.Top) { if (tStones == 0 && b.stonesAt(13 - target - 1) != 0) { capturesTotal += b.stonesAt(13 - target - 1); } } } } } else { for (int i = 0; i <= 5; i++) { //position == BOTTOM totalStones -= b.stonesAt(i); //subtract all the stones from the bottom row if (b.stonesAt(i) - (6 - i) == 0) { //for the bottom row goAgainTotal -= 1; //subtract go agains } int target = i + b.stonesAt(i); if (target < 6) { int tStones = b.stonesAt(target); if (b.whoseMove() == Position.Bottom) { if (tStones == 0 && b.stonesAt(13 - target - 1) != 0) { capturesTotal -= b.stonesAt(13 - target - 1); } } } } } capturesTotal = (b.whoseMove() == Position.Top) ? capturesTotal : -1 * capturesTotal; totalStones = (b.whoseMove() == Position.Top) ? totalStones : -1 * totalStones; goAgainTotal = (b.whoseMove() == Position.Top) ? goAgainTotal : -1 * goAgainTotal; score += totalStones + capturesTotal + goAgainTotal; return(score); }
/*Evaluate function used when the end game is not clear * Uses heuristic found on github by previous student * Code belongs to Chan Kim ([email protected]) */ public override int evaluate(Board b) { int score = b.stonesAt(13) - b.stonesAt(6); int stonesTotal = 0; int goAgainsTotal = 0; int capturesTotal = 0; for (int i = 7; i <= 12; i++) { int priority = 0; int target = b.stonesAt(i) % (13 - i); int targetStonesAt = b.stonesAt(target + 7); if (b.whoseMove() == Position.Bottom) { stonesTotal -= b.stonesAt(i); if ((b.stonesAt(i) - (13 - i) == 0) || (b.stonesAt(i) - (13 - i)) == 13) { goAgainsTotal -= (1 + priority); } if (targetStonesAt == 0 && b.stonesAt(i) == (13 - i + target + 7)) { capturesTotal += (b.stonesAt(i) + b.stonesAt(12 - target)); } } else { stonesTotal += b.stonesAt(i); if ((b.stonesAt(i) - (13 - i) == 0) || (b.stonesAt(i) - (13 - i)) == 13) { goAgainsTotal += (1 + priority); } if (targetStonesAt == 0 && b.stonesAt(i) == (13 - i + target + 7)) { capturesTotal -= (b.stonesAt(i) + b.stonesAt(12 - target)); } } priority++; } for (int i = 0; i <= 5; i++) { int priority = 0; int target = b.stonesAt(i) % (13 - i); int targetStonesAt = b.stonesAt(target); if (b.whoseMove() == Position.Bottom) { stonesTotal += b.stonesAt(i); if ((b.stonesAt(i) - (6 - i) == 0) || (b.stonesAt(i) - (6 - i)) == 13) { goAgainsTotal -= (1 + priority); } if (targetStonesAt == 0 && b.stonesAt(i) == (13 - i + target)) { capturesTotal -= (b.stonesAt(i) + b.stonesAt(12 - target)); } } else { stonesTotal -= b.stonesAt(i); if ((b.stonesAt(i) - (6 - i) == 0) || (b.stonesAt(i) - (6 - i)) == 13) { goAgainsTotal += (1 + priority); } if (targetStonesAt == 0 && b.stonesAt(i) == (13 - i + target)) { capturesTotal += (b.stonesAt(i) + b.stonesAt(12 - target)); } } priority++; } score += stonesTotal + capturesTotal + goAgainsTotal; return(score); //int score; //if (us == Position.Top) // score = b.scoreTop() - b.scoreBot(); //else // score = b.scoreBot() - b.scoreTop(); //return score; }
// evaluates the board from minimax search for total stones, possible replays and captures public override int evaluate(Board b) { int score = b.stonesAt(13) - b.stonesAt(6); int totalStones = 0; //total stones on the board int playAgain = 0; //total go-agains from ending in own bin int captures = 0; //total number of possible captures int targetPit = 0; //last pit into which stones from current pit will go if (b.whoseMove() == Position.Top) { for (int i = 7; i < 13; i++) { totalStones += b.stonesAt(i); if (b.stonesAt(i) == (13 - i)) { playAgain++; } targetPit = i + b.stonesAt(i); if (targetPit < 13 && (b.stonesAt(targetPit) == 0 && b.stonesAt(12 - i) > 0)) { captures++; } } } else { for (int i = 0; i < 6; i++) { totalStones -= b.stonesAt(i); if (b.stonesAt(i) == (13 - i)) { playAgain--; } targetPit = i + b.stonesAt(i); if (targetPit < 13 && (b.stonesAt(targetPit) == 0 && b.stonesAt(12 - i) > 0)) { captures--; } } } return(score + playAgain + captures + totalStones); }
// evaluates the board based on potential go-agains, captures, and stones each side has // and returns a score based on those values public override int evaluate(Board b) { int score = b.stonesAt(13) - b.stonesAt(6); int totalStones = 0; int goAgains = 0; int captures = 0; for (int i = 7; i <= 12; i++) { int priority = 0; int target = b.stonesAt(i) % (13 - i); int targetStonesAt = b.stonesAt(target + 7); if (b.whoseMove() == Position.Bottom) { totalStones -= b.stonesAt(i); if ((b.stonesAt(i) - (13 - i) == 0) || (b.stonesAt(i) - (13 - i)) == 13) { goAgains -= (1 + priority); } if (targetStonesAt == 0 && b.stonesAt(i) == (13 - i + target + 7)) { captures += (b.stonesAt(i) + b.stonesAt(12 - target)); } } else { totalStones += b.stonesAt(i); if ((b.stonesAt(i) - (13 - i) == 0) || (b.stonesAt(i) - (13 - i)) == 13) { goAgains += (1 + priority); } if (targetStonesAt == 0 && b.stonesAt(i) == (13 - i + target + 7)) { captures -= (b.stonesAt(i) + b.stonesAt(12 - target)); } } priority++; } for (int i = 0; i <= 5; i++) { int priority = 0; int target = b.stonesAt(i) % (13 - i); int targetStonesAt = b.stonesAt(target); if (b.whoseMove() == Position.Bottom) { totalStones += b.stonesAt(i); if ((b.stonesAt(i) - (6 - i) == 0) || (b.stonesAt(i) - (6 - i)) == 13) { goAgains -= (1 + priority); } if (targetStonesAt == 0 && b.stonesAt(i) == (13 - i + target)) { captures -= (b.stonesAt(i) + b.stonesAt(12 - target)); } } else { totalStones -= b.stonesAt(i); if ((b.stonesAt(i) - (6 - i) == 0) || (b.stonesAt(i) - (6 - i)) == 13) { goAgains += (1 + priority); } if (targetStonesAt == 0 && b.stonesAt(i) == (13 - i + target)) { captures += (b.stonesAt(i) + b.stonesAt(12 - target)); } } priority++; } score += totalStones + captures + goAgains; return(score); }
// The overriden evaluate() function checks various features of the current board, and // attempts to predict the score in order to assisst the minimax function in // choosing the best move to make. The score will generally be negative if // bottom is predicted to win, and positive if top is predicted to win. public override int evaluate(Board b) { // heuristics int score = b.stonesAt(13) - b.stonesAt(6); // necessary, tested as one of the best heuristics int stonesTotal = 0; // established that it is very good, both by tests and articles (1) int goAgainsTotal = 0; // established as accurate, it will add an extra point if a 'go-again' is possible (2) int capturesTotal = 0; // established as accurate, it adds the actual number of points that would be captured (3) int opponentWinning = 0; // not entirely accurate, the weights are subject to change (4) // TOP loop - calcuate heuristics for the top player for (int i = 7; i <= 12; i++) { // add all the stones in the top row stonesTotal += b.stonesAt(i); // add all the 'go-again's in the top row if (b.stonesAt(i) - (13 - i) == 0) { goAgainsTotal += 1; } // add all of stones that can be obtained through captures int target = i + b.stonesAt(i); if (target < 13) { int targetStones = b.stonesAt(target); if (b.whoseMove() == Position.Top) { if (targetStones == 0 && b.stonesAt(13 - target - 1) != 0) { capturesTotal += b.stonesAt(13 - target - 1); } } } } // BOTTOM loop - calcuate heuristics for the bottom player for (int i = 0; i <= 5; i++) { // subtract all the stones in the bottom row stonesTotal -= b.stonesAt(i); // add all the 'go-again's in the bottom row if (b.stonesAt(i) - (6 - i) == 0) { goAgainsTotal -= 1; } // subtract all of stones that can be obtained through captures int target = i + b.stonesAt(i); if (target < 6) { int targetStones = b.stonesAt(target); if (b.whoseMove() == Position.Bottom) { if (targetStones == 0 && b.stonesAt(13 - target - 1) != 0) { capturesTotal -= b.stonesAt(13 - target - 1); } } } } // calculate the 'closeness' of the opponent winning if (b.whoseMove() == Position.Top) { // if you are top and your opponent is close to winning, give some points to MIN if (b.stonesAt(6) > 24) { opponentWinning -= 3; } } else { // if you are bottom and your opponent is close to winning, give some points to MAX if (b.stonesAt(13) > 24) { opponentWinning += 3; } } // add up all of the heuristics and return what is believed the score will be score += stonesTotal + capturesTotal + opponentWinning + goAgainsTotal; return(score); }
/* * Evaluate: return a number saying how much we like this board. * TOP is MAX, so positive scores should be better for TOP. * This default just counts the score so far. Override to improve! */ public virtual int evaluate(Board b) { return(b.stonesAt(13) - b.stonesAt(6)); }
//Function evaulates the board and returns a score paired with a board space value public int evaluate(Board b) { int score = 0; if (b.whoseMove() == Position.Top) { //oppoDiff is used to keep the difference between the current hole and the opposite one across the board for (int i = 12; i >= 7; i--) { int lastHole = (i + b.stonesAt(i)) % 13; // CASE 1.0: If there's a go-again available, add 2 to the score if (b.stonesAt(i) == 13 - i) { score += 2; } // CASE 1.1: If there's a go-again available for the opponent, subtract 1 from the score //also use loop for... // CASE 2.0: If the holes are empty, check to see if they can be filled // ...and... //CASE 2.1: Check opponent's holes to see if they can be filled for (int j = 5; j >= 0; j--) { int lastOppoHole = (j + b.stonesAt(j)) % 13; //CASE 1.1 check... if (b.stonesAt(j) == 6 - j) { score -= 2; //Counter-attack: If this opponent hole can be filled by the stones in the current hole, //add to score if (b.stonesAt(j) < lastHole) { score += 5; } } //CASE 2.0 check... if (b.stonesAt(j) == 0) { if (lastHole >= j) { score += 5; } } //CASE 2.1 check... if (j + lastOppoHole >= i) { score -= 2; } } //If the last stone is placed within the top... if (lastHole < 13) { // CASE 3.0: Possible stone capture if (b.stonesAt(lastHole) == 0) { //if the last stone is placed in an empty hole on the top score += 1; if (b.stonesAt(getOpposite(lastHole)) != 0) { //if there are stones found in the opposite hole, add them to the score score += b.stonesAt(getOpposite(lastHole)); } } //CASE 3.1: Last stone placed will contribute to a possible capture from your opponent else { //If the opposite hole is empty and not 0 if (b.stonesAt(getOpposite(lastHole)) == 0 && getOpposite(lastHole) != 0) { for (int j = b.stonesAt(getOpposite(lastHole - 1)); j >= 0; j--) { //If any of the holes leading up to the opposite empty hole have enough stones //to put one in the empty hole and capture, subtract from the score if (b.stonesAt(j) + j == b.stonesAt(getOpposite(lastHole))) { score -= b.stonesAt(i); } } } } } } } else { for (int i = 5; i >= 0; i--) { //int lasthole is the hole that gets the last stone from hole i int lastHole = (i + b.stonesAt(i)) % 13; // CASE 1.0: If there's a go-again available, add 2 to the score if (b.stonesAt(i) == 6 - i) { score += 2; } // CASE 1.1: If there's a go-again available for the opponent, subtract 1 from the score //also use loop for... // CASE 2.0: if the holes are empty, check to see if they can be filled for (int j = 12; j >= 7; j--) { int lastOppoHole = (j + b.stonesAt(j)) % 13; if (b.stonesAt(j) == 13 - j) { score -= 2; //Counter-attack: If this opponent hole can be filled by the stones in the current hole, //add to score if (b.stonesAt(j) < lastHole) { score += 5; } } //CASE 2.0 case check... if (b.stonesAt(j) == 0) { if (lastHole >= j) { score += 5; } } //CASE 2.1 check... if (j + lastOppoHole >= i) { score -= 2; } } //If the last stone is placed within the bottom... if (lastHole < 6) { //CASE 3.0: Possible stone capture if (b.stonesAt(lastHole) == 0) { //if the last stone is placed in an empty hole on the bottom score += 1; //if there are stones found in the opposite hole, add them to the score if (b.stonesAt(getOpposite(lastHole)) != 0) { score += b.stonesAt(getOpposite(lastHole)); } } //CASE 3.1: Last stone placed will contribute to a possible capture from your opponent else { //If the opposite hole is empty and not 7 if (b.stonesAt(getOpposite(lastHole)) == 0 && getOpposite(lastHole) != 7) { for (int j = b.stonesAt(getOpposite(lastHole - 1)); j >= 0; j--) { //If any of the holes leading up to the opposite empty hole have enough stones //to put one in the empty hole and capture, subtract from the score if (b.stonesAt(j) + j == b.stonesAt(getOpposite(lastHole))) { score -= b.stonesAt(i); } } } } } } } return(score); }
/*Evaluate function used when the end game is not clear * Uses 5 heuristics found by researchers at the University of Kansas to be the best * Heuristic research found at https://fiasco.ittc.ku.edu/publications/documents/Gifford_ITTC-FY2009-TR-03050-03.pdf * h1 is my score - opponent's score * h2 is how close I am to winning * h3 is how close the opponent is to winning * h4 is the number of stones close to my home * h5 is the number of stones far from my home (on my side of the board) */ public override int evaluate(Board b) { int h1, h2, h3, h4, h5, h6, target, sum; h6 = 0; if (us == Position.Top) { h2 = b.stonesAt(13); h3 = b.stonesAt(6); h1 = h2 - b.scoreBot(); h4 = b.stonesAt(11) + b.stonesAt(12); h5 = b.stonesAt(7) + b.stonesAt(8); for (int i = 7; i < 13; i++) { target = i + b.stonesAt(i); if (target == 13) //calculating go-agains { //if (b.stonesAt(target) == 0 && b.stonesAt(12 - target) != 0) // h6 += b.stonesAt(12 - target); h6 = 100; } } } else { h2 = b.stonesAt(6); h3 = b.stonesAt(13); h1 = h2 - b.scoreTop(); h4 = b.stonesAt(4) + b.stonesAt(5); h5 = b.stonesAt(0) + b.stonesAt(1); for (int i = 0; i < 6; i++) { target = i + b.stonesAt(i); if (target == 6) //calculating go-agains { //if (b.stonesAt(target) == 0 && b.stonesAt(12 - target) != 0) // h6 += b.stonesAt(12 - target); h6 = 100; } } } sum = (h1 + 10) + (h2 + 8) - (h3 + 8) - (h4 + 4) + (h5 + 4) + (h6 + 0); sum = (us == Position.Top) ? sum : -1 * sum; if (h2 > 24) //If we have at least half of the stones { sum += 500; } else if (h3 > 24) //If opponent has at least half of the stones { sum -= 500; } return(sum); //int score; //if (us == Position.Top) // score = b.scoreTop() - b.scoreBot(); //else // score = b.scoreBot() - b.scoreTop(); //return score; }
/*Evaluate function used when the end game is not clear * Uses 5 heuristics found by researchers at the University of Kansas to be the best * Heuristic research found at https://fiasco.ittc.ku.edu/publications/documents/Gifford_ITTC-FY2009-TR-03050-03.pdf * h1 is my score - opponent's score * h2 is how close I am to winning * h3 is how close the opponent is to winning * h4 is the number of stones close to my home * h5 is the number of stones far from my home (on my side of the board) */ public override int evaluate(Board b) { int h1, h2, h3, h4, h5, sum; if (us == Position.Top) { h2 = b.stonesAt(13); h3 = b.stonesAt(6); h1 = h2 - b.scoreBot(); h4 = b.stonesAt(11) + b.stonesAt(12); h5 = b.stonesAt(7) + b.stonesAt(8); } else { h2 = b.stonesAt(6); h3 = b.stonesAt(13); h1 = h2 - b.scoreTop(); h4 = b.stonesAt(4) + b.stonesAt(5); h5 = b.stonesAt(0) + b.stonesAt(1); } sum = (h1 + 10) + (h2 + 8) - (h3 + 8) - (h4 + 4) + (h5 + 4); sum = (us == Position.Top) ? sum : -1 * sum; if (h2 > 24) //If we have at least half of the stones { sum += 500; } else if (h3 > 24) //If opponent has at least half of the stones { sum -= 500; } return(sum); //int score; //if (us == Position.Top) // score = b.scoreTop() - b.scoreBot(); //else // score = b.scoreBot() - b.scoreTop(); //return score; }