Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GameState] add concept of active player and non active players #15

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import fr.tvbarthel.mtg.engine.*
import fr.tvbarthel.mtg.engine.agent.ConsoleAgent
import fr.tvbarthel.mtg.engine.agent.RandomAgent
import fr.tvbarthel.mtg.engine.card.white.Plains
import kotlin.random.Random

fun main() {
val engine = GameEngine()

val seed = Random.nextLong()
val player1 = Player(1).apply { repeat(60) { library.add(Card()) } }
val player2 = Player(2).apply { repeat(60) { library.add(Card()) } }
val player1 = Player(1).apply { repeat(60) { library.add(Plains()) } }
val player2 = Player(2).apply { repeat(60) { library.add(Plains()) } }
val state = GameState(seed, listOf(player1, player2))

val config = GameConfig(state, mapOf(1 to RandomAgent(), 2 to ConsoleAgent()))
Expand Down
22 changes: 20 additions & 2 deletions src/main/kotlin/fr/tvbarthel/mtg/engine/GameState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,23 @@ package fr.tvbarthel.mtg.engine
data class GameState(
val seed: Long,
val players: List<Player> = mutableListOf(),
val turn: Int = 0
)
var turn: Int = 0,
var startingPlayer: Int = 0, /* index of the starting player */
var activePlayer: Int = 0 /* index of the current active player */
) {

/**
* Used to know if the game has ended or not.
*/
fun isGameOver(): Boolean = players.find { it.health == 0 } != null

/**
* Retrieve the current active player.
*/
fun activePlayer(): Player = players[activePlayer]

/**
* Retrieve current non actives players.
*/
fun nonActivePlayers(): List<Player> = players.filterIndexed { index, player -> index != activePlayer }
}
22 changes: 20 additions & 2 deletions src/main/kotlin/fr/tvbarthel/mtg/engine/playing/PlayingStage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,30 @@ package fr.tvbarthel.mtg.engine.playing
import fr.tvbarthel.mtg.engine.Agent
import fr.tvbarthel.mtg.engine.GameState
import fr.tvbarthel.mtg.engine.Stage
import fr.tvbarthel.mtg.engine.playing.phase.BeginningPhase
import fr.tvbarthel.mtg.engine.playing.phase.CombatPhase
import fr.tvbarthel.mtg.engine.playing.phase.EndingPhase
import fr.tvbarthel.mtg.engine.playing.phase.MainPhase

/**
* [Stage] which must ensure the opening stage.
*/
class PlayingStage : Stage {
class PlayingStage(
val beginningPhase: BeginningPhase = BeginningPhase(),
val mainPhase: MainPhase = MainPhase(),
val combatPhase: CombatPhase = CombatPhase(),
val endingPhase: EndingPhase = EndingPhase()
) : Stage {
override fun proceed(agents: Map<Int, Agent>, state: GameState): GameState {
return state
var tempState: GameState = state

while (!state.isGameOver()) {
val newTurn = Turn(beginningPhase, mainPhase, combatPhase, endingPhase)
tempState = newTurn.play(agents, tempState)
tempState.activePlayer = (tempState.activePlayer + 1) % tempState.players.size
tempState.turn++
}

return tempState
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import fr.tvbarthel.mtg.engine.Step
*/
class DamageStep : Step {
override fun proceed(agents: Map<Int, Agent>, state: GameState): GameState {
state.nonActivePlayers().forEach { it.health = 0 }
return state
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package fr.tvbarthel.mtg.engine.opening
import fr.tvbarthel.mtg.engine.Card
import fr.tvbarthel.mtg.engine.GameState
import fr.tvbarthel.mtg.engine.Player
import fr.tvbarthel.mtg.engine.card.white.Plains
import io.kotlintest.shouldThrow
import io.kotlintest.specs.StringSpec
import io.mockk.MockKAnnotations
Expand All @@ -29,7 +30,7 @@ class FromHandToBottomLibraryTest : StringSpec() {
"given card inside hand when apply then card at bottom of library" {
// given
player.hand.add(card)
repeat(10) { player.library.add(Card()) }
repeat(10) { player.library.add(Plains()) }
val state = GameState(12354890L, listOf(player))

// when
Expand All @@ -42,7 +43,7 @@ class FromHandToBottomLibraryTest : StringSpec() {

"given card not inside hand when apply then exception" {
// given
repeat(10) { player.library.add(Card()) }
repeat(10) { player.library.add(Plains()) }
val state = GameState(12354890L, listOf(player))

// when
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fr.tvbarthel.mtg.engine.opening

import fr.tvbarthel.mtg.engine.*
import fr.tvbarthel.mtg.engine.card.white.Plains
import io.kotlintest.TestCase
import io.kotlintest.specs.StringSpec
import io.mockk.MockKAnnotations
Expand Down Expand Up @@ -36,10 +37,10 @@ class OpeningStageTest : StringSpec() {

MockKAnnotations.init(this)
player1 = Player(1)
repeat(60) { player1.library.add(Card()) }
repeat(60) { player1.library.add(Plains()) }

player2 = Player(2)
repeat(60) { player2.library.add(Card()) }
repeat(60) { player2.library.add(Plains()) }

agents = mapOf(player1.id to agent1, player2.id to agent2)
players = mutableListOf(player1, player2)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package fr.tvbarthel.mtg.engine.playing

import fr.tvbarthel.mtg.engine.Agent
import fr.tvbarthel.mtg.engine.GameState
import fr.tvbarthel.mtg.engine.Player
import fr.tvbarthel.mtg.engine.playing.phase.BeginningPhase
import fr.tvbarthel.mtg.engine.playing.phase.CombatPhase
import fr.tvbarthel.mtg.engine.playing.phase.EndingPhase
import fr.tvbarthel.mtg.engine.playing.phase.MainPhase
import io.kotlintest.TestCase
import io.kotlintest.specs.StringSpec
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.RelaxedMockK
import kotlin.test.assertEquals

class PlayingStageTest : StringSpec() {

@RelaxedMockK
lateinit var beginningPhase: BeginningPhase
@RelaxedMockK
lateinit var mainPhase: MainPhase
@RelaxedMockK
lateinit var combatPhase: CombatPhase

@RelaxedMockK
lateinit var endingPhase: EndingPhase

@RelaxedMockK
lateinit var agents: Map<Int, Agent>

private lateinit var state: GameState
private lateinit var player1: Player
private lateinit var player2: Player

override fun beforeTest(testCase: TestCase) {
super.beforeTest(testCase)

player1 = Player(1).apply { health = 20 }
player2 = Player(2).apply { health = 20 }
state = GameState(12354890L, players = listOf(player1, player2))

every { beginningPhase.proceed(any(), any()) } returns state
every { mainPhase.proceed(any(), any()) } returns state
every { endingPhase.proceed(any(), any()) } returns state
}

init {
MockKAnnotations.init(this)

"given empty state when proceed one turn then active player became second player" {
// given
val gameOverTurn = 0
every { combatPhase.proceed(any(), any()) } answers {
if (state.turn == gameOverTurn) player1.health = 0
state
}

// when
PlayingStage(beginningPhase, mainPhase, combatPhase, endingPhase).proceed(agents, state)

// then
assertEquals(1, state.activePlayer)
}

"given empty state when proceed 2 turn then active player became first player" {
// given
val gameOverTurn = 1
every { combatPhase.proceed(any(), any()) } answers {
if (state.turn == gameOverTurn) player1.health = 0
state
}

// when
PlayingStage(beginningPhase, mainPhase, combatPhase, endingPhase).proceed(agents, state)

// then
assertEquals(0, state.activePlayer)
}
}
}