** Running Tests for 0,0,0 **
Player 0 should bet: 0
Player 1 should bet: 0
Player 2 should bet: 0
** Running Tests for 100,0,0 **
Player 0 should bet: 99
Player 1 should bet: 0
Player 2 should bet: 0
** Running Tests for 0,100,0 **
Player 0 should bet: 0
Player 1 should bet: 99
Player 2 should bet: 0
** Running Tests for 0,0,100 **
Player 0 should bet: 0
Player 1 should bet: 0
Player 2 should bet: 99
** Running Tests for 100,100,0 **
Player 0 should bet: 99
Player 1 should bet: 99
Player 2 should bet: 0
** Running Tests for 0,100,100 **
Player 0 should bet: 0
Player 1 should bet: 99
Player 2 should bet: 99
** Running Tests for 100,100,100 **
Player 0 should bet: 100
Player 1 should bet: 100
Player 2 should bet: 100
** Running Tests for 2,5,11 **
Player 0 should bet: 2
Player 1 should bet: 0
Player 2 should bet: 0
** Running Tests for 2,5,10 **
Player 0 should bet: 2
Player 1 should bet: 0
Player 2 should bet: 0
** Running Tests for 2,5,9 **
Player 0 should bet: 2
Player 1 should bet: 5
Player 2 should bet: 2
** Running Tests for 2,4,10 **
Player 0 should bet: 2
Player 1 should bet: 0
Player 2 should bet: 1
** Running Tests for 2,3,10 **
Player 0 should bet: 2
Player 1 should bet: 2
Player 2 should bet: 3
** Running Tests for 2,3,4 **
Player 0 should bet: 2
Player 1 should bet: 2
Player 2 should bet: 3
** Running Tests for 4,6,7 **
Player 0 should bet: 4
Player 1 should bet: 2
Player 2 should bet: 6
Last active
October 13, 2015 00:07
-
-
Save supernova-at/09abd6be8b8af3417346 to your computer and use it in GitHub Desktop.
Candygram: Final Jeopardy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileOverview | |
* Final Jeopardy algorithm for contestants to determine how much to bet in Final Jeopardy. | |
*/ | |
/** | |
* The determineBet function takes an array of player scores | |
* and an index into that array that allows us to determine the player's score. | |
* | |
* The assumption is that the player has 50% confidence that they'll get the | |
* answer correct, so we do no sort of 'hedging our bets' here. | |
* | |
* The goal of the algorithm is to place as high as possible, which is slightly | |
* different than make the most money possible. The latter would make for a | |
* pretty boring algorithm: always bet the max. | |
* | |
* So we take into account cases where players under us can overtake us and | |
* attempt to guard against that. | |
* | |
* @param {Array} scores - Player dollar amounts (Numbers) | |
* @param {Number} playerIndex - the player to figure out the bet for | |
* @return {Number} the amount the player should bet | |
*/ | |
function determineBet(scores, playerIndex) { | |
// Get the player score before we sort. | |
var playerScore = scores[playerIndex]; | |
// scores is not guaranteed to be sorted, do that now. | |
scores.sort(function (a, b) { | |
// Ascending numeric sort. | |
return a - b; | |
}); | |
// Now that the scores are sorted, the highest one will be at the end. | |
var highestScore = scores[scores.length - 1]; | |
// Likewise, lowest will be at the beginning. | |
var lowestScore = scores[0]; | |
// For convenience. | |
var hasHighestScore = (playerScore === highestScore); | |
var hasLowestScore = (playerScore === lowestScore); | |
// The highest score = the lowest indicates that everyone is tied. | |
var allTied = (hasLowestScore && hasLowestScore); | |
if (allTied) { | |
// Bet the maximum. | |
// Betting less than this would open us to getting it right but still | |
// losing. | |
return playerScore; | |
} | |
/* | |
* Determine the scores above and below us. | |
*/ | |
// "Skip over" all the people who are tied with us. | |
var firstIndex = scores.indexOf(playerScore); | |
var lastIndex = scores.lastIndexOf(playerScore); | |
// If we have the lowest score, there's no score below us. | |
// Otherwise, get the closest score below us. | |
var previousScore = (hasLowestScore) ? null : scores[firstIndex - 1]; | |
// If we have the highest score, there's no score above us. | |
// Otherwise, get the closest score above us. | |
var nextScore = (hasHighestScore) ? null : scores[lastIndex + 1]; | |
// If we have the highest score, make sure the guy below us can't pass us. | |
if (hasHighestScore) { | |
// What's his maximum score? Doubling his money. | |
var previousMax = (previousScore * 2); | |
// Make sure we stay above that no matter what (if possible) | |
// to ensure a win. | |
var difference = playerScore - previousMax; | |
if (difference > 0) { | |
// He can't pass us unless we open the door. | |
// Maximize our winnings but don't put us below previousMax. | |
return difference - 1; | |
} | |
else if (difference === 0) { | |
// If we bet zero, he can tie us by doubling his money. | |
// If we bet anything else we open ourselves up to losing, so | |
// eliminate that possibility by betting zero, even though ties stink. | |
// Worst we can do is tie for the lead. | |
return 0; | |
} | |
else { | |
// difference < 0, which means he can pass us if he doubles his money. | |
// Don't let that happen, but don't bet the farm either - safeguard | |
// ourselves from being overtaken by the third place guy too. | |
// We could go through every other player in the list here and really | |
// determine the best bet but the football game is about to start so | |
// I'm taking the easy way out :) | |
// Note: using * -1 here because we already know difference < 0. | |
// Math.abs would have to figure that out and so would be slightly | |
// less performant. | |
return (difference * -1) + 1; | |
} | |
} | |
else if (hasLowestScore) { | |
// I'm not sure there's a legitimate reason for the lowest guy to bet | |
// anything other than the max. He'll always need help from others to | |
// actually win. | |
return playerScore; | |
} | |
else { | |
// We're the guy in the middle. | |
// Can we pass the leader? | |
var doubleMoney = playerScore * 2; | |
var canOvertake = (doubleMoney > highestScore); | |
// Can the lowest guy pass us? | |
var canBeOvertaken = (lowestScore * 2) > playerScore; | |
if (canOvertake) { | |
// Even if we can be overtaken, prefer to go for the win | |
// as opposed to avoiding the loss. | |
// Don't bet max to shield ourselves from tying if everyone gets it | |
// wrong. | |
return (highestScore - playerScore + 1); | |
} | |
else if (canBeOvertaken) { | |
// We have to bet something, lock the previous guy out. | |
return ((lowestScore * 2) - playerScore + 1); | |
} | |
else { | |
// Can't overtake and can't be overtaken if we bet zero. Play it safe. | |
return 0; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment