10
\$\begingroup\$

The sci-fi shooter Destiny 2 contains guns which have the ability to regenerate ammunition directly into the magazine if, and only if x (precision) shots are landed (in a fixed amount of time), returning y bullets to the magazine. For example, the perk (ability) "Triple Tap" will return 1 bullet to the magazine if 3 precision hits are landed (x = 3, y = 1 in this case). A gun may also have multiple perks.

Task
Your task is to take the initial magazine capacity of a gun, and take a list of perks in the form of x and ys in a suitable format, and return the highest number of shots that could be fired before having to reload the weapon. Input may be in any form suitable (list with magazine capacity as element 0, list of tuples, list/capacity being two different variables etc.)

Examples

Input1 = [4, (3, 1)] # format here is [magazine, (x, y)...]
Output1 = 5

Input2 = [6, (3, 1), (4, 2)]
Output2 = 23

Input3 = [100, (1, 2)] 
Output3 = NaN # any version of NaN or Infinity would be fine here

A worked example of Input2/Output2 can be found here (courtesy of @Arnauld in comments).

Rules

  • All values (including magazine size) maybe be zero, but never negative.
  • Input/Output may be in any suitable form.

This is , so shortest answer wins!

\$\endgroup\$
12
  • 6
    \$\begingroup\$ Welcome to Code Golf and nice first question! For future reference, we recommend using the Sandbox to get feedback on challenge ideas before posting them to main. I'd suggest doing a worked through example, as it took me a second to understand exactly why e.g. the first test case is 5 \$\endgroup\$ Commented Mar 26, 2022 at 21:50
  • 5
    \$\begingroup\$ "any version of NaN or Infinity would be fine here" How about a negative number? \$\endgroup\$
    – Jonah
    Commented Mar 26, 2022 at 21:50
  • 3
    \$\begingroup\$ To add to @Jonah's comment, typed languages would have to use a very code golf unfriendly floating point type just to return that NaN or Infinity. \$\endgroup\$
    – Noodle9
    Commented Mar 27, 2022 at 10:31
  • 1
    \$\begingroup\$ Suggested test case (provided that it's valid): [100, (1, 2)] \$\endgroup\$
    – Arnauld
    Commented Mar 28, 2022 at 10:26
  • 1
    \$\begingroup\$ If there are multiple perks, when exactly do they trigger? How do you get 23 shots in test case 2? \$\endgroup\$
    – Zgarb
    Commented Mar 28, 2022 at 10:49

6 Answers 6

8
\$\begingroup\$

J, 60 51 bytes

(0(i.~+_*1-e.)[+/\@,(*#)$])_1++/@(*0=]|/1+[:i.*./)/

Try it online!

Feels like there might be a closed form solution, but I didn't find one. So instead I simulate the required number of times, which is bounded (see explanation).

Consider 6 f (1 2,:3 4) where we take the perks as the right argument, as a matrix like this:

1 2 <- y values
3 4 <- x values
  • 1+[:i.*./)/ 1...<the LCM of 3,4>:

    1 2 3 4 5 6 7 8 9 10 11 12
    
  • ]|/ Modded by 3 and 4:

    1 2 0 1 2 0 1 2 0 1 2 0
    1 2 3 0 1 2 3 0 1 2 3 0
    
  • 0= Where does that equal 0:

    0 0 1 0 0 1 0 0 1 0 0 1
    0 0 0 1 0 0 0 1 0 0 0 1
    
  • * Multiply elementwise by 1 2:

    0 0 1 0 0 1 0 0 1 0 0 1
    0 0 0 2 0 0 0 2 0 0 0 2
    
  • +/@ Sum the rows:

    0 0 1 2 0 1 0 2 1 0 0 3
    
  • _1+ Minus 1:

    _1 _1 0 1 _1 0 _1 1 0 _1 _1 2
    
  • ((*#)$]) Repeat that 6 times:

    _1 _1 0 1 _1 0 _1 1 0 _1 _1 2 _1 _1 0 1 _1 0 _1 1 0 _1 _1 2 _1 _1 0 1 _1 0 _1 1 0 _1 _1 2 _1 _1 0 1 _1 0 _1 1 0 _1 _1 2 _1 _1 0 1 _1 0 _1 1 0 _1 _1 2 _1 _1 0 1 _1 0 _1 1 0 _1 _1 2
    
  • [+/\@, Append the 6 and scan sum:

    6 5 4 4 5 4 4 3 4 4 3 2 4 3 2 2 3 2 2 1 2 2 1 0 2 1 0 0 1 0 0 _1 0 0 _1 _2 0 _1 _2 _2 _1 _2 _2 _3 _2 _2 _3 _4 _2 _3 _4 _4 _3 _4 _4 _5 _4 _4 _5 _6 _4 _5 _6 _6 _5 _ 6 _6 _7 _6 _6 _7 _8 _6
    
    • The answer is now the index of the first 0. If there is no zero within 6 repetitions, there there will never be a 0, and we can continue forever.
  • 0(i.~+_*1-e.) Find the index of the first 0, and add infinity if there is no zero:

    23
    
\$\endgroup\$
6
  • 1
    \$\begingroup\$ Nice job with the quick answer, I too was actually wondering if there was an elegant mathematical solution, but no luck so far :-( \$\endgroup\$ Commented Mar 27, 2022 at 22:21
  • \$\begingroup\$ LCM doesn't work if any of the inputs is 0. \$\endgroup\$ Commented Mar 28, 2022 at 14:11
  • \$\begingroup\$ I was a bit confused on this because there were no test cases, but if the magazine size is 0, my function returns 0 (seems correct). If x=0, y=positve, returns infinity (seem correct). If x=0, y=0, returns infinity (incorrect). So is it just the last case I need to fix? \$\endgroup\$
    – Jonah
    Commented Mar 28, 2022 at 14:41
  • \$\begingroup\$ @Capercailie Can you clarify this ^^? \$\endgroup\$
    – Jonah
    Commented Mar 28, 2022 at 19:33
  • 1
    \$\begingroup\$ @Capercailie I would just give a list of the different inputs / outputs. I will try to correct my answer for these edge cases tonight. \$\endgroup\$
    – Jonah
    Commented Mar 29, 2022 at 13:02
4
\$\begingroup\$

05AB1E, 25 bytes

˜>P*U¹εÅ0`gª¦Xи}.«+<.¥+0k

First input as a list of [x,y] pairs, second input the starting ammunition.
Outputs -1 for Infinity/NaN, because 05AB1E doesn't have either.

Port of @Jonah's J answer.
Thanks to @DominicVanEssen for noticing some bugs in my program (previously failed if \$y>x\$; if there were a mixture of both valid and invalid \$[x,y]\$ pairs in the input; and if either \$x=0\$ and/or \$y=0\$).

Try it online or verify all test cases.

Explanation:

˜           # Flatten the (implicit) first input-list of [x,y]-pairs
 >          # Increase each by 1 (edge case for the 0s)
  P         # Take the product of this list
   *        # Multiply it by the (implicit) second input-integer
    U       # Pop and store this value in variable `X`
¹ε          # Map over the [x,y]-pairs of the first input-list:
  Å0        #  Convert both to a list of that many 0s
    `       #  Pop and push both lists of 0s to the stack
     g      #  Pop the top and get its length to transform it back into an integer
      ª     #  Append it to the list
       ¦    #  Remove the first 0
            #  (an [x,y] pair is now a list of x-1 amount of 0s appended with y)
        Xи  #  Cycle-repeat this list `X` amount of times
 }          # After the map:
  .«        # Reduce the list of infinite lists by:
    +       #  Adding the values at the same positions together
     <      # Then decrease each by 1
      .¥    # Undelta this list with leading 0
        +   # Add the second (implicit) input-integer to each value
         0k # Get the 0-based index of the fist 0 (or -1 if there are none)
            # (after which the top of the stack is output implicitly as result)
\$\endgroup\$
6
  • \$\begingroup\$ This seems to run forever if the perk is bigger than the shots needed to get it... \$\endgroup\$ Commented Mar 28, 2022 at 13:17
  • \$\begingroup\$ @DominicvanEssen Ah, I assumed the ammunition returned would never be bigger than the amounts shot, but I guess that was a wrong assumption.. Fixed at the cost of 1 byte. \$\endgroup\$ Commented Mar 28, 2022 at 13:30
  • \$\begingroup\$ But what about this, though...? \$\endgroup\$ Commented Mar 28, 2022 at 13:39
  • \$\begingroup\$ @DominicvanEssen Ugh.. Now I understand why people were complaining about input-validation in my first challenge. Anyway, fixed again (at no cost). \$\endgroup\$ Commented Mar 28, 2022 at 13:54
  • \$\begingroup\$ try this... \$\endgroup\$ Commented Mar 28, 2022 at 14:00
3
\$\begingroup\$

Charcoal, 26 bytes

I⌕E×θΠEη§ι⁰⁻ιΣEη×÷ι§λ⁰§λ¹θ

Try it online! Link is to verbose version of code. Takes the capacity and list of perks as separate inputs. Charcoal doesn't have Infinity or NaN so -1 is output instead. Explanation:

 ⌕                          Find index of
                         θ  Capacity in
      Eη                    Map over perks
        §ι⁰                 Perk `x` value
     Π                      Take the product
   ×                        Multiplied by
    θ                       First input
  E                         Map over implicit range
            ι               Current value
           ⁻                Subtract
              Eη            Map over perks
                  ι         Current value
                 ÷          Integer divided by
                   §λ⁰      Perk `x` value
                ×           Multiplied by
                      §λ¹   Perk `y` value
             Σ              Take the sum
I                           Cast to string
                            Implicitly print
\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6), 67 bytes

Expects (magazine)(perks). Returns NaN for ∞.

This processes a simulation, one shot at a time.

(n,q=0,m=n)=>g=a=>m?n>m--|!q++?g(a,a.map(([x,y])=>q%x?0:m+=y)):+g:q

Try it online!

Commented

( n,                    // n = initial number of bullets
  q = 0,                // q = number of shots
  m = n                 // m = number of bullets in the magazine
) =>                    //
g = a =>                // a[] = array of perks, in [x, y] format
m ?                     // if there's still at least one bullet:
  n > m-- |             //   if m is less than n (decrement m afterwards)
  !q++ ?                //   or q is still 0 (increment q afterwards):
    g(                  //     do a recursive call:
      a,                //       pass a[] unchanged
      a.map(([x, y]) => //       for each perk [x, y] in a[]:
        q % x ?         //         if x does not divide q:
          0             //           do nothing
        :               //         else:
          m += y        //           add y bullets
      )                 //       end of map()
    )                   //     end of recursive call
  :                     //   else:
    +g                  //     return NaN
:                       // else:
  q                     //   return the total number of shots
\$\endgroup\$
2
\$\begingroup\$

Clojure, 160 bytes

#(loop[m %[x & y](apply map vector(for[[a b]%&](cycle(concat(repeat(dec a)0)[b]))))i 0](cond(= 0 m)i(>=(- m)%)(/ 1 0.)1(recur(apply - 1(Math/abs m)x)y(inc i))))

Try it online!

Similarly to Jonah's answer, this simulates the shooting process. However, as Clojure's collections are lazy, we do not set any bounds, but cycle through infinite lists of extra added bullets (like 0 0 1 0 0 1 0 0 1...) until the number of bullets in the magazine m reaches zero.

When at any stage the magazine is refilled to its maximum capacity, this should go on indefinitely, and in such case Infinity is returned. Note: Clojure version on TIO is probably too old, as it doesn't accept ##Inf literal.

\$\endgroup\$
1
\$\begingroup\$

R, 78 75 bytes

function(a,x,y){b=a;while(sum(x*a)&(a=a+sum(y[!T%%x])-1)<b)T=T+1;T/(a<b)-1}

Try it online!

Input is ammunition a, a vector of x hit values, and a vector of the corresponding y perk values.
Uses either Inf or NA as "any version of NaN or Infinity" output options...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.