Skip to content
{{ message }}

Instantly share code, notes, and snippets.

# steren/poker.js

Last active Jan 9, 2016
Poker Tournament manager script to be used with Google Spreadsheet
 // Poker Tournament script // by Steren Giannini http://www.steren.fr // # How to use // Use "=computePlayerScoreAndRank()" to generate a tournament ladder, as first argument select a column of player name, as second argument, select the cells of game ///////////// // Variables ///////////// // When participating, how much goes for this party? var contribPrice = 7; // When participating, how much goes for the pot? var potPrice = 1; // How much does a bounty represent as a gain var bountyGain = 2; // How much total money should you put to go into a party var buyInPrice = contribPrice + potPrice + bountyGain; // Coefficients used in the point computation, for 3rd place, use pointCoefs var pointCoefs = [ 0, 5, 4, 3, 2.5, 2.25, 2, 1.75, 1.5, 1.25 ]; // coefficients used in the gain coefficient, for 3rd place, use gainCoefs var gainCoefs = [ 0, contribPrice / 2, 2 * contribPrice / 7, 2 * contribPrice / 13 ]; // Number under which, every game will count in the final score, above this number of playes games, score is ajusted. var playedGamesNonAjustedLimit = 8; //////////// // Functions //////////// /** * From a player position, return this player's score. * @param position: number of the position in the game * @param totalPlayers: the total player number in the game */ function computePointsFromPosition(position, totalPlayers) { var points; if(position > pointCoefs.length - 1) { points = Math.round(totalPlayers + 1 - position); } else { points = Math.round(pointCoefs[position] * (totalPlayers - position + 1)); } return points; } /** * Compute real gain for a player, considering money won (Ladder + bounties) and money spent */ function computeGainsFromPosition(position, totalPlayers) { var gain = 0; if (position < gainCoefs.length) { gain = Math.round( totalPlayers * gainCoefs[position] ); } else if (position == gainCoefs.length) { // the last paid person wins the rest. gain = totalPlayers * contribPrice - Math.round(totalPlayers * gainCoefs) - Math.round(totalPlayers * gainCoefs) - Math.round(totalPlayers * gainCoefs); } return gain; } /** * for every game, count the number of players */ function computePlayerPerGames(positions) { // store the number of player for one game var playerPerGames = []; // for every game for(var game = 0; game < positions.length; game++) { playerPerGames[game] = 0; // for every player for(var player = 0; player < positions.length; player++) { if( positions[player][game] !== "") { playerPerGames[game]++; } } } return playerPerGames; } /** * Based on number of player per games, compute the real number of games */ function computeGameNumber(playerPerGames) { var gameNumber = 0; for(var i = 0; i < playerPerGames.length; i++) { if(playerPerGames[i]) { gameNumber++; } } return gameNumber; } /** * Compute all results for the given player * @param playerPositions: an array containing the positions of this player for each game * @param playerPerGames: an array containing the total number of player per games (result of computePlayerPerGames() ) * @param playerBounties: bounties for this player. * @param gameNumber: Total of games with more than 0 player (in order to remove empty game columns) * @return object containing all results for the given player. */ function computeForPlayer(playerPositions, playerPerGames, playerBounties, gameNumber) { var result = {} var totalScore = 0; var totalGain = 0; // Number of time a player has win the game var totalWin = 0; // Number of time a player has had a gain > 0 var totalITM = 0; // Number of played games for the given player var totalPlayedGames = 0; // Number of time a player has received a bounty from another player var bountyNumberForPlayer = 0; // Average position of this player var averagePosition = 0; // Number of time a player has finished last in the game var lostNumberForPlayer = 0; for(var i = 0; i < gameNumber; i++) { if( playerPositions[i] !== "" ) { totalScore += computePointsFromPosition(playerPositions[i], playerPerGames[i]); var playerGameGain = computeGainsFromPosition(playerPositions[i], playerPerGames[i]); totalGain += playerGameGain; if (playerGameGain > 0) { totalITM++; } totalPlayedGames++; averagePosition += playerPositions[i]; if( playerPositions[i] === playerPerGames[i]) { lostNumberForPlayer++; } } if( playerPositions[i] === 1 ) { totalWin++; } if( playerBounties[i] !== "" ) { bountyNumberForPlayer = bountyNumberForPlayer + playerBounties[i]; } } // Now we potentially adjust the totalScore for players who played too many games. // (Previously used formula) //var maxCountedGames = Math.floor(gameNumber * 3 / 4); //var averageScore = totalScore / totalPlayedGames; //if(totalPlayedGames > playedGamesNonAjustedLimit && totalPlayedGames > maxCountedGames){ // totalScore = totalScore - (totalPlayedGames - maxCountedGames) * averageScore; //} var averageScore = totalScore / totalPlayedGames; if(totalPlayedGames > playedGamesNonAjustedLimit){ totalScore = totalScore - (totalPlayedGames - playedGamesNonAjustedLimit) * averageScore / 3; } averagePosition = totalPlayedGames === 0 ? 0 : averagePosition / totalPlayedGames; result.totalScore = totalScore; result.totalGain = totalGain; result.totalITM = totalITM; result.totalWin = totalWin; result.totalPlayedGames = totalPlayedGames; result.bountyNumberForPlayer = bountyNumberForPlayer; result.averagePosition = averagePosition; result.lostNumberForPlayer = lostNumberForPlayer; return result; } /** * Main entry point * Compute for the scores of every given players, based on all their positions * @param playerNames: range of cell containing the player names. * @param positions: range double array, one row per player, in columns: the positions and bounties for one game (one game = 2 consecutive columns). * @return: a sorted multi columns array with: the player name as first column, other data as next columns */ function computePlayerScoreAndRank(playerNames, positionsAndBounties) { // playerNames is a [][], we need to transform it to an array. var playerNamesArray = []; for(var p = 0; p < playerNames.length; p++) { playerNamesArray.push(playerNames[p]); } // split the big game array in two smaller arrays, one containing only the player's positions and the other containing the player's bounties var positions = []; var bounties = []; for(var player = 0; player < positionsAndBounties.length; player++) { positions[player] = []; bounties[player] = []; for(var game = 0; game < positionsAndBounties[player].length / 2; game++) { positions[player][game] = positionsAndBounties[player][2 * game]; bounties[player][game] = positionsAndBounties[player][2 * game + 1]; } } var playerPerGames = computePlayerPerGames(positions); var gameNumber = computeGameNumber(playerPerGames); var playerScores = []; var playerAverage = []; var playerITMs = []; var playerWins = []; var playerLasts = []; var playerGains = []; var playerBounties = []; var playerPlayedGames = []; var playerRes; // for every player, compute his score and other data for(var player = 0; player < positions.length; player++) { playerRes = computeForPlayer(positions[player], playerPerGames, bounties[player], gameNumber); playerScores[player] = playerRes.totalScore; playerWins[player] = playerRes.totalWin; playerITMs[player] = playerRes.totalITM; playerLasts[player] = playerRes.lostNumberForPlayer; playerBounties[player] = playerRes.bountyNumberForPlayer; playerPlayedGames[player] = playerRes.totalPlayedGames; //Total gain is gain + bounties - buy ins playerGains[player] = playerRes.totalGain + playerBounties[player] * bountyGain - playerPlayedGames[player] * buyInPrice } var result = arrayTranspose([playerNamesArray, playerPlayedGames, playerScores, playerWins, playerITMs, playerLasts, playerGains, playerBounties]); var sortFunction = function (a, b) { if (a > b) return 1; if (a < b) return -1; // a must be equal to b return 0; }; // now time to sort everything, we write a custom sorting function that taks into account the score return result.sort(sortFunction).reverse(); } /** * Given a JavaScript 2d Array, this function returns the transposed table. * Example: arrayTranspose([[1,2,3],[4,5,6]]) returns [[1,4],[2,5],[3,6]]. * @param data: JavaScript 2d Array * @return a JavaScript 2d Array */ function arrayTranspose(data) { if (data.length == 0 || data.length == 0) { return null; } var ret = []; for (var i = 0; i < data.length; ++i) { ret.push([]); } for (var i = 0; i < data.length; ++i) { for (var j = 0; j < data[i].length; ++j) { ret[j][i] = data[i][j]; } } return ret; } /////////// // TESTS // /////////// /** Check tests results by displaying the Log view (View > Logs) */ function test() { Logger.log("Running tests"); Logger.log("Test compute player per games:"); var scores = computePlayerPerGames([[1,3,2], [2,2,""], ["",1,1]]); if( scores !== 2 || scores !== 3 || scores !== 2 ) { Logger.log("FAIL"); } else { Logger.log("OK"); } Logger.log("Test point per position"); if(computePointsFromPosition(1, 19) == 95) { Logger.log("OK"); } else { Logger.log("FAIL"); } if(computePointsFromPosition(2, 14) == 52) { Logger.log("OK"); } else { Logger.log("FAIL"); } if(computePointsFromPosition(6, 12) == 14) { Logger.log("OK"); } else { Logger.log("FAIL"); } if(computePointsFromPosition(11, 15) == 5) { Logger.log("OK"); } else { Logger.log("FAIL"); } if(computePointsFromPosition(4, 20) == 43) { Logger.log("OK"); } else { Logger.log("FAIL"); } Logger.log("Test gain per position"); if(computeGainsFromPosition(1, 19) == 67) { Logger.log("OK"); } else { Logger.log("FAIL"); } if(computeGainsFromPosition(2, 14) == 28) { Logger.log("OK"); } else { Logger.log("FAIL"); } if(computeGainsFromPosition(6, 12) == 0) { Logger.log("OK"); } else { Logger.log("FAIL"); } if(computeGainsFromPosition(11, 15) == 0) { Logger.log("OK"); } else { Logger.log("FAIL"); } if(computeGainsFromPosition(4, 20) == 8) { Logger.log("OK"); } else { Logger.log("FAIL"); } } /** calls computePlayerScoreAndRank() on current active sheet */ function triggerMainFunctionOnRealSheet() { var playerNamesRange = "A6:A40"; var positionsAndBountiesRange = "B6:AM40"; var testSheet = SpreadsheetApp.getActive(); Logger.log("testing on current sheet: " + testSheet.getSheetName()); var result = computePlayerScoreAndRank(testSheet.getRange(playerNamesRange).getValues(), testSheet.getRange(positionsAndBountiesRange).getValues()); Logger.log(result); }
to join this conversation on GitHub. Already have an account? Sign in to comment