start rework of algorithm

This commit is contained in:
David Westgate 2025-02-20 14:18:56 -08:00
parent b9c90d2493
commit f2710588ea
3 changed files with 110 additions and 76 deletions

View File

@ -6,7 +6,7 @@ import ChipsSelector from "@/components/ChipsSelector";
import ChipDistributionSummary from "@/components/ChipDistributionSummary"; import ChipDistributionSummary from "@/components/ChipDistributionSummary";
const IndexScreen = () => { const IndexScreen = () => {
const [playerCount, setPlayerCount] = useState(2); const [playerCount, setPlayerCount] = useState(2);
const [buyInAmount, setBuyInAmount] = useState<number | null>(null); const [buyInAmount, setBuyInAmount] = useState<number>(20);
const [numberOfChips, setNumberOfChips] = useState<number>(5); const [numberOfChips, setNumberOfChips] = useState<number>(5);
const [totalChipsCount, setTotalChipsCount] = useState<number[]>([]); const [totalChipsCount, setTotalChipsCount] = useState<number[]>([]);
const handleSave = () => { const handleSave = () => {

View File

@ -9,7 +9,7 @@ import {
import { MaterialIcons } from "@expo/vector-icons"; import { MaterialIcons } from "@expo/vector-icons";
interface BuyInSelectorProps { interface BuyInSelectorProps {
setBuyInAmount: React.Dispatch<React.SetStateAction<number | null>>; setBuyInAmount: React.Dispatch<React.SetStateAction<number>>;
} }
const defaultBuyInOptions = [10, 25, 50]; const defaultBuyInOptions = [10, 25, 50];
@ -26,8 +26,8 @@ const BuyInSelector: React.FC<BuyInSelectorProps> = ({ setBuyInAmount }) => {
setBuyInAmount(numericValue); setBuyInAmount(numericValue);
} else { } else {
setCustomAmount(""); setCustomAmount("");
setBuyInAmountState(null); setBuyInAmountState(25);
setBuyInAmount(null); setBuyInAmount(25);
} }
}; };

View File

@ -1,10 +1,10 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
import { View, Text, StyleSheet } from "react-native"; import { View, Text, StyleSheet } from "react-native";
import { ColorValue } from "react-native"; import { ColorValue } from "react-native";
interface ChipDistributionSummaryProps { interface ChipDistributionSummaryProps {
playerCount: number; playerCount: number;
buyInAmount: number | null; buyInAmount: number;
totalChipsCount: number[]; totalChipsCount: number[];
colors?: ColorValue[]; colors?: ColorValue[];
} }
@ -15,92 +15,126 @@ const ChipDistributionSummary = ({
totalChipsCount, totalChipsCount,
colors = ["white", "red", "green", "blue", "black"], colors = ["white", "red", "green", "blue", "black"],
}: ChipDistributionSummaryProps) => { }: ChipDistributionSummaryProps) => {
const [chipCountPerPlayer, setChipCountPerPlayer] = useState< // const [chipCountPerPlayer, setChipCountPerPlayer] = useState<
Record<string, { count: number; value: number }> // Record<string, { count: number; value: number }>
>({}); // >({});
useEffect(() => {
if (
buyInAmount !== null &&
playerCount > 0 &&
totalChipsCount.every((chips) => chips > 0)
) {
const validDenominations = [ const validDenominations = [
0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, 0.05, 0.1, 0.25, 0.5, 1, 2, 2.5, 5, 10, 20, 50, 100,
]; ];
const availableColors = Math.min(colors.length, 5); // Re-organize the inputs in a map for convience
let selectedChips: number[] = []; const chipMap: Map<ColorValue, number> = useMemo(() => {
let maxDenomination = buyInAmount / 2; const m: Map<ColorValue, number> = new Map<ColorValue, number>();
totalChipsCount.map((v, i) => {
m.set(colors[i], v);
});
return m;
}, [playerCount, buyInAmount, totalChipsCount]);
// Select the denominations for available colors (up to 5 colors) // Helper function to return the closest (but lower) valid denomination to the target
for (let i = validDenominations.length - 1; i >= 0; i--) { const findFloorDenomination = (target: number) => {
if ( let current: number = validDenominations[0];
validDenominations[i] <= maxDenomination && validDenominations.forEach((value, index) => {
selectedChips.length < availableColors if (value < target) current = value;
) { });
selectedChips.unshift(validDenominations[i]); return current;
}
}
// Ensure the selected chips are sorted from low to high denomination
selectedChips = selectedChips.sort((a, b) => a - b);
let distribution = new Array(selectedChips.length).fill(0);
let remainingValue = buyInAmount;
let remainingChips = [...totalChipsCount.slice(0, selectedChips.length)];
// First pass: Distribute at least one chip of each selected denomination per player
for (let i = 0; i < selectedChips.length; i++) {
const chipValue = selectedChips[i];
if (remainingValue >= chipValue && remainingChips[i] >= playerCount) {
distribution[i] = 1;
remainingValue -= chipValue;
remainingChips[i] -= playerCount;
}
}
// Second pass: Distribute remaining buy-in amount fairly across chip colors
while (remainingValue > 0) {
let allocatedInRound = false;
for (let i = 0; i < selectedChips.length; i++) {
if (remainingValue <= 0) break;
const chipValue = selectedChips[i];
if (remainingChips[i] >= playerCount && remainingValue >= chipValue) {
distribution[i] += 1;
remainingValue -= chipValue;
remainingChips[i] -= playerCount;
allocatedInRound = true;
}
}
if (!allocatedInRound) break; // Prevent infinite loops
}
// Create a mapping from chip color names to chip counts and denominations
let chipMap: Record<string, { count: number; value: number }> = {};
for (let i = 0; i < selectedChips.length; i++) {
if (distribution[i] > 0) {
// Map denomination and color to chip count
chipMap[colors[i]] = {
count: distribution[i],
value: selectedChips[i],
}; };
}
}
setChipCountPerPlayer(chipMap); const maxDenomination = useMemo(() => {
if (chipMap.size > 3) {
return findFloorDenomination(buyInAmount / 2);
} else { } else {
setChipCountPerPlayer({}); return findFloorDenomination(buyInAmount / 4);
} }
}, [buyInAmount, playerCount, totalChipsCount, colors]); }, [chipMap]);
useEffect(() => {
const testDistribution: Map<ColorValue, number> = new Map();
const numColors = chipMap.size;
testDistribution.set(colors[numColors - 1], maxDenomination);
const maxDenominationIndex: number =
validDenominations.indexOf(maxDenomination);
console.log("test distribution", testDistribution);
}, [chipMap, maxDenomination]);
// useEffect(() => {
// if (
// buyInAmount !== null &&
// playerCount > 0 &&
// totalChipsCount.every((chips) => chips > 0)
// ) {
// const availableColors = Math.min(colors.length, 5);
// let selectedChips: number[] = [];
// let maxDenomination = buyInAmount / 2;
// // Select the denominations for available colors (up to 5 colors)
// for (let i = validDenominations.length - 1; i >= 0; i--) {
// if (
// validDenominations[i] <= maxDenomination &&
// selectedChips.length < availableColors
// ) {
// selectedChips.unshift(validDenominations[i]);
// }
// }
// // Ensure the selected chips are sorted from low to high denomination
// selectedChips = selectedChips.sort((a, b) => a - b);
// let distribution = new Array(selectedChips.length).fill(0);
// let remainingValue = buyInAmount;
// let remainingChips = [...totalChipsCount.slice(0, selectedChips.length)];
// // First pass: Distribute at least one chip of each selected denomination per player
// for (let i = 0; i < selectedChips.length; i++) {
// const chipValue = selectedChips[i];
// if (remainingValue >= chipValue && remainingChips[i] >= playerCount) {
// distribution[i] = 1;
// remainingValue -= chipValue;
// remainingChips[i] -= playerCount;
// }
// }
// // Second pass: Distribute remaining buy-in amount fairly across chip colors
// while (remainingValue > 0) {
// let allocatedInRound = false;
// for (let i = 0; i < selectedChips.length; i++) {
// if (remainingValue <= 0) break;
// const chipValue = selectedChips[i];
// if (remainingChips[i] >= playerCount && remainingValue >= chipValue) {
// distribution[i] += 1;
// remainingValue -= chipValue;
// remainingChips[i] -= playerCount;
// allocatedInRound = true;
// }
// }
// if (!allocatedInRound) break; // Prevent infinite loops
// }
// // Create a mapping from chip color names to chip counts and denominations
// let chipMap: Record<string, { count: number; value: number }> = {};
// for (let i = 0; i < selectedChips.length; i++) {
// if (distribution[i] > 0) {
// // Map denomination and color to chip count
// chipMap[colors[i]] = {
// count: distribution[i],
// value: selectedChips[i],
// };
// }
// }
// setChipCountPerPlayer(chipMap);
// } else {
// setChipCountPerPlayer({});
// }
// }, [buyInAmount, playerCount, totalChipsCount, colors]);
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.title}>Chip Distribution Summary:</Text> <Text style={styles.title}>Chip Distribution Summary:</Text>
{Object.keys(chipCountPerPlayer).length > 0 ? ( {/**Object.keys(chipCountPerPlayer).length > 0 ? (
<View style={styles.chipContainer}> <View style={styles.chipContainer}>
{Object.entries(chipCountPerPlayer).map( {Object.entries(chipCountPerPlayer).map(
([color, { count, value }]) => ( ([color, { count, value }]) => (
@ -115,7 +149,7 @@ const ChipDistributionSummary = ({
<Text style={styles.noDataText}> <Text style={styles.noDataText}>
No valid distribution calculated yet. No valid distribution calculated yet.
</Text> </Text>
)} )**/}
</View> </View>
); );
}; };