TeraRaidCalc: Type Matchups as a Scoring Problem
The problem
Tera Raids in Pokémon Scarlet and Violet punish lazy team choices. I kept doing mental arithmetic for type effectiveness, tera overrides, and bulk - so I turned the problem into code.
The goal was quick raid prep: rank a shortlist of counters before I burned a raid sandwich, not build a full competitive VGC simulator.
Pokemon Battle Types Explained
Every Pokémon has one or two types. When you attack, the move's type is checked against the defender's types on a chart: super effective (2×), not very effective (½×), or no effect (0× from immunities). Dual-types multiply those modifiers, which is why a Water move into Grass/Dragon feels different from Water into pure Grass.
STAB (same-type attack bonus) is the quiet multiplier people forget in raid panic. When a Pokémon uses a move that matches one of its own types, damage gets a 1.5× boost. That is why a high Attack stat on the "right" offensive type matters as much as raw super effectiveness on paper.
Immunities are hard zeros, not small penalties. Ground cannot hit Flying; Electric cannot hit Ground in the classic loop. In raids those edges show up as wasted turns if you bring a counter that looks good on a chart but cannot damage the boss at all.
Tera Raid bosses add a tera type on top of their base typing. Terastalizing can change which moves are super effective against them and which resistances they keep from their original types. A Fire Tera Charizard is not the same threat model as base Fire/Flying - the calculator has to score against both layers.
The scoring model
Instead of a single "super effective" lookup, the app ranks candidates with several signals:
- Type effectiveness against both original and tera types
- Defensive bulk (HP, Defense, Sp. Defense)
- Offensive potential (Attack, Sp. Attack) and STAB potential
- Speed tier advantages and immunity interactions
React and TypeScript keep the UI responsive while the scoring logic stays in plain functions I can reason about and adjust. A chart tells you one matchup; a score sorts ten Pokémon you already own.
What I learned
Domain rules explode quickly. Tera types rewrite matchups; immunities zero out entire categories; speed ties matter for support roles. Encoding game knowledge in data structures is harder than drawing type charts on paper.
There is no universal "best" counter without context - raid level, your box, and whether you need bulk or burst all shift the ranking. The tool reflects that by sorting, not declaring a single winner.
What I'd improve next
Move-based recommendations, event raid presets, and offline caching of Pokémon data so the app works without repeated API calls.