计数器跟踪数组内的多个值

时间:2016-10-26 06:29:36

标签: javascript arrays combinations counter

这看起来有点复杂,所以我会尽我所能尽可能清楚。我正在寻找的特定功能动态创建花钱|钱赢了赌博游戏的图表。

我有一个用户可以赌的种类的彩票。用户可以购买6件物品,每件物品有6个奖品:

enter image description here

这些可以放入对象或数组中。

var prices = [5,10,28,50,56,280]

var possibleWins = [40,80,250,400,500,2500]

我正在尝试创建一个图表来计算每场比赛每项特定项目需要花多少钱才能保证你获得金钱 - 在300场比赛中。

以下是图表应如何开始的示例:

enter image description here

投资=最大可能的奖金+总花费(这是负数)

第二排假设第一场比赛已经发生并丢失。等等。

这个想法是从最小的项目开始,但是即使你获胜也不会再让你积极。这就是为什么在第9行我们切换到 rock 。 (我们的投资是0,如果我们再次投球,我们赢得的最多就是40.所以即使我们赢了,我们实际上也会输掉5个。)

另外值得指出的是,如果你赢了1项;你赢得了特定游戏的所有项目。所以你得到所有的奖品。

我一直在研究这几天,其中一些相关的问题是我最初的尝试(但老实说我不知道​​):

How to find the lowest possible combination of keys within an array

Counter that generates the lowest sum from a combination of indexes above the previous value

Add an arrays keys to themselves until exceeding a limit?

编辑:每场比赛必须购买至少1件商品且不能跳过游戏

3 个答案:

答案 0 :(得分:9)

基本上,这个提议依赖于获取下一个项目的功能

    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;
        }
    }(),

以零开始于价格并将值递增1,直到找到项目组合。然后返回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使用一个数组,其价格和所需金额可以通过组合给定的价格来达到。如果成功,则返回包含项目的数组,否则返回空数组。

第三部分是使用项目,只要投资不是负面的。如果发生这种情况,则会获取新的项目集。

&#13;
&#13;
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);
}
&#13;
table { border-collapse: collapse; font-family: Sans-Serif; }
th { border: 1px solid #ccc; padding: 0 10px; }
td { text-align: center; border: 1px solid #ccc; }
&#13;
&#13;
&#13;

答案 1 :(得分:4)

这是我的解决方案

&#13;
&#13;
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;
      }
    }
  }
}
&#13;
table {
  border-collapse: collapse;
}
tr * {
  border: solid 1px black;
}
.first {
  border-top: solid 4px blue;
}
&#13;
<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>
&#13;
&#13;
&#13;

答案 2 :(得分:2)

您可以创建一个对象,其中属性名称设置为possibleWins的值。设置在每轮投资限额的所有可能组合。数组不包含小于该特定回合限制的所有可能的数字组合。也就是说,数字不会分散在每种可能的组合中。例如,在第40轮,[10, 10, 10, 10, 0, 0, 0, 0]作为数组包含在内;虽然数组也可以重新排列为[10, 0, 10, 10, 0, 10, 0, 10],或者总和小于40的其他索引组合。

将小于该轮的limit的其他可能允许组合推送到对应于返回对象的特定轮的数组。

此实施不会尝试找到每轮的选择路线,这将导致积极的结果。可以针对每个数组中的每个匹配索引,随机索引的组合或每个可能的索引组合来迭代整个数组集。

该方法是一个基本模板,可以从中进行选择。包含值的组合的更多可选数组,即对象属性名称,即特定的一轮,或者数组内的值,在属性名称值小于当前轮次的对象的属性中,可以添加到数组数组中;找到导致预期结果的选择组合。

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);