Skip to content

Instantly share code, notes, and snippets.

@supernova-at
Last active October 13, 2015 00:07
Show Gist options
  • Save supernova-at/09abd6be8b8af3417346 to your computer and use it in GitHub Desktop.
Save supernova-at/09abd6be8b8af3417346 to your computer and use it in GitHub Desktop.
Candygram: Final Jeopardy
/**
* @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;
}
}
}

Outputs

** 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment