Skip to content

Commit

Permalink
feat(core): support really big scores
Browse files Browse the repository at this point in the history
Support calculating really (really!) big scores by introducing mathjs to handle the final score compounding.
  • Loading branch information
kleinfreund committed Jan 17, 2025
1 parent 9027ee4 commit a4b6dbe
Show file tree
Hide file tree
Showing 43 changed files with 310 additions and 136 deletions.
104 changes: 103 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
"build": "vite build",
"prepare": "husky"
},
"dependencies": {
"mathjs": "^14.0.1"
},
"devDependencies": {
"@commitlint/cli": "^19.6.1",
"@commitlint/config-conventional": "^19.6.0",
Expand Down
1 change: 1 addition & 0 deletions src/lib/calculateScore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ describe('calculateScore', async () => {
(await import('./test-files/032.js')).default('Four wild + Flower Pot'),
(await import('./test-files/033.js')).default('Run from 2024-04-10 16:52 UTC'),
(await import('./test-files/034.js')).default('Run from 2024-04-09 19:20 UTC'),
(await import('./test-files/035.js')).default('https://www.youtube.com/watch?v=hcZF7NJGuPE'),
])('$message', ({ initialState, expected }) => {
const score = calculateScore(getState(initialState))

Expand Down
22 changes: 12 additions & 10 deletions src/lib/doBigMath.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { add, BigNumber, bignumber, divide, floor, multiply, pow } from 'mathjs'

import type { DeckName, Score } from './types.js'

export function doBigMath (initialScore: Score, deck: DeckName) {
const chips = initialScore.chips.reduce((totalChips, chips) => {
return totalChips + chips
}, 0)
return add(totalChips, bignumber(chips))
}, bignumber(0))
const multiplier = initialScore.multiplier.reduce((totalMultiplier, [operation, multiplier]) => {
return operation === '+'
? totalMultiplier + multiplier
: totalMultiplier * multiplier
}, 0)
const operator = operation === '+' ? add : multiply
return operator(totalMultiplier, bignumber(multiplier))
}, bignumber(0))

let actualScore
let actualScore: BigNumber
if (deck === 'Plasma Deck') {
actualScore = Math.pow((chips + multiplier) / 2, 2)
actualScore = pow(divide(add(chips, multiplier), bignumber(2)), bignumber(2)) as BigNumber // mathjs type bug
} else {
actualScore = chips * multiplier
actualScore = multiply(chips, multiplier) as BigNumber // mathjs type bug
}

// Balatro seems to round values starting at a certain threshold and it seems to round down. 🤔
return actualScore > 10000 ? Math.floor(actualScore) : actualScore
const score = actualScore.greaterThan(10000) ? floor(actualScore) : actualScore
return score.toString()
}
26 changes: 16 additions & 10 deletions src/lib/formatScore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@ import { formatScore } from './formatScore.js'

describe('formatScore', () => {
test.each([
[1, '1'],
[1.5, '2'],
[1.49, '1'],
[1.44, '1'],
[123_456_789, '123,456,789'],
[47_123_456_789, '47,123,456,789'],
[29_000_000_000_000, '2.900e13'],
[77_000_000_000_000_000, '7.700e16'],
[860_000_000_000_000_000_000, '8.600e20'],
])('works', (score, formattedScore) => {
['1', '1'],
['1.44', '1'],
['1.49', '1'],
['1.5', '2'],
['1000', '1,000'],
['123456789', '123,456,789'],
['47123456789', '47,123,456,789'],
['999999999999', '999,999,999,999'],
['1000000000000', '1.000e12'],
['29000000000000', '2.900e13'],
['77000000000000000', '7.700e16'],
['81319879990278560', '8.132e16'],
['860000000000000000000', '8.600e20'],
['854450000000000000000', '8.545e20'],
['1.6126936982633295697683283009811179373062885736448e+50', '1.613e50'],
])('formatScore(\'%s\') = \'%s\'', (score, formattedScore) => {
expect(formatScore(score)).toBe(formattedScore)
})
})
30 changes: 20 additions & 10 deletions src/lib/formatScore.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
export function formatScore (score: number): string {
if (score < 1_000_000_000_000) {
return new Intl.NumberFormat('en', { maximumFractionDigits: 0 }).format(score)
} else {
const almostCorrect = new Intl.NumberFormat('en', {
notation: 'scientific',
maximumSignificantDigits: 4,
}).format(score).toLowerCase()
const [prefix, suffix] = almostCorrect.split('e')
return prefix!.padEnd(5, '0') + 'e' + suffix!
import { BigNumber, bignumber, divide, round } from 'mathjs'

export function formatScore (score: string): string {
if (score.includes('e+')) {
const [prefix, suffix] = score.split('e+') as [string, string]
const number = Number(prefix.substring(0, 6))

return `${number.toFixed(3)}e${suffix}`
}

const bigNumber = bignumber(score)
if (bigNumber.lessThan(1_000_000_000_000)) {
return new Intl.NumberFormat('en', { maximumFractionDigits: 0 })
.format(bigNumber.toNumber())
}

const decimalValue = divide(bigNumber, bignumber(Math.pow(10, score.length - 1))) as BigNumber
const roundedValue = round(decimalValue, 3).toString()
const prefix = roundedValue + (roundedValue.includes('.') ? '' : '.')

return `${prefix.padEnd(5, '0')}e${String(score.length - 1)}`
}
6 changes: 3 additions & 3 deletions src/lib/test-files/001.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ export default (message: string): TestCase => {
{ rank: '7', suit: 'Diamonds' },
],
scores: [
{ score: 108, formattedScore: '108', luck: 'none' },
{ score: 108, formattedScore: '108', luck: 'average' },
{ score: 108, formattedScore: '108', luck: 'all' },
{ score: '108', formattedScore: '108', luck: 'none' },
{ score: '108', formattedScore: '108', luck: 'average' },
{ score: '108', formattedScore: '108', luck: 'all' },
],
},
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/test-files/002.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ export default (message: string): TestCase => {
{ rank: '4', suit: 'Hearts', edition: 'holographic' },
],
scores: [
{ score: 600, formattedScore: '600', luck: 'none' },
{ score: 600, formattedScore: '600', luck: 'average' },
{ score: 600, formattedScore: '600', luck: 'all' },
{ score: '600', formattedScore: '600', luck: 'none' },
{ score: '600', formattedScore: '600', luck: 'average' },
{ score: '600', formattedScore: '600', luck: 'all' },
],
},
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/test-files/003.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export default (message: string): TestCase => {
{ rank: '7', suit: 'Hearts', enhancement: 'bonus' },
],
scores: [
{ score: 147, formattedScore: '147', luck: 'none' },
{ score: 147, formattedScore: '147', luck: 'average' },
{ score: 147, formattedScore: '147', luck: 'all' },
{ score: '147', formattedScore: '147', luck: 'none' },
{ score: '147', formattedScore: '147', luck: 'average' },
{ score: '147', formattedScore: '147', luck: 'all' },
],
},
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/test-files/004.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ export default (message: string): TestCase => {
{ rank: '6', suit: 'Diamonds' },
],
scores: [
{ score: 539, formattedScore: '539', luck: 'none' },
{ score: 539, formattedScore: '539', luck: 'average' },
{ score: 539, formattedScore: '539', luck: 'all' },
{ score: '539', formattedScore: '539', luck: 'none' },
{ score: '539', formattedScore: '539', luck: 'average' },
{ score: '539', formattedScore: '539', luck: 'all' },
],
},
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/test-files/005.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ export default (message: string): TestCase => {
{ rank: 'Queen', suit: 'Diamonds', debuffed: true },
],
scores: [
{ score: 16.25, formattedScore: '16', luck: 'none' },
{ score: 16.25, formattedScore: '16', luck: 'average' },
{ score: 16.25, formattedScore: '16', luck: 'all' },
{ score: '16.25', formattedScore: '16', luck: 'none' },
{ score: '16.25', formattedScore: '16', luck: 'average' },
{ score: '16.25', formattedScore: '16', luck: 'all' },
],
},
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/test-files/006.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ export default (message: string): TestCase => {
{ rank: '7', suit: 'Hearts', debuffed: true },
],
scores: [
{ score: 134, formattedScore: '134', luck: 'none' },
{ score: 134, formattedScore: '134', luck: 'average' },
{ score: 134, formattedScore: '134', luck: 'all' },
{ score: '134', formattedScore: '134', luck: 'none' },
{ score: '134', formattedScore: '134', luck: 'average' },
{ score: '134', formattedScore: '134', luck: 'all' },
],
},
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/test-files/007.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ export default (message: string): TestCase => {
{ rank: '4', suit: 'Clubs' },
],
scores: [
{ score: 3192, formattedScore: '3,192', luck: 'none' },
{ score: 3192, formattedScore: '3,192', luck: 'average' },
{ score: 3192, formattedScore: '3,192', luck: 'all' },
{ score: '3192', formattedScore: '3,192', luck: 'none' },
{ score: '3192', formattedScore: '3,192', luck: 'average' },
{ score: '3192', formattedScore: '3,192', luck: 'all' },
],
},
}
Expand Down
Loading

0 comments on commit a4b6dbe

Please sign in to comment.