Skip to content

Instantly share code, notes, and snippets.

@pablitar
Created October 27, 2018 23:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pablitar/e802f45625125f53b30d76fd55ed2028 to your computer and use it in GitHub Desktop.
Save pablitar/e802f45625125f53b30d76fd55ed2028 to your computer and use it in GitHub Desktop.
Gimnasio Pokemon 20182C TADP Aula 407
package pokemon
import scala.util.Try
object GimnasioPokemon {
type Actividad = Pokemon => Pokemon
class NoPuedeRealizarActividadException extends RuntimeException
trait TipoPokemon {
def debilidades: Set[TipoPokemon] = Set()
def esDebilContra(unTipo: TipoPokemon) = debilidades.contains(unTipo)
def unapply(unPokemon: Pokemon): Option[Pokemon] =
Some(unPokemon).filter(unPokemon => unPokemon.tieneTipo(this))
}
case object Pelea extends TipoPokemon
case object Normal extends TipoPokemon
case object Fantasma extends TipoPokemon
case object Electrico extends TipoPokemon
case object Agua extends TipoPokemon
case object Fuego extends TipoPokemon {
override val debilidades = Set(Agua, Tierra, Roca)
}
case object Tierra extends TipoPokemon {
override val debilidades = Set(Agua)
}
case object Roca extends TipoPokemon {
override val debilidades = Set(Agua)
}
trait Piedra
case object PiedraElectrica extends Piedra
case class EspeciePokemon(resistenciaEvolutiva: Int,
tipo: TipoPokemon,
tipoSecundario: Option[TipoPokemon] = None,
evolucion: Option[(Pokemon => Boolean, EspeciePokemon)] = None)
trait EstadoPokemon {
def realizarActividad(pokemon: Pokemon, actividad: Actividad): Pokemon = actividad(pokemon)
def unapply(unPokemon: Pokemon): Option[Pokemon] =
Some(unPokemon).filter(unPokemon => unPokemon.estado == this)
}
case object OK extends EstadoPokemon
case object KO extends EstadoPokemon {
override def realizarActividad(pokemon: Pokemon, actividad: Actividad): Pokemon = {
throw new NoPuedeRealizarActividadException
}
}
case class Dormido(turnosRestantes: Int = 3) extends EstadoPokemon {
override def realizarActividad(pokemon: Pokemon, actividad: Actividad): Pokemon = {
if (turnosRestantes <= 1) pokemon.cambiarEstado(OK)
else pokemon.cambiarEstado(copy(turnosRestantes - 1))
}
}
case object Paralizado extends EstadoPokemon
case class Rutina(nombre: String, actividades: Seq[Actividad])
case class Pokemon(
experiencia: Int,
energia: Int,
energiaMaxima: Int,
fuerza: Int,
velocidad: Int,
especie: EspeciePokemon,
piedra: Option[Piedra] = None,
intercambiado: Boolean = false,
estado: EstadoPokemon = OK) {
def darPiedra(unaPiedra: Piedra) = copy(piedra = Some(unaPiedra)).chequearEvolucion()
def tienePiedra(unaPiedra: Piedra): Boolean = piedra.contains(unaPiedra)
def esDebilContra(unTipo: TipoPokemon) = tipo.esDebilContra(unTipo) || tipoSecundario.exists(_.esDebilContra(unTipo))
require(energia >= 0, "La energia debe ser mayor a 0")
def perderEnergia(unaEnergia: Int): Pokemon =
copy(energia = (energia - unaEnergia).max(0))
def ganarExperiencia(unaExperiencia: Int): Pokemon = {
copy(experiencia = experiencia + unaExperiencia).chequearEvolucion()
}
def chequearEvolucion(): Pokemon = {
especie.evolucion.find({ case (condicion, especie) => condicion(this)
}).map(ev => this.evolucionar(ev._2)).getOrElse(this)
}
def evolucionar(unaEspecie: EspeciePokemon): Pokemon = copy(especie = unaEspecie)
//Fuerza, Tipo principal, Tipo secundario
def recuperarAlMaximo: Pokemon = copy(energia = energiaMaxima)
def tipo = especie.tipo
def nivel: Int = experiencia / especie.resistenciaEvolutiva
def tipoSecundario = especie.tipoSecundario
def realizarActividad(actividad: Actividad): Pokemon = {
estado.realizarActividad(this, actividad)
}
def realizarRutina(rutina: Rutina): Try[Pokemon] = Try {
rutina.actividades.foldLeft(this)(_ realizarActividad _ )
}
def cambiarEstado(unEstado: EstadoPokemon): Pokemon = copy(estado = unEstado)
def tieneTipo(tipoPokemon: TipoPokemon): Boolean = tipo == tipoPokemon || tipoSecundario.contains(tipoPokemon)
}
object PokemonConFuerza {
def unapply(unPokemon: Pokemon): Option[Int] = Some(unPokemon.fuerza)
}
object Actividades {
val descansar: Actividad = pokemon => (pokemon match {
case OK(p) if p.energia < p.energiaMaxima * 0.5 => p.cambiarEstado(Dormido())
case p => p
}).recuperarAlMaximo
def levantarPesas(peso: Int): Actividad = {
case Fantasma(pokemon) => throw new NoPuedeRealizarActividadException()
case Paralizado(pokemon) => pokemon.cambiarEstado(KO)
case pokemon@PokemonConFuerza(fuerza) if peso > fuerza * 10 =>
pokemon.perderEnergia(10).cambiarEstado(Paralizado)
case Pelea(pokemon) => pokemon.ganarExperiencia(peso * 2)
case pokemon => pokemon.ganarExperiencia(peso)
// else pokemon.ganarExperiencia(pokemon.puntosAGanar(peso))
}
def nadar(minutos: Int): Actividad =
pokemon => (pokemon match {
case unPokemon if unPokemon.esDebilContra(Agua) => unPokemon.cambiarEstado(KO)
case Agua(unPokemon) => unPokemon.copy(velocidad = unPokemon.velocidad + minutos / 60)
case unPokemon => unPokemon
}).ganarExperiencia(20 * minutos).perderEnergia(minutos)
def usarPiedra(piedra: Piedra)(pokemon: Pokemon) = pokemon.darPiedra(piedra)
}
object Especies {
val charmeleon = EspeciePokemon(120, Fuego)
val charmander = EspeciePokemon(100, Fuego, evolucion = Some((_.nivel >= 16, charmeleon)))
val pikachu = EspeciePokemon(100, Electrico, evolucion = Some((_.tienePiedra(PiedraElectrica), charmeleon)))
val machoke = EspeciePokemon(120, Pelea)
}
object Criadero {
def crearPikachu: Pokemon = Pokemon(0, 100, 100, 5, 10, Especies.pikachu)
def crearMachoke: Pokemon = Pokemon(0, 100, 100, 5, 5, Especies.machoke)
}
}
object GimnasioPokemonApp extends App {
import GimnasioPokemon._
val unMachoke = Criadero.crearMachoke
var pikachu = Criadero.crearPikachu
pikachu = Actividades.levantarPesas(5)(pikachu)
println(pikachu)
pikachu = Actividades.levantarPesas(5)(pikachu)
println(pikachu)
private val nadarMucho: Actividades = Actividades.nadar(30)
pikachu = nadarMucho(pikachu)
println(pikachu)
println(Actividades.levantarPesas(5)(unMachoke))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment