# Pocket Pokemon Type Evaluator

Yes, I know there are already three pokemon type questions, but almost all submissions hardcode the whole chart in one way or other. I think it'd be nice to change the requirement a bit to encourage more shortcut-taking typically seen in decision problems.

# Objective

Write a program/function/whatever that accepts the attacking type and the defending type(s), and output something that can be identified as the final multiplier.

As usual, you can see the pokemon type chart here. Also available as text form (copied from another question linked above and modified a bit):

                                            Attacking Type
No  Fi  Fl  Po  Gr  Ro  Bu  Gh  St  Fr  Wa  Gr  El  Ps  Ic  Dr  Da  Fa
Normal        1   2   1   1   1   1   1   0   1   1   1   1   1   1   1   1   1   1
Fighting      1   1   2   1   1 0.5 0.5   1   1   1   1   1   1   2   1   1 0.5   2
D   Flying        1 0.5   1   1   0   2 0.5   1   1   1   1 0.5   2   1   2   1   1   1
e   Poison        1 0.5   1 0.5   2   1 0.5   1   1   1   1 0.5   1   2   1   1   1 0.5
f   Ground        1   1   1 0.5   1 0.5   1   1   1   1   2   2   0   1   2   1   1   1
e   Rock        0.5   2 0.5 0.5   2   1   1   1   2 0.5   2   2   1   1   1   1   1   1
n   Bug           1 0.5   2   1 0.5   2   1   1   1   2   1 0.5   1   1   1   1   1   1
d   Ghost         0   0   1 0.5   1   1 0.5   2   1   1   1   1   1   1   1   1   2   1
i   Steel       0.5   2 0.5   0   2 0.5 0.5   1 0.5   2   1 0.5   1 0.5 0.5 0.5   1 0.5
n   Fire          1   1   1   1   2   2 0.5   1 0.5 0.5   2 0.5   1   1 0.5   1   1 0.5
g   Water         1   1   1   1   1   1   1   1 0.5 0.5 0.5   2   2   1 0.5   1   1   1
Grass         1   1   2   2 0.5   1   2   1   1   2 0.5 0.5 0.5   1   2   1   1   1
T   Electric      1   1 0.5   1   2   1   1   1 0.5   1   1   1 0.5   1   1   1   1   1
y   Psychic       1 0.5   1   1   1   1   2   2   1   1   1   1   1 0.5   1   1   2   1
p   Ice           1   2   1   1   1   2   1   1   2   2   1   1   1   1 0.5   1   1   1
e   Dragon        1   1   1   1   1   1   1   1   1 0.5 0.5 0.5 0.5   1   2   2   1   2
Dark          1   2   1   1   1   1   2 0.5   1   1   1   1   1   0   1   1 0.5   2
Fairy         1 0.5   1   2   1   1 0.5   1   2   1   1   1   1   1   1   0 0.5   1


You can choose to either accept one or two defending types (the final multiplier for two defending types is just the product of all individual defending types). Both types of submissions are allowed, as they will be in separate categories.

# Rules

You can choose any methods of input in any form, structure or order (e.g ['fire',['water','rock']]/['fire',['rock']]/['fire','rock'], 'water,ice,ghost'/'water,ghost',dragondragonsteel/dragondragon).

The only requirement is that the types being inputted must be exactly their names and nothing else. Moreover, the types are required to be in one case only: so if you choose "psychic/Psychic/PSYCHIC", you must also use the same case for every other types (e.g "poison/Poison/POISON"). The available casing are: all lowercase, capital case and all uppercase.

You can output anything as long as different multipliers corresponds to one and only one output value.

There will not be two defensive types of the same type.

Standard loopholes are disallowed.

Shortest byte wins.

• Can we use the two letter identifiers from the chart? – Jo King Jul 9 '18 at 9:17
• I'm not sure if other aliases to the types should be allowed, because while I want the challenge to be liberal to allow creative solutions, allowing different identifiers seems to open too many possibilities (and potential loopholes too). – Voile Jul 9 '18 at 9:31
• So, this is It's super effective! with more relaxed I/O formats. Is that correct? Or am I missing another difference? (I don't think this qualifies as kolmogorov-complexity, BTW.) – Arnauld Jul 9 '18 at 9:55
• @Arnauld Yes. People can still try hardcoding the whole matrix (even if it might not be the best approach anymore), so I decided to leave kolmogorov-complexity in ;-) – Voile Jul 9 '18 at 10:37
• (and since there are more than 2 possible outputs, this is not a decision-problem either...) – Arnauld Jul 9 '18 at 13:04

# JavaScript (ES6), 270246 221 bytes

Takes input in currying syntax (a)(d) where a is the attacking type as a string and d are the defending type(s) as an array of strings. The case doesn't matter.

Returns a standard multiplier as a float.

a=>d=>d.map(d=>r*='0124'["ijfkj{jjnjjJ[kefjiZj[jxnjni^YnEW]vfeziiz]okjZmniV{oZvjhjnmj[zrfijij[yVzej[jjejjhujkmjZkZ[fjiuznjjz~zjfRjbkjy".charCodeAt((i=g(d)*18+g(a))/3)>>i%3*2&3]/2,g=s=>parseInt(s,36)*64%97%54%21%18,r=1)&&r


### How?

The base-36 interpretation $$\N\$$ of a given Pokemon type string is converted to a coordinate $$\C\$$ in $$\[0..17]\$$ using the following minimal perfect hash function:

$$C=((((N\times64)\bmod97)\bmod54)\bmod21)\bmod18$$

The chart is rearranged using the new coordinates and encoded as a single string with 6 bits of payload data per character, using ASCII codes in the range $$\[64..127]\$$.

There are 2 bits per cell, so the length of the string is $$\(18\times18\times2)/6=108\$$ characters.

For the curious, here is the code that encodes the string.

# Python 2, 305 bytes

def f(l):d=[int(t[2:],36)%123%28%21for t in l];return reduce(lambda x,y:x*int("eJx1UIENwDAIekkM/982FW3skprUzA4oCHe6O6Jb9F05XXeATlDIouUndGLGRUYxTDD6o0YlhSmh/adnW7o8DzS6O9PWAmM9WnbLssktWgLjoNG1iwAw/RM4DqCIaZH3mv6l5MkF22fKKp6Vxtnji05OrsnADjaX+AByt1Y8".decode('base64').decode('zip')[d[0]*21:][y])/2.,d[1:],1)


Try it online!

Also hardcoding the whole matrix..

• It seems like [d[0]*21+y] should work. Using #coding:L1 instead of base64 gets 253 bytes. – Lynn Jul 12 '18 at 14:29

## ABAP, 691 bytes

### Form-Subroutine taking two or three types in capital case

DATA:x(180) TYPE x,v type x,b,c.DEFINE g.GET BIT:&1 + 1 OF &2 INTO b,&1 + 2 OF &2 INTO c.SET BIT:7 of v TO b,8 of v TO c.IF v = 3.o = 2.ELSE.o = v / 2.ENDIF. END-OF-DEFINITION.
DEFINE f.FIND &1(3) IN'NorFigFlyPoiGroRocBugGhoSteFrrWatGraElePsyIceDraDarFai'RESULTS data(&2). END-OF-DEFINITION.
r,d s.DATA(l) = r-offset / 3 * 2.DATA(n) = o.IF strlen( e ) > 2.f e t.n = ( t-offset / 3 ) * 5.g l x+n.n = o.ENDIF.o = ( s-offset / 3 ) * 5.g l x+o.o = o * n.WRITE o.ENDFORM.


Newlines in the code replace required spaces around the END-OF-DEFINITION keywords. Might as well keep it as "readable" as possible.

Can be called by another program like so:

REPORT z.
PERFORM f USING 'Fighting' 'Normal' 'Rock'.


Result: 4

REPORT z.
PERFORM f USING 'Ghost' 'Normal' ''.


Result: 0

REPORT z.
PERFORM f USING 'Fairy' 'Poison' 'Normal'.


Result: 0.5

## Explanation

Geez, what a monster. Far from competitive as per usual, but I learned a lot about handling bits and bytes in ABAP - or rather that I don't want to do it ever again.

The type weakness table was converted to bit pairs:
00 = 0x, 01 = 0.5x, 10 = 1x, 11 = 2x
Each row of the table was then converted to 5 bytes each and all concatenated into one 180 character long byte-like string, which is hard coded into the program obviously.

The bytes for each row are padded with a trailing zero because ABAP doesn't work with half a byte offsets - or at least I couldn't get it to work properly. I couldn't use a higher number base either (like base-64) due to how ABAP handles them and how complicated and lengthy it gets to do so. Also dealing with overflows. Meh.

DATA:                "Multiple declarations
x(180) TYPE x,     "Byte-like string of length 180, holds the type weakness table
v      TYPE x,     "One byte
b, c.              "One letter chars for saving the values of bits (implicit char -> number conversion)

DEFINE g.  "Define a macro for reading two bits, we need this multiple times
GET BIT: "Get bits from the hex encoded weakness table; index starts at 1
&1 + 1 OF &2 INTO b, "get bit 1 ==> offset + 1
&1 + 2 OF &2 INTO c. "get bit 2 ==> offset + 2

SET BIT: "Unfortunately this is the best way of copying over bits (that I am aware of) to another value. Sets the two least significant bits so we get a value between 0 and 3.
7 of v TO b, "Set result bit 1
8 of v TO c. "Set result bit 2

"This is the best I could come up with.
IF v = 3. "If it's a binary 11 (3 in base10)
o = 2.  "then it's double damage
ELSE.  "For everything else the bit's base10 value can simply be halved, as 0/2=0, 1/2 =.5, 2/2=1.
o = v / 2.
ENDIF.
END-OF-DEFINITION. "End of macro bits

DEFINE f. "Define macro for finding the column/row of types in the weaknesses table both horizontally or vertically
"Find first occurrence of the first three letters of the type and save the result to a newly initialized variable
FIND &1(3) IN 'NorFigFlyPoiGroRocBugGhoSteFrrWatGraElePsyIceDraDarFai' RESULTS data(&2).
END-OF-DEFINITION. "End of macro types

FORM f USING a d e. "This subroutine has three parameters: [a]ttack, [d]efender primary, d[e]fender secondary
DATA(o) ='1.00'. "Quick declaration of a number with 2 decimals

"The type weakness table, encoded as binary, written in hexadecimal.
"Each table row corresponds to 4.5 bytes = 36 bits, padded with half a byte of 0's => 40 bits = 5 bytes = 10 characters each

f:a r,d s. "Call type index macro for the attack and primary defender type, saves the result in r (for attacker) and s (for defender)
DATA(l) = r-offset / 3 * 2. "Find the attacker's "table column". Each column is 2 bits wide, but type abbreviations are 3 letters

DATA(n) = o. "Result of the secondary defender's type weakness will be saved here; default (if no type is given) = 1x from o's default value

IF strlen( e ) > 2. "When there was a secondary type given (length of type name > 2 characters)
f e t. "Call type index macro for the secondary defender type.
n = ( t-offset / 3 ) * 5. "Divide offset by 3 because abbreviations are 3 letters wide, then multiply by 5 to find the correct "table row" (5 bytes per row)
g l x+n. "Call the bit reading macro; use attacker's column offset in bits and the defender's secondary type's row offset in bytes
n = o.   "Save the resulting number to n temporarily
ENDIF.

o = ( s-offset / 3 ) * 5. "Get primary type's row offset in bytes
g l x+o. "Call bit reading macro: attacker's column offset (bits), defender's primary row offset (bytes)
o = o * n. "Multiply weakness by secondary weakness
WRITE o.   "Print result
ENDFORM. "End of subroutine


Phew. How's that for some way too verbose code. There might be a better way to do it, but I doubt anyone else is mad enough to try golfing in ABAP. Still, suggestions are welcome, of course!

# C (gcc), 382 363 bytes

I wanted to try something a little different, so I made a sparse array of the values that were not equal to 1 and encoded them in a base-90 format so that the column that they are on could be converted to +/-1.0 and added to a 1.0 multiplier.

Thanks to ceilingcat for the suggestion.

*y[]={"8(;","i56n9(q@wyD","j8o;t?","678:)tz","#ln9qr>u","4k7o;rw","456:;<tvyD","!pvC","n;<=?wz","8oq<=twB","mnr=>B","56mn9;<s>B","k%s>?B","jl;@1","km;<=tAx",";x2","4pvCD","j6;<xy"};i,j;float f(int**s){int k[3]={};float f=1;for(i=18;i--;)for(j=3;j--;s[j]&&!strcmp(z[i],s[j])?k[j]=i:0);for(char*t=y[*k];i=*t-33,*t++;)for(j=0;++j<3;)f*=i%18-k[j]?1:i/18/2.;return f;}


Try it online!