Kotlin core finished

Finish basic function
Update card's effect
This commit is contained in:
secminhr 2018-08-26 13:43:22 +00:00
parent 1c24ba8d26
commit cb4ce44ea3
5 changed files with 765 additions and 0 deletions

127
Cards.kt Normal file
View File

@ -0,0 +1,127 @@
import java.util.*
abstract class AggressiveCard: Card {
override fun startSkill() {
println(activeString)
owner.enemy.effectBuffer = this.effects
owner.enemy.attackingCard = this
owner.enemy.effectBuffer.forEach { it.apply() }
owner.enemy.effectBuffer = emptyArray()
owner.enemy.attackingCard = null
}
override fun toString(): String {
return "${this.id}. ${this.name}"
}
}
abstract class DefensiveCard: Card {
class NotInPassiveContextException: Exception()
override fun startSkill() {
if(owner.effectBuffer.isEmpty()) {
throw NotInPassiveContextException()
}
println(activeString)
this.effects.forEach { it.apply() }
}
override fun toString(): String {
return "${this.id}. ${this.name}"
}
}
abstract class GeneralCard: Card {
override fun startSkill() {
println(activeString)
this.effects.forEach { it.apply() }
}
override fun toString(): String {
return "${this.id}. ${this.name}"
}
}
class AttackCard(override val owner: Character): AggressiveCard() {
override val name = "攻擊"
override val id = 1
override val effects: Array<Effect> = arrayOf(Damage(owner.enemy, decreaseLife = 2))
override val activeString = "$owner 攻擊 ${owner.enemy}"
}
class DefendCard(override val owner: Character): DefensiveCard() {
override val name = "防禦"
override val id = 2
override val effects: Array<Effect> = arrayOf(Defense(owner))
override val activeString = "$owner 防禦成功"
}
class HealCard(override val owner: Character): GeneralCard() {
override val name = "治癒"
override val id = 3
override val effects: Array<Effect> = arrayOf(Heal(owner, increaseLife = 2))
override val activeString = "$owner 回復2點生命"
}
class SupplyCard(override val owner: Character): GeneralCard() {
override val name = "補給"
override val id = 4
override val effects: Array<Effect> = arrayOf(DrawFromDeck(owner, numberOfCards = 2))
override val activeString = "$owner 增加2張手牌"
}
class RobbingCard(override val owner: Character): AggressiveCard() {
override val name = "強奪"
override val id = 5
override val effects: Array<Effect> = arrayOf(ChooseFromCharacterHand(owner, owner.enemy))
override val activeString = "$owner 正在對 ${owner.enemy} 行搶"
}
class SurpriceCard(override val owner: Character): AggressiveCard() {
override val name = "奇襲"
override val id = 6
override val effects: Array<Effect> = arrayOf(Damage(owner.enemy, decreaseLife = 2),
LoseCard(owner.enemy))
override val activeString = "$owner 發動奇襲"
}
class AwareCard(override val owner: Character): DefensiveCard() {
override val name = "洞悉"
override val id = 7
override val effects: Array<Effect> = arrayOf(Defense(owner), DrawFromDeck(owner, numberOfCards = 2))
override val activeString = "$owner 洞悉了 ${owner.enemy}${owner.attackingCard}並抽取2張手牌"
}
class PlanCard(override val owner: Character): GeneralCard() {
override val name = "妙策"
override val id = 8
override val effects: Array<Effect> = arrayOf(ChooseFromDeck(owner))
override val activeString = "$owner 有個妙策"
}
class SweepCard(override val owner: Character): AggressiveCard() {
override val name = "掃射"
override val id = 9
private val damage = Random().nextInt(6)
override val effects: Array<Effect>
get() = arrayOf(Damage(owner.enemy, decreaseLife = damage))
override val activeString = "$owner${owner.enemy} 進行掃射,威力是 $damage"
}
class BlessCard(override val owner: Character): GeneralCard() {
override val name = "加護"
override val id = 10
override val effects: Array<Effect> = arrayOf(Heal(owner, increaseLife = 3), SolvePoison(owner))
override val activeString = "$owner 獲得加護身上的毒素一掃而空並回復3點生命"
}
class PoisonCard(override val owner: Character): GeneralCard() {
override val name = "劇毒"
override val id = 11
override val effects: Array<Effect> = arrayOf(Poison(owner.enemy))
override val activeString = "$owner 在食物下毒,${owner.enemy} 中毒了"
}
class ChaosCard(override val owner: Character): AggressiveCard() {
override val name = "狂亂"
override val id = 12
override val effects: Array<Effect> = arrayOf(Heal(owner, increaseLife = 3),
Damage(owner.enemy, decreaseLife = 3))
override val activeString = "$owner 進入狂亂模式,回復三點生命,並對 ${owner.enemy} 造成三點傷害"
}
class ReverseCard(override val owner: Character): DefensiveCard() {
override val name = "反制"
override val id = 13
override val effects: Array<Effect> = arrayOf(Reverse(owner), Defense(owner))
override val activeString = "$owner 反制了 ${owner.enemy} 的攻擊,反彈了其效果"
}

211
Character.kt Normal file
View File

@ -0,0 +1,211 @@
class Ann: Character() {
override val name = ""
override val id = 1
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}
class Guo: Character() {
override val name = "圭月"
override val id = 2
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}
class May: Character() {
override val name = ""
override val id = 3
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}
class Rabbit: Character() {
override val name = "小兔"
override val id = 4
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}
class Silver: Character() {
override val name = ""
override val id = 5
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}
class Tadashisaku: Character() {
override val name = "正作"
override val id = 6
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}
class W: Character() {
override val name = "W"
override val id = 7
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}
class Thunder: Character() {
override val name = "桑德"
override val id = 8
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}
class Haier: Character() {
override val name = "海爾"
override val id = 9
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}
class Yukimura: Character() {
override val name = "雪村"
override val id = 10
override val deck: Deck by lazy {
val deck = Deck(mutableListOf(AttackCard(this),
DefendCard(this),
HealCard(this),
SupplyCard(this),
RobbingCard(this),
SurpriceCard(this),
AwareCard(this),
PlanCard(this),
SweepCard(this),
BlessCard(this),
PoisonCard(this),
ChaosCard(this),
ReverseCard(this)))
deck.shuffle()
deck
}
}

213
Effect.kt Normal file
View File

@ -0,0 +1,213 @@
import java.util.*
class WrongParameterException: Exception()
//This class take subjects[0] as the one to be damaged
class Damage(override vararg val subjects: Character,
private val decreaseLife: Int) : Effect() {
init {
if (subjects.isEmpty() || decreaseLife <= 0) {
throw WrongParameterException()
}
}
private val subject = subjects[0]
override val reverseEffect: Effect
get() = Damage(subject.enemy, decreaseLife = decreaseLife)
override val id = 1
override fun apply() {
subject.life -= decreaseLife
}
}
//This class take subjects[0] as the one the be healed
class Heal(override vararg val subjects: Character, private val increaseLife: Int) : Effect() {
init {
if (subjects.isEmpty() || increaseLife <= 0) {
throw WrongParameterException()
}
}
private val subject = subjects[0]
override val reverseEffect: Effect
get() = Heal(subject.enemy, increaseLife = increaseLife)
override val id = 2
override fun apply() {
subject.life += increaseLife
}
}
//This class take subjects[0] as the one who draws from the deck
class DrawFromDeck(override vararg val subjects: Character,
private val numberOfCards: Int): Effect() {
init {
if (subjects.isEmpty() || numberOfCards <= 0) {
throw WrongParameterException()
}
}
private val subject = subjects[0]
override val reverseEffect: Effect
get() = DrawFromDeck(subject.enemy, numberOfCards = numberOfCards)
override val id = 3
override fun apply() {
subject.drawFromDeck(numberOfCards)
}
}
//This class take subjects[0] as the one who draws
//subjects[1] as the one whose cards is taken
class ChooseFromCharacterHand(override vararg val subjects: Character): Effect() {
init {
if (subjects.size < 2) {
throw WrongParameterException()
}
}
private val taker = subjects[0]
private val giver = subjects[1]
override val reverseEffect: Effect
get() = ChooseFromCharacterHand(giver, taker)
override val id = 4
override fun apply() {
taker.chooseFromCards(giver.hand)
}
}
//This class take subjects[0] as the one who loses one card randomly
class LoseCard(override vararg val subjects: Character): Effect() {
init {
if (subjects.isEmpty()) {
throw WrongParameterException()
}
}
private val subject = subjects[0]
override val reverseEffect: Effect
get() = LoseCard(subject.enemy)
override val id = 5
override fun apply() {
val cards = subject.hand
val index = Random().nextInt(cards.size)
cards.toMutableList().removeAt(index)
}
}
//This class take subject[0] as the one who chooses the card
class ChooseFromDeck(override vararg val subjects: Character): Effect() {
init {
if (subjects.isEmpty()) {
throw WrongParameterException()
}
}
private val subject = subjects[0]
override val reverseEffect: Effect
get() = ChooseFromDeck(subject.enemy)
override val id = 6
override fun apply() {
val random = Random()
val first = random.nextInt(subject.deck.size)
var second = random.nextInt(subject.deck.size)
while(second == first) {
second = random.nextInt(subject.deck.size)
}
var third = random.nextInt(subject.deck.size)
while(third == first || third == second) {
third = random.nextInt(subject.deck.size)
}
val cards = subject.deck.cards
subject.chooseFromCards(mutableListOf(cards[first], cards[second], cards[third]))
}
}
//This class take subject[0] as the one who was poisoned
class SolvePoison(override vararg val subjects: Character): Effect() {
init {
if (subjects.isEmpty()) {
throw WrongParameterException()
}
}
private val subject = subjects[0]
override val reverseEffect: Effect
get() = SolvePoison(subject.enemy)
override val id = 7
override fun apply() {
subject.poisoned = false
}
}
//The class take subject[0] as the one who's going to be poisoned
class Poison(override vararg val subjects: Character): Effect() {
init {
if (subjects.isEmpty()) {
throw WrongParameterException()
}
}
private val subject = subjects[0]
override val reverseEffect: Effect
get() = Poison(subject.enemy)
override val id = 8
override fun apply() {
subject.poisoned = true
}
}
//This class take subject[0] as the one who needs to defense attack
class Defense(override vararg val subjects: Character): Effect() {
init {
if (subjects.isEmpty()) {
throw WrongParameterException()
}
}
private val subject = subjects[0]
override val reverseEffect: Effect
get() = Defense(subject.enemy)
override val id = 9
override fun apply() {
subject.effectBuffer = emptyArray()
subject.attackingCard = null
}
}
//This class take subject[0] as the one who wants to reflect the effect
class Reverse(override vararg val subjects: Character): Effect() {
init {
if (subjects.isEmpty()) {
throw WrongParameterException()
}
}
private val subject = subjects[0]
override val reverseEffect: Effect
get() = Reverse(subject.enemy)
override val id = 10
override fun apply() {
subject.effectBuffer = subject.effectBuffer.map { it.reverseEffect }.toTypedArray()
subject.effectBuffer.forEach { it.apply() }
}
}

34
GameLoop.kt Normal file
View File

@ -0,0 +1,34 @@
class GameLoop(private val first: Character,
private val second: Character,
val complition: (Character, Character) -> Unit) {
fun init() {
//enemy must be initialize first since the Card initiate needs them
first.enemy = second
second.enemy = first
first.endGameAsLoser = { //first's deck is dry
complition(second, first)
}
second.endGameAsLoser = { //second's deck is dry
complition(first, second)
}
first.drawFromDeck(3)
second.drawFromDeck(3)
}
fun start() {
while(first.life > 0 && second.life > 0) {
first.nextTurn()
second.nextTurn()
}
endGame()
}
private fun endGame() {
val winner = if (first.life > 0) first else second
val loser = winner.enemy
complition(winner, loser)
}
}

180
Interfaces.kt Normal file
View File

@ -0,0 +1,180 @@
import java.util.*
import kotlin.math.abs
import kotlin.properties.Delegates
abstract class Character {
//basic info
abstract val name: String
abstract val id: Int
abstract val deck: Deck
var life: Int by Delegates.observable(20) {_, old, new ->
val diff = abs(old-new)
if (new < old) {
println("${this.name} 受到 $diff 點傷害")
} //heal description is provided in HealCard
}
var poisoned: Boolean by Delegates.observable(false) {_, _, new ->
if(new) {
println("${this.name} 中毒了")
} else {
println("${this.name} 毒性解除")
}
}
var hand: Cards = emptyList<Card>().toMutableList()
lateinit var enemy: Character //This will be set in GameLoop.init
lateinit var endGameAsLoser: () -> Unit //This will be set in GameLoop.init
var turn = 0
var effectBuffer: Array<Effect> by Delegates.observable(emptyArray()) { _, old, new ->
if(new.isNotEmpty() /* been clean*/ &&
old.map { it.reverseEffect }.toTypedArray().contentNotEquals(new) /*tmp effect of reverse*/) {
val defensiveInHand = hand.filter { it is DefensiveCard }
if (defensiveInHand.isNotEmpty()) {
println("請選擇要使用的防禦卡片或是打0放棄")
println(defensiveInHand.filterIndexed { index,_ ->
if (index != 0) {
defensiveInHand[index].name != defensiveInHand[index-1].name
} else {
true
}
})
val scanner = Scanner(System.`in`)
var id = scanner.nextInt()
while(id != 0) {
if(defensiveInHand.indexOfFirst { it.id == id } == -1){
id = scanner.nextInt()
continue
} else {
val index = hand.indexOfFirst { it.id == id }
hand[index].startSkill()
hand.removeAt(index)
break
}
}
}
}
}
var attackingCard: Card? = null
fun drawFromDeck(num: Int = 1) {
for (i in 1..num) {
try {
val card = deck.firstCard
println("${this.name}抽到了 ${card.id}. ${card.name}")
hand.add(card)
println("牌組剩餘 ${deck.size} 張牌")
} catch (e: NoSuchElementException) {
println("牌庫已空,你抽到了死神")
life = -9999
endGameAsLoser()
}
}
}
fun chooseFromCards(cards: Cards) {
println("請選擇一張")
cards.forEach { println("${it.id}. ${it.name} ") }
val scanner = Scanner(System.`in`)
while(true) {
val id = scanner.nextInt()
val card = try {
cards.filter { it.id == id }[0]
} catch (e: IndexOutOfBoundsException) {
continue
}
println("${this.name} 選擇了 ${card.name}")
hand.add(card)
break
}
}
fun nextTurn() {
turn++
println("${this.name} 的第 $turn 回合")
if (this.poisoned) {
println("中毒扣1滴血")
this.life--
}
println("生命值: $life")
println("請出牌:(或輸入0放棄)")
println(this.hand.filter { !(it is DefensiveCard) })
val scanner = Scanner(System.`in`)
var id = scanner.nextInt()
while (id != 0) {
val index = hand.indexOfFirst {
it.id == id
}
if (index == -1) {
println("請出牌:(或輸入0放棄)")
id = scanner.nextInt()
continue
} else {
if (hand[index] is DefensiveCard) {
println("請出牌:(或輸入0放棄)")
id = scanner.nextInt()
continue
} else {
hand[index].startSkill()
hand.removeAt(index)
drawFromDeck()
break
}
}
}
}
override fun toString() = this.name
}
fun <T> Array<T>.contentNotEquals(array: Array<out T>) = !this.contentEquals(array)
class Deck(cards: Cards) {
var cards: Cards = cards
private set
val size: Int
get() = cards.size
val firstCard: Card
get() {
val card = cards.first()
cards.removeAt(0)
return card
}
fun shuffle() = cards.shuffle()
}
class EmptyDeckException: Exception()
typealias Cards = MutableList<Card>
interface Card {
val owner: Character
val name: String
val id: Int
val activeString: String
//This must be a calculated property instead of a stored value
//in order to prevent StackOverflowError
val effects: Array<Effect>
fun startSkill()
}
abstract class Effect {
abstract val subjects: Array<out Character> //The structure of subjects will defined by the concrete classes
abstract val reverseEffect: Effect
abstract val id: Int
abstract fun apply()
override fun toString(): String = this.javaClass.name
override fun equals(other: Any?): Boolean {
return if(other is Effect) {
this.id == other.id
} else {
false
}
}
override fun hashCode() = this.id
}