Advertisement
maumd

Untitled

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