better distribution with fibbonachi

This commit is contained in:
David Westgate 2025-03-09 14:30:45 -07:00
parent 1216e76381
commit f04496bf24

View File

@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useMemo, useState } from "react"; import React, { useCallback, useEffect, useMemo, useState } from "react";
import { View, Text, StyleSheet } from "react-native"; import { View, Text } from "react-native";
import { ColorValue } from "react-native"; import { ColorValue } from "react-native";
import i18n from "@/i18n/i18n"; import i18n from "@/i18n/i18n";
import styles from "@/styles/styles"; import styles from "@/styles/styles";
@ -22,7 +22,7 @@ const ChipDistributionSummary = ({
selectedCurrency = "$", selectedCurrency = "$",
}: ChipDistributionSummaryProps) => { }: ChipDistributionSummaryProps) => {
const validDenominations: validDenomination[] = [ const validDenominations: validDenomination[] = [
0.05, 0.1, 0.25, 0.5, 1, 2, 2.5, 5, 10, 20, 50, 100, 0.05, 0.1, 0.25, 1, 5, 10, 20, 50, 100,
]; ];
const [denominations, setDenominations] = useState<validDenomination[]>([]); const [denominations, setDenominations] = useState<validDenomination[]>([]);
const [distributions, setDistributions] = useState<number[]>([]); const [distributions, setDistributions] = useState<number[]>([]);
@ -38,26 +38,38 @@ const ChipDistributionSummary = ({
| 5 | 5
| 10 | 10
| 20 | 20
| 25
| 50 | 50
| 100; | 100;
const findFloorDenomination = (target: number): validDenomination => { const findFloorDenomination = (target: number): validDenomination => {
let current: validDenomination = validDenominations[0]; let current: validDenomination = validDenominations[0];
validDenominations.forEach((value, index) => { validDenominations.forEach((value, _) => {
if (value < target) current = value; if (value < target) current = value;
}); });
return current; return current;
}; };
// Bound for the value of the highest chip // Bound for the value of the highest chip
// This is somewhat arbitray, but 1/3 to 1/4 is reasonable depending on the number of colors. // This is somewhat arbitray and imperfect, but 1/3 to 1/5 is reasonable depending on the number of colors.
const maxDenomination = useMemo(() => { const maxDenomination: validDenomination = useMemo(() => {
if (totalChipsCount.length > 3) { let max: validDenomination;
return findFloorDenomination(buyInAmount / 3); switch (totalChipsCount.length) {
} else { case 5:
return findFloorDenomination(buyInAmount / 4); case 4:
max = findFloorDenomination(buyInAmount / 3);
break;
case 3:
max = findFloorDenomination(buyInAmount / 4);
break;
case 2:
case 1:
default:
max = findFloorDenomination(buyInAmount / 5);
break;
} }
}, [totalChipsCount]); return max;
}, [totalChipsCount, buyInAmount]);
const potValue = useMemo( const potValue = useMemo(
() => buyInAmount * playerCount, () => buyInAmount * playerCount,
@ -67,7 +79,7 @@ const ChipDistributionSummary = ({
// The total value of all chips distributed to a single player. Ideally should be equal to buyInAmount // The total value of all chips distributed to a single player. Ideally should be equal to buyInAmount
const totalValue = useMemo(() => { const totalValue = useMemo(() => {
let value = 0; let value = 0;
for (let i = 0; i < totalChipsCount.length; i++) { for (let i = 0; i < distributions.length; i++) {
value += distributions[i] * denominations[i]; value += distributions[i] * denominations[i];
} }
return value; return value;
@ -81,7 +93,7 @@ const ChipDistributionSummary = ({
// Redenominate the chips in case of failure to properly distribute. // Redenominate the chips in case of failure to properly distribute.
// Move the shuffle index to the next lowest denomination, and keep all else same // Move the shuffle index to the next lowest denomination, and keep all else same
const redenominate = useCallback( const _redenominate = useCallback(
( (
invalidDenomination: validDenomination[], invalidDenomination: validDenomination[],
shuffleIndex: number shuffleIndex: number
@ -113,36 +125,43 @@ const ChipDistributionSummary = ({
// Dynamically set denominations and distributions from changing inputs // Dynamically set denominations and distributions from changing inputs
useEffect(() => { useEffect(() => {
let testDenomination: validDenomination[] = []; let testDenomination: validDenomination[] = [];
const numColors = totalChipsCount.length; const totalNumColors = totalChipsCount.length;
const testDistribution: number[] = [];
for (let i = 0; i < numColors; ++i) {
testDistribution.push(0);
}
// Start with max denominations, then push on the next adjacent lower denomination // Start with max denominations, then push on the next adjacent lower denomination
testDenomination.push(maxDenomination); testDenomination.push(maxDenomination);
let currentDenominationIndex: number = let currentDenominationIndex: number =
validDenominations.indexOf(maxDenomination); validDenominations.indexOf(maxDenomination);
for (let i = numColors - 2; i >= 0; i = i - 1) { for (
let i = totalNumColors - 2;
i >= 0 && currentDenominationIndex > 0;
i = i - 1
) {
currentDenominationIndex -= 1; currentDenominationIndex -= 1;
const currentDemoniation = validDenominations[currentDenominationIndex]; const currentDemoniation = validDenominations[currentDenominationIndex];
testDenomination.push(currentDemoniation); testDenomination.push(currentDemoniation);
} }
testDenomination.reverse(); testDenomination.reverse();
let numColors = testDenomination.length;
const testDistribution: number[] = [];
for (let i = 0; i < numColors; ++i) {
testDistribution.push(0);
}
// Distribute the chips using the test denomination // Distribute the chips using the test denomination
// If distribution fails to equal the buy-in, redenominate and re-try // If distribution fails to equal the buy-in, redenominate and re-try
// Algorithm could be improved with more complexity and optimization // Algorithm could be improved with more complexity and optimization
let remainingValue = buyInAmount; let remainingValue = buyInAmount;
let fail = true;
let failCount = 0;
while (fail && failCount < 1) {
let stop = false; let stop = false;
while (remainingValue > 0 && !stop) { while (remainingValue > 0 && !stop) {
let distributed = false; let distributed = false;
for (let i = numColors - 1; i >= 0; i = i - 1) { for (let i = numColors - 1; i >= 0; i = i - 1) {
if (testDistribution[i] < maxPossibleDistribution[i]) { if (testDistribution[i] < maxPossibleDistribution[i]) {
if (remainingValue >= testDenomination[i]) { for (
let j = reverseFib[i];
j > 0 && remainingValue >= testDenomination[i];
j = j - 1
) {
testDistribution[i] = testDistribution[i] + 1; testDistribution[i] = testDistribution[i] + 1;
remainingValue = remainingValue - testDenomination[i]; remainingValue = remainingValue - testDenomination[i];
distributed = true; distributed = true;
@ -153,16 +172,6 @@ const ChipDistributionSummary = ({
stop = true; stop = true;
} }
} }
if (remainingValue !== 0) {
const redenominateIndex = failCount % numColors;
testDenomination = redenominate(testDenomination, redenominateIndex);
failCount += 1;
fail = true;
} else {
fail = false;
}
}
setDenominations(testDenomination); setDenominations(testDenomination);
setDistributions(testDistribution); setDistributions(testDistribution);
}, [totalChipsCount, maxDenomination, buyInAmount, playerCount]); }, [totalChipsCount, maxDenomination, buyInAmount, playerCount]);
@ -170,7 +179,7 @@ const ChipDistributionSummary = ({
return ( return (
<> <>
<View style={styles.container}> <View style={styles.container}>
{totalChipsCount.map((_, index) => ( {denominations.map((denomination, index) => (
<View style={{ flexDirection: "row" }} key={index}> <View style={{ flexDirection: "row" }} key={index}>
<Text <Text
style={{ style={{
@ -180,7 +189,7 @@ const ChipDistributionSummary = ({
...(colors[index] === "white" && styles.shadow), ...(colors[index] === "white" && styles.shadow),
}} }}
> >
{`${distributions[index]} ${i18n.t("chips")}: ${selectedCurrency}${denominations[index]} ${i18n.t("each")}`} {`${distributions[index]} ${i18n.t("chips")}: ${selectedCurrency}${denomination} ${i18n.t("each")}`}
</Text> </Text>
</View> </View>
))} ))}