Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 1x 1x 1x 11x 20x 135x 11x 135x 11x 124x 597x 124x 53x 53x 71x 11x 1x 8x 61x 8x 61x 8x 53x 158x 53x 18x 18x 35x 8x 1x 175x 1x 1x 1x 1x | import { arrayEquals, replace } from "../utils"; import { cartesianProduct } from "./combinatorics"; import { RandomDevice } from "./RandomDevice"; import { WithOdds } from "./WithOdds"; /** * Computes all possible sets from the provided list of random devices along * with the odds of obtaining this particular set. * * @param {Array<RandomDevice<any>>} devices * The list of random devices from which to generate possible sets. * @returns {Array<SetWithOdds<any>>} * All possible sets that can be obtainded from this lsit of random devices * along with the odds of obtaining this particular set. */ export function odds<T>(devices: RandomDevice<T>[]): WithOdds<T[]>[] { const product = cartesianProduct( ...devices.map((d) => d.getOutcomesWithOdds()) ); const combined = product.map((sets) => sets.reduce(combineSetWithOdds)); const grouped = combined.reduce( (acc: WithOdds<T[]>[], current: WithOdds<T[]>) => { if (acc.length === 0) { return [current]; } else { // Find an equivalent set const matchingSetIndex = acc.findIndex(({ value }) => arrayEquals(value.sort(), current.value.sort()) ); if (matchingSetIndex > -1) { // Update the existing set by adding the odds const updatedSet = { oddsOfValue: acc[matchingSetIndex].oddsOfValue.add( current.oddsOfValue ), value: acc[matchingSetIndex].value, }; return replace(acc, matchingSetIndex, updatedSet); } else { // Add the set return [...acc, current]; } } }, [] ); return grouped; } export function roll<O, R>( device: RandomDevice<O>, numberOfDevices: number, resultTransformationFn: (outcomes: O[]) => R, resultEqualFn: (a: R, b: R) => boolean ): WithOdds<R>[] { const raw: WithOdds<R>[] = odds<O>([ ...Array(numberOfDevices).fill(device), ]).map(({ value, oddsOfValue }) => ({ oddsOfValue, value: resultTransformationFn(value), })); const sameResultsCombined = raw.reduce( (acc: WithOdds<R>[], current: WithOdds<R>) => { if (acc.length === 0) { return [current]; } else { // Find an equivalent result const matchingResultIndex = acc.findIndex(({ value }) => resultEqualFn(value, current.value) ); if (matchingResultIndex > -1) { // Update the existing result by adding the odds const updatedResult = { oddsOfValue: acc[matchingResultIndex].oddsOfValue.add( current.oddsOfValue ), value: acc[matchingResultIndex].value, }; return replace(acc, matchingResultIndex, updatedResult); } else { // Add the set return [...acc, current]; } } }, [] ); return sameResultsCombined; } /** * Combine two sets with odds into a single one. Sets are merged and odds are * multiplied. * * @param O * Type for the first set. * @param P * Type for the second set. * @param {WithOdds<O[]>} first * The first set to be combined. * @param {WithOdds<P[]>} second * The second set to be combined. * @returns {WithOdds<(O | P)[]>} * The result of combining the two sets. */ export function combineSetWithOdds<O, P>( first: WithOdds<O[]>, second: WithOdds<P[]> ): WithOdds<(O | P)[]> { return { oddsOfValue: first.oddsOfValue.multiply(second.oddsOfValue), value: [...first.value, ...second.value], }; } export * from "./combinatorics"; export * from "./Fraction"; export * from "./RandomDevice"; export * from "./WithOdds"; |