title: What's my type? Well... Probably

text:
# Question
Title: What's my type? Well... Probably
There are a lot™ of pokemon. One of the defining characteristics of pokemon is their type, of which every1 pokemon has up to two types, a primary type and an optional secondary type. There are mechanical implications to each type, and so it is very useful to know what type a given pokemon is during battle. But there's no way that I'm going to memorize the type(s) of every single possible pokemon. So I need you to write me a program that takes the name of a pokemon as input, and outputs what type(s) this pokemon (probably) is.

Probably, you say? This is because it would be difficult to correctly identify every single pokemon's type(s), especially if you're trying to make your program as short as possible. So you do not need to identify every single pokemon with 100% reliability, you just need to make a reasonably good guess. You must find the optimal balance between identifying as many pokemon as possible, and keeping your code as short as possible. Your entry's score is calculated as follows:

```
Length of program * (1 / ratio of correct guesses) ^ 2

```

For example, if you wrote a program that was 500 bytes long, and it correctly identifies 50% of inputs, your score would be 2000 `(500 * (1/0.5)^2) == 500 * 4`, and a program that is 1000 bytes long that correctly identifies *all* of the inputs would have a score of 1000. For the purposes of scoring, 1/0 will be considered to equal infinity (so you better identify at least one of them correctly).

Since there are a lot™ of pokemon, we'll restrict this challenge to the first generation of pokemon, of which there are 151 pokemon2 and 17 types3. Here is a dataset of all the gen 1 pokemon by name, pokedex number, and type(s).

```
#,Name,Type 1,Type 2
1,Bulbasaur,Grass,Poison
2,Ivysaur,Grass,Poison
3,Venusaur,Grass,Poison
4,Charmander,Fire,
5,Charmeleon,Fire,
6,Charizard,Fire,Flying
7,Squirtle,Water,
8,Wartortle,Water,
9,Blastoise,Water,
10,Caterpie,Bug,
11,Metapod,Bug,
12,Butterfree,Bug,Flying
13,Weedle,Bug,Poison
14,Kakuna,Bug,Poison
15,Beedrill,Bug,Poison
16,Pidgey,Normal,Flying
17,Pidgeotto,Normal,Flying
18,Pidgeot,Normal,Flying
19,Rattata,Normal,
20,Raticate,Normal,
21,Spearow,Normal,Flying
22,Fearow,Normal,Flying
23,Ekans,Poison,
24,Arbok,Poison,
25,Pikachu,Electric,
26,Raichu,Electric,
27,Sandshrew,Ground,
28,Sandslash,Ground,
29,Nidoran,Poison,
30,Nidorina,Poison,
31,Nidoqueen,Poison,Ground
32,Nidoran,Poison,
33,Nidorino,Poison,
34,Nidoking,Poison,Ground
35,Clefairy,Fairy,
36,Clefable,Fairy,
37,Vulpix,Fire,
38,Ninetales,Fire,
39,Jigglypuff,Normal,Fairy
40,Wigglytuff,Normal,Fairy
41,Zubat,Poison,Flying
42,Golbat,Poison,Flying
43,Oddish,Grass,Poison
44,Gloom,Grass,Poison
45,Vileplume,Grass,Poison
46,Paras,Bug,Grass
47,Parasect,Bug,Grass
48,Venonat,Bug,Poison
49,Venomoth,Bug,Poison
50,Diglett,Ground,
51,Dugtrio,Ground,
52,Meowth,Normal,
53,Persian,Normal,
54,Psyduck,Water,
55,Golduck,Water,
56,Mankey,Fighting,
57,Primeape,Fighting,
58,Growlithe,Fire,
59,Arcanine,Fire,
60,Poliwag,Water,
61,Poliwhirl,Water,
62,Poliwrath,Water,Fighting
63,Abra,Psychic,
64,Kadabra,Psychic,
65,Alakazam,Psychic,
66,Machop,Fighting,
67,Machoke,Fighting,
68,Machamp,Fighting,
69,Bellsprout,Grass,Poison
70,Weepinbell,Grass,Poison
71,Victreebel,Grass,Poison
72,Tentacool,Water,Poison
73,Tentacruel,Water,Poison
74,Geodude,Rock,Ground
75,Graveler,Rock,Ground
76,Golem,Rock,Ground
77,Ponyta,Fire,
78,Rapidash,Fire,
79,Slowpoke,Water,Psychic
80,Slowbro,Water,Psychic
81,Magnemite,Electric,Steel
82,Magneton,Electric,Steel
83,Farfetch'd,Normal,Flying
84,Doduo,Normal,Flying
85,Dodrio,Normal,Flying
86,Seel,Water,
87,Dewgong,Water,Ice
88,Grimer,Poison,
89,Muk,Poison,
90,Shellder,Water,
91,Cloyster,Water,Ice
92,Gastly,Ghost,Poison
93,Haunter,Ghost,Poison
94,Gengar,Ghost,Poison
95,Onix,Rock,Ground
96,Drowzee,Psychic,
97,Hypno,Psychic,
98,Krabby,Water,
99,Kingler,Water,
100,Voltorb,Electric,
101,Electrode,Electric,
102,Exeggcute,Grass,Psychic
103,Exeggutor,Grass,Psychic
104,Cubone,Ground,
105,Marowak,Ground,
106,Hitmonlee,Fighting,
107,Hitmonchan,Fighting,
108,Lickitung,Normal,
109,Koffing,Poison,
110,Weezing,Poison,
111,Rhyhorn,Ground,Rock
112,Rhydon,Ground,Rock
113,Chansey,Normal,
114,Tangela,Grass,
115,Kangaskhan,Normal,
116,Horsea,Water,
117,Seadra,Water,
118,Goldeen,Water,
119,Seaking,Water,
120,Staryu,Water,
121,Starmie,Water,Psychic
122,Mr. Mime,Psychic,Fairy
123,Scyther,Bug,Flying
124,Jynx,Ice,Psychic
125,Electabuzz,Electric,
126,Magmar,Fire,
127,Pinsir,Bug,
128,Tauros,Normal,
129,Magikarp,Water,
130,Gyarados,Water,Flying
131,Lapras,Water,Ice
132,Ditto,Normal,
133,Eevee,Normal,
134,Vaporeon,Water,
135,Jolteon,Electric,
136,Flareon,Fire,
137,Porygon,Normal,
138,Omanyte,Rock,Water
139,Omastar,Rock,Water
140,Kabuto,Rock,Water
141,Kabutops,Rock,Water
142,Aerodactyl,Rock,Flying
143,Snorlax,Normal,
144,Articuno,Ice,Flying
145,Zapdos,Electric,Flying
146,Moltres,Fire,Flying
147,Dratini,Dragon,
148,Dragonair,Dragon,
149,Dragonite,Dragon,Flying
150,Mewtwo,Psychic,
151,Mew,Psychic,

```

And here is a list of all the available types:

```
Bug
Dragon
Electric
Fairy
Fighting
Fire
Flying
Ghost
Grass
Ground
Ice
Normal
Poison
Psychic
Rock
Steel
Water

```

Your input will always be one of the specified 151 gen 1 pokemon2. Your output must be one or two of the specified types. If outputting multiple types, you can choose the format to return them in (for example, separated by a space or a comma), but it must be consistent. Your input and output may be of any combination of upper and lower case that you require, just please specify what casing is required for your submission.

To count as a correct guess, you must match both types exactly. For example, outputting just "fire" for charizard, or outputting "ground + \<anything else\>" for diglett, both of these would be considered an entirely wrong guess.

Notes/edge cases

* Entry 29 in the Pokedex is "Nidoran (female)", and entry 32 is "Nidoran (male)". Because both of these are just "Poison" type, the input will simply be "Nidoran", with no male/female designation. For calculating "ratio of correct guesses", treat Nidoran as a single entry (number of correct guesses / 150).
* Every entry is comprised of only alphabetical characters with the following exceptions. To score these as correct guesses, the punctuation and spaces *may not* be removed or altered.
    + 83: Farfetch'd (Normal, Flying)
    + 122: Mr. Mime (Psychic, Fairy)
* In pokemon mechanics, the order of the types is significant, as in "Type A/Type B" is different than "Type B/Type A". This is ignored for the purposes of this challenge, e.g. "Bulbasaur is 'Grass,Poison', but an output of 'Poison,Grass' is considered correct." The only types that Gen 1 pokemon have in both orders are "Rock/Ground" and "Ground/Rock" types, which are listed separately in the dataset, but can be counted as the same type for this challenge.

---

* 1: There is arguably also a "???" type, which may or may not count as being a type.
* 2: See Nidoran.
* 3: Pokebiology was very primitive in the year of 1996, and both Fairy and Steel types were not yet recognized as being their own type when Gen 1 was released. Nevertheless, this challenge uses types as understood by our current modern day understanding of pokebiology.

# Answer
> 26 votes
# Jelly, 181 bytes, accuracy 148/150, score ≈ 185.925

```
ȷ;€ȷḥ€⁸ḣ5¤ḋ“¢ṣẉṙ.þbɦṪỊ2ßẓʂẹ{©ṗḷ⁺¶ɱıEDẓẇlR³ṣɼcṭɲ9^O⁹¿ƭ{ÑṬṄLȥȧ§Spṗ¡¶?ṁcØÑ"Ḷ9ọẈ⁽~ƊŒ°Fȷðḳẓ@*Ƙ>Uƭ⁺aɦṪṇẈfẸȥsɱƑhṁt/.rẏỊSṠ8Ġe¥Ṡ )§’b97¤%97ḃ⁴UÄị“Ḅ ṚṘṢOṚıƁqø⁷)^ʋ<:Ɓ(ʠKÄ§)ṬƘH1ḍ×Uµ(5;§XMoƑ»ḲŒt¤

```

Try it online!

Function submission: outputs a list of 1 or 2 type names. The footer in the TIO! link runs the program on all possible inputs.

## Explanation

### Algorithm

This is mostly based on my standard "map these large inputs to these small outputs" program, which I've used on many questions before (see this answer and this answer for the history), and it's reached the point that these questions can mostly be answered in an automated way: here's the program that generated the bulk of this answer. The basic idea is to write a program that runs the input through a lot of different hash functions, then take the dot product of the hashes with a hardcoded vector in a finite field – working out an appropriate hardcoded vector for this is simply a case of solving a lot of simultaneous linear equations, which is trivial for a computer to do.

This time, though, there was a bit more manual work and ingenuity involved than usual. One observation is that a lossy algorithm is permitted (at a cost in score), so I chose to look at only the first five characters of each Pokémon's name (or all of them, if the name is shorter than that); this introduces a large number of beneficial collisions (turns out that Pokémon whose name start the same way normally have the same type!), and there are only two collisions that lead to incorrect results: Dragonite with Dragonair, ("Drago"), and Poliwrath with Poliwag and Poliwhirl ("Poliw" – Poliwag and Poliwhirl have the same type, but Poliwrath's is different). This produces a lot of savings, both due to the beneficial collisions, and because Dragonite and Poliwrath have unique types that would otherwise be difficult to encode.

The next trick was to order the types carefully. Each type is internally stored as a number, in the order `fighting ghost fairy Grass dragon normal poison psychic bug water flying ground Ice fire rock electric steel` (which is what the compressed string `“Ḅ ṚṘṢOṚıƁqø⁷)^ʋ<:Ɓ(ʠKÄ§)ṬƘH1ḍ×Uµ(5;§XMoƑ»` near the end of the program decompresses to – most types are shorter in lowercase, but Grass and Ice are shorter in titlecase for some reason). This order was chosen with a lot of manual experimentation so that for all dual-typed Pokémon, their types are at most five elements apart in the list. A type or type pair can then be encoded as a one- or two-digit number in bijective base 16, with the less significant digit being the lower-numbered type, and the more significant digit being the distance between the types; this encoding maps all the type pairings onto the range 1 (pure Fighting) to 91 (Electric/Flying). This reduces the codomain of the mapping function, and thus means that the hardcoded vector can contain smaller numbers and thus be shorter. An advantage of skipping Dragonite and Poliwrath is that their types would not encode very well in this pattern, with Dragon being six spaces from Flying in the list, and Fighting nine spaces away from Water.

Possible improvement: using a smaller modulus than 97, which is a little wasteful. I realised while writing this proof that it's actually OK for the modulus to not be prime – you can use two or more different finite fields and combine the results into a single vector that works modulo a non-prime. (In theory this would work for any size of codomain, although Jelly doesn't have finite field operators so it would only be easily expressible in Jelly for square-free numbers.) The odds of the equations being unsolvable would be higher, but hopefully it wouldn't be too bad to calculate them. I'd need to generate a new encoding program to be able to handle that, though.

### Expressing the algorithm in Jelly

```
ȷ;€ȷḥ€⁸ḣ5¤ḋ“…’b97¤%97ḃ⁴UÄị“…»ḲŒt¤
ȷ;€ȷ                               1000 hash function configurations
    ḥ€                             with each of them, hash
       ḣ5                            the first 5 characters of
      ⁸  ¤                           the function input
          ḋ      ¤                 dot product with
           “…’                       a very large hardcoded number
              b97                    converted to base 97 digits
                  %97              take the result modulo 97
                     ḃ⁴            express in bijective base 16
                       U           reverse digit order
                        Ä          cumulative sum
                         ị      ¤  index into
                          “…»        a hardcoded compressed string
                             Ḳ       split on spaces
                              Œt     and converted to titlecase

```

The first large constant is the vector used to do the mapping. The second is the list of type names – it was shorter to write this in mixed case and fix the case later than it would have been to write it in the correct case from the start.

# Answer
> 22 votes
# PHP, 5 bytes, score = 347.222

Correctly guesses 18 Pokemon.

```
Water

```

Try it online!

# Answer
> 13 votes
# Node.js, score = 579 (579 bytes, 100%)

This is at the other end of the spectrum, as opposed to @dingledooper's answer, as it gives the correct answer for all inputs.

```
s=>(g=i=>["GrassPoisonFireFlyingWaterBugNormalElectricGroundFairyFightingPsychicRockSteelIceGhostDragon".match(/.[a-z]+/g)[(B=Buffer)(`7$1 !7$<)&5!4$J%8,$*6#$?!P*<!4'R.+#&9$B !=,$M(!9%!"B+$K$B04$d%!3% 5%!A(@.$;+J*:#&3#&=&N$@*$&1(: P$6 !?(,9&6#!K/!"#3(T$6(,S&N$B$J#!? !?(,7!6"1!1'J!>*H"@*T,$5 !C(6%!.$3%@'-+$C+>&<(,9!8+J+P"1 +% O+>*4#&#&#&_!J0J!6'p(<#.=#&S"4&:$8+8):)F +7'< !="6)&o/!$J)+7'#g+$a$1!$.$;#&3&X&1#,="l$1"1'Z'-&1"Z(,= !A"V0#Q&4&4(!= !W%4$4%!;%#c+L$x%#7,$5*8!$K/!y"#G !3'6(:(,&`.replace(/[2-~]/g,c=>"1".repeat(B(c)[0]-49)))[parseInt(s,36)%9313%1248*2|i]-32]])``+" "+g(1)

```

Try it online!

# Answer
> 12 votes
# jAvAscRIpt, 273 characters, score = 322.5425

This answer includes insincere rules-lawyering, but it doesn't seem to literally abuse a standard loophole. It might count as "adding input or rules".

Since the Question says

> "If outputting multiple types, you can choose the format to return them in (for example, separated by a space or a comma), but it must be consistent. Your input and output may be of any combination of upper and lower case that you require, just please specify what casing is required for your submission."

,

inputs to this submission must follow the casing of the revised Pokéorthography (that I made up) to have it generate the correct answer 138 out of 150 times. This is the revised Pokéorthography:

```
muk Poison
Mew Psychic
Abra Psychic
seEl Water
ONIx Rock Ground
JynX Psychic Ice
ekans Poison
arbok Poison
zUbAt Poison Flying
glooM Grass Poison
ParaS Bug Grass
GOLem Rock Ground
dODUO Normal Flying
Hypno Psychic
diTtO Normal
eeVeE Normal
WeedLE Bug Poison
KakuNA Bug Poison
pIDGEy Normal Flying
fEAROw Normal Flying
RaIcHu Electric
vulpix Fire
gOlBat Poison Flying
oddiSH Grass Poison
meOwTh Normal
mankey Fighting
machop Fighting
ponyta Fire
dODRIo Normal Flying
grimer Poison
gastlY Ghost Poison
gengaR Ghost Poison
krAbby Water
cubone Ground
RHYdon Rock Ground
hoRsea Water
seAdra Water
stAryu Water
magmar Fire
PinsIr Bug
taUrOs Normal
lapRaS Ice Water
KaBUtO Rock Water
ZAPDOs Electric Flying
Mewtwo Psychic
ivysAUr Grass Poison
MetaPod Bug
pIDGEot Normal Flying
raTtAta Normal
sPEARow Normal Flying
PiKaChu Electric
nidoran Poison
nidoran Poison
VenoNAt Bug Poison
DiGletT Ground
DuGtriO Ground
peRsIan Normal
psYduck Water
goLduck Water
poLiwag Water
Kadabra Psychic
MachokE Fighting
MachamP Fighting
GEOdude Rock Ground
SloWbRo Psychic Water
dewGONG Ice Water
haUntER Ghost Poison
Drowzee Psychic
kiNgler Water
VoLtOrb Electric
MaRowaK Ground
koffing Poison
weezing Poison
RHYhorn Rock Ground
chAnSey Normal
tangEla Grass
goLdeen Water
seAking Water
StaRmIe Psychic Water
SCyTHer Bug Flying
JoLtEon Electric
flareoN Fire
poRyGon Normal
OmANyTe Rock Water
OmAStAr Rock Water
snOrLax Normal
mOlTreS Fire Flying
DratInI Dragon
venuSAur Grass Poison
sqUirtle Water
CateRpie Bug
BeedRIll Bug Poison
raTiCate Normal
nidorina Poison
nidorino Poison
nIdoking Poison Ground
clEfAiRy Fairy
clEfAbLe Fairy
PAraSEct Bug Grass
VenoMOth Bug Poison
PrimeaPe Fighting
arcaniNe Fire
Alakazam Psychic
GRAveler Rock Ground
rapidaSh Fire
SloWpOke Psychic Water
MAGNETon Electric Steel
shEllder Water
cloYSTEr Ice Water
Mr. mimE Psychic Fairy
maGikarp Water
gYARados Water Flying
vaPoreon Water
KaBUtOps Rock Water
aRtICuNo Ice Flying
bulbASaur Grass Poison
cHaRizArd Fire Flying
waRtortle Water
blAstoise Water
pIDGEotto Normal Flying
SaNdshRew Ground
SaNdslAsh Ground
nIdoqueen Poison Ground
ninetaLes Fire
vilePLume Grass Poison
growliThe Fire
poLiwhirl Water
PolIwRAth Fighting Water
teNtaCool Water Poison
MAGNEMite Electric Steel
ElEcTrode Electric
EXeggCute Psychic Grass
EXeggUtor Psychic Grass
HitmonLee Fighting
liCkItung Normal
DragOnAir Dragon
DRaGOnIte Dragon Flying
charmaNder Fire
charmeLeon Fire
BUtTErfree Bug Flying
jiGgLypUff Normal Fairy
wiGgLytUff Normal Fairy
bellSProut Grass Poison
weepINbell Grass Poison
victREebel Grass Poison
teNtaCruel Water Poison
fARFEtch'd Normal Flying
HitmonChan Fighting
kaNgAskhan Normal
ElEcTabuzz Electric
AEROdactyl Rock Flying

```

This is the program:

```
p=>(n=[..."PoisonPsychicWaterRockGrassBugNormalElectricFireFightingGhostGroundIceDragonFairyFlyingSteel".match(/.[a-z]+/g)],m=[n,[" "].concat([11,12,15,0,4,2,16,14].map(i=>n[i]))],[0,1].map(j=>m[j][parseInt([6,4,2,0].map(i=>+(p.charCodeAt(i+j)<91)).join(""),2)]).join(" "))

```

Or more legibly:

```
t=p=>{n=[..."PoisonPsychicWaterRockGrassBugNormalElectricFireFightingGhostGroundIceDragonFairyFlyingSteel".match(/.[a-z]+/g)]
m=[n,[" "].concat([11,12,15,0,4,2,16,14].map(i=>n[i]))]
return[0,1].map(j=>m[j][parseInt([6,4,2,0].map(i=>+(p.charCodeAt(i+j)<91)).join(""),2)]).join(" ")}

```
* I wrote some other code to help find which type tuples to flip such that the number of types on each side becomes smaller than a power of two, which I didn't achieve on the secondaries: there are 15 first types and 9 second types. The list above reflects that order.
* I also had a program work out the order of types on the lookup lists based on their appearance in the list of pokémon sorted by name length (the above one), since you can store less bits in the casing of shorter names.

This all might not be optimal, since for example, it does not prioritize keeping the set of types used for short-name-pokémon small over doing it generally for all pokémon, and generally isn't some rigorous thing with a binary tree in it. That approximately 60-80 line piece of code is also useful for testing. Should I add it?

# Answer
> 6 votes
# Charcoal, ~~496~~ 400 bytes, score 400

```
ＥΦＥ⪪”}⊞λ⪫¡↥↙vＱ�≡⧴ï\`⊕B◨V~R&‖7≔NＰv,BJ？…u“κo=B)↘ⅉ⁶2∧Ｍ÷5№?m⁹Ｕ↑Ｏ∕№f}B≡MＤ|“⧴{x⁼⮌≦3ＧE⁷℅64↑jEo0ºＢjUＱ｜ÞＵ⪪↗↘↨→ξ¡Ｙ➙Ｆ◧À⎚≔ eω↗3⎇ητ>ⅉ↓ρηX∧"⟧Φζ⊘Ｑ←R]ＢＬHfδ>@J%>;⊖Ｕf3‽ρIＶ⭆W↧ＵＺＷ!⎚Ｈ#o？ⅈ8avdQTＬ^¶¶E◨¹…＆5⌕¹ＷⅉＪ"UＲ«³:⟧⭆·⎚↧ns？;⟧*≡↖,)k⁺⁴ＷF e´ζwE▶L⍘τ±ïχD↶～Ａ≡1⁶ＯＳkＪ^\ωη▷¶«"³AH;_Ｗ↷q%⟧‹➙⦃λＺ›⊞'≡＆Ｂ↔⧴↧⭆⊖ＭU？κL«8▷ＩZ⁶1Σ:1w▷U›Ｗ{L⁵№sΦπ⁸σIPH{:κ/ï\À!e⟦Y�PM⦃¶W.ξ3ζＸVＬsＫL⟲ＰＵoＯψI；▶～w∕X3⊙,Sp✳v⊙⎇αkμZτ-ε:ν&[÷c⁰L¡⁴Ｍ.ω±YuＴＺ+)7≕⊖“B?Lec{”¶⪪ι ⊙ι№θλ⊟ι

```

Try it online! Link is to verbose version of code. Outputs the types in alphabetical order. Explanation: The compressed string contains a list of all the unique prefixes for a given type followed by that type. These are then filtered for the prefixes that match the input string and then the types are extracted.

Previous 496 byte solution outputs the types in the order given in the question:

```
≔⪪”↶37₂？γ"Π⎚«ζ∨↖↘o*&J›7M‽ ±pλ⁹ＭgΠf⊟Ｖ³!Ｐ¹y⁰κ⊘X⮌GQ⟧÷±Ｘ´ＶkGº↗ＤＺwG³↘»§/V↑Ｘ″ypＬKνＮ^Ｉ→λ↶” υ⭆⪪”}∨Ｄ¤Y1Ｈ∧2gW±²＆ＪψＡχ∕ κ2⊕m⁴η；δＫE↘L⎚▷μ²θ[⌈J_；$⁼σ⊗}/¶Ｃ~Mv？"V↗7{<|´0⁹ï8'➙1≡⦃Iü◨Rqp⍘td‴⁼xYＨïω⪫ψ ＰρＲN:ζg↖Ｂï↑⪪ÀＭmＰ；e″=y﹪⌊κAλ＆↗↔ςJβ～‹τ¿�λ▶⊘Þ？{↥⊙↓⁷_Ｇ;›Ｄ⁸⦃℅⁹τωx➙ＵXVςυ；FZ@ºηＷ⸿⟦ＥI∕-↗Ｔh_pEGOχ3↷⁻@ε∕Πg⸿“ΣA«CKＬ↙⁵O>？¤↷⊗KP⊘B{℅＆:≕Xe↑ＨＮ⧴↖η‴Ｅl¡4hw⁻¬×�⍘～o⊕δ～⊕”¶⎇∧ι⊙⪪ι №θλ§υκω⭆⪪”}∧αf.M‴%iＩ»⁷⁰τ➙:⁼\p'↥'�fＰ{Ｐζ⊖№ ↑″⟲σfＨ940⁵êＹＳ↙Y«9≕%Sm↙⁶|π✳σqＤ⟦➙γ[Ｚ₂›1⊖0@⊕S6←ψqＰ⎇›w\；ＭＷ;5Ｋ⌕Ｙυλ³⁴↓↷◧Ｔ(gＢ±Wï…↙↖iº÷τ⎇≔2Φ←nYρa¤←⊕ê⪪vＫ∕Z.8Z73×ζ⊞”¶⎇⊙⪪ι №θλ⁺/§υκω

```

Try it online! Link is to verbose version of code. Explanation: Starts off by getting a list of all of the types, then works through all of the unique prefixes for each type, outputting the types for which the input contains those prefixes. The verbose code was generated by a program so it's probably not the optimal approach.

# Answer
> 5 votes
# Python 3, 584 bytes

```
s="lambda s:['4C,sir1e8.!x7l1ew#az#z+rm*br1*H%-t%0rti$5l,x+.0J%#4tt+c%!dos#ni8b(!T7l#ld#iw#tl778V,y6*K*g*H2Kr#s%#3ar#D2tc#d&#4ku#ed#eno$Steel!/!on76q#g8ow6k*Di&!T+id2z*Ek1u#f*rb2Gr*b(0L6y#w&#Ghost!H,G,en&#5p#s6u#V*d*Gl$Electric!pd#hu#El#J2V2/-ud#Gr6l+On#h%#Fire!iz1o$3v#uf#sk#yg#P7n1e2Di8ns+ur2L*R(-bu8Om$Fairy!uf1*fa$Fighting!wr1ac#H*nk#Pr$Dragon!Dra'])or['Fire']"
for i in"8t#97+S96,o95Grass!e94Bug!93Normal!e92o#91#M90#Ice!9/gn$Ground9.Pa$Psychic9-#Rock!9,a#9+e#9*i#9(at$Water9&g$Poison9%y$Flying9$'])+['9#','9!']*any(i in s for i in['".split('9'):s=s.replace(i[0],i[1:])
f=eval(s)

```

Try it online!

The code decompresses into this:

```
lambda s:
  ['Bug'               ] * any(i in s for i in [ 'Ca' ,'sir','Met','Pa'                                                             ])
 +['Psychic'           ] * any(i in s for i in [ 'xe' ,'Sl' ,'Mew','az','ze' ,'rmi','br' ,'Mi' ,'Hy'                                ])
 +['Flying',  'Rock'   ] * any(i in s for i in [ 'ty'                                                                               ])
 +['Flying',  'Ice'    ] * any(i in s for i in [ 'rti'                                                                              ])
 +['Grass'             ] * any(i in s for i in [ 'ela','xe' ,'Pa'                                                                   ])
 +['Psychic', 'Ice'    ] * any(i in s for i in [ 'Jy'                                                                               ])
 +['Flying',  'Bug'    ] * any(i in s for i in [ 'tte','cy'                                                                         ])
 +['Flying'            ] * any(i in s for i in [ 'dos','nit','bat'                                                                  ])
 +['Water'             ] * any(i in s for i in [ 'Te' ,'Sl' ,'ld' ,'iw','tle','Se' ,'St' ,'Va' ,'ya' ,'oi' ,'Ki','gi','Ho','Kr','sy'])
 +['Flying',  'Normal' ] * any(i in s for i in [ 'ear','Do' ,'tc' ,'dg'                                                             ])
 +['Poison',  'Bug'    ] * any(i in s for i in [ 'ku' ,'ed' ,'eno'                                                                  ])
 +['Steel'             ] * any(i in s for i in [ 'gn'                                                                               ])
 +['Ground'            ] * any(i in s for i in [ 'one','Sa' ,'oq' ,'gt','owa','oki','Dig'                                           ])
 +['Poison'            ] * any(i in s for i in [ 'Te' ,'ido','zi' ,'Ek','Mu' ,'fi' ,'rbo','Gri','bat'                               ])
 +['Water',   'Ice'    ] * any(i in s for i in [ 'La' ,'oy' ,'wg'                                                                   ])
 +['Poison',  'Ghost'  ] * any(i in s for i in [ 'Ha' ,'Ga' ,'eng'                                                                  ])
 +['Poison',  'Grass'  ] * any(i in s for i in [ 'ep' ,'sa' ,'ou' ,'Vi','di' ,'Gl'                                                  ])
 +['Electric'          ] * any(i in s for i in [ 'pd' ,'hu' ,'El' ,'Jo','Vo' ,'gn'                                                  ])
 +['Ground',  'Rock'   ] * any(i in s for i in [ 'ud' ,'Gra','ole','On','hy'                                                        ])
 +['Flying',  'Fire'   ] * any(i in s for i in [ 'iz' ,'Mo'                                                                         ])
 +['Normal'            ] * any(i in s for i in [ 'ev' ,'uf' ,'kha','yg','Pe' ,'Sn' ,'Meo','Dit','nse','uro','Li','Rat'              ])
 +['Water',   'Rock'   ] * any(i in s for i in [ 'but','Om'                                                                         ])
 +['Fairy'             ] * any(i in s for i in [ 'uf' ,'Mi' ,'fa'                                                                   ])
 +['Fighting'          ] * any(i in s for i in [ 'wr' ,'Mac','Hi' ,'nk','Pr'                                                        ])
 +['Dragon'            ] * any(i in s for i in [ 'Dra'                                                                              ])
 or['Fire']

```

# Answer
> 5 votes
# JavaScript (Node.js), score = 566 (566 bytes, 100%)

> -6 bytes because 3 Pokemons actually contain their types in their names (and other simplifications)

Even if a way has been found to answer this question by "encoding" the types in the casing of an arranged Pokedex, i tried to achieve 100% accuracy without using this trick while trying to outgolf the other 100% classic Javascript answer, and it turned out pretty well :)
The input is the name of the Pokemon in lower case. The output are the corresponding types, with only the first character uppercased, and multiple types are separated by a space. There is also a trailing space if that's acceptable.

```
s=>`NormalDgAttIcaEarUfWthIaFeDodTuNseSkTauDitEvYgSn_BugRpiMetFrEdKuPaScEnoIns_GrassSauDdGloEpPaLsViExTan_RockUdAvOleNixOmaRhKabAe_WaterRtlOiPsLdIwTenSloSeaSeeWgOyKrNglOmaStaKabGiGyLapVa_GhostStlHauGen_PoisonSauEdKuEkArbNidBaDdOoViVenLsWeNtGriMuStlGenKo_FireHarVuEsWlRcPonRapGmFl_IceWgOyJyLapRti_DragonTin_ElectricHuGnVoLecJoPd_FlyingIzRfDgEarBatDodScDosAeRtiLtrNit_GroundDsOqDokDigGtUdAvOleNixCubOwaRh_FightingNkPriWrTmMac_PsychicBrAzSloWzPnExRmiJyMrMew_FairyEfUfMr_SteelGn`.split`_`.map(t=>(r=t.match(/.[a-z]+/g)).find(e=>RegExp(e,'i').test(s))?r[0]+" ":"").join``

```

Try it online!

---

A little explanation:
Every type is accompanied by a list of strings, that are as short as possible (2 to 4 characters) and that matches any part (ignoring the case) of the highest possible (when useful) number of corresponding Pokemons, unambiguously.
Dual types are achieved by matching the 2 types separately.
The casing in the long string is used to delimit the beginning of each value.
I did the long string by hand, but i think that this is the shortest possible combination.
I don't know of an official golfing way to compress the long string, so i tried to develop a custom program (by using 6 bits instead of 7 to store each "character", because the ASCII values of the long string are all comprised between 65 and 122), but sadly the gain in bytes was inferior to the length of my custom decompression code (a hundred bytes), so i gave up on the compression.

# Answer
> 3 votes
# Jelly, 57 bytes, accuracy 148/150, score ≈ 58.5509

```
e€ØaḄḃW¹?⁴UÄị“Ɓ[0ḲTọŻZ4⁹ɗrƑkṭkẏḳoḂʠCṂtɠØƭ⁴Ṡ¬ỤþV⁶Ḳ¥;0ḥȧ»Ḳ¤

```

Try it online!

A monadic link that takes a string argument and returns a list of strings. Taking inspiration from @JanH’s Javascript answer, this relies on the wording of the question that states that the casing of input and output can be specified in the answer. As such, this answer expects the input to be one of the following Pokémon:

```
BULBaSAuR
IVySAuR
VENuSAuR
CHARMAnDER
CHARMElEON
CHaRIZaRD
SQUIrTle
WARTOrTle
BLASToIse
CATERPIe
METAPOd
BUTTerFREe
wEEDLe
kAKUNa
BEeDRILl
PiDgEY
PIDGeOtTO
PIdGeOT
RATTaTa
RATICaTe
SPeArOW
FeArOW
EKAns
ARBok
PIKAchu
RAIchu
SANDShREw
SANDSlASh
NIDORan
NIDORIna
NIdoQUEen
NIDORan
NIDORIno
NidOKIng
CLEFaiRy
CLEFabLe
VUlPIX
NINETaLES
JIgGLYPuFf
WIgGLYTuFf
zUBat
GoLBat
OdDIsH
gLOoM
VILEpLUmE
pARAs
PARaSECt
VeNONAt
VEnOMOTh
DIGlETt
DUGtRIo
MEOwTh
PERSiAn
PSYdUck
GOLdUck
MAnkey
PRIMeape
GROWLiTHE
ARCAnINE
POLiWag
POLIWhIrl
POlIWrAth
ABRA
KADABRA
ALAKAZAM
MAchop
MAChoke
MAChamp
BELLSpROuT
WEEPInBElL
VICTReEBeL
TeNTACOol
TEnTACRUel
GEodUDe
GRAveLEr
goLEm
POnYTA
RAPIdASH
SloWpOke
slOwBro
MAgneMite
MagnEton
FARFEtCh'D
dOdUO
DoDrIO
sEel
DEwgOng
GRIMer
Muk
SHELlDer
CLOysTer
gaSTly
HauNTer
geNGar
oNIx
DROWZEE
HYPNO
KRaBby
KINgLer
VOLTorb
ELECTRode
ExeggCUtE
ExeggUToR
CUbONe
MARoWAk
HITMOnlee
HITMONchan
LICKITuNg
KOFFIng
WEEZIng
RHyhORn
RhyDOn
CHANsEy
TANGElA
KANGASKhAn
HOrSea
SEaDra
GOLdEen
SEAkIng
STaRyu
stArMie
Mr. miMe
ScyTHEr
jyNX
ELECTABuzz
MAgMAR
PINSIr
TAUrOs
MAGIkArp
GyarAdOS
LapRas
DItTo
EEvEe
VAPOrEon
JOLTeon
FLArEON
PORYgOn
OManYtE
OMasTaR
KabUtO
KAButOpS
AERodACtYL
SNORlAx
aRTICuNO
zaPdOS
mOLTrES
DRaTINI
DRAGoNAIR
DraGONiTE
MEWTWO
MEW

```

The casing of the Pokémon encodes a binary number. If this number is non-zero it is interpreted as a bijective base-16 number. This is then reversed, cumulative summed and then looked up into the list of powers. Zero matches the last power in the list, psychic. The powers are lower-case except for grass and ice which are title case, since as @ais523 discovered this gives the shortest compressed string. The precise compressed string here is different because of the different algorithm used.

The two missed ones relate to four-letter double-power ones that are too short to encode their power in the casing.

## Detailed explanation

```
e€Øa               | For each character, check whether it is a lowercase letter
    Ḅ              | Convert from binary
       ¹?          | If non-zero:
     ḃ   ⁴         | - Then convert to bijective base 16
      W            | - Else wrap in a list
          U        | Reverse list
           Ä       | Cumulative sum
            ị“…»Ḳ¤ | Index into compressed string split at spaces

```

Verification of accuracy

# Answer
> 1 votes
# Python 3, 888 Bytes, Accuracy 86/150, Score 1200

score is 1200.64... but that doesn't matter. Here's my pitiful attempt:

```
s="{'GasPs:BarIsrVsOiGomVpeBpWnVe,Fr:CaCeVpNtsGleAnPyRdMmFrn,FrFi:CidMts,Wtr:SrWoeBtePdkGdkPigPwlSeSlKbKgrHsSdGdnSkgSrMkVr,Bug:CrMadPs,BugFi:BrStr,BugPs:WdKuBrVotVm,FiNm:PgPeoPgtSawFrFtDdoDr,Nm:RtaRcMwPsnLigCnyKsTrDtoEvePynSrx,Ps:EasAbkNonNrNrGmMukKfgWzg,Et:PauRcVtbEteEaJtn,Gu:SswSshDltDtoCoMok,GuPs:NqnNk,Fiy:CaCa,FiyNm:JyWy,FiPs:ZbtGb,BugGas:PrsPs,Ft:MkPeMhMheMhpHoeHn,FtWtr:Pwh,Pcc:ArKaaAaDweHpoMtMew,PsWtr:TalTc,GuRc:GdeGeGlmOiRhnRd,PccWtr:SpSwoSre,EtSel:MeeMe,IceWtr:DggCsLr,GotPs:GtHnrGg,GasPcc:EgeEgr,Gas:Tga,FiyPcc:MM,IcePcc:Jn,FiWtr:Ga,RcWtr:OneOsrKuKt,FiRc:Aa,FiIce:Ac,EtFi:Zd,Dg:DtiDor,DgFi:Doe'}"
for i in ",', '",":': '":s=s.replace(i[0],i[1:])
d=eval(s);h=lambda x:x[::len(x)//2]
def f(s):r=[k for k in d if h(s)in d[k]][0];return[i for i in "Bug Dragon Electric Fairy Fighting Fire Flying Ghost Grass Ground Ice Normal Poison Psychic Rock Steel Water".split() if h(i)in r]

```

Uses the fact that the `s[::len(s)//2]` subset is pretty darn good for uniqueness, for both names and types. Stores everything in a big honking compressed dict, and fails to be good.

# Answer
> 0 votes
# Python 2, 1022 bytes, 100%

I generated a hash of each name and only recorded the unique first characters, then for the types I used bitwise operations.

It didn't work as well as I'd have hoped but here's my attempt anyway:

```
import zlib,base64,hashlib;d=lambda x:zlib.decompress(base64.b64decode(x)).split();h=d('eJwdkcsBBCEMQlt5JaiJv3LUaP8lLLMHnEQHhLjSoHfWJXawUsUTMQknjNYPxan2KI2XjFI4HXMd70aMyvtOXhfUH1EK85GdnYqEo1AHzRa1f1u6ri6uiOaLojI4L7iPLU5FsttwPzyR4pEyyZHPNKlyM/zpq8tiMwulMo7+Twzt25W2MLkm3cw6R5BQDFl9wsWy2kZLEr/I8NtbywwF6szDvKg5l5ap0mqVJls74lsWivry5mbNxMmHqyz7uuK+TdMUQrxQ1IFNKTszcTJT+a4qkZJIf0KSpsaXjaV+yZZzti5x+qar0On4PE6sUcyFhNXLOQNvjLTwgmfNZmtspp3O0Gvp4d7Tk33xJHRZkz7Y+QpHEHFLqoiheZ1AQZrNH4nfgPQ=');n=d('eJxNUYkNAyEMWyUjhHzQ/Rdr7EBV6STAefycyVILMQlx21vF8gxUjWbde2bMc5usEhePPkMVgGMexVgagkfPhidb0d2QxkeWFy7nLmHHa7tshbW9wBu00wsXLg/GLGEA/WWXuNkUjNPeWpsHpTHkY2G/ylIJHQw7s34a5kSh6S3+tMJoXJlPCHD/2C+VEz0V4KOahY7rj/25i+G+oJEN9xlM0bFCGJ51Qx5H45sixihAnxSaxmnOm5c67MzPYaSYdFI/t0MMk8dNLw8y4iSxyVL8C+8IYSA=');f=lambda x:','.join(v for i,v in enumerate('Grass Poison Fire Flying Water Bug Normal Electric Ground Fairy Fighting Psychic Rock Steel Ice Ghost Dragon'.split())if 2**i&next(int(v)for k,v in zip(h,n)if hashlib.md5(x).hexdigest()[:len(k)]==k))

```

---
Tags: code-golf, string, classification
---


# Question
Title: Print, Increment, Decrement, Alias - Interpret Prindeal
*Prindeal* (pronounced prin-dee-al) is a new esoteric programming language that only has four commands: ***pr****int*, ***in****crement*, ***de****crement*, and ***al****ias*. Despite its minimalism, complex mathematical operations can be done in Prindeal by cleverly combining the four commands.

Your task in this code golf challenge is to write the shortest program that can run Prindeal code.

The spec is long but I've tried to make it as clear as possible and I believe that if you make the effort to learn Prindeal you'll find it to be quite elegant!

---

# Intrepreting Prindeal

## Preprocessing

Before a Prindeal program can be interpreted these things need to be removed from it in this order:

1. Anything after a `#` sign to the end of the line it's on, plus the `#` itself. (These are comments.)
2. Trailing whitespace on any line.
3. Completely empty lines.

For example, the Prindeal program

```
p cat #The next line has 7 trailing spaces.
p dog

#p mouse

```

would be preprocessed into

```
p cat
p dog

```

From here on we'll assume this preprocessing step has been done.

## Variables

We quickly need to define variables before showing how they are used.

Variables (and references to variables) are what are passed into the arguments of Prindeal commands. **Variables are always global**, so modifications to a variable, no matter where they occur, are reflected everywhere.

Each variable holds a **non-negative arbitrary-precision integer** (0, 1, 2, 3, ...). Variables do not need to be pre-initialized - **they always start with the value 0** the first time they are used or called for.

A variable name may be any non-empty string of alphanumerics and underscores that does not start with a digit - `[a-zA-Z_][0-9a-zA-Z_]*` in regex. They are case sensitive, so `spiny_lumpsuck3r` and `Spiny_lumpsuck3r` are different variables.

## Execution

Prindeal is an imperative programming language. When a Prindeal program is run its statements are executed from top to bottom in order and then the program ends.

Every **non-indented** line in a Prindeal program is a statement that involves the execution of a single command which may or may not take arguments.

Indented lines only occur after *alias* commands. Specifically, exactly **three lines indented with single spaces occur after every *alias* command** and are considered a part of it. So *alias* statements are really four lines long. (They could be one line, four is merely more readable.)

### Non-*alias* Statements

With the exception of *alias*, every statement in a Prindeal program has the form:

```
[command name] [argument 1] [argument 2] [argument 3] ...

```

There may be an arbitrary number of arguments (including none at all). Each argument is always a **variable** or (as we'll see when discussing *alias*) a **reference to a variable**.

Once done executing, **each statement is flagged as either a *failure* or *success*** depending on if errors were encountered or not. (This only really matters when we get around to using *alias*.)

The built-ins *print*, *increment*, and *decrement* are statements with the above form. Here is what they do:

1. *print* has command name `p` and takes one argument. It prints the name of the variable passed in and its value (in decimal) separated by " = ", then a newline. It is always flagged as a *success*.

For example, the Prindeal program

```
p _MyVariable_321
p screaming_hairy_armadillo

```

would output

```
_MyVariable_321 = 0
screaming_hairy_armadillo = 0

```

because all variables start at 0. (The spaces before and after the equals sign are required.)
2. *increment* has command name `i` and takes one argument. It increments the value of the variable passed in by 1. It is always flagged as a *success*..

For example, the program

```
i alpaca
p alpaca
i alpaca
p alpaca

```

would output

```
alpaca = 1
alpaca = 2

```

Note how `alpaca` was incremented from 0 to 1 even though it had never been accessed before.
3. *decrement* has command name `d` and takes one argument. If the variable passed in is nonzero its value is decremented by 1 and the statement is flagged as a *success*. If the variable passed in is 0 then nothing is done and the statement is flagged as a *failure*.

For example, the program

```
i malamute
p malamute
d malamute    #success
p malamute
d malamute    #failure
p malamute
d akita       #failure
p akita

```

would output

```
malamute = 1
malamute = 0
malamute = 0
akita = 0

```

Notice that decrementing a variable with value 0 is the only way to produce a *failure*.

### The *alias* Statement and Aliased Commands

The *alias* command has a special syntax and is the most powerful because it can be used to define new commands. The *alias* command name is `a` and an *alias* statement has the form:

```
a [name of new command]
 [statement A]
 [statement B]
 [statement C]

```

Where each `[statement X]` represents any non-*alias* statement, i.e. something with the form `[command name] [argument 1] [argument 2] [argument 3] ...`.

The aliased command's name `[name of new command]` may be any non-empty string of alphanumerics and underscores that does not start with a digit - `[a-zA-Z_][0-9a-zA-Z_]*` in regex.

(This is the same set of names as variables but aliased **commands and variables are different things used in different places**. A variable could be named the same as a command with no ill consequences.)

When an *alias* statement is executed, a new command is added alongside the original four `p` `i` `d` `a` commands. The new command can be used as the `[command name]` in statements and called with arguments just like any other non-*alias* command.

When a statement with an aliased command name is executed, exactly **two more statements from its original *alias* statement are run:**

* `[statement A]` is always run
* `[statement B]` is run if `[statement A]` was a *success*
* `[statement C]` is run if `[statement A]` was a *failure*

Statements A, B, and C are **always run lazily**, i.e. they are evaluated on the fly at the time they are run.

When done executing, **the aliased command is flagged with the same *success* or *failure* flag as statement B or C, whichever one was executed**. (*alias* statements themselves do not need to be flagged since they cannot occur within themselves.)

> **Alias Example 1**
>
> Say we want a new command that increments the variable `frog` twice. This alias statement achieves it:
>
> ```
> a increment_frog_twice
>  i frog
>  i frog
>  d frog
>
> ```
>
> Statement A (`i frog`) is always run and always flagged as a *success* so statement B (`i frog`) is also always run and the variable `frog` is thus incremented by 2. The `increment_frog_twice` command is always flagged as a *success* because statement B is always run and B is always a *success*. Statement C (`d frog`) is never run.
>
> So the output to
>
> ```
> a increment_frog_twice
>  i frog
>  i frog
>  d frog
> p frog
> increment_frog_twice
> p frog
>
> ```
>
> would be
>
> ```
> frog = 0
> frog = 2
>
> ```

We can generalize this example so that *any* variable can be incremented twice by giving the aliased command an argument.

**Within an *alias* statement the positive integers 1, 2, 3, etc. represent the 1st, 2nd, 3rd, etc. arguments passed into the aliased command.** (These arguments might be plain variables or references to variables themselves.) These numbers can only appear within the arguments of statement A, B, and C in an *alias* statement. It doesn't make sense for them to appear elsewhere.

> **Alias Example 2**
>
> This generalizes the last example - any variable passed into `increment_twice` will be incremented by 2 because `1` is a reference to the first argument passed in:
>
> ```
> a increment_twice
>  i 1
>  i 1
>  d 1 #never reached
> p toad
> increment_twice toad
> p toad
>
> ```
>
> The output of this program would be
>
> ```
> toad = 0
> toad = 2
>
> ```
>
> We could then alias another command that takes in two arguments and calls `increment_twice` on both of them:
>
> ```
> a increment_twice
>  i 1
>  i 1
>  d 1 #never reached
> a increment_both_twice
>  increment_twice 1
>  increment_twice 2
>  d 1 #never reached
> increment_both_twice platypus duck
> p platypus
> p duck
>
> ```
>
> The output here would be
>
> ```
> platypus = 2
> duck = 2
>
> ```

It's important to realize that aliased commands can be recursive, as this is where their true power lies. For example, we can make a command that sets any variable passed in to 0:

> **Alias Example 3**
>
> The `set_to_zero` command takes one argument and sets its variable to 0 and is flagged as a *success* when done:
>
> ```
> a set_to_zero
>  d 1
>  set_to_zero 1
>  i _dummy_
> i oryx
> i oryx
> i oryx
> p oryx
> set_to_zero oryx
> p oryx
>
> ```
>
> The output of this program would be
>
> ```
> oryx = 3
> oryx = 0
>
> ```
>
> What's happening is that when `set_to_zero oryx` is run, `d 1` successfully decrements `oryx` from from 3 to 2, then `set_to_zero 1` is called, which is the same as calling `set_to_zero oryx` again. So the process repeats until `d 1` is a *failure*, stopping the recursion and increment the `_dummy_` variable so a *success* is produced.

---

# Challenge

Write a program that can execute Prindeal code exactly as described above. Take the Prindeal code in via stdin, the command line, or as a text file. Print the Prindeal program's output to stdout or your language's closest alternative.

Alternatively, you can write a function that takes in the code as a string and prints or returns the output string.

Additionally, you can assume that:

* The input Prindeal code will only contain newlines and printable ASCII and (optionally) that it ends with an empty line.
* The input code will be valid Prindeal - well formed and syntactically correct.
* Running the code will not produce any infinite loops nor any invalid references to commands that have not been defined or arguments that have not been given.
* The command names `p`, `i`, `d`, and `a` will never be aliased over. (You may ***not*** assume that variables will not have these names.)

Also, it doesn't matter if your variable values aren't truly arbitrary-precision integers as only numbers less than about 1000 will be tested. It's also alright if you language has recursion limits (such as Python) that more complex Prindeal programs might encounter as long as the test program below works.

# Test Program

Here is a large Prindeal program that builds up the operations of addition, multiplication, and exponentiation through the use of dummy variables (starting with `_` by convention) and many helper aliases:

```
#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C

```

(If you're playing around with this code be aware that many of the commands will fail if the same variable is given multiple times as an argument. This can easily be fixed but the resulting code is longer.)

Your Prindeal interpreter should be able to produce the exact output:

```
A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

```

# Scoring

The shortest code in bytes wins. Tiebreaker goes to earlier submission.

*Brownie Bonus: Write a cool program in Prindeal. I implemented addition and multiplication, can you do subtraction or division?*

# Answer
# Pyth, ~~162~~ 136 bytes

```
JfTmchcd\#).zKHW<ZlJI!e=T@J~+Z1=@Tk)=k0 .x=J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0,=Y.x@H=eT0?qN\pps[Td\=dYb)?xGN?qN\iXHThY?YXTH_1=k1XKT:JZ=+Z3

```

Demonstration.

Golfed out 26 characters by inlining variables and changing from `I` and `E` based control flow to `?` and `.x` based control flow.

For the first time ever, I ran out of variables in Pyth. Every single variable in Pyth (`bdkGHNTY` and `JK`) was in use, and I wanted to use `b` as a newline. Fortunaely, I was able to use `N` to mean two completely different things in different parts of the program, and so it still works.

### Ungolfed (run with -m):

```
JfTmchcd\#).z
KH
W<ZlJ
  I!e=T@J~+Z1
    =@Tk)
  =k0
     .x
      =J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0
      ,
        =Y.x@H=eT0
        ?qN\p
          ps[Td\=dYb)
          ?xGN
            ?qN\i
              XHThY
              ?Y
                XTH_1
                =k1
            XKT:JZ=+Z3

```
> 9 votes

# Answer
# Python 2, ~~600~~ ~~584~~ ~~397~~ 373 bytes

This is my own golfed reference solution. Anyone is welcome to improve it or follow its logic in their own answer as long as attribution is given.

The neat part about it is that no recursion is done, so it will never have problems with Python's recursion limit. For example, Sp's Countup Prindeal program can run indefinitely.

```
p=filter(len,[l.split('#')[0].split()for l in input().split('\n')]);m={};v={};i=0
while i<len(p):
 s=p[i]
 if'('in`s`:s=s[f]
 n,f=s[0],0
 if n in m:a,b,c=([s[int(g)]if g.isdigit()else g for g in t]for t in m[n]);p=[a,(b,c)]+p[i+1:];i=0;continue
 s=s[1]
 q=v.get(s,0)
 if'd'>n:m[s]=p[i+1:i+4];i+=3
 elif'i'<n:print s,'=',q
 elif'd'<n:v[s]=q+1
 elif q:v[s]-=1
 else:f=1
 i+=1

```

It's a program that takes in the quoted program string with newlines escaped, e.g.
`'p _MyVariable_321\np screaming_hairy_armadillo'`.

I took various golfing cues from Sp's and Pietu's answers. Thanks guys :)
> 9 votes

# Answer
# Python 3, ~~345~~ ~~336~~ ~~335~~ 328 bytes

```
a=0
A={}
V={}
def f(l):
 if l[0]in"d p i":c,u=l;U=V[u]=V.get(u,0)+"pi".find(c);S=U<0;V[u]+=S;c<"p"or print(u,"=",U)
 else:d=lambda q:[w.isdigit()and l[int(w)]or w for w in A[l[0]][q]];S=f(d(1+f(d(0))))
 return S
for z in open("P"):
 l=z.split("#")[0].split()
 if"a "==z[:2]:a,s,*x=3,l[1]
 elif l*a:x+=l,;a-=1;A[s]=x
 elif l:f(l)

```

*(-6 bytes thanks to @orlp)*

Still golfing. Assumes the program is stored in a file named `P`.

Putting the calls to `f` inside the lambda `d` would save a few bytes, but it would make the last test case hit max recursion depth.

## Some Prindeal programs

### The useless subtraction program

Here is a useless subtraction program. It's useless because, even though it subtracts properly, it doesn't return success/failure accordingly.

The output should be:

```
a = 15
b = 6
__________ = 0
a = 9
b = 6

```

### Countup

```
a helper
 p 1
 countup 1
 i success

a countup
 i 1
 helper 1
 d failure

countup n

```

Counts upwards and prints `n` forever. Could possibly work as a test for interpreter speed (beware the long tracebacks on keyboard interrupt).
> 6 votes

# Answer
# JavaScript (ES6), 273 ~~258~~

**Edit** Fixed bugs and added a real test suite.

Not counting leading spaces and newlines.

Surely can be golfed a little more.

Too tired to write an explanation now, I think it's a good example of using closures to keep alive temporary values (parameters).

Test running the snippet on any EcmaScript 6 compliant browser (notably not Chrome not MSIE. I tested on Firefox, Safari 9 could go)

```
F=p=>(
  p=p.match(/^[^#\n]+/gm).filter(r=>r.trim(o='',v=[])),
  s={
    '':_=>1,
    p:a=>o+=a+` = ${v[a]||0}\n`,
    i:a=>v[a]=-~v[a],
    d:a=>v[a]&&v[a]--,
    a:(n,j)=>s[n]=(u,t,a)=>x(p[!x(p[j+1],0,a,1)+j+2],0,a,1)
  },
  p.map(x=(r,i,w,l,a=r.split(/ +/).slice(l).map(x=>-x?w[x]:x))=>s[a[0]](a[1],i,a)),
  o
)

// TEST

$('#O tr').each(function() {
  var $cells = $(this).find('td')
  var prg = $cells.eq(0).text()
  console.log(prg)
  var output = F(prg)
  $cells.eq(1).text(output)
})
```

```
#O td { vertical-align:top; white-space: pre; border: 1px solid #888; font-family:monospace }
```

```
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr><th>Program</th><th>Outpout</th></tr>
<tbody id=O>
<tr><td>p _MyVariable_321
p screaming_hairy_armadillo</td><td></td></tr>
<tr><td>i alpaca
p alpaca
i alpaca
p alpaca</td><td></td></tr>
<tr><td>i malamute
p malamute
d malamute    #success
p malamute
d malamute    #failure
p malamute
d akita       #failure
p akita</td><td></td></tr>
<tr><td>a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog</td><td></td></tr>
<tr><td>a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck</td><td></td></tr>
<tr><td>a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx</td><td></td></tr>
<tr><td>#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C
</td><td></td></tr>
</tbody>
</table>
```
> 6 votes

# Answer
# C#6, 653 bytes

Here's my entry, amidst a sea of Python...

```
class P{string[]l;string r="";Dictionary<string,int>v=new Dictionary<string,int>();Dictionary<string,int>s=new Dictionary<string,int>();public string R(string t){l=t.Split('\n');for(int i=0;i<l.Length;i++){var z=l[i].Split(' ');if(z[0]=="a"){s.Add(z[1],i);i+=3;}else E(i, null);}return r;}bool E(int n,string[]p){var z=l[n].Split(' ');var a=z.Skip(1).Select(x=>Char.IsDigit(x[0])?p[int.Parse(x)-1]:x).ToArray();if(a.Length>0&&!v.ContainsKey(a[0]))v[a[0]]=0;if (z[0]=="p")r+=$"{a[0]} = {v[a[0]]}\n";else if(z[0]=="i")v[a[0]]++;else if(z[0]=="d")if(v[a[0]]>0)v[a[0]]--;else return false;else{var y=s[z[0]];return E(y+1,a)?E(y+2,a):E(y+3,a);}return true;}}

```

Expanded and commented:

```
class Prindeal
{
    string[] lines;
    string result = "";
    Dictionary<string, int> variables = new Dictionary<string, int>();
    Dictionary<string, int> statements = new Dictionary<string, int>();

    public string Run(string text)
    {
        lines = text.Split('\n');

        for (int i = 0; i < lines.Length; i++)
        {
            // Split on spaces to get the statement and any arguments
            var z = lines[i].Split(' ');

            // Are we defining a new statement?
            if (z[0] == "a")
            {
                // Add to the statements dictionary, step over definition statements
                statements.Add(z[1], i);
                i += 3;
            }
            else
            {
                // Execute the statement
                Execute(i, null);
            }
        }

        return result;
    }

    bool Execute(int lineNumber, string[] parameters)
    {
        // Split on spaces to get the statement and any arguments
        var z = lines[lineNumber].Split(' ');

        // Parse the arguments - if it's a number, get the corresponding
        // parameter from the calling statement
        var arguments = z.Skip(1).Select(
            x => Char.IsDigit(x[0]) ?
            parameters[int.Parse(x) - 1] :
            x)
            .ToArray();

        // If the first argument isn't already in the variables dict, add it
        if (arguments.Length > 0 && !variables.ContainsKey(arguments[0])) variables[arguments[0]] = 0;

        // Print statement, using string interpolation
        if (z[0] == "p")
            result += $"{arguments[0]} = {variables[arguments[0]]}\n";
        // Increment statement
        else if (z[0] == "i")
            variables[arguments[0]]++;
        // Decrement statement
        else if (z[0] == "d")
            if (variables[arguments[0]] > 0)
                variables[arguments[0]]--;
            else
                return false;
        else
        {
            // Get the line number to jump to
            var y = statements[z[0]];

            // Execute A ? B : C
            return Execute(y + 1, arguments) ? Execute(y + 2, arguments) : Execute(y + 3, arguments);
        }

        // If we reach this point, it's from a 'p', 'i' or 'd' statement which has succeeded
        return true;
    }
}

```

To use it, simply instantiate the class and call the `R()` method, for example:

```
string prindealText = new StreamReader("prindeal.txt").ReadToEnd();
Console.WriteLine(new P().R(prindealText));

```
> 3 votes

# Answer
# Common Lisp, ~~758~~ ~~646~~ 619

```
(progn(set-macro-character #\#(get-macro-character #\;))(setf(readtable-case *readtable*):invert)(#3=defun v(s)(if(boundp s)(eval s)0))(#3# i(s)(set s(1+ (v s))))(#3# d(s)(and(plusp(v s))(set s(1-(v s)))))(#3# p(s)(format t"~A = ~A~%"s(v s)))(defmacro a(n . p)`(#3#,(cadr n)(&rest g)(if,@p)))(#3# k(s)(typecase s(integer`(nth,(1- s)g))(symbol `',s)(t(list*(car s)(mapcar 'k(cdr s))))))(#3# r()(prog(l p q)$(setf p()l(make-string-input-stream(or(read-line()()())(return))))@(when(setf p(read l()()))(push p q)(go @))(if q(return(k(reverse q)))(go $))))(do ((x(r)(r)))((not x))(eval(if(eq(car x)'a)`(,@x,(r),(r),(r))x))))

```

Put this in `file.lisp` and call for example `sbcl --script file.lisp`; input is read from the standard input stream.

This version parses a *superset* of Prindeal: without not much difficulties, you can access all Common Lisp from a Prindeal source. I consider this a *feature* of the intepreter.

### Commented version

```
;; copy-readtable is only used during development, so that I do not
;; mess with my running environment. The real code starts with the
;; progn below, which is superfluous of course inside a let.
(let ((*readtable* (copy-readtable)))

  ;; I use PROGN in the golfed version so that I can have the whole
  ;; program as a unique tree. This allows me to define reader
  ;; variables like #3=defun in order to gain a few bytes by writing
  ;; #3# instead of defun. Reader variables are removed in
  ;; this human-friendly version.
  (progn
    ;; Let # point to the same reader function as ;
    ;; Of course, ; is still usable as a comment delimiter
    (set-macro-character #\#
                         (get-macro-character #\;))

    ;; :invert does what is necessary to enable case-sensitive reading
    ;; and printing of symbols
    (setf (readtable-case *readtable*) :invert)

    ;; value of symbol, or zero
    (defun v(s)(if(boundp s)(eval s)0))

    ;; increment
    (defun i(s)(set s(1+ (v s))))

    ;; decrement
    (defun d(s)(and(plusp(v s))(set s(1-(v s)))))

    ;; print
    (defun p(s)(format t"~A = ~A~%"s(v s)))

    ;; alias: wrap an "if" inside a "defun".
    ;; YES, that means you can redefine ANY lisp function with "a" !
    ;; A safer version would properly intern symbols in a dedicated package.
    ;;
    ;; Notice the G variable.  We take advantage of the "unhygienic"
    ;; (what a bad adjective) nature of macros to create a context
    ;; where G is bound to the argument list. The same G is referenced
    ;; implicitely later.
    (defmacro a(n . p)`(defun,(cadr n)(&rest g)(if,@p)))

    ;; Canonicalize expressions:
    ;;
    ;; - if s is a symbol, return s quoted. All functions manipulate
    ;; symbols in order to allow the undeclared use of variables. With
    ;; symbols, we can check for boundness.
    ;;
    ;; - if s is an integer, then we are inside an alias definition. The
    ;; integer is replaced by an access to the s'th element of the
    ;; implicit argument list G using (nth (1- s) g). G will be bound
    ;; when the expressions is injected in the defun corresponding to
    ;; the alias, or else an error will be signaled: either because G
    ;; is unbound, or because you defined a variable named G which is
    ;; by construction not a list. Since we do not sanitize properly
    ;; the input, you could bind G globally to a list, but that would be
    ;; nasty.
    ;;
    ;; - Finally, if s is a list, apply k to all but the first
    ;; elements of s.  The first element is a symbol but we do not
    ;; need to quote it because we want to call the function
    ;; associated with the symbol. Due to the Lisp-2-ness
    ;; of Common Lisp, functions and variables can coexist
    ;; with the same name.
    ;;
    (defun k(s)(typecase s
                 (integer`(nth,(1- s)g))
                 (symbol`',s)
                 (t(list*(car s)(mapcar #'k(cdr s))))))

    ;; Reader function
    (defun r()
      (prog (l ; current line, as an input-stream reading a string
             p ; current read form
             q ; whole line and return value, as a list
             )

         ;; PROG includes an implicit TAGBODY. Below, $ and @ are
         ;; labels for GO statements (gotos).

       $ (setf
          ;; emtpy p
          p ()

          ;; Read a whole line and if we do not fail, build an input
          ;; stream to read from it.
          l (make-string-input-stream
             (or (read-line()()()) ;; try to read a line,
                 (return)          ;; but return from prog if we reach
                                   ;; the end of file.
                 )))
       @ (when (setf p (read l()()))
           ;; Read a lisp expression, put it in p and if p is not nil
           ;; push it into q.  A nil could happen at the end of the
           ;; line or if someone (you know who) inserted an empty list
           ;; in the file being read.
           ;;
           ;; Thanks to the readtable which now handles comments
           ;; and spaces for us, nothing needs to be done here to
           ;; preprocess the input.

           (push p q) (go @))

         ;; If we read an empty line, q can be nil. In this case, go
         ;; back to $ and read another line. If q is not nil, reverse
         ;; it (we pushed, remember), canonicalize it and return the
         ;; result.
         (if q (return(k(reverse q))) (go $)))
      )

    ;; Read/eval loop.  When reading "(a name)", we read the three
    ;; next lines and append them to the first so that it builds a
    ;; call the the alias definition macro a. Otherwise, just eval x.
    (do((x(r)(r))((not x))
      (eval (if (eq(car x'a))
                `(,@x,(r),(r),(r))
                x)))))

```

# Example

```
~$ sbcl --script file.lisp < testfile

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

```

If we replace `eval` by `print` in the read/eval loop, then we can see what is being evaluated:

```
(a 's (i '_) (d '_) (d '_))
(a 'f (d '_) (d '_) (d '_))
(a 'z (d (nth 0 g)) (z (nth 0 g)) (s))
(a 'n (z (nth 0 g)) (i (nth 0 g)) (s))
(a 'move (moveH (nth 0 g) (nth 1 g)) (move (nth 0 g) (nth 1 g)) (s))
(a 'moveH (d (nth 0 g)) (i (nth 1 g)) (f))
(a 'dupe (dupeH1 (nth 0 g) (nth 1 g) (nth 2 g))
   (dupe (nth 0 g) (nth 1 g) (nth 2 g)) (s))
(a 'dupeH1 (d (nth 0 g)) (dupeH2 (nth 1 g) (nth 2 g)) (f))
(a 'dupeH2 (i (nth 0 g)) (i (nth 1 g)) (s))
(a 'copy (z (nth 1 g)) (copyH (nth 0 g) (nth 1 g)) (s))
(a 'copyH (dupe (nth 0 g) (nth 1 g) '_copy) (move '_copy (nth 0 g)) (s))
(a 'addTo (copy (nth 1 g) '_add) (move '_add (nth 0 g)) (s))
(a 'add (z (nth 0 g)) (addH (nth 0 g) (nth 1 g) (nth 2 g)) (s))
(a 'addH (addTo (nth 0 g) (nth 1 g)) (addTo (nth 0 g) (nth 2 g)) (s))
(a 'mul (mulH1 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 2 g)) (s))
(a 'mulH1 (z (nth 0 g)) (copy (nth 1 g) '_mul) (s))
(a 'mulH2 (mulH3 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 1 g)) (s))
(a 'mulH3 (d '_mul) (addTo (nth 0 g) (nth 1 g)) (f))
(a 'mulBy (mul '_mulBy (nth 0 g) (nth 1 g)) (copy '_mulBy (nth 0 g)) (s))
(a 'pow (powH1 (nth 0 g) (nth 2 g)) (powH2 (nth 0 g) (nth 1 g)) (s))
(a 'powH1 (n (nth 0 g)) (copy (nth 1 g) '_pow) (s))
(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s))
(a 'powH3 (d '_pow) (mulBy (nth 0 g) (nth 1 g)) (f))
(p 'A)
(p 'B)
(p 'C)
(n 'A)
(n 'B)
(add 'C 'A 'B)
(p '____)
(p 'A)
(p 'B)
(p 'C)
(add 'B 'A 'C)
(p '____)
(p 'A)
(p 'B)
(p 'C)
(mul 'd 'B 'C)
(p '____)
(p 'd)
(mulBy 'd 'B)
(p '____)
(p 'd)
(d 'A)
(mulBy 'd 'A)
(p '____)
(p 'd)
(pow 'A 'C 'B)
(p '____)
(p 'A)
(p 'B)
(p 'C)
(pow 'A 'B 'C)
(p '____)
(p 'A)
(p 'B)
(p 'C)
(pow 'C 'A 'B)
(p '____)
(p 'A)
(p 'B)
(p 'C)

```

### Macroexpansion

If we pick the following alias definition:

```
(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s))

```

... we can see references to a variable named `g` which is nowhere to be found in the lexical scope. But after macroexpansion, here is the actual code being evaluated:

```
(defun powH2 (&rest g)
  (if (powH3 (nth 0 g) (nth 1 g))
      (powH2 (nth 0 g) (nth 1 g))
      (s)))

```

Now, `g` refers to the argument list of the function being defined.
> 3 votes

# Answer
# Python 2, 486 bytes

**This is the reference solution which I golfed more (currently -98 bytes).**

```
import sys;sys.setrecursionlimit(2000)
def r(s):
 n=s[0]
 if n in A:f=lambda i:r([s[int(t)]if'0'<t[0]<':'else t for t in A[n][i]]);return f(1+(f(0)or 0))
 k=s[1]
 if'i'<n:print k,'=',V.get(k,0)
 elif'd'<n:V[k]=-~V[k]if k in V else 1
 elif'a'<n:
    if~-(k in V)or V[k]<1:return 1
    V[k]-=1
 else:A[k]=s[2:]
A={};V={};c=filter(bool,([l,l[:l.find('#')]]['#'in l]for l in input().split('\n')))
while c:
 s=c[0].split();c=c[1:]
 if'a'!=s[0]:r(s)
 else:r(['a',s[1]]+map(str.split,c[:3]));c=c[3:]

```

Changes (that I recall):

* automatic boolean-integer conversion (`[l,l[:l.find('#')]]['#'in l]`).
* set or increment in one statement (`V[k]=-~V[k]if k in V else 1`)
* more aliases to longer expressions (`k=s[1]`)
* no counter in the main loop, clearing the input list instead
* `print` automatically adding spaces (`print k,'=',V.get(k,0)`)
* checking digits 1-9 (`'0'<t[0]<':'`)
* flipping the return values of `r` around to save `return`s
* removing repetition of slicing and splitting (`map(str.split,c[:3]))`)
> 2 votes

# Answer
# C++, 752 bytes

**Thanks to @ceilingcat for some very nice pieces of golfing - now even shorter (yet again!)**

This one is C++ - as idiomatic as I could make it.
That means making it more C++-ish and less C-ish.
That also means it is bigger than the equivalent C program.
I think C++ rivals Java for the most verbose standard library.

```
#import<bits/stdc++.h>
#define a first
#define c(s);else if(B==#s)
#define e(n)(n=regex_replace(n,regex{"^ *(.*?) *(#.*)?$"},"$1")).size()
#define f(n)for(;getline(cin,n),!e(n););
#define i p.top().a
#define j p.size()
#define k n[o[0]]
#define U;using
U namespace std;U g=string;U h=istream_iterator<g>U s=vector<g>;map<g,s>m;map<g,int>n;stack<pair<pair<int,s>,s>>p;main(int v){for(g X,Y,Z;getline(cin,X);)if(e(X))for(p.push({{0,{X,"",""}},{}});bool z=j;){g B;s C,o;copy(h(stringstream(i.second[i.a])>>B),h(),back_inserter(C));for(g x:C)o.push_back((v=atoi(&x[0]))>0?p.top().second[v-1]:x);if(0)c()c(p)cout<<o[0]+" = "<<k<<'\n'c(i)k++c(d)k-=z=k c(a){f(X)f(Y)f(Z)m[o[0]]={X,Y,Z};}else{p.push({{0,m[B]},o});continue;}while(j&&i.a)p.pop();j?i.a-=~!z:0;}}

```

Try it online!

Below is the original. If anyone can think of a way to make it more idiomatic and shorter at the same time please let me know.

```
#include <array>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <stack>

typedef std::vector<std::string> List;
typedef std::pair<std::string, List> Statement;
typedef std::array<std::string, 3> Alias;
typedef std::pair<long, Alias> IndexedAlias;
typedef std::pair<IndexedAlias, List> Item;

std::map<std::string, Alias> aliases;
std::map<std::string, long> variables;
std::stack<Item> stack;
std::regex re("^ *(.*?) *(#.*)?$");

int main()
{
    std::string line, line1, line2, line3;
    while (std::getline(std::cin, line)) // control-Z to exit
    {
        line = std::regex_replace(line, re, "$1");
        if (line.empty()) continue;
        stack.push(Item{ { 0, { { line, "", "" } } }, {} });

        bool flag;
        while (!stack.empty())
        {
            Statement statement;
            std::istringstream ss(stack.top().first.second[stack.top().first.first]);
            ss >> statement.first;
            std::copy(std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>(), std::back_inserter(statement.second));

            List arguments;
            std::transform(std::begin(statement.second), std::end(statement.second), std::back_inserter(arguments),
                [](std::string arg){ int i = atoi(arg.c_str()); return i > 0 ? stack.top().second[i - 1] : arg; });

            flag = true;
            if (statement.first == "")
                ;
            else if (statement.first == "p")
                std::cout << arguments[0] << " = " << variables[arguments[0]] << std::endl;
            else if (statement.first == "i")
                variables[arguments[0]]++;
            else if (statement.first == "d")
                variables[arguments[0]] -= (flag = variables[arguments[0]]);
            else if (statement.first == "a")
            {
                do { std::getline(std::cin, line1); line1 = std::regex_replace(line1, re, "$1"); } while (line1.empty());
                do { std::getline(std::cin, line2); line2 = std::regex_replace(line2, re, "$1"); } while (line2.empty());
                do { std::getline(std::cin, line3); line3 = std::regex_replace(line3, re, "$1"); } while (line3.empty());
                aliases.insert(std::make_pair(arguments[0], Alias{ { line1, line2, line3 } }));
            }
            else
            {
                stack.push(Item{ { 0, aliases[statement.first] }, arguments });
                continue;
            }

            while (!stack.empty() && stack.top().first.first) stack.pop();
            if (!stack.empty()) stack.top().first.first += 1 + !flag;
        }
    }

    std::cout << "-- Variables --" << std::endl;
    std::transform(std::begin(variables), std::end(variables), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, long>::value_type pair){ std::ostringstream ss; ss << pair.first << " = " << pair.second; return ss.str(); });
    std::cout << "-- Aliases --" << std::endl;
    std::transform(std::begin(aliases), std::end(aliases), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, Alias>::value_type pair){ std::ostringstream ss; ss << pair.first << " = [1]:" << pair.second[0] << " [2]:" << pair.second[1] << " [3]:" << pair.second[1]; return ss.str(); });
    std::cout << "---------------" << std::endl;

    return 0;
}

```
> 2 votes

# Answer
# Uiua (tentative), 468 characters

**Note that due to a bug in the interpreter, there is a spurious error preventing proper execution. Once the bug is fixed, I will update this answer to reflect that. Until then, I'm leaving the (tentative) in the heading.**

```
p←⊂↯→(⊟∶□0□,)¬/+≡(|2≅!)→(↯→∶⧻).≡⊢.→(.!⊡1)!→→(⊡2)⊡1,∶
;∧(|2!⊡∶(⊂□1⊟□&p/+∺(×≅→∶∷!⊢∶⊡1.),∶&pf⊂∶" = ",p)_(⊂□1⊟□∺([∶∷□]+→(∶→≅.)!⊡1∶!⊢.)p)_(⊂⊟→□→≡(⍜'⊡1⍜!'↥0)/×≡(≥0!⊡1).∺([∶∷□]-∶→(∶→≅.)!⊡1∶!⊢.)p)_(|2↬2∶□/(⊂⊂∶@ ∷!)⊡-∶2!⊢,∶↬2∶□/(⊂⊂∶@ ∷!)⊢,∶→→;∺(|2⍜'↘1∺(|2□⍣(!⊡parse)(→;;)!)⊜□≠,@ !)→,↘1⊡∶!⊡2,⊗∶≡⊢!⊡2,⊢,)⊗∶["p""i""d"]!⊢,∶⊜□≠@ .!∶)⊂{1[{"1"0}]}□→(▽¬∵(|1↥=@ ∶=@a.⊢!).)≡(⍜'↘1(∵⍜!(↘1))⍜⊢(⍜!(↘2)))⊜·▽∵(4;).+1⇡÷4⧻.▽∵(|1↥=@ ⊢∶≅"a ".↙2!)..▽↧1∵⧻.∵⍜!(⇌▽\↥×≠@\r∶≠@ ..⇌▽=0\+=@#.)⊜□≠@\n.&ru@\00

```

This is my first Uiua program of more than a couple dozen characters, so I'm sure there's lots of places I could golf it more effectively. It was a good opportunity to practice the language, though :)

## Non-minified version

```
# preexec state_alias_array command -> state_array command_arg alias_array
preexec ← (
  ⊡1,∶ # put state on top
  !→→(⊡2) # get aliases (for later)
  →(.!⊡1) # get variable name (put two copies on stack for later)
  ≡⊢. # get list of current variable names
  ¬/+≡(|2 ≅!) →(↯→∶⧻). # test if we need to add a new variable
  ⊂↯→(⊟∶□0□,) # add variable if necessary
)

# exec<T> state_alias_array command -> state_alias_array
execp ← (
  preexec
  &pf⊂∶" = ", # print "varName = "
  &p/+∺(×≅→∶∷!⊢∶⊡1.),∶ # print "varValue\n"
  ⊂□1⊟□
)
execi ← (
  preexec
  ∺([∶∷□]+→(∶→≅.)!⊡1∶!⊢.) # increment the relevant variable
  ⊂□1⊟□ # reform state_alias_array
)
execd ← (
  preexec
  ∺([∶∷□]-∶→(∶→≅.)!⊡1∶!⊢.) # decrement the relevant variable
  /×≡(≥0!⊡1). # check if <0
  →≡(⍜'⊡1⍜!'↥0) # reset back up to 0
  ⊂⊟→□ # reform state_alias_array
)
execcall ← (|2
  ⊢, # get alias name
  ⊗∶≡⊢!⊡2, # get index of call
  ↘1⊡∶!⊡2, # get subcommands
  →,
  ∺(|2
    ⊜□≠,@ ! # split box"thing 1 2" into [box"thing" box"1" box"2"]
    ⍜'↘1∺(|2 □⍣(!⊡parse)(→;;)!) # turn the 1 and 2 into first and second arguments
  )
  →→; # original call no longer necessary
  □/(⊂⊂∶@ ∷!)⊢,∶ # join [box"i" box"dog"] into box"i dog"
  ↬2∶ # call first
  ⊡-∶2!⊢,∶ # select second or third based on success
  □/(⊂⊂∶@ ∷!) # join [box"i" box"dog"] into box"i dog"
  ↬2∶
)

execline ← (|2
  ∶⊜□≠@ .!∶ # split command
  !⊡∶execp_execi_execd_execcall⊗∶["p""i""d"]!⊢, # dispatch correct command
)

&ru@\00

⊜□≠@\n. # split lines
∵⍜!(
  ▽=0\+=@#. # remove comments
  ⇌▽\↥×≠@\r∶≠@ ..⇌ # remove trailing whitespace
)
▽↧1∵⧻. # remove blank lines

▽∵(|1 ↥=@ ⊢∶≅"a ".↙2!).. # get alias definitions
⊜· ▽∵(4;).+1⇡÷4⧻. # separate out each alias
≡(
  ⍜⊢(⍜!(↘2)) # remove alias decl
  ⍜'↘1(∵⍜!(↘1)) # remove indentation
)
→(▽¬∵(|1 ↥=@ ∶=@a.⊢!).) # remove alias definitions from command list
⊂{1 [{"123illegalvariable" 0}]}□ # group last success, state array and alias array
∧execline # exec all instructions
;

```
> 2 votes

# Answer
# Python 3, 1322 bytes

**Golfed:**

```
import re,sys;sys.setrecursionlimit(2000);F,L=filter,list
class P:
 N,O,F=0,{},{}
 def __init__(S,c):
  S.B,S.E={"p":S.P,"i":S.I,"d":S.D,"a":S.L},dict(enumerate(F(None,[i.split('#')[0].rstrip()for i in c.splitlines()])))
  while S.N in S.E:S.X(S.E[S.N])
 def V(S, v, y, z=0):
  if re.match("[\w_][\d\w_]*",v):
   if not v in y:
    if z is not None:y[v]=z
    else:return False
   return True
  return False
 def A(S):S.N+=1
 def P(S,v):
  if S.V(v,S.O):print("{0} = {1}".format(v, S.O[v]));return True
  return False
 def I(S,v):
  if S.V(v, S.O):S.O[v]+=1;return True
  return False
 def D(S,v):
  if S.V(v,S.O)and S.O[v]>0:S.O[v]-=1;return True
  return False
 def L(S,v):
  e=[]
  if S.V(v,S.F,e):
   for i in range(3):S.A();e.append(S.E[S.N].lstrip())
   return True
  return False
 def C(S,c,v):
  def R(Z,v):
   for i in re.findall("\s(\d+)", Z):Z=Z.replace(" %s"%i," %s"%v[int(i)-1])
   return Z
  Q,m,f=map(lambda l:R(l,v),S.F[c])
  if S.X(Q,False):return S.X(m,False)
  return S.X(f,False)
 def X(S,Z,C=True):
  u=re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?",Z)
  if u:
   c,v=map(lambda i:''if i is None else i,u.groups());v=L(F(None,v.split(' ')))
   if S.V(c,S.F,None):
    T=S.C(c, v)
    if C:S.A()
   elif S.V(c,S.B,None):
    T=S.B[c](*v)
    if C:S.A()
   else:return False
   return T
  return False

```

**Ungolfed:**

```
import re

class Prindeal:
    iline = 0
    local = {}
    udef = {}
    content  = {}

    def __init__(self, c):
        self.built = {
            "p": self.print,
            "i": self.increment,
            "d": self.decrement,
            "a": self.alias,
        }
        self.content = dict(enumerate(filter(None, [i.split('#')[0].rstrip()for i in c.splitlines()])))
        while self.iline in self.content:
            self.execute_line(self.content[self.iline])

    def validate_name(self, varname, stack, default=0):
        if re.match("[\w_][\d\w_]*", varname):
            if not varname in stack:
                if default is not None:
                    stack[varname] = default
                else:
                    return False
            return True
        return False

    def advance_stack(self):
        self.iline += 1

    def print(self, varname):
        if self.validate_name(varname, self.local):
            print("{0} = {1}".format(varname, self.local[varname]))
            return True
        return False

    def increment(self, varname):
        if self.validate_name(varname, self.local):
            self.local[varname] += 1
            return True
        return False

    def decrement(self, varname):
        if self.validate_name(varname, self.local) and self.local[varname] > 0:
            self.local[varname] -= 1
            return True
        return False

    def alias(self, aliasname):
        indexed_lines = []
        if self.validate_name(aliasname, self.udef, indexed_lines):
            for i in range(3):
                self.advance_stack()
                indexed_lines.append(self.content[self.iline].lstrip())
            return True
        return False

    def execute_alias(self, cmd, variables):
        def parse_args(line, variables):
            for i in re.findall("\s(\d+)", line):
                line = line.replace(" %s" % i, " %s" % variables[int(i) - 1])
            return line
        init, success, failure = map(lambda l: parse_args(l, variables), self.udef[cmd])
        if self.execute_line(init, False):
            return self.execute_line(success, False)
        return self.execute_line(failure, False)

    def execute_line(self, line, cont=True):
        valid_execution = re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?", line)
        if valid_execution:
            cmd, variables = map(lambda i: '' if i is None else i, valid_execution.groups())
            variables = list(filter(None, variables.split(' ')))
            if self.validate_name(cmd, self.udef, None):
                temp = self.execute_alias(cmd, variables)
                if cont:
                    self.advance_stack()
            elif self.validate_name(cmd, self.built, None):
                temp = self.built[cmd](*variables)
                if cont:
                    self.advance_stack()
            else:
                return False
            return temp
        return False

```

**Usage:**

```
P(c)

```

Where `c` is the text content.

**Examples:**

*Single-line strings are accepted:*

* `P("p cat")`
* `P("p dog\ni dog\np dog")`

*Multi-lined strings are also accepted:*

```
P("""
p dog
i dog
p dog
""")

```

Or:

```
P("""p dog
i dog
p dog""")

```

Etc.

**Notes:**

This works correctly for all test cases, but reaches the recursion limit on:

```
pow C A B   #C = A ^ B = 9 ^ 3 = 729

```

Hence the `sys.setrecursionlimit(2000)`.
> 1 votes

# Answer
# Haskell, 1009

I did my best to golf it; my ungolfed code consisted of over 3,000 characters. At this point I can't remember what all the functions are doing so golfing it more mean guessing what will break it and what won't.

```
import qualified Data.Map as M
import Control.Monad.State.Lazy
import Data.List
type A=M.Map String
data P=P(A Int)(A([String]->StateT P IO Int))
a f=evalStateT f(P M.empty$M.fromList[("i",\(b:_)->(+1)%b),("d",\(b:_)->pred%b),("p",\(b:_)->i b>>= \v->liftIO(putStrLn$b++"="++show v)>>q 1)])
e(k:l)=do{(P v a)<-get;put.P v$M.insert k(m l)a;q 1}
g t s f= \a->t a>>= \b->if b>0then s a else f a
f%k=f<$>i k>>= \v->if v<0then k#0>>q 0else k#v>>q 1
i k=get>>= \(P v _)->q$M.findWithDefault 0 k v
k#v=get>>= \(P b a)->put$P(M.insert k v b)a
l k=get>>= \(P _ a)->q$a M.!k
f s=let(f:a)=r s in($a)<$>l f>>=id
m(t:s:f:_)=g(k t)(k s)(k f)
k s=let(f:b)=r s in\a->($(map((\y z->if all(\c->c>'/'&&c<':')z then y!!(read z-1)else z)a)b))<$>l f>>=id
n=dropWhileEnd(==' ').takeWhile(not.(=='#')).dropWhile(==' ')
o[]=[]
o(l:ls)|(head.r$l)=="a"=(l:take 3 ls):(o$drop 3 ls)|1>0=[l]:o ls
p s|length s>1=e$(n.tail.head$s):tail s|1>0=f.head$s
q=return
main=join$a.(\s->mapM_ p(o.filter(not.null).map n.lines$s))<$>getContents
r=words

```
> 1 votes

# Answer
# Python - ~~695~~ 688 bytes

```
def p(v):print v,"=",w.get(v,0)
def i(v):w[v]=w.get(v,0)+1
def d(v):
 if v in w:
<TAB>w[v]-=1
<TAB>if not w[v]:del w[v]
 else:return 1
def a(n,b,d,h):
 def g(*a):
<TAB>i=1;f=b;s=d;t=h
<TAB>for v in a:v=q+v+q;k=q+j(i)+q;f=c(f,k,v);s=c(s,k,v);t=c(t,k,v);i+=1
<TAB>y=u(t,e)if u(f,e)else u(s,e);i=1;return y
 e[n]=g
q="'";w=x={};u=eval;e={'a':a,'d':d,'i':i,'p':p};import sys;l=sys.stdin.readlines();r="";j=str;c=j.replace;sys.setrecursionlimit(2000)
for h in l:
 h = h.strip()
 if not h:continue
 l = h.split();f=l[0];n=f+"("
 if "#" in f:continue
 for g in l[1:]:
<TAB>b=g.find("#")+1
<TAB>if b:g=g[:b-1]
<TAB>if g:n+="'%s',"%g
<TAB>if b:break
 if x:x-=1;d+='"%s)",'%n
 else:x=(f=="a")*3;d=n
 if not x:d+=")\n";r+=d
exec r in e

```

`<TAB>` is a literal tab character.
> 1 votes

# Answer
# APL (Dyalog Unicode), ~~449~~ ~~422~~ ~~388~~ 383 bytes

This is a somewhat optimized APL version of a program to run the Prindeal code. It assumes that the index origin is 0 (⎕IO←0). The Prindeal program to run is in an enclosed string array P.

```

z
L←0
V←N←F←M←⍬
r←{⍬≡h←⍸⎕D∊⍨⊃¨t←↑⍵:t⋄t[h]←⍺[⍎¨t[h]]⋄t}
R←{⍵/⍨∊0≠⍴∘∊¨⍵}{' '(≠⊆⊢)⍵/⍨~∨\'#'=⍵}∘∊¨P
k:e↑L⌷R
L+←1
→k/⍨L<⍴R

{y}←e c;x
y←1
→((⊃c)∘≡∘,¨'pida')/p i d a
y←e c r x⌷⍨2-e c r 0⌷x←↑F[M⍳0⌷c]
→0
p:N[x],’=‘,2⊥⌽↑V[x←g c]
→0
i:V[x]←⊂{⍬≡⍵:1⋄⊃⍵:0,∇1↓⍵⋄1,1↓⍵}↑V[x←g c]
→0
d:→0/⍨~y←(,0)≢m←↑V[x←g c]
V[x]←⊂m↓⍨-(1=⍴m)⍱⊃⌽m←{⍬≡⍵:⍬⋄~⊃⍵:1,∇1↓⍵⋄0,1↓⍵}m
→0
a:M←M,1⌷c
F←F,⊂R[L+1+⍳3]
L+←3

x←g c
x←N⍳1⌷c
→0/⍨x<⍴N
N←N,1⌷c
V←V,⊂,0

```

The code length was a bit less until I reread the specification that requires arbitrary precision integers. I added code to provide this functionality although I'd hate to wait around for a Prindel program that requires this feature to execute. Dialog APL does have some prewritten routines ('big') to provide this functionality, However, I felt it would be a bit of a cheat to use all that extra 'hidden' code and call it an inherent part of the language.

In any case, the program consists of eight basic functions as follows:

```
 z - this function initializes variables, strips comments, trailing blanks and empty lines; then loops through the Prindeal program code.

 e - this executes a Prindeal statement either an inherent statement (p,i,d,a) or a defined alias. Recursive.

 g - gets a reference to a variable value (defines if as-of-yet undefined)

 r - at execution time, resolves numerical reference to arguments in alias functions

```

Comments and improvements are welcomed. I first dabbled in APL in the late 60s and early 70s. Life took me in another direction, but apparently I never lost my interest in the language. I recently took a look at the state of the language (via Dialog) and found that what was a powerful language back in the day had only grown in complexity and capability. I'm using some of these code golf challenges to introduce me to the newer (to me) language features and have a bit of fun ... lifelong learning.

In any case, here is the output from the test program:

     z
 A = 0
 B = 0
 C = 0
 ____ = 0
 A = 1
 B = 1
 C = 2
 ____ = 0
 A = 1
 B = 3
 C = 2
 ____ = 0
 d = 6
 ____ = 0
 d = 18
 ____ = 0
 d = 0
 ____ = 0
 A = 8
 B = 3
 C = 2
 ____ = 0
 A = 9
 B = 3
 C = 2
 ____ = 0
 A = 9
 B = 3
 C = 729

```

> 0 votes

---
Tags: code-golf, math, arithmetic, interpreter, recursion
---


title: Primes in the prime factorisation

text:
# Question
Title: Primes in the prime factorisation
I saw another prime challenge coming by in PPCG, and I do love me some primes. Then I misread the introductory text, and wondered what the creative brains here had come up with.

It turns out the question posed was trivial, but I wonder if the same is true of the question I (mis)read:

---

\\$6\\$ can be represented by \\$2^1\times3^1\\$, and \\$50\\$ can be represented by \\$2^1\times5^2\\$.

## Your task:

Write a program or function to determine how many distinct primes there are in this *representation* of a number.

## Input:

An integer \\$n\\$ such that \\$1 \< n \< 10^{12}\\$, taken by any normal method.

## Output:

The number of distinct primes that are required to *represent the unique prime factors* of \\$n\\$.

## Test cases:

```
Input      Factorisation      Unique primes in factorisation representation
24         2^3*3^1            2 (2, 3)
126        2^1*3^2*7^1        3 (2, 3, 7)
8          2^3                2 (2, 3)
64         2^6                1 (2) (6 doesn't get factorised further)
72         2^3*3^2            2 (2, 3)
8640       2^6*3^3*5^1        3 (2, 3, 5)
317011968  2^11*3^5*7^2*13^1  6 (2, 3, 5, 7, 11, 13)
27         3^3                1 (3)

```

This is not an OEIS sequence.

## Scoring:

This is , lowest score in bytes wins!

# Answer
# Mathematica, 39 bytes

```
Count[Union@@FactorInteger@#,_?PrimeQ]&

```

Try it online!

thanks to Martin Ender (-11 bytes)
> 5 votes

# Answer
# Jelly,  ~~9~~  7 bytes

```
ÆFFQÆPS

```

**Try it online!** or **Check out the test Suite.**

## How?

```
ÆFFQÆPS   ~ Full program.

ÆF        ~ Prime factorization as [prime, exponent] pairs.
  F       ~ Flatten.
   Q      ~ Deduplicate.
    ÆP    ~ For each, check if it is prime. 1 if True, 0 if False.
      S   ~ Sum.

```
> 5 votes

# Answer
# 05AB1E, ~~9~~ 7 bytes

Saved 2 bytes thanks to *Kevin Cruijssen*

```
ÓsfìÙpO

```

Try it online!

**Explanation**

```
Ó        # push the prime factor exponents of the input
 sfì     # prepend the prime factors of the input
    Ù    # remove duplicates
     p   # check each if it is prime
      O  # sum

```
> 5 votes

# Answer
# \+ numbers, ~~80~~ 78 bytes

```
function(n)sum(isPrime(unique(unlist(rle(primeFactors(n))))))
library(numbers)

```

Try it online!

Similar to Giuseppe (using `numbers` package and `rle`) but no assignments.
> 5 votes

# Answer
# MATL, 8 bytes

```
&YFhuZpz

```

Try it online!
> 4 votes

# Answer
# Gaia, 6 bytes

```
ḋ_uṗ¦Σ

```

Try it online!

---

* computes the prime factorization, as **\[prime, exponent\]** pairs.
* `_` flattens the list.
* `u` removes duplicate elements.
* `ṗ¦` maps through the elements and returns **1** if a prime is found, **0** otherwise.
* `Σ` sums the list.
> 4 votes

# Answer
## CJam (13 bytes)

```
{mFe__&:mp1b}

```

Online test suite

This is pretty straightforward: get primes with multiplicities, reduce to distinct values, filter primes, count.

Sadly Martin pointed out some cases which weren't handled by the mildly interesting trick in my original answer, although he did also provide a 1-byte saving by observing that since `mp` gives `0` or `1` it can be mapped rather than filtered.
> 3 votes

# Answer
# Ohm v2, ~~6~~ 5 bytes

-1 byte thanks to @Mr.Xcoder

```
ä{UpΣ

```

Try it online!
> 2 votes

# Answer
# APL (Dyalog Unicode) + `dfns`, 29 bytes

```
⎕CY'dfns'
{≢∪⍵/⍨1pco⍵}∘∊2pco⊢

```

Try it online!

-6 bytes from Adám.

## Explanation

```
{≢∪⍵/⍨1pco⍵}∘∊2pco⊢ ⊢ → input
                2pco  prime factors and exponents as matrix
{            }∘∊      flatten and use as right arg for:
    ⍵/⍨              filter out values in arg
        1pco⍵         which aren't prime
 ≢∪                   count the unique values

```
> 2 votes

# Answer
# Actually, 7 bytes

```
w♂i╔♂pΣ

```

Try it online!

Explanation:

```
w♂i╔♂pΣ
w        factor into [prime, exponent] pairs
 ♂i      flatten to 1D list
   ╔     unique elements
    ♂p   for each element: 1 if prime else 0
      Σ  sum

```
> 1 votes

# Answer
# Husk,  ~~11~~  10 bytes

```
#ṗuS+omLgp

```

Try it online!

---

**EDIT:** Saved 1 byte thanks to Zgarb.
> 1 votes

# Answer
# Python 2, ~~142~~ ~~135~~ 119 bytes

```
f=lambda n,d=2:n-1and(n%d and f(n,d+1)or[d]+f(n/d))or[]
p=f(input())
print sum(f(n)==[n]for n in set(p+map(p.count,p)))

```

Try it online!
> 1 votes

# Answer
# Brachylog, 7 bytes

```
ḋọcdṗˢl

```

Try it online!

```
           The output
      l    is the length of
  c        the concatenated
 ọ         list of pairs [value, number of occurrences]
ḋ          from the prime factorization of
           the input
   d       with duplicates removed
    ṗˢ     and non-primes removed.

```

A fun 9-byte version: `ḋọ{∋∋ṗ}ᶜ¹`
> 1 votes

# Answer
# Ruby `-rprime`, 66 bytes

```
->n{Prime.prime_division(n).flatten.uniq.count{|i|Prime.prime? i}}

```

Try it online!
> 1 votes

# Answer
# Japt, 11 bytes

```
k
âUü ml)èj

```

Try it

## Alternative

```
k
â¡x¶X})xj

```

Try it
> 1 votes

# Answer
# Husk, 9 bytes

```
#ṗuṁS:Lgp

```

Try it online!

Slight improvement over Mr. XCoder's answer.
> 1 votes

# Answer
# Vyxal `s`, 37 bitsv2, 4.625 bytes

```
ǐĊfUæ

```

Try it Online!'

Takes the counts of the prime factorization which gives a list of \[prime, exponent\] for each prime, flattens, uniquifies, finds the primes.
> 1 votes

# Answer
# Maxima, 104 bytes

So long, it can be golfed much more.

Try it online!

```
f(n):=lreduce(lambda([x,y],x+y),map(lambda([x],if primep(x)then 1 else 0),unique(flatten(ifactors(n)))))

```
> 1 votes

# Answer
# \+ numbers, 92 bytes

```
function(n)sum(1|unique((x=c((r=rle(primeFactors(n)))$l,r$v))[isPrime(x)]))
library(numbers)

```

Try it online!
> 0 votes

# Answer
# Pyth, 15 bytes

```
smP_d{+PQlM.gkP

```

**Try it here!**
> 0 votes

# Answer
# J, 20 bytes

```
3 :'+/1 p:~.,__ q:y'

```

Counted by hand lol, so tell me if this is off.

Any golfing suggestions?

Boring submission: flatten the prime factorization table and count primes.
> 0 votes

# Answer
# Pari/GP, 47 bytes

```
n->#Set(select(isprime,concat(Vec(factor(n)))))

```

Try it online!
> 0 votes

# Answer
# Javascript (ES6), 145 bytes

```
n=>{for(a=[b=l=0],q=n,d=2;q>=2;)q%d?(b&&(a.push(0),l++),d++,b=0):(q/=d,a[l]++,b=1);for(i in a){for(d=1,e=a[i];e%d;d++);e-d||n%e&&l++};return l+1}

```
> 0 votes

# Answer
# Factor, 62 bytes

```
group-factors flatten unique values [ prime? ] filter length ;

```

Attempt This Online!
> 0 votes

---
Tags: code-golf, math, primes, integer
---