0

I have this trait:

 trait Pokemon { type Move; fn pick_move(&self) -> Self::Move; } 

Certain types implement the trait, like so:

 #[derive(PartialEq, Clone, Copy)] enum Fire { Charmander, Charmeleon, Charizard } #[derive(PartialEq, Clone, Copy)] enum FireMove { Ember, FlameThrower, FireBlast } #[derive(PartialEq, Clone, Copy)] enum Water { Squirtle, Wartortle, Blastoise } #[derive(PartialEq, Clone, Copy)] enum WaterMove { Bubble, WaterGun } impl Pokemon for Fire { type Move = FireMove; fn pick_move(&self) -> Self::Move { match self { Self::Charmander => Self::Move::Ember, Self::Charmeleon => Self::Move::FlameThrower, Self::Charizard => Self::Move::FireBlast, } } } impl Pokemon for Water { type Move = WaterMove; fn pick_move(&self) -> Self::Move { if *self == Water::Squirtle { return Self::Move::Bubble; } Self::Move::WaterGun } } 

For the types that implemented the Pokemon trait, I want to implement a trait Battle:

 trait Battle { fn battle(&self) -> ??; } 

In the end, what I'd want to achieve is that I should be able to call .battle on any type that implements the Pokemon trait and eventually be able to return the Pokemon that wins a battle.

I've thought about using such a method too:

 fn battle<T>(pokemon: T, foe: T) -> T where T: Pokemon { let p_move = pokemon.pick_move(); let f_move = foe.pick_move(); if p_move == f_move { return pokemon; } foe } 

Unfortunately, here I'm not able to compare the Moves of the arguments that have been passed.

One way I came close to achieving this is by doing something like this:

 trait Battle { type Pokemons; fn battle(&self, foe: Self::Pokemons) -> Self::Pokemons; } #[derive(PartialEq, Clone, Copy)] enum PokemonTypes { Fire(Fire), Water(Water), Grass(Grass) } impl Battle for Fire { type Pokemons = PokemonTypes; fn battle(&self, foe: Self::Pokemons) -> Self::Pokemons { match foe { Self::Pokemons::Water(pokemon) => Self::Pokemons::Water(pokemon), _ => Self::Pokemons::Fire(*self) // because Fire beats Grass type } } } 

So basically, how do I implement this Battle trait that should help me compare the moves and/or the pokemon types and decide the winner?

1
  • Why dont instead of pokemon types (which is ok) you have a MovementType Enum that wraps the movements? Commented Jun 25, 2021 at 8:24

1 Answer 1

1

You could abstract the move types into another enum, and remove the associated type in the trait:

#[derive(PartialEq, Clone, Copy)] enum Move { Water(WaterMove), Fire(FireMove), } trait Pokemon { fn pick_move(&self) -> Move; } 

And then the same way, you can directly use your implementation for the Battle system, but implementing battle over PokemonType:

#[derive(PartialEq, Clone, Copy)] enum PokemonType { Fire(Fire), Water(Water), } trait Battle { fn battle(&self, foe: PokemonType) -> PokemonType; } impl Battle for PokemonType { fn battle(&self, foe: PokemonType) -> PokemonType { match (self, foe) { (p1@PokemonType::Water(_), p2@PokemonType::Fire(_)) => { *p1 // do watever } _ => foe // handle other patterns } } } 

Playground

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, this is very much possible. However, I would appreciate any suggestions that may be in line with my current approach?
@WaveMetric, So basically, how do I implement this Battle trait that should help me compare the moves and/or the pokemon types and decide the winner?, It do not diverge too much from your approach. But good luck!
I appreciate the quick response @Netwave! :) I was trying out some examples with associated types and wanted help in knowing whether such an example is possible with the current Rust syntax.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.