2

I am writing an app in javascript to try to figure out item builds for characters in a video game. There are about 25 top-tier items, and you can carry 6 at a time. They have very different effects, which leads me to believe that while one item may seem like it isn't very good by itself, it can become much stronger when combined with others.

Questions:

  1. How can I get a list of all the different distinct combinations of 6 items? How many combinations will there be? Is it just 25c6 (~134k)? Or do I need to remove duplicates? (Sorry, I've been out of math class awhile.)

  2. How would you implement something like this in Javascript? Is there already a math library that can do this?

  3. Does it seem possible to brute force calculate the damage of all the possible combinations and save the top item combinations? If not, is there a better algorithm to find strong combinations?

EDIT: Here's my code based on everyone's suggestions:

function getAllCombinations(n, k, callback)
{
    var iterate = function(remaining, args)
    {   
        var len = args.length;
        for (var i = args[len - 1]; i < n; i++)
        {
            args.splice(len);
            args[len - 1] = i;
            if (remaining)
            {
                args.push(i);
                iterate(remaining - 1, args);
            }
            else
            {
                callback.apply(null, args);         
            }
        }        
    }
    iterate(k - 1, [0]);
}

var itemsCount = 25;
var itemSlots = 6;
getAllCombinations(itemsCount, itemSlots, function(a, b, c, d, e, f)
{   
    // calculateDamage(hero, arguments);
});
Shawn
  • 125
  • 2
    The answer to question 3 depends a lot on the details of how the items interact and I don't think anything much can be said in full generality. (Even for apparently simple interactions the resulting problem can end up being NP-complete: see http://math.stackexchange.com/questions/10414/math-wizardry-formula-for-selecting-the-best-spell .) Anyway, this seems like more or less a programming question. The answer to the math part of this question is: yes, it's ${25 \choose 6}$. This isn't too many combinations, so brute force should be alright anyway. – Qiaochu Yuan Apr 26 '11 at 22:49
  • Probably belongs on SO. – Sophie Alpert Apr 26 '11 at 23:04

2 Answers2

5

The brain-dead way to enumerate all combinations would be to nest 6 for loops, one loop for each item slot. In the innermost loop, you'd calculate the total effectiveness for that gear-set and then take a max. This is pretty flexible, since you can change your measurement and re-run the program at will.

However, this might be a bit slow. There are likely less than ${25 \choose 6}$ item combos due to the fact that you wouldn't want to (say) equip two helms, but it's pretty close to that number. The actual number is $i_1 i_2 i_3 i_4 i_5 i_6$ where $i_j$ is the number of choices for slot $j$.

Javascript isn't the fastest platform (although it's getting faster... a ton of research is going into optimizing it these days). I would say try it and see if it's fast enough on a commodity PC.

To make your program faster, consider throwing out combinations that are clearly inferior before doing the inner loops. This is a bit harder, but it can be done.

This doesn't feel like a math problem. :)

Updated:

So ${25 \choose 6} = 177,100$ which is calculated the quick way using the definition, or you can do it the slow way and check how long it takes to implement the for loops from Yuval's answer, modified slightly. Copy the code below into a web page and load it with Javascript enabled...

<HEAD>
  Calculating...
</HEAD>


<BODY>
  <SCRIPT>
    x= 0;
    for (i0 = 0; i0 < 25; i0++)
      for (i1 = i0; i1 < 25; i1++)
        for (i2 = i1; i2 < 25; i2++)
          for (i3 = i2; i3 < 25; i3++)
            for (i4 = i3; i4 < 25; i4++)
              for (i5 = i4; i5 < 25; i5++)
                x++;
     document.write(x);
  </SCRIPT>
</BODY>

Not exactly HTML5 compliant, but it gets the job done. Also, I would expect your inner function will be a bit more complex than x++ but this gives you a rough idea. For me, this code runs virtually instantly.

Note that the answer output here is 593,775 which is not ${25 \choose 6}$. See the comments as to why this change was made.

Fixee
  • 11,565
  • wouldnt this create a lot of duplicate combos? a,a,a,a,a,b vs b,a,a,a,a,a – Shawn Apr 26 '11 at 23:07
  • I was assuming that you have a set of helm, shoulder, bracer, glove, chest, and leg items and that you couldn't equip a given item other than in its proper slot. If you want to avoid repetitions, use the code above which will give you the 177,100 unique sets of 6 items taken from 25. – Fixee Apr 26 '11 at 23:14
  • ok i tried that and it's working however it doesn't include a,a,a,a,a,a for example. it seems like it doesnt every have the same item twice. how could i fix that? – Shawn Apr 26 '11 at 23:19
  • btw i will probably dynmically add the for loops to support any number of item slots ;p – Shawn Apr 26 '11 at 23:21
  • @Shawn: if you want to allow a,a,a,a,a,a then start each for loop at the value before it (rather than the value + 1). I edited my code above to do this. It increases the number of total loops to 593,775 from 177,100. – Fixee Apr 26 '11 at 23:30
  • i had it doing that and it seemed correct but i wasnt sure. thanks so much, this is perfect : ) – Shawn Apr 26 '11 at 23:31
  • i will return in a few days for the next challenge. each item has a cost... for 3000 gold whats the highest damage i could achieve? :p – Shawn Apr 26 '11 at 23:31
  • @Shawn: Just test the cost in the inner loop and include the item-set only if the cost is under the budget. By the way, the folks around here are very helpful and friendly, but to be honest I think your question would find a better home on stackoverflow or programmers.SE. Cheers! – Fixee Apr 26 '11 at 23:34
  • 2
    The number of possibilities is $\binom{30}{6}$. Here $30 = 25 + 6 - 1$. – Yuval Filmus Apr 27 '11 at 00:17
  • if youre still around yuval how did you come up with that? i realized that it wasnt 25c6 anymore but didnt know what it was. thanks again for everyones help. i updated the original post with the code i used. – Shawn Apr 27 '11 at 17:59
  • @Shawn: Yuval used the standard method to count combinations with repetitions. See http://en.wikipedia.org/wiki/Combination#Number_of_combinations_with_repetition – Fixee Apr 28 '11 at 00:11
3

The simplest way is to use nested loops, like this (in C):

for (i0 = 0; i0 < 25; i0++)
  for (i1 = i0 + 1; i1 < 25; i1++)
    for (i2 = i1 + 1; i2 < 25; i2++)

And so on. Maybe you already have an iterator for it in javascript.

You can optimize it slightly by improving the upper bounds, but it's error-prone and makes only a small difference.


If you have a built-in heap in javascript then you can use one to keep only the highest N items, then you don't need to sort anything (though sorting 134k numbers is completely feasible).


To check whether such brute forcing is feasible, calculate the time it takes you to compute one combination, and multiply it by 134k.

In order to calculate the time, use a timer (if javascript has one), and compute the combined damage for M randomly chosen combination, where M is "big" but "much smaller" than 134k.

Yuval Filmus
  • 57,157