A counter keeping track of multiple values inside an array
Basically this proposal relies on a function to get the next items
getItems = function () { var price = 0, array = lottery.map(function (a) { return a.price; }); return function () { var items; do { items = combine(array, price); price++; } while (!items.length) return items; } }(),
which starts at price with zero and increments the value by one until a combination of items is found. Then the items
array is returned. The function works as generator.
The other important function is the combination of items with a given price and the try to get an array with the items.
function combine(array, sum) { function c(left, right, sum) { if (!sum) { result = right; return true; } return left.some(function (a, i, aa) { return a <= sum && c(aa.slice(i + (a > sum - a)), right.concat(a), sum - a); }); } var result = []; c(array.sort(function (a, b) { return b - a; }), [], sum); return result;}
combine
takes an array with prices and a wanted sum to reach with combinating the given prices. If successfull, an array with the items is returned, otherwise an empty array.
The third part is to use the items as long as the investment is not negative. If that happens, a new items set is fetched.
function combine(array, sum) { function c(left, right, sum) { if (!sum) { result = right; return true; } return left.some(function (a, i, aa) { return a <= sum && c(aa.slice(i + (a > sum - a)), right.concat(a), sum - a); }); } var result = []; c(array.sort(function (a, b) { return b - a; }), [], sum); return result;}var lottery = [{ name: 'twig', price: 5, win: 40 }, { name: 'rock', price: 10, win: 80 }, { name: 'shell', price: 28, win: 250 }, { name: 'chip', price: 50, win: 400 }, { name: 'gold', price: 56, win: 500 }, { name: 'diamond', price: 280, win: 2500 }], lotteryByPrice = lottery.reduce(function (r, a) { r[a.price] = a; return r; }, Object.create(null)), getItems = function () { var price = 0, array = lottery.map(function (a) { return a.price; }); return function () { var temp; do { temp = combine(array, price); price++; } while (!temp.length) return temp; } }(), createTableRow = function (element) { var table = document.createElement('table'), tr = document.createElement('tr'); ['Game', 'Items', 'Types', 'Spend Per Game', 'Total Spend', 'Max. Possible Winnigs', 'Investment'].forEach(function (a) { var th = document.createElement('th'); th.appendChild(document.createTextNode(a)); tr.appendChild(th); }); table.appendChild(tr); element.appendChild(table); return function (row) { var tr = document.createElement('tr'); ['game', 'items', 'types', 'spend', 'total', 'potential', 'investment'].forEach(function (k) { var td = document.createElement('td'); td.appendChild(document.createTextNode(row[k])); tr.appendChild(td); }); if (row.topBorder) { tr.style.borderTop = '2px solid #666'; } table.appendChild(tr); }; }(document.body), row = { game: null, items: null, types: null, spend: null, total: 0, potential: null, investment: null }, i, items = getItems(), add = function (a, b) { return a + b; }, winP = function (a) { return lotteryByPrice[a].win; }, nameP = function (a) { return lotteryByPrice[a].name; };for (i = 1; i <= 70; i++) { row.topBorder = false; while (row.total - items.reduce(add) + items.map(winP).reduce(add) < 0) { items = getItems(); row.topBorder = true; } row.game = i; row.items = items.length; row.types = items.map(nameP).join(' + '); row.spend = -items.reduce(add); row.total += row.spend; row.potential = items.map(winP).reduce(add); row.investment = row.potential + row.total; createTableRow(row);}
table { border-collapse: collapse; font-family: Sans-Serif; }th { border: 1px solid #ccc; padding: 0 10px; }td { text-align: center; border: 1px solid #ccc; }
Here is my solution
let items = [{ name: 'twig', price: 5, win: 40}, { name: 'rock', price: 10, win: 80}, { name: 'shell', price: 28, win: 250}, { name: 'chip', price: 50, win: 400}, { name: 'gold', price: 56, win: 500}, { name: 'diamond', price: 280, win: 2500}];let moves = [];Move.prototype.numberItems = function() { let count = 0; for (let n = 0; n < 6; n++) { count += this.counts[n]; } return count;}Move.prototype.nameItems = function() { let name = ''; for (let n = 0; n < 6; n++) { for (let x = 0; x < this.counts[n]; x++) { if (name != '') { name += ' - '; } name += items[n].name; } } return name;}Move.prototype.getWin = function() { let win = 0; for (let n = 0; n < 6; n++) { win += this.counts[n] * items[n].win; } return win;}function Move(cost, counts) { this.cost = cost; this.counts = counts.slice();}function run() { createMoves(100); moves.sort(function(a, b) { return (a.cost - b.cost); }); print();}function createMoves(maxCost) { let counts = []; for (let n = 0; n < 6; n++) { counts.push(0); } counts[0] ++; while (true) { let cost = whatCost(counts); if (cost < maxCost) { moves.push(new Move(cost, counts)); counts[0] ++; continue; } if (!escalate(counts)) { break; } }}function whatCost(counts) { let cost = 0; for (let n = 0; n < 6; n++) { cost += counts[n] * items[n].price; } return cost;}function escalate(counts) { for (let n = 0; n < 5; n++) { if (counts[n] != 0) { counts[n] = 0; counts[n + 1] ++; return true; } } return false;}function print() { let domResult = document.getElementById('results'); let game = 1; let moveInx = 0; let spent = 0; for (let moveInx = 0; moveInx < moves.length; moveInx++) { let myMove = moves[moveInx]; let items = myMove.numberItems(); let win = myMove.getWin(); let cost = myMove.cost; for (let repeat = 1;; repeat++) { let investment = win - spent - cost; if (investment < 0) { break; } spent += cost; let row = document.createElement('tr'); if (repeat == 1) { row.className = 'first'; } let cell = document.createElement('td'); cell.innerHTML = game; row.appendChild(cell); cell = document.createElement('td'); cell.innerHTML = items; row.appendChild(cell); cell = document.createElement('td'); cell.innerHTML = myMove.nameItems(); row.appendChild(cell); cell = document.createElement('td'); cell.innerHTML = cost; row.appendChild(cell); cell = document.createElement('td'); cell.innerHTML = spent; row.appendChild(cell); cell = document.createElement('td'); cell.innerHTML = win; row.appendChild(cell); cell = document.createElement('td'); cell.innerHTML = win - spent; row.appendChild(cell); domResult.appendChild(row); game++; if (game > 300) { return; } } }}
table { border-collapse: collapse;}tr * { border: solid 1px black;}.first { border-top: solid 4px blue;}
<button onclick="run()">Run</button><table> <thead> <tr> <th>Game</th> <th>Items</th> <th>Types</th> <th>Spent</th> <th>Total Spent</th> <th>Max win</th> <th>Profit</th> </tr> </thead> <tbody id="results"> </tbody></table>
You can create an object where property names are set the values of possibleWins
. Set all of the possible combinations of investing the limit at each round. The arrays do not contain all possible combinations of numbers less than the limit for that particular round. That is, the numbers are not dispersed in every possible combination. For example, at round 40
, [10, 10, 10, 10, 0, 0, 0, 0]
is included as an array; though the array could also be rearranged to [10, 0, 10, 10, 0, 10, 0, 10]
, or other combination of indexes totaling less than 40
.
Additional of the possible allowed combinations less than the limit
for that round be pushed to the array corresponding a specific round at the returned object.
This implementation does not attempt to locate the selection routes of each round which would lead to a positive outcome. The entire set of arrays can be iterated as to each matching index in each array, combination of random indexes, or every possible combination of indexes.
The approach is a base template from which possible selections can be made. Further optional arrays containing combinations of values less object property name, that is the particular round, or values within arrays from within arrays at properties of object having a property name value less than the current round, can be added to the array of arrays; to find the combinations of selections which lead to the expected outcome.
const [prices, possibleWins] = [ [5, 10, 28, 50, 56, 280], [40, 80, 250, 400, 500, 2500]];const counteropts = (prices, possibleWins) => { let rounds = {}; for (let price of prices) { let [chance, limit] = [[], possibleWins[prices.indexOf(price)]]; for (let buyin = price - price; buyin <= limit; buyin += price) { chance[chance.length] = buyin; } if (chance[chance.length - 1] !== limit) { chance = [...chance, limit] } for (let odd of Array.of(chance)) { let options = Array(); for (let choice of odd) { options[options.length] = [...odd.map( v => v !== choice && v + choice <= limit ? v + choice : 0 )]; if (options.length === prices.length -1) { for (let option of options[0]) { let keys = options[0].map((_, index) => index + 1) .filter(key => key * option <= limit); let opt = Array(keys.length).fill(option); options = [...options , opt.length < options[0].length ? [...opt, ...Array(options[0].length - opt.length).fill(0)] : opt ]; } rounds[limit] = [...options]; } } } } return rounds }let opts = counteropts(prices, possibleWins);console.log(opts);