Advertisement
oguzilerle

Colonist Balanced Dice

Oct 18th, 2024 (edited)
217
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 11.06 KB | Software | 0 0
  1. interface StandardDiceDeck {
  2.     totalDice: number
  3.     dicePairs: DicePair[]
  4. }
  5.  
  6. interface WeightedDiceDeck {
  7.     totalDice: number
  8.     dicePairs: DicePair[]
  9.     probabilityWeighting: number
  10.     recentlyRolledCount: number
  11. }
  12.  
  13. export class DiceControllerBalanced extends BaseDiceController {
  14.     private readonly minimumCardsBeforeReshuffling: number
  15.     private readonly probabilityReductionForRecentlyRolled: number
  16.     private readonly probabilityReductionForSevenStreaks: number
  17.  
  18.     private weightedDiceDeck: WeightedDiceDeck[]
  19.     private cardsLeftInDeck: number
  20.     private readonly recentRolls: number[]
  21.     private readonly maximumRecentRollMemory: number
  22.     private readonly weightedEventDiceDeck: DiceControllerBalancedCKEventDie
  23.  
  24.     private readonly sevenStreakCount: {playerColor: PlayerColor, streakCount: number}
  25.     private readonly totalSevensRolledByPlayer: Map<PlayerColor, number>
  26.  
  27.     private readonly logger: Logger
  28.     private readonly numberOfPlayers: number
  29.  
  30.     constructor(gameController: GameController) {
  31.         super()
  32.  
  33.         this.logger = gameController.logger
  34.         this.numberOfPlayers = gameController.players.length
  35.  
  36.         this.initWeightedDiceDeck()
  37.         this.reshuffleWeightedDiceDeck()
  38.         this.updateWeightedDiceDeckProbabilities()
  39.  
  40.         this.minimumCardsBeforeReshuffling = 13
  41.         this.probabilityReductionForRecentlyRolled = 0.34
  42.         this.probabilityReductionForSevenStreaks = 0.4
  43.  
  44.         this.recentRolls = []
  45.         this.maximumRecentRollMemory = 5
  46.  
  47.         this.sevenStreakCount = {playerColor: PlayerColor.None, streakCount: 0}
  48.         this.totalSevensRolledByPlayer = new Map<PlayerColor, number>()
  49.  
  50.         this.weightedEventDiceDeck = new DiceControllerBalancedCKEventDie(this.logger)
  51.     }
  52.  
  53.     throwDice(playerColor: PlayerColor): DicePair {
  54.         this.initTotalSevens(playerColor)
  55.         return this.drawWeightedCard(playerColor)
  56.     }
  57.  
  58.     throwEventDice(): number {
  59.         return this.weightedEventDiceDeck.throwEventDice()
  60.     }
  61.  
  62.     private drawWeightedCard(playerColor: PlayerColor): DicePair {
  63.         if(this.cardsLeftInDeck < this.minimumCardsBeforeReshuffling) this.reshuffleWeightedDiceDeck()
  64.         this.updateWeightedDiceDeckProbabilities()
  65.         this.adjustWeightedDiceDeckBasedOnRecentRolls()
  66.         this.adjustSevenProbabilityBasedOnSevens(playerColor)
  67.         return this.getWeightedDice(playerColor)
  68.     }
  69.  
  70.     private initWeightedDiceDeck() {
  71.         this.weightedDiceDeck = []
  72.         this.weightedDiceDeck.push({totalDice: 2, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  73.         this.weightedDiceDeck.push({totalDice: 3, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  74.         this.weightedDiceDeck.push({totalDice: 4, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  75.         this.weightedDiceDeck.push({totalDice: 5, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  76.         this.weightedDiceDeck.push({totalDice: 6, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  77.         this.weightedDiceDeck.push({totalDice: 7, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  78.         this.weightedDiceDeck.push({totalDice: 8, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  79.         this.weightedDiceDeck.push({totalDice: 9, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  80.         this.weightedDiceDeck.push({totalDice: 10, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  81.         this.weightedDiceDeck.push({totalDice: 11, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  82.         this.weightedDiceDeck.push({totalDice: 12, dicePairs: [], probabilityWeighting: 0, recentlyRolledCount: 0})
  83.     }
  84.  
  85.     private reshuffleWeightedDiceDeck() {
  86.         const standardDiceDeck = DiceControllerBalanced.getStandardDiceDeck()
  87.  
  88.         for(const [totalDiceIndex, dicePairsForTotalDice] of standardDiceDeck.entries()) {
  89.             this.weightedDiceDeck[totalDiceIndex].dicePairs = dicePairsForTotalDice.dicePairs
  90.         }
  91.  
  92.         const totalCombinations = 36
  93.         this.cardsLeftInDeck = totalCombinations
  94.     }
  95.  
  96.     private updateWeightedDiceDeckProbabilities() {
  97.         for(const diceDeckForTotalDice of this.weightedDiceDeck) {
  98.             diceDeckForTotalDice.probabilityWeighting = diceDeckForTotalDice.dicePairs.length / this.cardsLeftInDeck
  99.         }
  100.     }
  101.  
  102.     private getWeightedDice(playerColor: PlayerColor): DicePair {
  103.         const totalProbabilityWeight = this.getTotalProbabilityWeight()
  104.  
  105.         let targetRandomNumber = Math.random() * totalProbabilityWeight
  106.         for(const diceDeckForTotalDice of this.weightedDiceDeck) {
  107.             if(targetRandomNumber <= diceDeckForTotalDice.probabilityWeighting) {
  108.                 const drawnCard = ArrayUtils.randomElementFromArray(diceDeckForTotalDice.dicePairs)
  109.                 ArrayUtils.removeElementFromArray(diceDeckForTotalDice.dicePairs, drawnCard)
  110.  
  111.                 this.recentRolls.push(diceDeckForTotalDice.totalDice)
  112.                 diceDeckForTotalDice.recentlyRolledCount += 1
  113.                 this.cardsLeftInDeck -= 1
  114.  
  115.                 if(this.recentRolls.length > this.maximumRecentRollMemory) this.updateRecentlyRolled()
  116.                 if(diceDeckForTotalDice.totalDice == 7) this.updateSevenRolls(playerColor)
  117.                 return drawnCard
  118.             }
  119.             targetRandomNumber -= diceDeckForTotalDice.probabilityWeighting
  120.         }
  121.  
  122.         this.logger.logError('Something seriously wrong with weighted dice deck')
  123.         const defaultRollIfError = {dice1: 3, dice2: 4}
  124.         return defaultRollIfError
  125.     }
  126.  
  127.     private getTotalProbabilityWeight(): number {
  128.         let totalProbabilityWeight = 0
  129.         for(const dicePairs of this.weightedDiceDeck) {
  130.             totalProbabilityWeight += dicePairs.probabilityWeighting
  131.         }
  132.  
  133.         return totalProbabilityWeight
  134.     }
  135.  
  136.     private updateRecentlyRolled() {
  137.         const ignore0and1 = 2
  138.         const totalDiceFiveRollsAgo = this.recentRolls[0]
  139.         this.weightedDiceDeck[totalDiceFiveRollsAgo - ignore0and1].recentlyRolledCount -= 1
  140.         this.recentRolls.shift()
  141.     }
  142.  
  143.     private adjustWeightedDiceDeckBasedOnRecentRolls() {
  144.         for(const diceDeckForTotalDice of this.weightedDiceDeck) {
  145.             const probabilityReduction = (diceDeckForTotalDice.recentlyRolledCount * this.probabilityReductionForRecentlyRolled)
  146.             const probabilityMultiplier = 1 - probabilityReduction
  147.             diceDeckForTotalDice.probabilityWeighting *= probabilityMultiplier
  148.             if(diceDeckForTotalDice.probabilityWeighting < 0) diceDeckForTotalDice.probabilityWeighting = 0
  149.         }
  150.     }
  151.  
  152.     private initTotalSevens(playerColor: PlayerColor) {
  153.         if(this.totalSevensRolledByPlayer.get(playerColor) != undefined) return
  154.         this.totalSevensRolledByPlayer.set(playerColor, 0)
  155.     }
  156.  
  157.     private updateSevenRolls(playerColor: PlayerColor) {
  158.         const sevensRolledByPlayer = this.totalSevensRolledByPlayer.get(playerColor) ?? 0
  159.         this.totalSevensRolledByPlayer.set(playerColor, sevensRolledByPlayer + 1)
  160.  
  161.         if(playerColor == this.sevenStreakCount.playerColor) {
  162.             this.sevenStreakCount.streakCount += 1
  163.             return
  164.         }
  165.  
  166.         this.sevenStreakCount.playerColor = playerColor
  167.         this.sevenStreakCount.streakCount = 1
  168.     }
  169.  
  170.     protected adjustSevenProbabilityBasedOnSevens(playerColor: PlayerColor) {
  171.         if(this.numberOfPlayers < 2) return
  172.         const streakAdjustmentPercentage = this.getStreakAdjustmentConstant(playerColor)
  173.         const playerSevensAdjustmentPercentage = this.getSevenImbalanceAdjustment(playerColor)
  174.  
  175.         let sevenProbabilityAdjustment = 1 * playerSevensAdjustmentPercentage + streakAdjustmentPercentage
  176.  
  177.         const minimumAdjustment = 0
  178.         const maximumAdjustment = 2
  179.         if(sevenProbabilityAdjustment < minimumAdjustment) sevenProbabilityAdjustment = minimumAdjustment
  180.         if(sevenProbabilityAdjustment > maximumAdjustment) sevenProbabilityAdjustment = maximumAdjustment
  181.  
  182.         const ignore0and1 = 2
  183.         const sevenIndex = 7 - ignore0and1
  184.         this.weightedDiceDeck[sevenIndex].probabilityWeighting *= sevenProbabilityAdjustment
  185.     }
  186.  
  187.     private getStreakAdjustmentConstant(player: PlayerColor): number {
  188.         const isStreakForOrAgainstPlayer = this.sevenStreakCount.playerColor == player ? -1 : 1
  189.         return this.probabilityReductionForSevenStreaks * this.sevenStreakCount.streakCount * isStreakForOrAgainstPlayer
  190.     }
  191.  
  192.     private getSevenImbalanceAdjustment(playerColor: PlayerColor): number {
  193.         const totalSevens = this.getTotalSevensRolled()
  194.         if(totalSevens < this.totalSevensRolledByPlayer.size) return 1
  195.  
  196.         const sevensPerPlayer = this.totalSevensRolledByPlayer.get(playerColor) ?? 0
  197.  
  198.         const percentageOfTotalSevens = sevensPerPlayer / totalSevens
  199.         const idealPercentageOfTotalSevens = 1 / this.totalSevensRolledByPlayer.size
  200.  
  201.         const adjustmentBecauseOfSevensImbalance = 1 + ((idealPercentageOfTotalSevens - percentageOfTotalSevens) / idealPercentageOfTotalSevens)
  202.  
  203.         return adjustmentBecauseOfSevensImbalance
  204.     }
  205.  
  206.     private getTotalSevensRolled(): number {
  207.         let totalSevensRolled = 0
  208.         for(const totalSevensRolledByPlayer of this.totalSevensRolledByPlayer.values()) {
  209.             totalSevensRolled += totalSevensRolledByPlayer
  210.         }
  211.  
  212.         return totalSevensRolled
  213.     }
  214.  
  215.     private static getStandardDiceDeck(): StandardDiceDeck[] {
  216.         const standardDiceDeck: StandardDiceDeck[] = []
  217.         standardDiceDeck.push({totalDice: 2, dicePairs: [{dice1: 1, dice2: 1}]})
  218.         standardDiceDeck.push({totalDice: 3, dicePairs: [{dice1: 1, dice2: 2}, {dice1: 2, dice2: 1}]})
  219.         standardDiceDeck.push({totalDice: 4, dicePairs: [{dice1: 1, dice2: 3}, {dice1: 2, dice2: 2}, {dice1: 3, dice2: 1}]})
  220.         standardDiceDeck.push({totalDice: 5, dicePairs: [{dice1: 1, dice2: 4}, {dice1: 2, dice2: 3}, {dice1: 3, dice2: 2}, {dice1: 4, dice2: 1}]})
  221.         standardDiceDeck.push({totalDice: 6, dicePairs: [{dice1: 1, dice2: 5}, {dice1: 2, dice2: 4}, {dice1: 3, dice2: 3}, {dice1: 4, dice2: 2}, {dice1: 5, dice2: 1}]})
  222.         standardDiceDeck.push({totalDice: 7, dicePairs: [{dice1: 1, dice2: 6}, {dice1: 2, dice2: 5}, {dice1: 3, dice2: 4}, {dice1: 4, dice2: 3}, {dice1: 5, dice2: 2}, {dice1: 6, dice2: 1}]})
  223.         standardDiceDeck.push({totalDice: 8, dicePairs: [{dice1: 2, dice2: 6}, {dice1: 3, dice2: 5}, {dice1: 4, dice2: 4}, {dice1: 5, dice2: 3}, {dice1: 6, dice2: 2}]})
  224.         standardDiceDeck.push({totalDice: 9, dicePairs: [{dice1: 3, dice2: 6}, {dice1: 4, dice2: 5}, {dice1: 5, dice2: 4}, {dice1: 6, dice2: 3}]})
  225.         standardDiceDeck.push({totalDice: 10, dicePairs: [{dice1: 4, dice2: 6}, {dice1: 5, dice2: 5}, {dice1: 6, dice2: 4}]})
  226.         standardDiceDeck.push({totalDice: 11, dicePairs: [{dice1: 5, dice2: 6}, {dice1: 6, dice2: 5}]})
  227.         standardDiceDeck.push({totalDice: 12, dicePairs: [{dice1: 6, dice2: 6}]})
  228.  
  229.         return standardDiceDeck
  230.     }
  231. }
  232.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement