This commit is contained in:
2022-10-26 14:32:18 +03:00
parent 7a555d5d0f
commit 955231eff0
163 changed files with 3287 additions and 0 deletions
@@ -0,0 +1,51 @@
# Задание
На основе базового класса pokemon написать свои классы для заданных видов покемонов. Каждый вид покемона должен иметь один или два типа и стандартные базовые характеристики:
-очки здоровья (HP)\
-атака (attack)\
-защита (defense)\
-специальная атака (special attack)\
-специальная защита (special defense)\
-скорость (speed)
**Моё несогласие (DRY)** \
Вышеизложенное считаю не целесообразным и неправильным с точки зрения принципов SOLID в части "_На основе базового класса pokemon написать свои классы для заданных видов покемонов_" т. к.:-
- разные классы воспроизводят одинаковую логику, но с разными параметрами. Это нарушение принципа DRY (Don't Repeat Yourself)
## Классы
Классы покемонов должны наследоваться в соответствии с цепочкой эволюции покемонов. На основе базовых классов PhysicalMove, SpecialMove и StatusMove реализовать свои классы для заданных видов атак.
Атака должна иметь стандартные тип, силу (power) и точность (accuracy). Должны быть реализованы стандартные эффекты атаки. Назначить каждому виду покемонов атаки в соответствии с вариантом.
Уровень покемона выбирается минимально необходимым для всех реализованных атак.
Используя класс симуляции боя Battle, создать 2 команды покемонов (каждый покемон должен иметь имя) и запустить бой.
Базовые классы и симулятор сражения находятся в jar-архиве (обновлен 9.10.2018, исправлен баг с добавлением атак и кодировкой). Документация в формате javadoc - здесь.
Информацию о покемонах, цепочках эволюции и атаках можно найти на сайтах http://poke-universe.ru, http://pokemondb.net, http://veekun.com/dex/pokemon
# Комментарии
**Цель работы:** на простом примере разобраться с основными концепциями ООП и научиться использовать их в программах.
### Что надо сделать (краткое описание)
Ознакомиться с документацией, обращая особое внимание на классы pokemon и Move. При дальнейшем выполнении лабораторной работы читать документацию еще несколько раз.
Скачать файл pokemon.jar. Его необходимо будет использовать как для компиляции, так и для запуска программы. Распаковывать его не надо! Нужно научиться подключать внешние jar-файлы к своей программе.
Написать минимально работающую программу и посмотреть как она работает.
> Battle b = new Battle();\
> pokemon p1 = new pokemon("Чужой", 1);\
> pokemon p2 = new pokemon("Хищник", 1);\
> b.addAlly(p1);\
> b.addFoe(p2);\
> b.go();
Создать один из классов покемонов для своего варианта. Класс должен наследоваться от базового класса pokemon. В конструкторе нужно будет задать типы покемона и его базовые характеристики.\
После этого попробуйте добавить покемона в сражение.\
Создать один из классов атак для своего варианта (лучше всего начать с физической или специальной атаки). Класс должен наследоваться от класса PhysicalMove или SpecialMove.\
В конструкторе нужно будет задать тип атаки, ее силу и точность. После этого добавить атаку покемону и проверить ее действие в сражении.\
Не забудьте переопределить метод describe, чтобы выводилось нужное сообщение.\
Если действие атаки отличается от стандартного, например, покемон не промахивается, либо атакующий покемон также получает повреждение, то в классе атаки нужно дополнительно переопределить соответствующие методы (см. документацию).\
При реализации атак, которые меняют статус покемона (наследники StatusMove), скорее всего придется разобраться с классом Effect. Он позволяет на один или несколько ходов изменить состояние покемона или модификатор его базовых характеристик.\
Доделать все необходимые атаки и всех покемонов, распределить покемонов по командам, запустить сражение.
@@ -0,0 +1,18 @@
package pokemon
import ru.ifmo.se.pokemon.Battle
import ru.ifmo.se.pokemon.Pokemon
fun Battle.addAllies(vararg allies: Pokemon) {
allies.forEach { addAlly(it) }
}
fun Battle.addFoes(vararg allies: Pokemon) {
allies.forEach { addFoe(it) }
}
fun chance(percent: Int): Boolean {
return Math.random() < (percent / 100)
}
fun chance(percent: Int, action: () -> Unit): Boolean {
return Math.random() < (percent / 100)
}
@@ -0,0 +1,77 @@
package pokemon
import ru.ifmo.se.pokemon.*
fun main() {
val battle = Battle()
val facade = CustomAttack(
Type.DARK, 70, 100, "Facade",
listOf(Effect().condition(Status.BURN).stat(Stat.ATTACK, (70 * 2)),
Effect().condition(Status.POISON).stat(Stat.ATTACK, (70 * 2)),
Effect().condition(Status.PARALYZE).stat(Stat.ATTACK, (70 * 2)))
)
val zenHeadbutt = CustomAttack(Type.PSYCHIC, 80, 90, "Zen Headbutt")
val calmMind = CustomAttack(Type.PSYCHIC, 0, 0, "Calm Mind",
selfActions = { it.setMod(Stat.SPECIAL_ATTACK, 1); it.setMod(Stat.SPECIAL_DEFENSE, 1) }
)
val doubleTeam = CustomAttack(Type.NORMAL, 0, 100, "Double Team",
selfActions = { it.setMod(Stat.EVASION, 1) }
)
val tackle = CustomAttack(Type.NORMAL, 40, 100, "Tackle")
val sandAttack = CustomAttack(Type.GROUND, 0, 100, "Sand Attack",
opponentActions = { it.setMod(Stat.ACCURACY, -1) }
)
val psychic = CustomAttack(Type.PSYCHIC, 90, 100, "Psychic",
opponentActions = { it.setMod(Stat.SPECIAL_DEFENSE, -1) }
)
val chargeBeam = CustomAttack(Type.ELECTRIC, 50, 90, "Charge Beam",
opponentActions = { chance(70) { it.setMod(Stat.SPECIAL_ATTACK, 1) } }
)
val wildCharge = CustomAttack(Type.ELECTRIC, 90, 100, "Wild Charge",
opponentActions = { chance(30) { it.setMod(Stat.SPEED, -1) } }
)
val crunch = CustomAttack(Type.DARK, 80, 100, "Crunch",
opponentActions = { chance(20) { it.setMod(Stat.DEFENSE, -1) } }
)
val stringShot = CustomAttack(Type.BUG, 0, 95, "String Shot",
opponentActions = { it.setMod(Stat.SPEED, -2) }
)
val sableye = Spok("Sableye", 1).apply {
setStatsFromArgs(50.0, 75.0, 75.0, 65.0, 65.0, 50.0)
addTypes(Type.DARK, Type.GHOST)
addMoves(facade, zenHeadbutt, calmMind, doubleTeam)
}
val eeve = Spok("Eevee", 1).apply {
setStatsFromArgs(55.0, 55.0, 50.0, 45.0, 65.0, 55.0)
addTypes(Type.NORMAL)
addMoves(tackle, facade, sandAttack)
}
val umbreon = Spok("Umbreon", 1).apply {
setStatsFromArgs(95.0, 65.0, 110.0, 60.0, 130.0, 65.0)
addTypes(Type.DARK)
addMoves(tackle, facade, sandAttack, psychic)
}
val grubbin = Spok("Grubbin", 1).apply {
setStatsFromArgs(47.0, 62.0, 45.0, 55.0, 45.0, 46.0)
addTypes(Type.BUG)
addMoves(chargeBeam, wildCharge)
}
val charjabug = Spok("Charjabug", 1).apply {
setStatsFromArgs(57.0, 82.0, 95.0, 55.0, 75.0, 36.0)
addTypes(Type.BUG, Type.ELECTRIC)
addMoves(chargeBeam, wildCharge, crunch)
}
val vikavolt = Spok("Vikavolt", 1).apply {
setStatsFromArgs(77.0, 70.0, 90.0, 145.0, 75.0, 43.0)
addTypes(Type.BUG, Type.ELECTRIC)
addMoves(chargeBeam, wildCharge, crunch, stringShot)
}
battle.addAllies(sableye, eeve, umbreon)
battle.addFoes(grubbin, charjabug, vikavolt)
battle.go()
}
@@ -0,0 +1,37 @@
package pokemon
import ru.ifmo.se.pokemon.Effect
import ru.ifmo.se.pokemon.PhysicalMove
import ru.ifmo.se.pokemon.Pokemon
import ru.ifmo.se.pokemon.Type
open class CustomAttack(
type: Type,
power: Number,
accuracy: Number,
desc: String = "",
private val selfEffects: List<Effect> = emptyList(),
private val opponentEffects: List<Effect> = emptyList(),
private val selfActions: (Pokemon) -> Unit = {},
private val opponentActions: (Pokemon) -> Unit = {},
) :
PhysicalMove(type, power.toDouble(), (accuracy.toDouble() / 100)) {
override fun applySelfEffects(p0: Pokemon?) {
super.applySelfEffects(p0)
selfEffects.forEach { p0?.addEffect(it) }
selfActions(p0!!)
}
override fun applyOppEffects(p0: Pokemon?) {
super.applySelfEffects(p0)
opponentEffects.forEach { p0?.addEffect(it) }
opponentActions(p0!!)
}
private var description: String = "использовал $desc"
override fun describe() = description
fun setDescription(desc: String) {
description = desc
}
}
@@ -0,0 +1,56 @@
package pokemon
import ru.ifmo.se.pokemon.Move
import ru.ifmo.se.pokemon.Pokemon
import ru.ifmo.se.pokemon.Stat
import ru.ifmo.se.pokemon.Type
class Spok (
name: String,
level: Int = 1,
types: List<Type> = emptyList(),
stats: Map<Stat, Double> = mapOf(),
moves: List<Move> = listOf(Move.getStruggleMove())
) : Pokemon(name, level) {
init {
super.setLevel(level)
super.setType(*types.toTypedArray())
if (stats.isNotEmpty()) { setStatsFromMap(stats) }
moves.forEach { addMove(it) }
}
fun setStatsFromArgs(
hp: Double,
attack: Double,
defense: Double,
specialAttack: Double,
specialDefense: Double,
speed: Double
) {
super.setStats(hp, attack, defense, specialAttack, specialDefense, speed)
}
private fun setStatsFromMap(stats: Map<Stat, Double>) {
try {
super.setStats(
stats[Stat.HP]!!,
stats[Stat.ATTACK]!!,
stats[Stat.DEFENSE]!!,
stats[Stat.SPECIAL_ATTACK]!!,
stats[Stat.SPECIAL_DEFENSE]!!,
stats[Stat.SPEED]!!,
)
} catch (npe: NullPointerException) {
throw Exception("Stats Set Failed")
}
}
fun addTypes(vararg types: Type) {
super.setType(*types)
}
fun addMoves(vararg moves: Move) {
moves.forEach { addMove(it) }
}
}
@@ -0,0 +1,5 @@
Manifest-Version: 1.0
Main-Class: pokemon.GameKt
Class-Path: Pokemon.jar kotlin-stdlib.jar kotlin-reflect.jar kotlin-test
.jar