# Calculate Bloons RBE

In Bloons Tower Defense 6, the strength of different bloons can be measured by their Red Bloon Equivalent (RBE), or the number of single pops it takes to completely defeat the bloon.

The RBE for the bloon types are as follows (sourced from the wiki)

Bloon RBE
red 1
blue 2
green 3
yellow 4
pink 5
black 11
white 11
purple 11
lead 23
zebra 23
rainbow 47
ceramic 104
moab 616
bfb 3164
zomg 16656
ddt 816
bad 55760

## The Challenge

Given a run-length encoded list of bloon types, calculate the total RBE. More specifically, find the RBE of each bloon type according to the table, multiply by the given count, and sum them all.

### Notes

• Input can be taken in any reasonable format (comma-separated string, list of tuples, etc.)
• You must output a single integer
• Assume that input will never be invalid
• Bloon types must be given exactly as shown in the table above, in lowercase
• This is , so the lowest score in bytes wins!

## Test Cases

Input: 1 red
Output: 1

Input: 7 green
Output: 21

Input: 5 bfb, 11 moab
Output: 22596

Input: 1 red, 2 yellow, 3 white, 4 zebra, 5 moab, 6 ddt
Output: 8110

Input: 1 moab, 1 bfb, 1 zomg, 1 ddt, 1 bad, 1 red, 1 blue, 1 green, 1 yellow, 1 pink, 1 black, 1 white, 1 purple, 1 lead, 1 zebra, 1 rainbow, 1 ceramic
Output: 77257

• Can the input be a list with repeats rather than run-length-encoded? e.g. [red, red, red] rather than 3 red Apr 14, 2023 at 13:59
• @Bbrk24 Some BTD6 rounds have hundreds of bloons, so it makes more sense to present the input as a list of frequencies. Apr 14, 2023 at 14:06
• Trivia: ceramics in freeplay become super-ceramics but only spawn 1 child in further layers. Also I believe RBE doesn't actually appear in-game in BTD6.
– qwr
Apr 15, 2023 at 2:40
• @qwr IIRC, super ceramics have the same RBE as normal ceramics if we don't account for freeplay health scaling. Apr 15, 2023 at 14:19

# JavaScript (ES6), 111 bytes

Expects a list of [count, bloon] pairs.

a=>a.reduce((t,[k,s])=>t+k*[23,3,104,616,3164,1,16656,4,47,23,816,55760,5,11,2][parseInt(s,36)*53%437%44%15],0)


Try it online!

### How?

The hash function was found by brute force:

parseInt(s, 36) * 53 % 437 % 44 % 15


It's a bit long but almost perfect:

• all slots from 0 to 14 are used
• black, white and purple (all scoring 11) gracefully collide on the same slot
• however, two distinct slots are used for lead and zebra (both scoring 23)

Below is a summary table sorted by final lookup index:

 string    | parseInt()  |      * 53     | mod 437 | mod 44 | mod 15 | value
-----------+-------------+---------------+---------+--------+--------+-------
"lead"    |      998293 |      52909529 |   191   |   15   |    0   |    23
"green"   |    28152239 |    1492068667 |   339   |   31   |    1   |     3
"ceramic" | 27013759860 | 1431729272580 |   134   |    2   |    2   |   104
"moab"    |     1057907 |      56069071 |   223   |    3   |    3   |   616
"bfb"     |       14807 |        784771 |   356   |    4   |    4   |  3164
"red"     |       35509 |       1881977 |   255   |   35   |    5   |     1
"zomg"    |     1664872 |      88238216 |    50   |    6   |    6   | 16656
"yellow"  |  2080372496 |  110259742288 |    37   |   37   |    7   |     4
"rainbow" | 59409106160 | 3148682626480 |   243   |   23   |    8   |    47
"zebra"   |    59454982 |    3151114046 |   127   |   39   |    9   |    23
"ddt"     |       17345 |        919285 |   274   |   10   |   10   |   816
"bad"     |       14629 |        775337 |    99   |   11   |   11   | 55760
"pink"    |     1190576 |      63100528 |   350   |   42   |   12   |     5
"black"   |    19468964 |    1031855092 |   204   |   28   |   13   |    11
"white"   |    54565250 |    2891958250 |   189   |   13   |   13   |    11
"purple"  |  1563335762 |   82856795386 |   336   |   28   |   13   |    11
"blue"    |      541526 |      28700878 |    29   |   29   |   14   |     2


# Python 3.9, 104 + 17 = 121 bytes

lambda l:sum([47,11,3164,616,16656,4,1,5,23,104,11,23,3,2,11,816,55760][hash(a*9828)%17]*b for a,b in l)


You also need to set an environment variable (I included it in the byte count).

PYTHONHASHSEED=65


Input is a list of tuples of the form (name, amount)

• I bet you could do better by compressing that crazy bit array somehow Apr 15, 2023 at 0:49

# Jelly, 47 bytes

ḋɓ“µCḅṃ’,14ḥⱮị⁽%xBŻ€ṁ@“£t¢Bƈ/¦£¤Bh¥ç¤¿€ƥṣ½‘¤ḅØ⁵


A dyadic Link that accepts the frequencies on the left and the respective bloons on the right and yields the total RBE.

Try it online!

### How?

ḋɓ“...’,14ḥⱮị⁽%xBŻ€ṁ@“...‘¤ḅØ⁵ - Link: frequencies, bloons
Ɱ                   - map across the bloons applying:
ḥ                    -   hash...
“...’                        -   ...with salt: 160553470
,14                     -   ...and values: [1,2,...,14]
¤    - nilad followed by link(s) as a nilad
⁽%x               -   10371
B              -   convert to binary -> [1,0,1,0,0,0,1,0,0,0,0,0,1,1]
Ż€            -   zero range each -> [[0,1],[0],[0,1],[0],[0],[0],[0,1],[0],[0],[0],[0],[0],[0,1],[0,1]]
“...‘     -   code-page indices = [2,116,1,66,156,47,5,2,3,66,104,4,23,3,11,12,164,223,10]
ṁ@          -   mould -> [[2,116],[1],[66,156],[47],[5],[2],[3,66],[104],[4],[23],[3],[11],[12,164],[223,10]]
ị                  - (hashed bloons) index into (that)
Ø⁵ - 250
ḅ   - convert from base (250) -> bloon RBEs
ɓ                             - dyadic chain:
ḋ                              -   (frequencies) dot-product (bloon RBEs)


# Excel, 203 bytes

=LET(
a,TEXTSPLIT(A1," ",","),
SUM(LOOKUP(TAKE(a,,-1),
{"b","bf","bla","blu","c","d","g","l","m","p","pu","r","re","w","y","z","zo"},
{55760,3164,11,2,104,816,3,23,616,5,11,47,1,11,4,23,16656})*TAKE(a,,1))
)


Input is comma-separated string, e.g. 1 red, 2 yellow, 3 white, 4 zebra, 5 moab, 6 ddt, in cell A1.

# C (gcc), 200 bytes

Takes an array of strings and its length as input.

f(s,n,c,t)char**s;{int L[]={47,23,55760,4,0,0,0,0,0,816,2,0,0,0,0,0,3,0,0,5,3164,0,0,0,616,16656,1,0,11,23,0,104};for(t=0;n--;t+=c*L[((**s*2[*s++]*7711)>>15)&31])for(c=atoi(*s);*(*s)++-32;);return t;}


Try it online!

• 173 bytes Apr 15, 2023 at 9:45

# Swift 2.2, 128 bytes

{$0.reduce(0){$0+$1.1*[0,16656,3164,0,5,616,3,0,0,11,1,816,0,23,0,0,23,0,55760,11,104,2,4,0,0,47][($1.0.hashValue>>8&63^6)%26]}}


Try it on SwiftFiddle!

Takes a dictionary, e.g. ["red": 3, "blue": 7].

It turns out that after some bit twiddling, each bloon type has a unique* hashValue mod 26. So far I haven't found a way to get the modulus any lower. Since Swift 3, hash values differ between runs of the same program, so this strategy is no longer viable.

*"white" and "black" map to the same value, but they also have the same RBE, so it works out.

# Retina, 146 bytes

.+ed
*
.+ue
*2*
.+en
*3*
.+y
*4*
.+nk
*5*
.+[khp]
*11*
.+e[ab]
*23*
.+n
*47*
.+c
*104*
.+ab
*616*
.+f
*3164*
.+g
*16656*
.+dt
*816*
.+ad
*55760*
_


Try it online! Takes input on separate lines but link is to test suite splits on ,  for convenience. Explanation: Each stage matches a colour of balloon to multiply its quantity appropriately. The shortest possible unique remaining substring is used at each point, with preference being given to the rightmost such substrings as this will be deleted and therefore can be ignored when matching subsequent substrings. In this way for instance .+nk matches and deletes the whole of pink allowing .+[khp] to only match black, white and purple. The final _ then calculates the total RBE which is converted back to decimal.

# 05AB1E, 81 bytes

ø.•4в#‡fÕçòÖ¹<÷E¤E%ÝÙ/J“Å;>Íslζ₂θ…•3ôs3δ£k•Ì¥δвιλùEmæâåÇÛZ•₄в•Cƒ2œÝù•3äÁ«.¥>sè*O


I suck at finding magic numbers, so this will have to do for now.. Replacing .•4в#‡fÕçòÖ¹<÷E¤E%ÝÙ/J“Å;>Íslζ₂θ…•3ô3δ£k with C, optional Ø, and some modulos will probably save some bytes.

Explanation:

ø                     # Zip/transpose the (implicit) input-list
# Pop and push the list of Bloons and list of counts separated to the stack
.•4в#‡fÕçòÖ¹<÷E¤E%ÝÙ/J“Å;>Íslζ₂θ…•
# Push compressed string "redblugreyelpinblawhipurleazebraicermoaddtbfbzombad"
3ô                  # Split it into parts of size 3
s                 # Swap so the input-list of Bloons is at the top
δ               # Map over each Bloon:
3 £              #  Leave just its first 3 characters
k             # Get the index of each in the list of strings
•Ì¥δвιλùEmæâåÇÛZ•     # Push compressed integer 1001001001006000000012000024057512200
₄в                  # Convert it to base-1000 as list:
#  [1,1,1,1,6,0,0,12,0,24,57,512,200]
•Cƒ2œÝù•          # Push compressed integer 13492391042348
3ä        # Split it into 3 equal-sized parts: [13492,39104,2348]
Á       # Rotate it once: [2348,13492,39104]
«      # Merge the two lists together
.¥    # Undelta it with leading 0: [0,1,2,3,4,10,10,10,22,22,46,103,615,815,3163,16655,55759]
>   # Increase each by 1
sè # Index the earlier indices into this list
*                     # Multiply each value by its count
O                    # Sum this list together
# (after which the result is output implicitly)


See this 05AB1E tip of mine (sections How to compress strings not part of the dictionary?, How to compress large integers?, and How to compress integer lists?) to understand why .•4в#‡fÕçòÖ¹<÷E¤E%ÝÙ/J“Å;>Íslζ₂θ…• is "redblugreyelpinblawhipurleazebraicermoaddtbfbzombad"; •Ì¥δвιλùEmæâåÇÛZ• is 1001001001006000000012000024057512200; •Ì¥δвιλùEmæâåÇÛZ•₄в is [1,1,1,1,6,0,0,12,0,24,57,512,200]; and •Cƒ2œÝù• is 13492391042348.

# Charcoal, 86 bytes

ＩΣＥ⪪Ｓ, ΠＩＥ⪪ι ⎇μ§⪪”)¶⊟S|4ηJ?α8⊕rüQG§﹪⊗βⅉ№8℅jo”9⌕⪪”&⌈⊟²…x⦃P⦄h¿◨Ｔ-α～⁶？Ｔ÷´Cgψ↥b·CQq”³…λ³λ


Try it online! Link is to verbose version of code. Explanation:

    Ｓ                               Input string
⪪ ,                              Split on literal string , 
Ｅ                                 Map over substrings
ι                        Current substring
⪪                         Split on literal string  
Ｅ                          Map over words
⎇μ                     If second word then
”...”      Compressed lookup table
⪪     ³     Split into substrings of length 3
⌕            Find index of
λ   Second word
…    Truncated to length
³  Literal integer 3
§                    Index into
”...”              Compressed lookup table
⪪     9             Split on literal string 9
λ Otherwise first word
Ｉ                           Cast to integer
Π                            Take the product
Σ                                  Take the sum
Ｉ                                   Cast to string
Implicitly print


77 bytes using the newer version of Charcoal on ATO by taking the input as a dictionary:

ＩΣＥＡ×ιＩ§⪪”)¶⊟S|4ηJ?α8⊕rüQG§﹪⊗βⅉ№8℅jo”9⌕⪪”&⌈⊟²…x⦃P⦄h¿◨Ｔ-α～⁶？Ｔ÷\´Cgψ↥b·CQq”³…κ³


Attempt This Online! Link is to verbose version of code.

# Scala, 162 bytes

Try it online!

val f:Seq[(Int,String)]=>Int=data=>data.foldLeft(0){case(t,(k,s))=>t+k*Seq(23,3,104,616,3164,1,16656,4,47,23,816,55760,5,11,2)((BigInt(s,36)*53%437%44%15).toInt)}


# Pyth, 61 bytes

sm*@[616C\/5 816J2K11ZKy8328hZ23KZZ3y52Z3164yJ55760)%Ced8027h


Try it online!

Takes input as a list of lists. The lookup portion could probably be compressed some more but who knows.

### Explanation

sm*@[...)%Ced8027hdQ    # implicitly add dQ
# implicitly assign Q = eval(input())
s                       # sum of
m                 Q    # map lambda d over Q
*              hd     #   multiply the first element of d by
ed           #   the last element of d
C             #   converted to int using base 256 and code points
%   8027       #   modulo 8027
@[...)               #   modularly indexed into the lookup table


# C#, 123 bytes

x=>x.Sum(y=>new[]{616,1,4,0,5,47,3164,104,16656,816,3,23,0,11,55760,2}[y.Key.Aggregate(0,(a,n)=>3*a+n)*75%1847%16]*y.Value)


Try it online!

Pretty similar to the existing JavaScript answer. I brute-forced another hash function:

y.Key.Aggregate(0,(a,n)=>3*a+n)*75%1847%16


C# has no built-in way to parse base 36 numbers (which the JavaScript answer uses), so I had to use Aggregate to get a unique int for each string which worked here (GetHashCode returns different values between program executions for strings so can't be used).

string  | aggregate |*75%1847%16
--------------------------------
red     |   1429    |     1
blue    |   4070    |     15
green   |   12743   |     10
yellow  |   41924   |     2
pink    |   4406    |     4
purple  |   41204   |     13
black   |   12131   |     13
white   |   13841   |     13
zebra   |   13930   |     11
lead    |   4216    |     11
rainbow |   119486  |     5
ceramic |   109962  |     7
moab    |   4331    |     0
bfb     |   1286    |     6
zomg    |   4723    |     8
ddt     |   1316    |     9
bad     |   1273    |     14