Project Here
Hey, it's been awhile! I'm sorry I didn't get to replying to the wonderful replies to my help thread, but it feels like I'm too late now, so I just want to say thank you here. I've been slowly working on another small project, with quite a few started and stopped inbetween. It seems I might be in a little bit of depression spell, but I'll try and work through it.
What are Breeding Chains/Why This Project
If you already know about pokemon breeding chains, or just simply don't care about the specifics, move past this section.
Pokemon can breed with each other, but only specific groups can do so. Pokemon also have the ability to learn special moves only through breeding with different species, and these are called egg moves. Sometimes, it takes a few generations of pokemon passing down a move to get the right egg group combination for the pokemon you want, and these are called breeding chains. For instance, Eevee is able to know the move Wish. No pokemon in Eevee's breeding groups (Field) can learn Wish just by level up. How does Eevee learn Wish then? We look for a pokemon that has a second egg group, such a Skitty, who learns Wish as an egg move, and while in the Field group, is also in the secondary Fairy egg group. From there, there are mutliple Fairy group pokemon who can learn Wish and breed with Skitty. Since Swirlix and Eevee can't breed, we get a mediator.
Thus we end up with a chain like this: =>
Female Skitty & Male Swirlix who learned Wish at level 45 -> Who then have a Male Skitty who know Wish at birth who breeds with a Female Eevee -> Eevee child with Wish as a starting move.
My notebooks back in high school have breeding chains written out, planning to get a desirable set of moves on a baby pokemon. So my thought would be a tool that could help with this creation. To be specific, I set out have the program make the chains for you, but we'll see why that didn't happen.
Goals
- parse pokemon information, not with api because way too many pokemon and data (done)
- display egg moves in an appealing manner (done)
- match pokemon that fit into multiple egg move groups (done)
- ability to make breeding chains in app (NOPE)
Data
First we want to figure out how we want to handle our data. PokeApi is available, but I was checking the specifics over 700 pokemon and the api is pretty complicated when it comes to listing moves. PokeAPI doesn't just have a list of moves, it has the data from all versions of the game for the move and how it's learned. For this reason, I went with a .json file of more basic pokemon information provided me by my friend Dakota that she's used for her projects. Here the moves are split into learned moves at what level, and a list of egg moves, which is perfect for all the data parsing we're going to do.
Working Outside of React
I knew I would have to be doing a lot of raw data parsing, so I started a normal javascript file that doesn't have anything to do with React. The takes care things as little as getting a moveset list from an object contain the levels and moves, and as big as comparing up to four arrays to find pokemon in the egg groups that learn a specific move. While there's a lengthy unused function, it ended up being around 250 lines long. There's a lot to parse! Things I learned about: the Set Object! This is a set of unique values, so it's good for getting rid of duplicates in an array, and just converting back by doing a spread operator on the set's contents.
I did it more in the unused function, but there's some light recursion happening as well. The problem is for baby pokemon, they are unable to breed so are listed in the undiscovered group with legendaries, so along their pages wouldn't be very useful as it's full of pokemon that can't breed. So if undiscovered, it looks for the pokemon's next evolution, and if it can't find any it just returns an empty array, which signals to react that it will display a message.
forEggMoves(move, pokemonName) {
const relatedPokemonGroup1 = Search.byEggAndMove(move, Pokedex[pokemonName].egg_groups[0]);
if (Pokedex[pokemonName].egg_groups[1]) {
const relatedPokemonGroup2 = Search.byEggAndMove(move, Pokedex[pokemonName].egg_groups[1]);
let combine = relatedPokemonGroup1.concat(relatedPokemonGroup2);
return sortByID([...new Set(combine)]);
} else if (Pokedex[pokemonName].egg_groups[0] === "Undiscovered") {
if (Pokedex[pokemonName].evolutions) {
let name = searchableName(Pokedex[pokemonName].evolutions[0][0]);
return Search.forEggMoves(move, name);
} else {
return [];
}
} else {
return sortByID(relatedPokemonGroup1);
}
}
Realtively Light Top Level Component
For once, the top level component is very light weight. It does the job of importing, but besides that it lets the pokemon entry and the pokedex do all the work with the pokemon's name, gotten from react router's url.
class App extends Component {
render() {
return (
<div className="app flex column h-center">
<Header
searchByPokemon={this.searchByPokemon}
/>
<Route
path={`${this.props.route}/:pokemon`}
render={({ match }) => {
return <PKMNEntry
key={`${Pokedex[match.params.pokemon].display_name}`}
searchName={Pokedex[match.params.pokemon].name}
name={Pokedex[match.params.pokemon].display_name}
eggGroup1={Pokedex[match.params.pokemon].egg_groups[0]}
eggGroup2={Pokedex[match.params.pokemon].egg_groups[1]}
eggMoves={Pokedex[match.params.pokemon].egg_moves}
learnedMoves={Pokedex[match.params.pokemon].moveset}
searchEggMoves={Search.forEggMoves}
searchByPokemon={this.searchByPokemon}
isEggChain={Search.isEggChain}
createMultiEggChain={Search.createMultiEggChain}
/>
}
} />
</div>
);
}
searchByPokemon = (pokemon) => {
window.scrollTo(0, 0);
this.props.history.push(`${searchableName(pokemon)}`);
}
}
The router in this project was actually quite tricky! The main method of finding pokemon is a select bar on the top of the page. It turns out the select bar doesn't like having Links inside of them, really only about onChange events. (note: put the on change on the select, not the options, firefox is okay with options but nothing else is learned that the hard way)
For this we needed to delve into the history. From my understanding, react router is a wrapper around the history package in the first place, but we can still do some forceful work towards it.
import React from 'react';
import ReactDOM from 'react-dom';
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';
import './style.scss';
import App from './App';
let history = createBrowserHistory();
ReactDOM.render(
<Router
history={history}
basename={process.env.PUBLIC_URL}
>
<App
route={process.env.PUBLIC_URL}
history={history}
/>
</Router>
, document.getElementById('root'));
From my testing and trying to get my site to work with github pages, the router holding it's history and basename are useless and helped nothing but I still kept them there. Originally I had App be a 'home' route at '/' to keep the history in the props, but that caused a lot of conflicts for the github pages project, so instead we just pass the route and history as props into the App component itself to work with it. Router is a little bit touchy, so it's going to be something I have to work with more on large "paged" projects.
Display Information
The most important part about the design is accessing the information in a quick manner. We could put all kinds of info, but at the end of the day this is a tool about getting the movesets, so we list the learned moves and then display what pokemon can help with learning egg moves at a glance.
The actual only use of state for this project is a live updater that finds pokemon in the egg groups of multiple moves with the checkboxes to the right. The goal of this is to get as many egg moves with one chain as you need, so you can use this to compare who's in what group quickly. In the more detailed egg move list, pokemon circled in red require a chain to complete the egg move pass down.
No Chain Maker
I have to admit that I reached a point that might have been out of my abilities. I've been sitting on this project for over a week trying to find a solution, but I couldn't find anything that worked well for me. I did make a function that will return the quickest path to a move, but usually we need to take into account specific pokemon we have and multiple move sets. To do this, I would need to stop input and get user feedback on every single stage of the chain. At that point, I think it's easier to click on the pokemon and go to the page to look at information then it would be filling out a forum at each stage of the chain and having to undo and redo each step. It would also be difficult to try and replace middle parts of the chain as well. For this reason, I decided that I wouldn't do a chain maker. Calculating ALL chains is a monstrous task that can very easily end up in a loop that I don't think I'm ready for yet, and the other option is cumbersome to what it supposed to be a simple display.
What's Next
I honestly don't know! I have a few other projects I was picking at, but I'm not in love with them. I didn't get a job yet, but the exciting news is I got a volunteer position for a pokemon fansite that I frequent to help with their design and other bigger plans, so that's really cool and hopefully I can learn a lot there. Again, thank you for any comments you've left that I didn't end up replying to before it's been an embarrassing long amount of days later, I'll perk up soon I think!
Top comments (0)