Compare commits
21 Commits
archive/se
...
b9a7b0a2af
| Author | SHA1 | Date | |
|---|---|---|---|
| b9a7b0a2af | |||
| fbc0ea2277 | |||
| f998d5f6f0 | |||
| c5895f094b | |||
| 8645d4a219 | |||
| c9e44bc604 | |||
| 7dad9052f7 | |||
| 65921c289a | |||
| cc4bc9d93e | |||
| c43cc7cac0 | |||
| e17ab6a552 | |||
| 786204dfaf | |||
| 026c666f03 | |||
| 6335cbee23 | |||
| 16857fe42c | |||
| 1a189ef0fe | |||
| f9a6e6af05 | |||
| 11834a7d44 | |||
| 51ef1f1607 | |||
| 7676dd8ed1 | |||
| 51604124fd |
56
build.sbt
56
build.sbt
@@ -1,56 +0,0 @@
|
||||
|
||||
|
||||
|
||||
Compile/mainClass := Some("de.knockoutwhist.KnockOutWhist")
|
||||
|
||||
name := "KnockOutWhist"
|
||||
version := {
|
||||
val major = sys.env.getOrElse("MAJOR_VERSION", "0")
|
||||
val minor = sys.env.getOrElse("MINOR_VERSION", "0")
|
||||
val buildNR = sys.env.getOrElse("BUI_COUNTER", "1")
|
||||
s"$major.$minor.$buildNR"
|
||||
}
|
||||
|
||||
ThisBuild / organization := "de.knockoutwhist"
|
||||
ThisBuild / version := version.value
|
||||
ThisBuild / scalaVersion := "3.5.1"
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.settings(
|
||||
name := "Projekt-zu-SE",
|
||||
fork in run := true,
|
||||
javaOptions in run += "-Xmx2G",
|
||||
assembly / mainClass := Some("de.knockoutwhist.KnockOutWhist"),
|
||||
assembly / assemblyJarName := s"KnockOutWhist-${version.value}.jar",
|
||||
)
|
||||
|
||||
|
||||
|
||||
libraryDependencies += "org.scalactic" %% "scalactic" % "3.2.18"
|
||||
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.18" % "test"
|
||||
libraryDependencies +="io.github.mkpaz" % "atlantafx-base" % "2.0.1"
|
||||
libraryDependencies += "org.scalafx" %% "scalafx" % "22.0.0-R33"
|
||||
|
||||
libraryDependencies += "org.scala-lang.modules" %% "scala-xml" % "2.3.0"
|
||||
libraryDependencies += "org.playframework" %% "play-json" % "3.1.0-M1"
|
||||
|
||||
libraryDependencies ++= {
|
||||
// Determine OS version of JavaFX binaries
|
||||
lazy val osName = System.getProperty("os.name") match {
|
||||
case n if n.startsWith("Linux") => "linux"
|
||||
case n if n.startsWith("Mac") => "mac"
|
||||
case n if n.startsWith("Windows") => "win"
|
||||
case _ => throw new Exception("Unknown platform!")
|
||||
}
|
||||
Seq("base", "controls", "fxml", "graphics", "media", "swing", "web")
|
||||
.map(m => "org.openjfx" % s"javafx-$m" % "21" classifier osName)
|
||||
}
|
||||
|
||||
libraryDependencies += "net.codingwell" %% "scala-guice" % "7.0.0"
|
||||
|
||||
Test / testOptions += Tests.Filter(_.equals("de.knockoutwhist.TestSequence"))
|
||||
|
||||
coverageEnabled := true
|
||||
coverageFailOnMinimum := true
|
||||
coverageMinimumStmtTotal := 85
|
||||
coverageMinimumBranchTotal := 100
|
||||
@@ -1 +0,0 @@
|
||||
sbt.version = 1.10.2
|
||||
@@ -1,3 +0,0 @@
|
||||
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.2.1")
|
||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.0")
|
||||
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.3.1")
|
||||
@@ -1,14 +1,12 @@
|
||||
package de.knockoutwhist
|
||||
|
||||
|
||||
import com.google.inject.{Guice, Inject, Injector}
|
||||
import de.knockoutwhist.components.{Configuration, DefaultConfiguration}
|
||||
import de.knockoutwhist.control.{ControlHandler, ControlThread}
|
||||
import com.google.inject.{Guice, Injector}
|
||||
import de.knockoutwhist.components.Configuration
|
||||
import de.knockoutwhist.control.ControlThread
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogic
|
||||
import de.knockoutwhist.di.KnockOutConfigurationModule
|
||||
import de.knockoutwhist.events.ui.GameState.MAIN_MENU
|
||||
import de.knockoutwhist.events.ui.GameStateUpdateEvent
|
||||
import de.knockoutwhist.ui.gui.GUIMain
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
import de.knockoutwhist.utils.events.EventListener
|
||||
|
||||
|
||||
object KnockOutWhist {
|
||||
@@ -17,19 +15,30 @@ object KnockOutWhist {
|
||||
Debug mode
|
||||
- Disables the random shuffle of the cards
|
||||
*/
|
||||
private val injector: Injector = Guice.createInjector(KnockOutConfigurationModule())
|
||||
val config: Configuration = injector.getInstance(classOf[Configuration])
|
||||
private[knockoutwhist] var DEBUG_MODE_VAR: Boolean = false
|
||||
|
||||
private var _config: Option[Configuration] = None
|
||||
|
||||
def config: Configuration = _config.get
|
||||
|
||||
def debugmode: Boolean = DEBUG_MODE_VAR
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
ControlThread.start()
|
||||
config.persistenceManager.loadManager()
|
||||
if(!TUIMain.initial) throw new IllegalStateException("TUI could not be started.")
|
||||
if(!GUIMain.initial) throw new IllegalStateException("GUI could not be started.")
|
||||
ControlThread.runLater {
|
||||
ControlHandler.invoke(GameStateUpdateEvent(MAIN_MENU))
|
||||
val injector: Injector = Guice.createInjector(KnockOutConfigurationModule())
|
||||
val config: Configuration = injector.getInstance(classOf[Configuration])
|
||||
entry(config)
|
||||
}
|
||||
|
||||
def entry(configuration: Configuration): Unit = {
|
||||
_config = Some(configuration)
|
||||
val baseLogic = BaseGameLogic(configuration)
|
||||
for (handler <- configuration.listener) baseLogic.addListener(handler)
|
||||
for (ui <- configuration.uis) {
|
||||
if (!ui.initial(baseLogic)) throw new IllegalStateException(s"${ui.getClass.getName} could not be started.")
|
||||
ui match {
|
||||
case eventListener: EventListener => baseLogic.addListener(eventListener)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
9
src/main/scala/de/knockoutwhist/Worksheet.sc
Normal file
9
src/main/scala/de/knockoutwhist/Worksheet.sc
Normal file
@@ -0,0 +1,9 @@
|
||||
//start from 0, stop at 9 inclusive
|
||||
for (i <- 0 until 10){
|
||||
println("Hi " + i)
|
||||
}
|
||||
|
||||
//or start from 0, stop at 9 inclusive
|
||||
for (i <- 0 to 9){
|
||||
println("Hi " + i)
|
||||
}
|
||||
@@ -33,4 +33,13 @@ end CardValue
|
||||
case class Card(cardValue: CardValue, suit: Suit) {
|
||||
|
||||
override def toString: String = s"$cardValue of $suit"
|
||||
|
||||
override def canEqual(that: Any): Boolean = that.isInstanceOf[Card]
|
||||
|
||||
override def equals(obj: Any): Boolean = obj match {
|
||||
case that: Card =>
|
||||
this.cardValue == that.cardValue &&
|
||||
this.suit == that.suit
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@ trait CardManager {
|
||||
|
||||
def nextCard(): Card
|
||||
|
||||
def remainingCards: Int = cardContainer.size - currentIndx
|
||||
|
||||
def removeCards(amount: Int): List[Card]
|
||||
|
||||
def createHand(amount: Int = 7): Hand
|
||||
|
||||
def grabSpecificCard(card: Card): Card
|
||||
|
||||
@@ -46,6 +46,14 @@ class CardBaseManager extends CardManager {
|
||||
}
|
||||
}
|
||||
|
||||
override def removeCards(amount: Int): List[Card] = {
|
||||
val removedCards = ListBuffer[Card]()
|
||||
for (_ <- 0 to amount) {
|
||||
removedCards += nextCard()
|
||||
}
|
||||
removedCards.toList
|
||||
}
|
||||
|
||||
override def createHand(amount: Int = 7): Hand = {
|
||||
val hand = ListBuffer[Card]()
|
||||
for (_ <- 1 to amount) {
|
||||
|
||||
@@ -11,6 +11,8 @@ object StubCardManager extends CardManager {
|
||||
|
||||
override def nextCard(): Card = Card(CardValue.Ace, Suit.Clubs)
|
||||
|
||||
override def removeCards(amount: Int): List[Card] = List(Card(CardValue.Ace, Suit.Clubs))
|
||||
|
||||
override def createHand(amount: Int): Hand = Hand(List(Card(CardValue.Ace, Suit.Clubs)))
|
||||
|
||||
override def grabSpecificCard(card: Card): Card = card
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
package de.knockoutwhist.components
|
||||
|
||||
import de.knockoutwhist.cards.CardManager
|
||||
import de.knockoutwhist.control.*
|
||||
import de.knockoutwhist.persistence.PersistenceManager
|
||||
import de.knockoutwhist.persistence.formats.FileFormatter
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.ui.UI
|
||||
import de.knockoutwhist.utils.CustomPlayerQueue
|
||||
import de.knockoutwhist.utils.events.EventListener
|
||||
|
||||
trait Configuration {
|
||||
def maincomponent: Maincomponent
|
||||
def matchcomponent: Matchcomponent
|
||||
def playeractrcomponent: Playeractrcomponent
|
||||
def playerlogcomponent: Playerlogcomponent
|
||||
def roundlogcomponent: Roundlogcomponent
|
||||
def trickcomponent: Tricklogcomponent
|
||||
def cardManager: CardManager
|
||||
def persistenceManager: PersistenceManager
|
||||
def fileFormatter: FileFormatter
|
||||
def uis: Set[UI]
|
||||
def listener: Set[EventListener]
|
||||
|
||||
def createRightQueue(players: Array[AbstractPlayer], start: Int = 0): CustomPlayerQueue[AbstractPlayer]
|
||||
|
||||
|
||||
@@ -2,29 +2,32 @@ package de.knockoutwhist.components
|
||||
|
||||
import com.google.inject.Guice
|
||||
import de.knockoutwhist.cards.CardManager
|
||||
import de.knockoutwhist.cards.base.CardBaseManager
|
||||
import de.knockoutwhist.control.*
|
||||
import de.knockoutwhist.control.controllerBaseImpl.*
|
||||
import de.knockoutwhist.di.KnockOutLogicModule
|
||||
import de.knockoutwhist.persistence.PersistenceManager
|
||||
import de.knockoutwhist.di.{KnockOutConfigurationModule, KnockOutLogicModule}
|
||||
import de.knockoutwhist.persistence.formats.FileFormatter
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.ui.UI
|
||||
import de.knockoutwhist.ui.gui.GUIMain
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
import de.knockoutwhist.utils
|
||||
import de.knockoutwhist.utils.CustomPlayerQueue
|
||||
import de.knockoutwhist.utils.baseQueue.{CustomPlayerBaseQueue, CustomPlayerQueueBuilder, QueueBuilder}
|
||||
import de.knockoutwhist.utils.baseQueue.QueueBuilder
|
||||
import de.knockoutwhist.utils.events.EventListener
|
||||
|
||||
object DefaultConfiguration extends Configuration {
|
||||
import scala.language.postfixOps
|
||||
|
||||
private val injector = Guice.createInjector(KnockOutLogicModule())
|
||||
class DefaultConfiguration extends Configuration {
|
||||
|
||||
def maincomponent: Maincomponent = injector.getInstance(classOf[Maincomponent])
|
||||
def matchcomponent: Matchcomponent = injector.getInstance(classOf[Matchcomponent])
|
||||
def playeractrcomponent: Playeractrcomponent = injector.getInstance(classOf[Playeractrcomponent])
|
||||
def playerlogcomponent: Playerlogcomponent = injector.getInstance(classOf[Playerlogcomponent])
|
||||
def roundlogcomponent: Roundlogcomponent = injector.getInstance(classOf[Roundlogcomponent])
|
||||
def trickcomponent: Tricklogcomponent = injector.getInstance(classOf[Tricklogcomponent])
|
||||
def cardManager: CardManager = injector.getInstance(classOf[CardManager])
|
||||
def persistenceManager: PersistenceManager = injector.getInstance(classOf[PersistenceManager])
|
||||
def fileFormatter: FileFormatter = injector.getInstance(classOf[FileFormatter])
|
||||
private val injector = Guice.createInjector(KnockOutLogicModule(), KnockOutConfigurationModule())
|
||||
|
||||
override def cardManager: CardManager = injector.getInstance(classOf[CardManager])
|
||||
override def fileFormatter: FileFormatter = injector.getInstance(classOf[FileFormatter])
|
||||
override def uis: Set[UI] = Set[UI](
|
||||
TUIMain(),
|
||||
GUIMain()
|
||||
)
|
||||
override def listener: Set[EventListener] = Set[EventListener](
|
||||
utils.DelayHandler
|
||||
)
|
||||
|
||||
override def createRightQueue(players: Array[AbstractPlayer], start: Int): CustomPlayerQueue[AbstractPlayer] = {
|
||||
val builder = injector.getInstance(classOf[QueueBuilder])
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.base.CardBaseManager
|
||||
import de.knockoutwhist.cards.{Card, Hand, Suit}
|
||||
import de.knockoutwhist.control.ControlHandler
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Round, Trick}
|
||||
|
||||
import scala.util.Random
|
||||
|
||||
case object AILogic {
|
||||
|
||||
def decideCard(ai: AbstractPlayer, round: Round, trick: Trick): Card = {
|
||||
if(trick.firstCard.isEmpty) return ai.currentHand().get.cards.maxBy(_.cardValue.ordinal)
|
||||
val firstCardSuit = trick.firstCard.get.suit
|
||||
val hand = ai.currentHand().get
|
||||
val cardsOfSuit = hand.cards.filter(_.suit == firstCardSuit)
|
||||
val trumpsInGame = trick.cards.keys.filter(_.suit == round.trumpSuit)
|
||||
if (cardsOfSuit.isEmpty) {
|
||||
val trumpCards = hand.cards.filter(_.suit == round.trumpSuit)
|
||||
if (trumpCards.isEmpty) hand.cards.minBy(_.cardValue.ordinal)
|
||||
else {
|
||||
val bestOption = decideWhichTrumpCard(hand, round, trick, trumpsInGame.toList)
|
||||
grabBestResult(bestOption, hand, round, trick)
|
||||
}
|
||||
} else {
|
||||
if(trumpsInGame.nonEmpty) cardsOfSuit.minBy(_.cardValue.ordinal)
|
||||
else cardsOfSuit.maxBy(_.cardValue.ordinal)
|
||||
}
|
||||
KnockOutWhist.config.cardManager.nextCard()
|
||||
}
|
||||
|
||||
|
||||
private def grabBestResult(bestOption: Option[Card], hand: Hand, round: Round, trick: Trick): Card = {
|
||||
bestOption match {
|
||||
case Some(card) => card
|
||||
case None =>
|
||||
val card = hand.cards.filter(_.suit != round.trumpSuit)
|
||||
if (card.isEmpty) hand.cards.minBy(_.cardValue.ordinal)
|
||||
else card.minBy(_.cardValue.ordinal)
|
||||
}
|
||||
}
|
||||
|
||||
private def decideWhichTrumpCard(hand: Hand, round: Round, trick: Trick, activeTrumps: List[Card]): Option[Card] = {
|
||||
val trumpCards = hand.cards.filter(_.suit == round.trumpSuit)
|
||||
if (round.playerQueue.size - trick.cards.size == 1 && activeTrumps.isEmpty) return Some(trumpCards.minBy(_.cardValue.ordinal))
|
||||
val highestTrump = trumpCards.maxBy(_.cardValue.ordinal)
|
||||
val activeTrump = activeTrumps.maxBy(_.cardValue.ordinal)
|
||||
if (highestTrump.cardValue.ordinal < activeTrump.cardValue.ordinal) None
|
||||
else {
|
||||
val higherTrumps = trumpCards.filter(_.cardValue.ordinal > activeTrump.cardValue.ordinal)
|
||||
if(round.playerQueue.size - trick.cards.size <= round.playersin.size * 0.5) Some(higherTrumps.minBy(_.cardValue.ordinal))
|
||||
else Some(highestTrump)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def decideTrumpSuit(ai: AbstractPlayer): Suit = {
|
||||
val hand = ai.currentHand().get
|
||||
hand.cards.groupBy(_.suit).maxBy(_._2.size)._1
|
||||
}
|
||||
|
||||
def decideTie(min: Int, max: Int): Int = {
|
||||
Random.between(min, max+1)
|
||||
}
|
||||
def decideDogCard(ai: AbstractPlayer, round: Round, trick: Trick, needstoplay: Boolean): Option[Card] = {
|
||||
val firstCardSuit = trick.firstCard.get.suit
|
||||
val hand = ai.currentHand().get
|
||||
val trumpsuit = round.trumpSuit
|
||||
val trumpsuitPlayed = trick.cards.keys.exists(_.suit == trumpsuit)
|
||||
if(needstoplay) {
|
||||
Some(hand.cards.head)
|
||||
} else if(trumpsuitPlayed) {
|
||||
sortbestcard(trick, trumpsuit, hand)
|
||||
} else {
|
||||
sortbestcard(trick, firstCardSuit, hand)
|
||||
}
|
||||
}
|
||||
|
||||
private def sortbestcard(trick: Trick, suit: Suit, hand: Hand): Option[Card] = {
|
||||
val highestCard = trick.cards.keys.filter(_.suit == suit).maxBy(_.cardValue.ordinal)
|
||||
if (hand.cards.head.suit == suit && hand.cards.head.cardValue.ordinal > highestCard.cardValue.ordinal) {
|
||||
return Some(hand.cards.head)
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.ui.gui.GUIMain
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
import de.knockoutwhist.utils.events.EventHandler
|
||||
import de.knockoutwhist.utils.{CustomThread, DelayHandler}
|
||||
|
||||
object ControlHandler extends EventHandler {
|
||||
|
||||
addListener(GUIMain)
|
||||
addListener(TUIMain)
|
||||
addListener(DelayHandler)
|
||||
|
||||
}
|
||||
|
||||
object ControlThread extends CustomThread {
|
||||
|
||||
setName("ControlThread")
|
||||
|
||||
def isControlThread: Boolean = Thread.currentThread().equals(ControlThread)
|
||||
|
||||
override def instance: CustomThread = ControlThread
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
object ControlThread {
|
||||
|
||||
def runLater[R](op: => R): Unit = {
|
||||
op
|
||||
}
|
||||
|
||||
}
|
||||
39
src/main/scala/de/knockoutwhist/control/GameLogic.scala
Normal file
39
src/main/scala/de/knockoutwhist/control/GameLogic.scala
Normal file
@@ -0,0 +1,39 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.RoundResult
|
||||
import de.knockoutwhist.control.sublogic.{PersistenceManager, PlayerInputLogic, PlayerTieLogic, UndoManager}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.CustomPlayerQueue
|
||||
import de.knockoutwhist.utils.events.EventHandler
|
||||
|
||||
trait GameLogic extends EventHandler with SnapshottingGameLogic {
|
||||
|
||||
def createSession(): Unit
|
||||
def endSession(): Unit
|
||||
def createMatch(players: List[AbstractPlayer]): Match
|
||||
def controlMatch(): Unit
|
||||
def controlPreRound(): Unit
|
||||
def controlRound(): Unit
|
||||
def endRound(winner: AbstractPlayer, roundResult: RoundResult): Match
|
||||
def controlTrick(): Unit
|
||||
def endTrick(): Round
|
||||
def controlPlayerPlay(): Unit
|
||||
def providePlayersWithCards(): Unit
|
||||
|
||||
def isWaitingForInput: Boolean
|
||||
|
||||
def playerInputLogic: PlayerInputLogic
|
||||
def playerTieLogic: PlayerTieLogic
|
||||
def undoManager: UndoManager
|
||||
def persistenceManager: PersistenceManager
|
||||
|
||||
def getCurrentState: GameState
|
||||
def getCurrentMatch: Option[Match]
|
||||
def getCurrentRound: Option[Round]
|
||||
def getCurrentTrick: Option[Trick]
|
||||
def getCurrentPlayer: Option[AbstractPlayer]
|
||||
def getTrumpPlayer: Option[AbstractPlayer]
|
||||
def getPlayerQueue: Option[CustomPlayerQueue[AbstractPlayer]]
|
||||
|
||||
}
|
||||
12
src/main/scala/de/knockoutwhist/control/GameState.scala
Normal file
12
src/main/scala/de/knockoutwhist/control/GameState.scala
Normal file
@@ -0,0 +1,12 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
enum GameState {
|
||||
|
||||
case MainMenu
|
||||
case Lobby
|
||||
case InGame
|
||||
case SelectTrump
|
||||
case TieBreak
|
||||
case FinishedMatch
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
trait Maincomponent {
|
||||
|
||||
def startMatch(): Unit
|
||||
|
||||
def enteredPlayers(players: List[AbstractPlayer]): Unit
|
||||
|
||||
def controlMatch(matchImpl: Match): Unit
|
||||
|
||||
def controlRound(matchImpl: Match, round: Round): Unit
|
||||
|
||||
def endRound(matchImpl: Match, round: Round, winner: AbstractPlayer, playersOut: List[AbstractPlayer]): Unit
|
||||
|
||||
def controlTrick(matchImpl: Match, round: Round, trick: Trick, currentIndex: Int = 0): Unit
|
||||
|
||||
def controlPlayer(matchImpl: Match, round: Round, trick: Trick, player: AbstractPlayer, currentIndex: Int): Unit
|
||||
|
||||
def playCard(trick: Trick, card: Card, player: AbstractPlayer): Trick
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.rounds.Match
|
||||
|
||||
trait Matchcomponent {
|
||||
|
||||
def isOver(matchImpl: Match): Boolean
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
trait Playeractrcomponent {
|
||||
|
||||
def playCard(matchImpl: Match, player: AbstractPlayer, round: Round, trick: Trick, currentIndex: Int): Unit
|
||||
|
||||
|
||||
def dogplayCard(matchImpl: Match, player: AbstractPlayer, round: Round, trick: Trick, currentIndex: Int): Unit
|
||||
|
||||
|
||||
def pickNextTrumpsuit(matchImpl: Match, remaining_players: List[AbstractPlayer], firstRound: Boolean, player: AbstractPlayer): Unit
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Suit}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round}
|
||||
|
||||
import scala.collection.immutable
|
||||
import scala.util.Try
|
||||
|
||||
trait Playerlogcomponent {
|
||||
|
||||
def trumpsuitStep(matchImpl: Match, remaining_players: List[AbstractPlayer]): Unit
|
||||
|
||||
def trumpSuitSelected(matchImpl: Match, suit: Try[Suit], remaining_players: List[AbstractPlayer], firstRound: Boolean, decided: AbstractPlayer): Unit
|
||||
|
||||
def preSelect(winners: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer]): Unit
|
||||
|
||||
def selectTie(winners: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit
|
||||
|
||||
def selectedTie(winner: List[AbstractPlayer],matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], value: Try[Int], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit
|
||||
|
||||
def evaluateTieWinner(matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card]): Unit
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round}
|
||||
|
||||
trait Roundlogcomponent {
|
||||
|
||||
def isOver(round: Round): Boolean
|
||||
|
||||
def dogNeedsToPlay(round: Round): Boolean
|
||||
|
||||
def finalizeRound(round: Round, matchImpl: Match, force: Boolean = false): (Match, Round, List[AbstractPlayer], List[AbstractPlayer])
|
||||
|
||||
def remainingPlayers(round: Round): List[AbstractPlayer]
|
||||
|
||||
def provideCards(matchImpl: Match, players: List[AbstractPlayer]): (Match,List[AbstractPlayer])
|
||||
|
||||
def smashResults(round: Round): Round
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
trait SnapshottingGameLogic {
|
||||
|
||||
def createSnapshot(): LogicSnapshot[this.type]
|
||||
|
||||
}
|
||||
|
||||
trait LogicSnapshot[T <: SnapshottingGameLogic] {
|
||||
|
||||
def restore(logic: T): Unit
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
trait Tricklogcomponent {
|
||||
|
||||
def controlSuitplayed(card: Try[Card], matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer): Unit
|
||||
|
||||
def controlDogPlayed(card: Try[Option[Card]], matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer): Unit
|
||||
|
||||
def alternativeCards(card: Card, round: Round, trick: Trick, player: AbstractPlayer): List[Card]
|
||||
|
||||
def wonTrick(trick: Trick, round: Round): (AbstractPlayer, Trick)
|
||||
}
|
||||
@@ -0,0 +1,426 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl
|
||||
|
||||
import de.knockoutwhist.cards.{Card, CardManager}
|
||||
import de.knockoutwhist.components.Configuration
|
||||
import de.knockoutwhist.control.GameState.*
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.{MatchUtil, RoundResult, RoundUtil, TrickUtil}
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.{BasePersistenceManager, BasePlayerInputLogic, BasePlayerTieLogic, BaseUndoManager}
|
||||
import de.knockoutwhist.control.sublogic.{PersistenceManager, PlayerInputLogic, PlayerTieLogic}
|
||||
import de.knockoutwhist.control.{GameLogic, GameState, LogicSnapshot}
|
||||
import de.knockoutwhist.events.global.*
|
||||
import de.knockoutwhist.events.global.tie.TieEvent
|
||||
import de.knockoutwhist.events.player.ReceivedHandEvent
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.persistence.MethodEntryPoint.{ControlMatch, ControlRound}
|
||||
import de.knockoutwhist.player.{AbstractPlayer, PlayerData}
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.CustomPlayerQueue
|
||||
import de.knockoutwhist.utils.events.EventHandler
|
||||
|
||||
import java.util.UUID
|
||||
import scala.util.Random
|
||||
|
||||
/*
|
||||
Main game logic controller
|
||||
*/
|
||||
final class BaseGameLogic(val config: Configuration) extends EventHandler with GameLogic {
|
||||
//Constants
|
||||
val ID: UUID = UUID.randomUUID()
|
||||
|
||||
//Logics
|
||||
val playerTieLogic: PlayerTieLogic = BasePlayerTieLogic(this)
|
||||
val playerInputLogic: PlayerInputLogic = BasePlayerInputLogic(this)
|
||||
val undoManager: BaseUndoManager = BaseUndoManager(this)
|
||||
val persistenceManager: PersistenceManager = BasePersistenceManager(this)
|
||||
|
||||
//Game State
|
||||
private[control] var state: GameState = GameState.MainMenu
|
||||
|
||||
//Variables
|
||||
private[control] var cardManager: Option[CardManager] = Some(config.cardManager)
|
||||
|
||||
private[control] var currentMatch: Option[Match] = None
|
||||
private[control] var currentRound: Option[Round] = None
|
||||
private[control] var currentTrick: Option[Trick] = None
|
||||
private[control] var currentPlayer: Option[AbstractPlayer] = None
|
||||
private[control] var playerQueue: Option[CustomPlayerQueue[AbstractPlayer]] = None
|
||||
|
||||
override def createSession(): Unit = {
|
||||
cardManager = Some(config.cardManager)
|
||||
|
||||
currentMatch = None
|
||||
currentRound = None
|
||||
currentTrick = None
|
||||
currentPlayer = None
|
||||
playerQueue = None
|
||||
invoke(GameStateChangeEvent(state, Lobby))
|
||||
state = Lobby
|
||||
}
|
||||
|
||||
override def createMatch(players: List[AbstractPlayer]): Match = {
|
||||
val matchImpl = Match(totalplayers = players, playersIn = players)
|
||||
currentMatch = Some(matchImpl)
|
||||
matchImpl
|
||||
}
|
||||
|
||||
override def controlMatch(): Unit = {
|
||||
if (currentMatch.isEmpty) throw new IllegalStateException("No current match set")
|
||||
val matchImpl = currentMatch.get
|
||||
|
||||
persistenceManager.update(ControlMatch)
|
||||
|
||||
if (matchImpl.isOver) {
|
||||
//Winner is the last person in the playersIn list
|
||||
val winner = matchImpl.playersIn.head
|
||||
|
||||
invoke(GameStateChangeEvent(state, FinishedMatch))
|
||||
state = FinishedMatch
|
||||
invoke(MatchEndEvent(winner))
|
||||
} else {
|
||||
if (matchImpl.roundlist.isEmpty) {
|
||||
if (cardManager.isEmpty) throw new IllegalStateException("No card manager set")
|
||||
val cardManagerImpl = cardManager.get
|
||||
val firstCard = cardManagerImpl.nextCard()
|
||||
val newRound = RoundUtil.createRound(firstCard.suit, true)
|
||||
|
||||
providePlayersWithCards()
|
||||
|
||||
val randomPlayer: Int = 1//Random.nextInt(matchImpl.playersIn.size)
|
||||
playerQueue = Some(config.createRightQueue(matchImpl.playersIn.toArray, randomPlayer))
|
||||
|
||||
matchImpl.playersIn.foreach(player => {invoke(ReceivedHandEvent(player))})
|
||||
|
||||
currentRound = Some(newRound)
|
||||
|
||||
invoke(NewRoundEvent())
|
||||
invoke(DelayEvent(500))
|
||||
|
||||
controlRound()
|
||||
return
|
||||
}
|
||||
currentMatch = Some(matchImpl.setNumberOfCards(matchImpl.numberofcards - 1))
|
||||
providePlayersWithCards()
|
||||
|
||||
matchImpl.playersIn.foreach(player => {invoke(ReceivedHandEvent(player))})
|
||||
|
||||
controlPreRound()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
override def controlPreRound(): Unit = {
|
||||
if (currentMatch.isEmpty) throw new IllegalStateException("No current match set")
|
||||
val matchImpl = currentMatch.get
|
||||
//Check if the last round had a winner
|
||||
val lastWinner = getTrumpPlayer
|
||||
if (lastWinner.isEmpty) throw new IllegalStateException("No last round winner found")
|
||||
|
||||
//Create new player queue starting with last round winner
|
||||
|
||||
playerQueue = Some(config.createRightQueue(
|
||||
matchImpl.playersIn.toArray,
|
||||
matchImpl.playersIn.indexOf(lastWinner.get)
|
||||
))
|
||||
|
||||
invoke(GameStateChangeEvent(state, SelectTrump))
|
||||
state = SelectTrump
|
||||
|
||||
invoke(TrumpSelectEvent(lastWinner.get))
|
||||
|
||||
playerInputLogic.requestTrumpSuit(lastWinner.get)
|
||||
}
|
||||
|
||||
override def controlRound(): Unit = {
|
||||
if (state != InGame)
|
||||
invoke(GameStateChangeEvent(state, InGame))
|
||||
state = InGame
|
||||
if (currentMatch.isEmpty) throw new IllegalStateException("No current match set")
|
||||
val matchImpl = currentMatch.get
|
||||
if (currentRound.isEmpty) throw new IllegalStateException("No current round set")
|
||||
val roundImpl = currentRound.get
|
||||
|
||||
persistenceManager.update(ControlRound)
|
||||
|
||||
if (MatchUtil.isRoundOver(matchImpl, roundImpl)) {
|
||||
val roundResult: RoundResult = RoundUtil.finishRound(roundImpl, matchImpl)
|
||||
if (roundResult.isTie) {
|
||||
invoke(GameStateChangeEvent(state, TieBreak))
|
||||
state = TieBreak
|
||||
|
||||
invoke(TieEvent(roundResult.winners))
|
||||
invoke(DelayEvent(2000))
|
||||
|
||||
playerTieLogic.handleTie(roundResult)
|
||||
return
|
||||
}
|
||||
val newMatch = endRound(roundResult.winners.head, roundResult)
|
||||
currentMatch = Some(newMatch)
|
||||
controlMatch()
|
||||
} else {
|
||||
|
||||
invoke(NewTrickEvent())
|
||||
invoke(DelayEvent(1000))
|
||||
|
||||
val trick = Trick()
|
||||
currentTrick = Some(trick)
|
||||
controlTrick()
|
||||
}
|
||||
}
|
||||
|
||||
override def endRound(winner: AbstractPlayer, roundResult: RoundResult): Match = {
|
||||
if (currentMatch.isEmpty) throw new IllegalStateException("No current match set")
|
||||
var matchImpl = currentMatch.get
|
||||
if (currentRound.isEmpty) throw new IllegalStateException("No current round set")
|
||||
val roundImpl = currentRound.get
|
||||
//Create final round snapshot
|
||||
val resultingRound = Round(
|
||||
trumpSuit = roundImpl.trumpSuit,
|
||||
firstRound = roundImpl.firstRound,
|
||||
tricklist = roundImpl.tricklist,
|
||||
winner = Some(winner)
|
||||
)
|
||||
|
||||
invoke(RoundEndEvent(winner, roundResult.tricked.filter(
|
||||
rp => rp.player == winner
|
||||
).map(rp => rp.amountOfTricks).sum))
|
||||
invoke(DelayEvent(2000))
|
||||
|
||||
if (roundResult.notTricked.nonEmpty && !roundImpl.firstRound) {
|
||||
if (matchImpl.dogLife) {
|
||||
invoke(ShowPlayersOutEvent(roundResult.notTricked))
|
||||
invoke(DelayEvent(2000))
|
||||
matchImpl = matchImpl.updatePlayersIn(matchImpl.playersIn.filterNot(roundResult.notTricked.contains(_)))
|
||||
} else {
|
||||
invoke(ShowDogsEvent(roundResult.notTricked))
|
||||
invoke(DelayEvent(2000))
|
||||
matchImpl = matchImpl.setDogLife()
|
||||
// Make players dogs
|
||||
roundResult.notTricked.foreach(player => {
|
||||
player.setDogLife()
|
||||
})
|
||||
}
|
||||
}
|
||||
roundResult.tricked.foreach(player => {
|
||||
player.player.resetDogLife()
|
||||
})
|
||||
matchImpl.addRound(resultingRound)
|
||||
}
|
||||
|
||||
override def controlTrick(): Unit = {
|
||||
if (currentMatch.isEmpty) throw new IllegalStateException("No current match set")
|
||||
val matchImpl = currentMatch.get
|
||||
if (playerQueue.isEmpty) throw new IllegalStateException("No player queue set")
|
||||
val queueImpl = playerQueue.get
|
||||
if (currentTrick.isEmpty) throw new IllegalStateException("No current trick set")
|
||||
val trickImpl = currentTrick.get
|
||||
|
||||
persistenceManager.update(ControlRound)
|
||||
|
||||
if (TrickUtil.isOver(matchImpl, queueImpl)) {
|
||||
val newRound = endTrick()
|
||||
if (newRound.tricklist.isEmpty || newRound.tricklist.last.winner.isEmpty) throw new IllegalStateException("Trick has no winner after ending trick")
|
||||
val winner = newRound.tricklist.last.winner.get
|
||||
currentRound = Some(newRound)
|
||||
|
||||
invoke(TrickEndEvent(winner))
|
||||
invoke(DelayEvent(2000))
|
||||
|
||||
queueImpl.resetAndSetStart(winner)
|
||||
controlRound()
|
||||
} else {
|
||||
val playerImpl = queueImpl.nextPlayer()
|
||||
currentPlayer = Some(playerImpl)
|
||||
controlPlayerPlay()
|
||||
}
|
||||
}
|
||||
|
||||
override def endTrick(): Round = {
|
||||
if (currentTrick.isEmpty) throw new IllegalStateException("No current trick set")
|
||||
val trickImpl = currentTrick.get
|
||||
if (currentRound.isEmpty) throw new IllegalStateException("No current round set")
|
||||
val roundImpl = currentRound.get
|
||||
val resultTrick = TrickUtil.finishTrick(trickImpl, roundImpl)
|
||||
val resultingTrick = Trick(
|
||||
cards = trickImpl.cards,
|
||||
winner = Some(resultTrick.winner),
|
||||
firstCard = trickImpl.firstCard
|
||||
)
|
||||
roundImpl.addTrick(resultingTrick)
|
||||
}
|
||||
|
||||
override def controlPlayerPlay(): Unit = {
|
||||
if (currentPlayer.isEmpty) throw new IllegalStateException("No current player set")
|
||||
val playerImpl = currentPlayer.get
|
||||
if (playerImpl.currentHand().isEmpty) {
|
||||
controlTrick()
|
||||
return
|
||||
}
|
||||
val handImpl = playerImpl.currentHand().get
|
||||
if (handImpl.cards.isEmpty) {
|
||||
controlTrick()
|
||||
return
|
||||
}
|
||||
invoke(TurnEvent(playerImpl))
|
||||
playerInputLogic.requestCard(playerImpl)
|
||||
}
|
||||
|
||||
override def isWaitingForInput: Boolean = {
|
||||
if (state == InGame || state == SelectTrump) {
|
||||
playerInputLogic.isWaitingForInput
|
||||
} else if (state == TieBreak) {
|
||||
playerTieLogic.isWaitingForInput
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
override def providePlayersWithCards(): Unit = {
|
||||
if (currentMatch.isEmpty) throw new IllegalStateException("No current match set")
|
||||
val matchImpl = currentMatch.get
|
||||
if (cardManager.isEmpty) throw new IllegalStateException("No card manager set")
|
||||
val cardManagerImpl = cardManager.get
|
||||
|
||||
cardManagerImpl.shuffleAndReset()
|
||||
|
||||
val handSize = matchImpl.numberofcards
|
||||
|
||||
matchImpl.playersIn.foreach(player => {
|
||||
val hand = if (!player.isInDogLife) {
|
||||
cardManagerImpl.createHand(handSize)
|
||||
} else {
|
||||
cardManagerImpl.createHand(1)
|
||||
}
|
||||
player.provideHand(hand)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Getters
|
||||
|
||||
override def getCurrentState: GameState = state
|
||||
override def getCurrentMatch: Option[Match] = currentMatch
|
||||
override def getCurrentRound: Option[Round] = currentRound
|
||||
override def getCurrentTrick: Option[Trick] = currentTrick
|
||||
override def getCurrentPlayer: Option[AbstractPlayer] = currentPlayer
|
||||
override def getPlayerQueue: Option[CustomPlayerQueue[AbstractPlayer]] = playerQueue
|
||||
|
||||
override def getTrumpPlayer: Option[AbstractPlayer] = {
|
||||
if (currentMatch.isEmpty) throw new IllegalStateException("No current match set")
|
||||
val matchImpl = currentMatch.get
|
||||
if (matchImpl.roundlist.isEmpty) return None
|
||||
val roundImpl = matchImpl.roundlist.last
|
||||
if (roundImpl.winner.isEmpty) return None
|
||||
Some(roundImpl.winner.get)
|
||||
}
|
||||
//Snapshotting
|
||||
|
||||
override def createSnapshot(): LogicSnapshot[BaseGameLogic.this.type] = {
|
||||
BaseGameLogicSnapshot(this).asInstanceOf[LogicSnapshot[BaseGameLogic.this.type]]
|
||||
}
|
||||
|
||||
override def endSession(): Unit = {
|
||||
cardManager = None
|
||||
currentMatch = None
|
||||
currentRound = None
|
||||
currentTrick = None
|
||||
currentPlayer = None
|
||||
playerQueue = None
|
||||
invoke(SessionClosed())
|
||||
invoke(GameStateChangeEvent(state, MainMenu))
|
||||
state = MainMenu
|
||||
}
|
||||
}
|
||||
|
||||
class BaseGameLogicSnapshot(
|
||||
val savedState: GameState,
|
||||
//Card Manager
|
||||
val cardContainer: Option[List[Card]],
|
||||
val cardIndex: Option[Int],
|
||||
|
||||
val currentMatch: Option[Match],
|
||||
val currentRound: Option[Round],
|
||||
val currentTrick: Option[Trick],
|
||||
val currentPlayer: Option[AbstractPlayer],
|
||||
|
||||
//Custom Player Queue
|
||||
val playerIndex: Option[Int],
|
||||
val players: Option[List[AbstractPlayer]],
|
||||
|
||||
val playerStates: Map[UUID, PlayerData]
|
||||
|
||||
) extends LogicSnapshot[BaseGameLogic] {
|
||||
|
||||
def this(gameLogic: BaseGameLogic) = {
|
||||
this(
|
||||
gameLogic.state,
|
||||
|
||||
gameLogic.cardManager.map(cm => cm.cardContainer),
|
||||
gameLogic.cardManager.map(cm => cm.currentIndx),
|
||||
|
||||
gameLogic.currentMatch,
|
||||
gameLogic.currentRound,
|
||||
gameLogic.currentTrick,
|
||||
gameLogic.currentPlayer,
|
||||
|
||||
gameLogic.playerQueue.map(pq => pq.currentIndex),
|
||||
gameLogic.playerQueue.map(pq => pq.duplicate().toList),
|
||||
|
||||
gameLogic.currentMatch match {
|
||||
case Some(m) => m.totalplayers.map(p => (p.id, p.generatePlayerData())).toMap
|
||||
case None => Map.empty[UUID, PlayerData]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override def restore(logic: BaseGameLogic): Unit = {
|
||||
logic.state = savedState
|
||||
|
||||
//Card Manager
|
||||
if (logic.cardManager.isDefined) {
|
||||
val cardManagerImpl = logic.cardManager.get
|
||||
if (cardContainer.isDefined && cardIndex.isDefined)
|
||||
cardManagerImpl.setState(cardContainer.get, cardIndex.get)
|
||||
} else {
|
||||
if (cardContainer.isDefined && cardIndex.isDefined) {
|
||||
val newCardManager = logic.config.cardManager
|
||||
newCardManager.setState(cardContainer.get, cardIndex.get)
|
||||
logic.cardManager = Some(newCardManager)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logic.currentMatch = currentMatch
|
||||
logic.currentRound = currentRound
|
||||
logic.currentTrick = currentTrick
|
||||
logic.currentPlayer = currentPlayer
|
||||
|
||||
//Custom Player Queue
|
||||
if (logic.playerQueue.isDefined) {
|
||||
if (players.isDefined && playerIndex.isDefined)
|
||||
logic.playerQueue = Some(logic.config.createRightQueue(
|
||||
players.get.toArray,
|
||||
playerIndex.get
|
||||
))
|
||||
} else {
|
||||
if (players.isDefined && playerIndex.isDefined)
|
||||
logic.playerQueue = Some(logic.config.createRightQueue(
|
||||
players.get.toArray,
|
||||
playerIndex.get
|
||||
))
|
||||
}
|
||||
|
||||
//Player States
|
||||
logic.currentMatch match {
|
||||
case Some(m) =>
|
||||
m.totalplayers.foreach(player => {
|
||||
val dataOpt = playerStates.get(player.id)
|
||||
if (dataOpt.isDefined)
|
||||
player.receivePlayerData(dataOpt.get)
|
||||
})
|
||||
case None => //Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.control.*
|
||||
import de.knockoutwhist.events.GLOBAL_STATUS.SHOW_FINISHED_MATCH
|
||||
import de.knockoutwhist.events.PLAYER_STATUS.SHOW_WON_PLAYER_TRICK
|
||||
import de.knockoutwhist.events.ROUND_STATUS.{PLAYERS_OUT, WON_ROUND}
|
||||
import de.knockoutwhist.events.round.ShowCurrentTrickEvent
|
||||
import de.knockoutwhist.events.ui.GameState.{MAIN_MENU, PLAYERS, TIE}
|
||||
import de.knockoutwhist.events.ui.GameStateUpdateEvent
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.events.{ShowGlobalStatus, ShowPlayerStatus, ShowRoundStatus}
|
||||
import de.knockoutwhist.persistence.MethodEntryPoint.{ControlMatch, ControlRound, ControlTrick}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.undo.UndoManager
|
||||
import de.knockoutwhist.undo.commands.EnterPlayersCommand
|
||||
import de.knockoutwhist.utils.Implicits.*
|
||||
|
||||
object MainLogic extends Maincomponent {
|
||||
|
||||
def startMatch(): Unit = {
|
||||
ControlHandler.invoke(GameStateUpdateEvent(PLAYERS))
|
||||
}
|
||||
|
||||
def enteredPlayers(players: List[AbstractPlayer]): Unit = {
|
||||
UndoManager.doStep(EnterPlayersCommand(players))
|
||||
}
|
||||
|
||||
def controlMatch(matchImpl: Match): Unit = {
|
||||
KnockOutWhist.config.persistenceManager.updateMatch(matchImpl)
|
||||
KnockOutWhist.config.persistenceManager.updateMethodEntryPoint(ControlMatch)
|
||||
if(KnockOutWhist.config.matchcomponent.isOver(matchImpl)) {
|
||||
ControlHandler.invoke(ShowGlobalStatus(SHOW_FINISHED_MATCH, KnockOutWhist.config.roundlogcomponent.remainingPlayers(matchImpl.roundlist.last).head))
|
||||
//ControlHandler.invoke(GameStateUpdateEvent(MAIN_MENU))
|
||||
} else {
|
||||
val remainingPlayer = matchImpl.roundlist.isEmpty ? matchImpl.totalplayers |: KnockOutWhist.config.roundlogcomponent.remainingPlayers(matchImpl.roundlist.last)
|
||||
val newMatch = KnockOutWhist.config.roundlogcomponent.provideCards(matchImpl, remainingPlayer)
|
||||
KnockOutWhist.config.playerlogcomponent.trumpsuitStep(newMatch._1, newMatch._2)
|
||||
}
|
||||
}
|
||||
|
||||
def controlRound(matchImpl: Match, round: Round): Unit = {
|
||||
KnockOutWhist.config.persistenceManager.updateMatch(matchImpl)
|
||||
KnockOutWhist.config.persistenceManager.updateRound(round)
|
||||
KnockOutWhist.config.persistenceManager.updateMethodEntryPoint(ControlRound)
|
||||
if(!KnockOutWhist.config.roundlogcomponent.isOver(round)) {
|
||||
val trick = Trick()
|
||||
controlTrick(matchImpl, round, trick)
|
||||
return
|
||||
}
|
||||
val result = KnockOutWhist.config.roundlogcomponent.finalizeRound(KnockOutWhist.config.roundlogcomponent.smashResults(round), matchImpl)
|
||||
if(result._3.size == 1) {
|
||||
endRound(result._1, result._2, result._3.head, result._4)
|
||||
} else {
|
||||
KnockOutWhist.config.playerlogcomponent.preSelect(result._3, result._1, result._2, result._4)
|
||||
}
|
||||
}
|
||||
|
||||
def endRound(matchImpl: Match, round: Round, winner: AbstractPlayer, playersOut: List[AbstractPlayer]): Unit = {
|
||||
val finalRound = Round(round.trumpSuit, round.tricklist, round.playersin, playersOut, round.startingPlayer, winner, firstRound = round.firstRound)
|
||||
val newMatch = matchImpl.addRound(finalRound)
|
||||
ControlHandler.invoke(ShowRoundStatus(WON_ROUND, finalRound, winner))
|
||||
ControlHandler.invoke(DelayEvent(2000L))
|
||||
if (finalRound.playersout.nonEmpty) {
|
||||
ControlHandler.invoke(ShowRoundStatus(PLAYERS_OUT, finalRound))
|
||||
}
|
||||
controlMatch(newMatch)
|
||||
}
|
||||
|
||||
def controlTrick(matchImpl: Match, round: Round, trick: Trick, currentIndex: Int = 0): Unit = {
|
||||
KnockOutWhist.config.persistenceManager.updateMatch(matchImpl)
|
||||
KnockOutWhist.config.persistenceManager.updateRound(round)
|
||||
KnockOutWhist.config.persistenceManager.updateTrick(trick)
|
||||
KnockOutWhist.config.persistenceManager.updateCurrentIndex(currentIndex)
|
||||
KnockOutWhist.config.persistenceManager.updateMethodEntryPoint(ControlTrick)
|
||||
if(currentIndex < round.playersin.size) {
|
||||
val player = round.playerQueue.nextPlayer()
|
||||
controlPlayer(matchImpl, round, trick, player, currentIndex)
|
||||
}else {
|
||||
val result = KnockOutWhist.config.trickcomponent.wonTrick(trick, round)
|
||||
val newRound = round.addTrick(result._2)
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_WON_PLAYER_TRICK, result._1, result._2))
|
||||
newRound.playerQueue.resetAndSetStart(result._1)
|
||||
ControlHandler.invoke(DelayEvent(1000L))
|
||||
controlRound(matchImpl, newRound)
|
||||
}
|
||||
}
|
||||
|
||||
def controlPlayer(matchImpl: Match, round: Round, trick: Trick, player: AbstractPlayer, currentIndex: Int): Unit = {
|
||||
ControlHandler.invoke(ShowCurrentTrickEvent(round, trick))
|
||||
if (!player.doglife) {
|
||||
KnockOutWhist.config.playeractrcomponent.playCard(matchImpl, player, round, trick, currentIndex)
|
||||
} else if (player.currentHand().exists(_.cards.nonEmpty)) {
|
||||
KnockOutWhist.config.playeractrcomponent.dogplayCard(matchImpl, player, round, trick, currentIndex)
|
||||
}else {
|
||||
controlTrick(matchImpl, round, trick, currentIndex+1)
|
||||
}
|
||||
}
|
||||
|
||||
def playCard(trick: Trick, card: Card, player: AbstractPlayer): Trick = {
|
||||
if (trick.firstCard.isEmpty) {
|
||||
trick.setfirstcard(card).addCard(card, player)
|
||||
} else {
|
||||
trick.addCard(card, player)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.control.{ControlHandler, Matchcomponent}
|
||||
import de.knockoutwhist.rounds.Match
|
||||
|
||||
object MatchLogic extends Matchcomponent {
|
||||
def isOver(matchImpl: Match): Boolean = {
|
||||
if (matchImpl.roundlist.isEmpty) {
|
||||
false
|
||||
} else {
|
||||
KnockOutWhist.config.roundlogcomponent.remainingPlayers(matchImpl.roundlist.last).size == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.control.{ControlHandler, Playeractrcomponent}
|
||||
import de.knockoutwhist.events.PLAYER_STATUS.*
|
||||
import de.knockoutwhist.events.ShowPlayerStatus
|
||||
import de.knockoutwhist.events.cards.RenderHandEvent
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
object PlayerControl extends Playeractrcomponent {
|
||||
|
||||
|
||||
def playCard(matchImpl: Match, player: AbstractPlayer, round: Round, trick: Trick, currentIndex: Int): Unit = {
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_TURN, player))
|
||||
ControlHandler.invoke(DelayEvent(500))
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_PLAY_CARD, player))
|
||||
ControlHandler.invoke(RenderHandEvent(player.currentHand().get, true))
|
||||
player.handlePlayCard(player.currentHand().get, matchImpl, round, trick, currentIndex)
|
||||
}
|
||||
|
||||
def dogplayCard(matchImpl: Match, player: AbstractPlayer, round: Round, trick: Trick, currentIndex: Int): Unit = {
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_TURN, player))
|
||||
ControlHandler.invoke(DelayEvent(500))
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_DOG_PLAY_CARD, player, KnockOutWhist.config.roundlogcomponent.dogNeedsToPlay(round)))
|
||||
ControlHandler.invoke(RenderHandEvent(player.currentHand().get, false))
|
||||
player.handleDogPlayCard(player.currentHand().get, matchImpl, round, trick, currentIndex, KnockOutWhist.config.roundlogcomponent.dogNeedsToPlay(round))
|
||||
}
|
||||
|
||||
def pickNextTrumpsuit(matchImpl: Match, remaining_players: List[AbstractPlayer], firstRound: Boolean, player: AbstractPlayer): Unit = {
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_TRUMPSUIT_OPTIONS, player))
|
||||
ControlHandler.invoke(RenderHandEvent(player.currentHand().get, false))
|
||||
player.handlePickTrumpsuit(matchImpl, remaining_players, firstRound)
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.{Card, Suit}
|
||||
import de.knockoutwhist.control.{ControlHandler, Playerlogcomponent}
|
||||
import de.knockoutwhist.events.ERROR_STATUS.{INVALID_NUMBER, NOT_A_NUMBER}
|
||||
import de.knockoutwhist.events.GLOBAL_STATUS.{SHOW_TIE, SHOW_TIE_TIE, SHOW_TIE_WINNER}
|
||||
import de.knockoutwhist.events.PLAYER_STATUS.SHOW_TIE_NUMBERS
|
||||
import de.knockoutwhist.events.cards.ShowTieCardsEvent
|
||||
import de.knockoutwhist.events.ui.GameState.{INGAME, TIE}
|
||||
import de.knockoutwhist.events.ui.GameStateUpdateEvent
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.events.{ShowErrorStatus, ShowGlobalStatus, ShowPlayerStatus}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round}
|
||||
import de.knockoutwhist.ui.gui.TieMenu
|
||||
import de.knockoutwhist.undo.UndoManager
|
||||
import de.knockoutwhist.undo.commands.{SelectTieCommand, TrumpSuitSelectedCommand}
|
||||
|
||||
import scala.collection.immutable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.util.Try
|
||||
|
||||
object PlayerLogic extends Playerlogcomponent {
|
||||
|
||||
def trumpsuitStep(matchImpl: Match, remaining_players: List[AbstractPlayer]): Unit = {
|
||||
if (matchImpl.roundlist.isEmpty) {
|
||||
val randomTrumpsuit = matchImpl.cardManager.nextCard().suit
|
||||
val newMatchImpl = matchImpl.setNumberOfCards(matchImpl.numberofcards - 1)
|
||||
val round = new Round(randomTrumpsuit, remaining_players, true)
|
||||
KnockOutWhist.config.maincomponent.controlRound(newMatchImpl, round)
|
||||
} else {
|
||||
val winner = matchImpl.totalplayers.filter(matchImpl.roundlist.last.winner.name == _.name).head
|
||||
KnockOutWhist.config.playeractrcomponent.pickNextTrumpsuit(matchImpl, remaining_players, false, winner)
|
||||
}
|
||||
}
|
||||
|
||||
def trumpSuitSelected(matchImpl: Match, suit: Try[Suit], remaining_players: List[AbstractPlayer], firstRound: Boolean, decided: AbstractPlayer): Unit = {
|
||||
if (suit.isFailure) {
|
||||
ControlHandler.invoke(ShowErrorStatus(INVALID_NUMBER))
|
||||
KnockOutWhist.config.playeractrcomponent.pickNextTrumpsuit(matchImpl, remaining_players, firstRound, decided)
|
||||
return
|
||||
}
|
||||
ControlHandler.invoke(GameStateUpdateEvent(INGAME))
|
||||
UndoManager.doStep(TrumpSuitSelectedCommand(matchImpl, suit.get, remaining_players, false, decided))
|
||||
}
|
||||
|
||||
def preSelect(winners: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer]): Unit = {
|
||||
if (!KnockOutWhist.debugmode) matchImpl.cardManager.shuffleAndReset()
|
||||
ControlHandler.invoke(ShowGlobalStatus(SHOW_TIE))
|
||||
ControlHandler.invoke(GameStateUpdateEvent(TIE))
|
||||
selectTie(winners, matchImpl, round, playersout, immutable.HashMap(), 0, matchImpl.cardManager.cardContainer.size - (winners.length - 1))
|
||||
}
|
||||
|
||||
def selectTie(winners: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit = {
|
||||
ControlHandler.invoke(GameStateUpdateEvent(TIE))
|
||||
if(currentIndex == winners.size) {
|
||||
evaluateTieWinner(matchImpl, round, playersout, cut)
|
||||
} else {
|
||||
val player = winners(currentIndex)
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_TIE_NUMBERS, player, remaining))
|
||||
|
||||
player.handlePickTieCard(winners, matchImpl, round, playersout, cut, currentStep, remaining, currentIndex)
|
||||
}
|
||||
}
|
||||
|
||||
def selectedTie(winner: List[AbstractPlayer],matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], value: Try[Int], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit = {
|
||||
if (value.isFailure) {
|
||||
ControlHandler.invoke(ShowErrorStatus(NOT_A_NUMBER))
|
||||
selectTie(winner, matchImpl, round, playersout, cut, currentStep, remaining, currentIndex)
|
||||
return
|
||||
}
|
||||
val selCard = matchImpl.cardManager.cardContainer(currentStep + (value.get - 1))
|
||||
UndoManager.doStep(SelectTieCommand(winner, matchImpl, round, playersout, cut, value.get, selCard, currentStep, remaining, currentIndex))
|
||||
}
|
||||
|
||||
def evaluateTieWinner(matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card]): Unit = {
|
||||
ControlHandler.invoke(ShowTieCardsEvent(cut.toList))
|
||||
val winner: ListBuffer[AbstractPlayer] = ListBuffer()
|
||||
var currentHighest: Card = null
|
||||
for ((player, card) <- cut) {
|
||||
if (currentHighest == null) {
|
||||
currentHighest = card
|
||||
winner += player
|
||||
} else {
|
||||
val compared = card.cardValue.ordinal.compareTo(currentHighest.cardValue.ordinal)
|
||||
if (compared > 0) {
|
||||
currentHighest = card
|
||||
winner.clear()
|
||||
winner += player
|
||||
} else if (compared == 0) {
|
||||
winner += player
|
||||
}
|
||||
}
|
||||
}
|
||||
if (winner.size == 1) {
|
||||
ControlHandler.invoke(ShowGlobalStatus(SHOW_TIE_WINNER, winner.head))
|
||||
KnockOutWhist.config.maincomponent.endRound(matchImpl, round, winner.head, playersout)
|
||||
return
|
||||
}
|
||||
ControlHandler.invoke(ShowGlobalStatus(SHOW_TIE_TIE))
|
||||
ControlHandler.invoke(DelayEvent(2000))
|
||||
preSelect(winner.toList, matchImpl, round, playersout)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.control.{ControlHandler, Roundlogcomponent}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.Implicits.*
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
object RoundLogic extends Roundlogcomponent{
|
||||
|
||||
def isOver(round: Round): Boolean = {
|
||||
round.playersin.map(_.currentHand()).count(_.get.cards.isEmpty) == round.playersin.size
|
||||
}
|
||||
|
||||
def dogNeedsToPlay(round: Round): Boolean = {
|
||||
round.playersin.filter(!_.doglife).map(_.currentHand()).exists(_.get.cards.isEmpty)
|
||||
}
|
||||
|
||||
def finalizeRound(round: Round, matchImpl: Match, force: Boolean = false): (Match, Round, List[AbstractPlayer], List[AbstractPlayer]) = {
|
||||
if (!force && round.tricklist.isEmpty)
|
||||
throw new IllegalStateException("No tricks played in this round")
|
||||
if (!force && !isOver(round))
|
||||
throw new IllegalStateException("Not all tricks were played in this round")
|
||||
val tricksMapped = round.tricklist
|
||||
.map(t => t.winner)
|
||||
.groupBy(identity).map((p, l) => (p, l.size)) //l.size = Anzahl gewonnener Tricks
|
||||
val winners = tricksMapped
|
||||
.filter((p, i) => i == tricksMapped.values.max)
|
||||
.keys
|
||||
var playersOut = round.firstRound
|
||||
? List()
|
||||
|: round.playersin.filter(!tricksMapped.contains(_))
|
||||
|
||||
var newMatch = matchImpl
|
||||
var newRound = round
|
||||
if (playersOut.nonEmpty && !matchImpl.dogLife) {
|
||||
newMatch = matchImpl.setDogLife()
|
||||
|
||||
val playersUpdated = ListBuffer[AbstractPlayer]()
|
||||
playersUpdated ++= tricksMapped.keys
|
||||
playersOut.foreach(p => {
|
||||
playersUpdated += p.setDogLife()
|
||||
})
|
||||
newMatch = newMatch.updatePlayers(playersUpdated.toList)
|
||||
newRound = newRound.updatePlayersIn(playersUpdated.toList)
|
||||
playersOut = List()
|
||||
}
|
||||
(newMatch, newRound, winners.toList, playersOut)
|
||||
}
|
||||
|
||||
def remainingPlayers(round: Round): List[AbstractPlayer] = {
|
||||
if (round.playersout == null) {
|
||||
return round.playersin
|
||||
}
|
||||
round.playersin.filter(!round.playersout.contains(_))
|
||||
}
|
||||
|
||||
def provideCards(matchImpl: Match, players: List[AbstractPlayer]): (Match,List[AbstractPlayer]) = {
|
||||
if (!KnockOutWhist.debugmode) matchImpl.cardManager.shuffleAndReset()
|
||||
val listbuff = new ListBuffer[AbstractPlayer]()
|
||||
for (player <- players) {
|
||||
if (!player.doglife) {
|
||||
val newPlayer = player.provideHand(matchImpl.cardManager.createHand(matchImpl.numberofcards))
|
||||
listbuff.addOne(newPlayer)
|
||||
} else {
|
||||
val newPlayer = player.provideHand(matchImpl.cardManager.createHand(1))
|
||||
listbuff.addOne(newPlayer)
|
||||
}
|
||||
}
|
||||
val matchResult = matchImpl.totalplayers.appendedAll(listbuff.toList).filter(!players.contains(_))
|
||||
(matchImpl.updatePlayers(matchResult), listbuff.toList)
|
||||
}
|
||||
|
||||
def smashResults(round: Round): Round = {
|
||||
val correctPlayers = round.playersin.groupMapReduce(_.id)(identity)((a, *) => a)
|
||||
val newTricks = round.tricklist.map(t => Trick(t.cards, correctPlayers.getOrElse(t.winner.id, t.winner), t.finished, t.firstCard))
|
||||
Round(round.trumpSuit, newTricks, round.playersin, round.playersout, round.startingPlayer, round.winner, round.firstRound)
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.{Card, Hand}
|
||||
import de.knockoutwhist.control.controllerBaseImpl.PlayerControl
|
||||
import de.knockoutwhist.control.{ControlHandler, Tricklogcomponent}
|
||||
import de.knockoutwhist.events.ERROR_STATUS.{INVALID_INPUT, INVALID_NUMBER, WRONG_CARD}
|
||||
import de.knockoutwhist.events.ShowErrorStatus
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.undo.UndoManager
|
||||
import de.knockoutwhist.undo.commands.{PlayerPlayCommand, PlayerPlayDogCommand}
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
object TrickLogic extends Tricklogcomponent {
|
||||
|
||||
def controlSuitplayed(card: Try[Card], matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer): Unit = {
|
||||
if (card.isFailure) {
|
||||
ControlHandler.invoke(ShowErrorStatus(INVALID_NUMBER))
|
||||
KnockOutWhist.config.playeractrcomponent.playCard(matchImpl, player, round, trick, currentIndex)
|
||||
return
|
||||
}
|
||||
val realCard = card.get
|
||||
if (trick.firstCard.isDefined) {
|
||||
val firstCard = trick.firstCard.get
|
||||
if (firstCard.suit != realCard.suit) {
|
||||
var hasSuit = false
|
||||
for (cardInHand <- player.currentHand().get.cards) {
|
||||
if (cardInHand.suit == firstCard.suit) {
|
||||
hasSuit = true
|
||||
}
|
||||
}
|
||||
if (hasSuit) {
|
||||
ControlHandler.invoke(ShowErrorStatus(WRONG_CARD, firstCard))
|
||||
KnockOutWhist.config.playeractrcomponent.playCard(matchImpl, player, round, trick, currentIndex)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
UndoManager.doStep(PlayerPlayCommand(matchImpl, round, trick, player, realCard, currentIndex))
|
||||
}
|
||||
|
||||
def controlDogPlayed(card: Try[Option[Card]], matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer): Unit = {
|
||||
if (card.isFailure) {
|
||||
ControlHandler.invoke(ShowErrorStatus(INVALID_INPUT))
|
||||
KnockOutWhist.config.playeractrcomponent.dogplayCard(matchImpl, player, round, trick, currentIndex)
|
||||
return
|
||||
}
|
||||
UndoManager.doStep(PlayerPlayDogCommand(matchImpl, round, trick, player, card.get, currentIndex))
|
||||
}
|
||||
|
||||
def alternativeCards(card: Card, round: Round, trick: Trick, player: AbstractPlayer): List[Card] = {
|
||||
if (trick.firstCard.isDefined) {
|
||||
val firstCard = trick.firstCard.get
|
||||
if (firstCard.suit != card.suit) {
|
||||
val alternatives: List[Card] = for cardInHand <- player.currentHand().get.cards
|
||||
if cardInHand.suit == firstCard.suit
|
||||
yield cardInHand
|
||||
if(round.trumpSuit == card.suit && alternatives.isEmpty) {
|
||||
return Nil
|
||||
}
|
||||
if (alternatives.nonEmpty) {
|
||||
return alternatives
|
||||
}
|
||||
}
|
||||
}
|
||||
Nil
|
||||
}
|
||||
|
||||
def wonTrick(trick: Trick, round: Round): (AbstractPlayer, Trick) = {
|
||||
val winningCard = {
|
||||
if (trick.cards.keys.exists(_.suit == round.trumpSuit)) {
|
||||
trick.cards.keys.filter(_.suit == round.trumpSuit).maxBy(_.cardValue.ordinal) //stream
|
||||
} else {
|
||||
trick.cards.keys.filter(_.suit == trick.firstCard.get.suit).maxBy(_.cardValue.ordinal) //stream
|
||||
}
|
||||
}
|
||||
val winningPlayer = trick.cards(winningCard)
|
||||
val finalTrick = Trick(trick.cards, winningPlayer, true)
|
||||
(winningPlayer, finalTrick)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl.sublogic
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogic
|
||||
import de.knockoutwhist.control.sublogic.PersistenceManager
|
||||
import de.knockoutwhist.control.{GameLogic, LogicSnapshot}
|
||||
import de.knockoutwhist.events.util.ReloadAllEvent
|
||||
import de.knockoutwhist.persistence.{MatchSnapshot, MethodEntryPoint}
|
||||
|
||||
class BasePersistenceManager(val gameLogic: BaseGameLogic) extends PersistenceManager {
|
||||
|
||||
private var currentSnapshot: MatchSnapshot = MatchSnapshot()
|
||||
|
||||
override def update(methodEntryPoint: MethodEntryPoint): MatchSnapshot = {
|
||||
currentSnapshot = currentSnapshot
|
||||
.withMethodEntryPoint(methodEntryPoint)
|
||||
.withGameLogicSnapShot(gameLogic.createSnapshot().asInstanceOf[LogicSnapshot[GameLogic]])
|
||||
currentSnapshot
|
||||
}
|
||||
|
||||
override def saveFile(path: String): Unit = {
|
||||
KnockOutWhist.config.fileFormatter.writeToFile(currentSnapshot, path + "." + KnockOutWhist.config.fileFormatter.fileEnding)
|
||||
}
|
||||
|
||||
override def loadFile(path: String): Unit = {
|
||||
currentSnapshot = KnockOutWhist.config.fileFormatter.readFromFile(path + "." + KnockOutWhist.config.fileFormatter.fileEnding)
|
||||
if currentSnapshot.entryPoint.isEmpty then
|
||||
throw new IllegalStateException("Loaded snapshot does not contain an entry point!")
|
||||
currentSnapshot.gameLogicSnapShot.foreach(_.restore(gameLogic))
|
||||
gameLogic.invoke(ReloadAllEvent())
|
||||
currentSnapshot.entryPoint.get match {
|
||||
case MethodEntryPoint.ControlMatch =>
|
||||
gameLogic.controlMatch()
|
||||
case MethodEntryPoint.ControlRound =>
|
||||
gameLogic.controlRound()
|
||||
case MethodEntryPoint.ControlTrick =>
|
||||
gameLogic.controlTrick()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl.sublogic
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Suit}
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogic
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.RoundUtil
|
||||
import de.knockoutwhist.control.sublogic.PlayerInputLogic
|
||||
import de.knockoutwhist.events.global.{CardPlayedEvent, TrumpSelectedEvent}
|
||||
import de.knockoutwhist.events.player.{RequestCardEvent, RequestTrumpSuitEvent}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
|
||||
final class BasePlayerInputLogic(gameLogic: BaseGameLogic) extends PlayerInputLogic {
|
||||
|
||||
val TIME_TO_RESPOND: Int = 30 // seconds
|
||||
|
||||
private var _waitingForInput: Boolean = false
|
||||
|
||||
|
||||
override def requestTrumpSuit(player: AbstractPlayer): Unit = {
|
||||
_waitingForInput = true
|
||||
gameLogic.invoke(RequestTrumpSuitEvent(player))
|
||||
}
|
||||
|
||||
override def receivedTrumpSuit(suit: Suit): Unit = {
|
||||
if (!_waitingForInput) throw new IllegalStateException("Not waiting for input")
|
||||
_waitingForInput = false
|
||||
val newRound = RoundUtil.createRound(suit)
|
||||
gameLogic.currentRound = Some(newRound)
|
||||
gameLogic.invoke(TrumpSelectedEvent(suit))
|
||||
gameLogic.controlRound()
|
||||
}
|
||||
|
||||
override def requestCard(player: AbstractPlayer): Unit = {
|
||||
_waitingForInput = true
|
||||
gameLogic.invoke(RequestCardEvent(player))
|
||||
}
|
||||
|
||||
override def receivedCard(card: Card): Unit = {
|
||||
if (!_waitingForInput) throw new IllegalStateException("Not waiting for input")
|
||||
_waitingForInput = false
|
||||
|
||||
if (gameLogic.currentTrick.isEmpty) throw new IllegalStateException("No current trick set")
|
||||
val trickImpl = gameLogic.currentTrick.get
|
||||
if (gameLogic.currentPlayer.isEmpty) throw new IllegalStateException("No current player set")
|
||||
val player = gameLogic.currentPlayer.get
|
||||
|
||||
|
||||
val newTrick = if (trickImpl.firstCard.isEmpty) {
|
||||
trickImpl
|
||||
.setfirstcard(card)
|
||||
.addCard(card, player)
|
||||
} else {
|
||||
trickImpl
|
||||
.addCard(card, player)
|
||||
}
|
||||
player.removeCard(card)
|
||||
|
||||
gameLogic.currentTrick = Some(newTrick)
|
||||
|
||||
gameLogic.invoke(CardPlayedEvent(player, newTrick))
|
||||
|
||||
gameLogic.controlTrick()
|
||||
}
|
||||
|
||||
override def receivedDog(dog: Option[Card]): Unit = {
|
||||
if (!_waitingForInput) throw new IllegalStateException("Not waiting for input")
|
||||
_waitingForInput = false
|
||||
|
||||
if (gameLogic.currentTrick.isEmpty) throw new IllegalStateException("No current trick set")
|
||||
val trickImpl = gameLogic.currentTrick.get
|
||||
if (gameLogic.currentPlayer.isEmpty) throw new IllegalStateException("No current player set")
|
||||
val player = gameLogic.currentPlayer.get
|
||||
|
||||
if (dog.isDefined) {
|
||||
val newTrick = if (trickImpl.firstCard.isEmpty) {
|
||||
trickImpl
|
||||
.setfirstcard(dog.get)
|
||||
.addCard(dog.get, player)
|
||||
} else {
|
||||
trickImpl
|
||||
.addCard(dog.get, player)
|
||||
}
|
||||
player.removeCard(dog.get)
|
||||
gameLogic.currentTrick = Some(newTrick)
|
||||
}
|
||||
gameLogic.controlTrick()
|
||||
}
|
||||
|
||||
override def isWaitingForInput: Boolean = _waitingForInput
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl.sublogic
|
||||
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.control.LogicSnapshot
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogic
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.{ResultPlayer, RoundResult}
|
||||
import de.knockoutwhist.control.sublogic.PlayerTieLogic
|
||||
import de.knockoutwhist.events.global.tie.*
|
||||
import de.knockoutwhist.events.player.RequestTieChoiceEvent
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
|
||||
final class BasePlayerTieLogic(gameLogic: BaseGameLogic) extends PlayerTieLogic {
|
||||
|
||||
private[control] var roundResult: Option[RoundResult] = None
|
||||
private[control] var tiedPlayers: List[AbstractPlayer] = Nil
|
||||
private[control] var tieBreakerIndex: Int = -1
|
||||
private[control] var lastNumber = -1
|
||||
private[control] var selectedCard: Map[AbstractPlayer, Card] = Map.empty
|
||||
private var _waitingForInput: Boolean = false
|
||||
|
||||
override def handleTie(roundResult: RoundResult): Unit = {
|
||||
this.roundResult = Some(roundResult)
|
||||
tiedPlayers = roundResult.winners
|
||||
tieBreakerIndex = -1
|
||||
lastNumber = 0
|
||||
selectedCard = Map.empty
|
||||
if (gameLogic.cardManager.isEmpty) throw new IllegalStateException("No card manager set")
|
||||
gameLogic.cardManager.get.shuffleAndReset()
|
||||
handleNextTieBreakerPlayer()
|
||||
}
|
||||
|
||||
override def handleNextTieBreakerPlayer(): Unit = {
|
||||
tieBreakerIndex += 1
|
||||
if(tieBreakerIndex >= 0 && tieBreakerIndex < tiedPlayers.size) {
|
||||
requestTieChoice(currentTiePlayer())
|
||||
} else {
|
||||
// All players have selected their tie-breaker cards
|
||||
// Find the highest card among selected cards
|
||||
|
||||
gameLogic.invoke(TieAllPlayersSelectedEvent())
|
||||
gameLogic.invoke(DelayEvent(2000))
|
||||
gameLogic.invoke(TieShowPlayerCardsEvent())
|
||||
|
||||
val winningEntry = selectedCard.values.maxBy(_.cardValue.ordinal)
|
||||
val winners = selectedCard.filter((_, card) => card == winningEntry).keySet.toList
|
||||
|
||||
gameLogic.invoke(TieWinningPlayersEvent(winners))
|
||||
gameLogic.invoke(DelayEvent(2000))
|
||||
if (winners.size > 1) {
|
||||
gameLogic.invoke(TieTieEvent(winners))
|
||||
|
||||
// Still a tie, handle again
|
||||
tiedPlayers = winners
|
||||
tieBreakerIndex = -1
|
||||
lastNumber = 0
|
||||
selectedCard = Map.empty
|
||||
gameLogic.cardManager.get.shuffleAndReset()
|
||||
handleNextTieBreakerPlayer()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Tie-breaker resolved
|
||||
roundResult = None
|
||||
tiedPlayers = Nil
|
||||
lastNumber = -1
|
||||
tieBreakerIndex = -1
|
||||
selectedCard = Map.empty
|
||||
|
||||
val winner = winners.head
|
||||
// Inform game logic about the winner
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override def currentTiePlayer(): AbstractPlayer = {
|
||||
tiedPlayers(tieBreakerIndex)
|
||||
}
|
||||
|
||||
override def requestTieChoice(player: AbstractPlayer): Unit = {
|
||||
_waitingForInput = true
|
||||
gameLogic.invoke(TieTurnEvent(player))
|
||||
gameLogic.invoke(RequestTieChoiceEvent(player, highestAllowedNumber()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player has selected a tie-breaker card
|
||||
* @param number the index of the selected card
|
||||
*/
|
||||
override def receivedTieBreakerCard(number: Int): Unit = {
|
||||
if (!_waitingForInput) throw new IllegalStateException("Not waiting for input")
|
||||
_waitingForInput = false
|
||||
|
||||
val player = tiedPlayers(tieBreakerIndex)
|
||||
val highestNumber = highestAllowedNumber()
|
||||
if (number < 0 || number > highestNumber)
|
||||
throw new IllegalArgumentException(s"Selected number $number is out of allowed range (0 to $highestNumber)")
|
||||
|
||||
if (gameLogic.cardManager.isEmpty) throw new IllegalStateException("No card manager set")
|
||||
|
||||
val cardManager = gameLogic.cardManager.get
|
||||
val card = cardManager.removeCards(number).last
|
||||
selectedCard += (player -> card)
|
||||
handleNextTieBreakerPlayer()
|
||||
}
|
||||
|
||||
override def highestAllowedNumber(): Int = {
|
||||
if (gameLogic.cardManager.isEmpty) throw new IllegalStateException("No card manager set")
|
||||
val remainingCards = gameLogic.cardManager.get.remainingCards
|
||||
|
||||
// The highest allowed number is total cards minus the number of tied players already selected
|
||||
// This ensures that each tied player can select a unique card
|
||||
remainingCards - (tiedPlayers.size - selectedCard.size - 1)
|
||||
}
|
||||
|
||||
override def isWaitingForInput: Boolean = _waitingForInput
|
||||
|
||||
|
||||
|
||||
override def createSnapshot(): LogicSnapshot[BasePlayerTieLogic.this.type] = BasePlayerTieLogicSnapshot(this).asInstanceOf[LogicSnapshot[BasePlayerTieLogic.this.type]]
|
||||
|
||||
// Getter
|
||||
override def getRoundResult: Option[RoundResult] = roundResult
|
||||
override def getTiedPlayers: List[AbstractPlayer] = tiedPlayers
|
||||
override def getTieBreakerIndex: Int = tieBreakerIndex
|
||||
override def getLastNumber: Int = lastNumber
|
||||
override def getSelectedCard: Map[AbstractPlayer, Card] = selectedCard
|
||||
|
||||
}
|
||||
|
||||
class BasePlayerTieLogicSnapshot(
|
||||
//Round result
|
||||
val winners: List[AbstractPlayer],
|
||||
val tricked: List[ResultPlayer],
|
||||
val notTricked: List[AbstractPlayer],
|
||||
|
||||
val tiedPlayers: List[AbstractPlayer],
|
||||
val tieBreakerIndex: Int,
|
||||
val lastNumber: Int,
|
||||
val selectedCard: Map[AbstractPlayer, Card]
|
||||
) extends LogicSnapshot[BasePlayerTieLogic] {
|
||||
|
||||
def this(logic: BasePlayerTieLogic) = {
|
||||
this(
|
||||
logic.roundResult.map(_.winners).getOrElse(Nil),
|
||||
logic.roundResult.map(_.tricked).getOrElse(Nil),
|
||||
logic.roundResult.map(_.notTricked).getOrElse(Nil),
|
||||
logic.tiedPlayers,
|
||||
logic.tieBreakerIndex,
|
||||
logic.lastNumber,
|
||||
logic.selectedCard
|
||||
)
|
||||
}
|
||||
|
||||
override def restore(logic: BasePlayerTieLogic): Unit = {
|
||||
if (winners.nonEmpty || tricked.nonEmpty || notTricked.nonEmpty) {
|
||||
logic.roundResult = Some(RoundResult(winners, tricked, notTricked))
|
||||
} else {
|
||||
logic.roundResult = None
|
||||
}
|
||||
logic.tiedPlayers = tiedPlayers
|
||||
logic.tieBreakerIndex = tieBreakerIndex
|
||||
logic.lastNumber = lastNumber
|
||||
logic.selectedCard = selectedCard
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,22 @@
|
||||
package de.knockoutwhist.undo
|
||||
package de.knockoutwhist.control.controllerBaseImpl.sublogic
|
||||
|
||||
import de.knockoutwhist.control.ControlThread
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogic
|
||||
import de.knockoutwhist.control.sublogic.UndoManager
|
||||
import de.knockoutwhist.undo.{Command, UndoneException}
|
||||
|
||||
object UndoManager {
|
||||
class BaseUndoManager(gameLogic: BaseGameLogic) extends UndoManager {
|
||||
|
||||
private var undoStack: List[Command] = Nil
|
||||
private var redoStack: List[Command] = Nil
|
||||
|
||||
def doStep(command: Command): Unit = {
|
||||
override def doStep(command: Command): Unit = {
|
||||
redoStack = Nil
|
||||
undoStack = command :: undoStack
|
||||
command.doStep()
|
||||
command.doStep(gameLogic)
|
||||
}
|
||||
|
||||
def undoStep(): Unit = {
|
||||
override def undoStep(): Unit = {
|
||||
ControlThread.runLater {
|
||||
undoStack match {
|
||||
case Nil => false
|
||||
@@ -21,7 +24,7 @@ object UndoManager {
|
||||
undoStack = stack
|
||||
redoStack = head :: redoStack
|
||||
try {
|
||||
head.undoStep()
|
||||
head.undoStep(gameLogic)
|
||||
} catch {
|
||||
case _: UndoneException =>
|
||||
}
|
||||
@@ -29,7 +32,7 @@ object UndoManager {
|
||||
}
|
||||
}
|
||||
|
||||
def redoStep(): Unit = {
|
||||
override def redoStep(): Unit = {
|
||||
ControlThread.runLater {
|
||||
redoStack match {
|
||||
case Nil => false
|
||||
@@ -37,7 +40,7 @@ object UndoManager {
|
||||
redoStack = stack
|
||||
undoStack = head :: undoStack
|
||||
try {
|
||||
head.doStep()
|
||||
head.doStep(gameLogic)
|
||||
} catch {
|
||||
case _: UndoneException =>
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl.sublogic.util
|
||||
|
||||
import de.knockoutwhist.rounds.{Match, Round}
|
||||
|
||||
object MatchUtil {
|
||||
|
||||
private def remainingRounds(matchImpl: Match, roundImpl: Round): Int = {
|
||||
// If no player has any cards left, there are no rounds remaining
|
||||
if !matchImpl.playersIn
|
||||
.map(player => player.currentHand()).exists(hand => hand.isDefined && hand.get.cards.nonEmpty) then return 0
|
||||
// Otherwise, calculate remaining rounds based on number of cards and tricks played
|
||||
matchImpl.numberofcards - roundImpl.tricklist.size
|
||||
}
|
||||
|
||||
def isRoundOver(matchImpl: Match, roundImpl: Round): Boolean = {
|
||||
remainingRounds(matchImpl, roundImpl) == 0
|
||||
}
|
||||
|
||||
def dogNeedsToPlay(matchImpl: Match, roundImpl: Round): Boolean = {
|
||||
remainingRounds(matchImpl, roundImpl) == 1
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl.sublogic.util
|
||||
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Round, Trick}
|
||||
|
||||
object PlayerUtil {
|
||||
|
||||
def canPlayCard(card: Card, round: Round, trick: Trick, player: AbstractPlayer): Boolean = {
|
||||
if (trick.firstCard.isEmpty)
|
||||
return true
|
||||
val alternatives = alternativeCards(card, round, trick, player)
|
||||
if (alternatives.nonEmpty) {
|
||||
return false
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
def alternativeCards(card: Card, round: Round, trick: Trick, player: AbstractPlayer): List[Card] = {
|
||||
if (trick.firstCard.isDefined) {
|
||||
val firstCard = trick.firstCard.get
|
||||
if (firstCard.suit != card.suit) {
|
||||
val alternatives: List[Card] = for cardInHand <- player.currentHand().get.cards
|
||||
if cardInHand.suit == firstCard.suit
|
||||
yield cardInHand
|
||||
if (round.trumpSuit == card.suit && alternatives.isEmpty) {
|
||||
return Nil
|
||||
}
|
||||
if (alternatives.nonEmpty) {
|
||||
return alternatives
|
||||
}
|
||||
}
|
||||
}
|
||||
Nil
|
||||
}
|
||||
|
||||
def playableCards(round: Round, trick: Trick, player: AbstractPlayer): List[Card] = {
|
||||
val handOption = player.currentHand()
|
||||
if (handOption.isEmpty) {
|
||||
throw new IllegalStateException("You have no cards!")
|
||||
}
|
||||
val hand = handOption.get
|
||||
if (trick.firstCard.isEmpty) {
|
||||
return hand.cards
|
||||
}
|
||||
val playableCards: List[Card] = for cardInHand <- hand.cards
|
||||
if canPlayCard(cardInHand, round, trick, player)
|
||||
yield cardInHand
|
||||
playableCards
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl.sublogic.util
|
||||
|
||||
import de.knockoutwhist.cards.Suit
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round}
|
||||
|
||||
object RoundUtil {
|
||||
|
||||
def createRound(trumpSuit: Suit, firstRound: Boolean = false): Round = {
|
||||
Round(trumpSuit, firstRound)
|
||||
}
|
||||
|
||||
def finishRound(round: Round, matchImpl: Match): RoundResult = {
|
||||
val tricksMapped = round.tricklist
|
||||
.map(t => t.winner)
|
||||
.filter(t => t.isDefined)
|
||||
.map(t => t.get)
|
||||
.groupBy(identity).map((p, l) => (p, l.size))
|
||||
val maxTricks = if (tricksMapped.isEmpty) 0 else tricksMapped.values.max
|
||||
val winners = tricksMapped
|
||||
.filter((p, i) => i == maxTricks)
|
||||
.keys.toList
|
||||
val trickedPlayers = tricksMapped.map((p, i) => ResultPlayer(p, i)).toList
|
||||
val notTrickedPlayers = matchImpl.playersIn.filterNot(p => tricksMapped.keySet.contains(p))
|
||||
RoundResult(winners, trickedPlayers, notTrickedPlayers)
|
||||
}
|
||||
|
||||
def roundEndSnapshot(winner: AbstractPlayer, round: Round): Round = {
|
||||
Round(
|
||||
round.trumpSuit,
|
||||
round.firstRound,
|
||||
round.tricklist,
|
||||
Some(winner)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case class RoundResult(winners: List[AbstractPlayer], tricked: List[ResultPlayer], notTricked: List[AbstractPlayer]) {
|
||||
def isTie: Boolean = winners.size > 1
|
||||
}
|
||||
|
||||
case class ResultPlayer(player: AbstractPlayer, amountOfTricks: Int)
|
||||
@@ -0,0 +1,13 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl.sublogic.util
|
||||
|
||||
import de.knockoutwhist.control.{GameLogic, LogicSnapshot}
|
||||
|
||||
object SnapshotUtil {
|
||||
|
||||
def generateSnapshots(gameLogic: GameLogic): (LogicSnapshot[? <: GameLogic], LogicSnapshot[? <: GameLogic]) = {
|
||||
val gameLogicSnapshot = gameLogic.createSnapshot()
|
||||
val playerTieLogicSnapshot = gameLogic.playerTieLogic.createSnapshot()
|
||||
(gameLogicSnapshot, playerTieLogicSnapshot.asInstanceOf[LogicSnapshot[? <: GameLogic]])
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package de.knockoutwhist.control.controllerBaseImpl.sublogic.util
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.CustomPlayerQueue
|
||||
|
||||
object TrickUtil {
|
||||
|
||||
def isOver(matchImpl: Match, queue: CustomPlayerQueue[AbstractPlayer]): Boolean = {
|
||||
queue.playersSinceLastReset() >= matchImpl.playersIn.length
|
||||
}
|
||||
|
||||
private def winningPlayer(trick: Trick, round: Round): AbstractPlayer = {
|
||||
val winningCard = {
|
||||
if (trick.cards.keys.exists(_.suit == round.trumpSuit)) {
|
||||
trick.cards.keys.filter(_.suit == round.trumpSuit).maxBy(_.cardValue.ordinal) //stream
|
||||
} else {
|
||||
trick.cards.keys.filter(_.suit == trick.firstCard.get.suit).maxBy(_.cardValue.ordinal) //stream
|
||||
}
|
||||
}
|
||||
val winningPlayer = trick.cards(winningCard)
|
||||
winningPlayer
|
||||
}
|
||||
|
||||
def finishTrick(trick: Trick, round: Round): TrickResult = {
|
||||
val winner = winningPlayer(trick, round)
|
||||
TrickResult(winner)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case class TrickResult(winner: AbstractPlayer)
|
||||
@@ -0,0 +1,26 @@
|
||||
package de.knockoutwhist.control.sublogic
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.control.GameLogic
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogic
|
||||
import de.knockoutwhist.persistence.{MatchSnapshot, MethodEntryPoint}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.events.{EventListener, SimpleEvent}
|
||||
|
||||
import scala.Unit
|
||||
|
||||
trait PersistenceManager {
|
||||
|
||||
def gameLogic: GameLogic
|
||||
def update(methodEntryPoint: MethodEntryPoint): MatchSnapshot
|
||||
|
||||
def saveFile(path: String): Unit
|
||||
def loadFile(path: String): Unit
|
||||
|
||||
def canLoadfile(path: String): Boolean = {
|
||||
val file = new java.io.File(path + "." + KnockOutWhist.config.fileFormatter.fileEnding)
|
||||
file.exists() && file.isFile && file.canRead
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.knockoutwhist.control.sublogic
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Suit}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
|
||||
trait PlayerInputLogic {
|
||||
|
||||
def requestTrumpSuit(player: AbstractPlayer): Unit
|
||||
def receivedTrumpSuit(suit: Suit): Unit
|
||||
def requestCard(player: AbstractPlayer): Unit
|
||||
def receivedCard(card: Card): Unit
|
||||
def receivedDog(dog: Option[Card]): Unit
|
||||
|
||||
def isWaitingForInput: Boolean
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package de.knockoutwhist.control.sublogic
|
||||
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.control.SnapshottingGameLogic
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.RoundResult
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
|
||||
trait PlayerTieLogic extends SnapshottingGameLogic {
|
||||
|
||||
def handleTie(roundResult: RoundResult): Unit
|
||||
def handleNextTieBreakerPlayer(): Unit
|
||||
def currentTiePlayer(): AbstractPlayer
|
||||
def requestTieChoice(player: AbstractPlayer): Unit
|
||||
def receivedTieBreakerCard(number: Int): Unit
|
||||
def highestAllowedNumber(): Int
|
||||
|
||||
def isWaitingForInput: Boolean
|
||||
|
||||
def getRoundResult: Option[RoundResult]
|
||||
def getTiedPlayers: List[AbstractPlayer]
|
||||
def getTieBreakerIndex: Int
|
||||
def getLastNumber: Int
|
||||
def getSelectedCard: Map[AbstractPlayer, Card]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.knockoutwhist.control.sublogic
|
||||
|
||||
import de.knockoutwhist.undo.Command
|
||||
|
||||
trait UndoManager {
|
||||
|
||||
def doStep(command: Command): Unit
|
||||
def undoStep(): Unit
|
||||
def redoStep(): Unit
|
||||
|
||||
}
|
||||
@@ -4,32 +4,21 @@ import com.google.inject.AbstractModule
|
||||
import de.knockoutwhist.cards.CardManager
|
||||
import de.knockoutwhist.cards.base.CardBaseManager
|
||||
import de.knockoutwhist.components.{Configuration, DefaultConfiguration}
|
||||
import de.knockoutwhist.control.controllerBaseImpl.*
|
||||
import de.knockoutwhist.control.*
|
||||
import de.knockoutwhist.persistence.PersistenceManager
|
||||
import de.knockoutwhist.persistence.formats.{FileFormatter, JSONFormatter, XMLFormatter}
|
||||
import de.knockoutwhist.persistence.stub.PersistenceBaseManager
|
||||
import de.knockoutwhist.persistence.formats.{FileFormatter, JSONFormatter}
|
||||
import de.knockoutwhist.utils.baseQueue.{CustomPlayerQueueBuilder, QueueBuilder}
|
||||
|
||||
class KnockOutLogicModule extends AbstractModule {
|
||||
override def configure(): Unit = {
|
||||
bind(classOf[Maincomponent]).toInstance(MainLogic)
|
||||
bind(classOf[Matchcomponent]).toInstance(MatchLogic)
|
||||
bind(classOf[Playeractrcomponent]).toInstance(PlayerControl)
|
||||
bind(classOf[Playerlogcomponent]).toInstance(PlayerLogic)
|
||||
bind(classOf[Roundlogcomponent]).toInstance(RoundLogic)
|
||||
bind(classOf[Tricklogcomponent]).toInstance(TrickLogic)
|
||||
bind(classOf[CardManager]).to(classOf[CardBaseManager])
|
||||
bind(classOf[QueueBuilder]).to(classOf[CustomPlayerQueueBuilder])
|
||||
bind(classOf[PersistenceManager]).toInstance(PersistenceBaseManager)
|
||||
bind(classOf[FileFormatter]).to(classOf[XMLFormatter])
|
||||
bind(classOf[FileFormatter]).to(classOf[JSONFormatter])
|
||||
}
|
||||
}
|
||||
|
||||
class KnockOutConfigurationModule extends AbstractModule {
|
||||
|
||||
override def configure(): Unit = {
|
||||
bind(classOf[Configuration]).toInstance(DefaultConfiguration)
|
||||
bind(classOf[Configuration]).to(classOf[DefaultConfiguration])
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package de.knockoutwhist.events
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round}
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
enum GLOBAL_STATUS {
|
||||
case SHOW_TIE
|
||||
case SHOW_TIE_WINNER
|
||||
case SHOW_TIE_TIE
|
||||
|
||||
case SHOW_START_MATCH
|
||||
case SHOW_TYPE_PLAYERS
|
||||
case SHOW_FINISHED_MATCH
|
||||
}
|
||||
|
||||
enum PLAYER_STATUS {
|
||||
case SHOW_TURN
|
||||
case SHOW_PLAY_CARD
|
||||
case SHOW_DOG_PLAY_CARD
|
||||
case SHOW_TIE_NUMBERS
|
||||
case SHOW_TRUMPSUIT_OPTIONS
|
||||
case SHOW_NOT_PLAYED
|
||||
case SHOW_WON_PLAYER_TRICK
|
||||
}
|
||||
enum ROUND_STATUS {
|
||||
case SHOW_START_ROUND
|
||||
case WON_ROUND
|
||||
case PLAYERS_OUT
|
||||
}
|
||||
|
||||
enum ERROR_STATUS {
|
||||
case INVALID_NUMBER
|
||||
case NOT_A_NUMBER
|
||||
case INVALID_INPUT
|
||||
case INVALID_NUMBER_OF_PLAYERS
|
||||
case IDENTICAL_NAMES
|
||||
case INVALID_NAME_FORMAT
|
||||
case WRONG_CARD
|
||||
}
|
||||
|
||||
abstract class ShowStatusEvent extends SimpleEvent
|
||||
|
||||
case class ShowGlobalStatus(status: GLOBAL_STATUS, objects: Any*) extends ShowStatusEvent {
|
||||
override def id: String = "ShowGlobalStatus"
|
||||
}
|
||||
|
||||
case class ShowPlayerStatus(status: PLAYER_STATUS, player: AbstractPlayer, objects: Any*) extends ShowStatusEvent {
|
||||
override def id: String = "ShowPlayerStatus"
|
||||
}
|
||||
|
||||
case class ShowErrorStatus(status: ERROR_STATUS, objects: Any*) extends ShowStatusEvent {
|
||||
override def id: String = "ShowErrorStatus"
|
||||
}
|
||||
|
||||
case class ShowRoundStatus(status: ROUND_STATUS, currentRound: Round, objects: Any*) extends ShowStatusEvent {
|
||||
override def id: String = "ShowRoundStatus"
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package de.knockoutwhist.events.cards
|
||||
|
||||
import de.knockoutwhist.cards.Hand
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
final case class RenderHandEvent(hand: Hand, showNumbers: Boolean) extends SimpleEvent {
|
||||
override def id: String = "RenderHandEvent"
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package de.knockoutwhist.events.cards
|
||||
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class ShowTieCardsEvent(card: List[(AbstractPlayer, Card)]) extends SimpleEvent {
|
||||
override def id: String = "ShowTieCardsEvent"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package de.knockoutwhist.events.directional
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Hand}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
case class RequestCardEvent(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer) extends SimpleEvent {
|
||||
override def id: String = "RequestCardEvent"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package de.knockoutwhist.events.directional
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Hand}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
case class RequestDogPlayCardEvent(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, player: AbstractPlayer, needstoplay: Boolean) extends SimpleEvent {
|
||||
override def id: String = "RequestDogPlayCardEvent"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package de.knockoutwhist.events.directional
|
||||
|
||||
import de.knockoutwhist.cards.Suit
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.Match
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
case class RequestPickTrumpsuitEvent(matchImpl: Match, remaining_players: List[AbstractPlayer], firstRound: Boolean, player: AbstractPlayer) extends SimpleEvent {
|
||||
override def id: String = "RequestPickTrumpsuitEvent"
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package de.knockoutwhist.events.directional
|
||||
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round}
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
import scala.collection.immutable
|
||||
import scala.util.Try
|
||||
|
||||
case class RequestTieNumberEvent(winner: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], currentStep: Int, remaining: Int, currentIndex: Int = 0) extends SimpleEvent {
|
||||
override def id: String = "RequestNumberEvent"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.Trick
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class CardPlayedEvent(player: AbstractPlayer, trick: Trick) extends SimpleEvent {
|
||||
override def id: String = s"CardPlayedEvent"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.control.GameState
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class GameStateChangeEvent(oldState: GameState, newState: GameState) extends SimpleEvent {
|
||||
override def id: String = s"GameStateChangeEvent(from=$oldState,to=$newState)"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class MatchEndEvent(winner: AbstractPlayer) extends SimpleEvent {
|
||||
override def id: String = "RoundEndEvent"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class NewRoundEvent() extends SimpleEvent {
|
||||
override def id: String = s"NewRoundEvent"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class NewTrickEvent() extends SimpleEvent {
|
||||
override def id: String = s"NewTrickEvent"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class RoundEndEvent(winner: AbstractPlayer, amountOfTricks: Int) extends SimpleEvent {
|
||||
override def id: String = s"RoundEndEvent()"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class SessionClosed() extends SimpleEvent {
|
||||
override def id: String = s"SessionClosed"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class ShowDogsEvent(dogs: List[AbstractPlayer]) extends SimpleEvent {
|
||||
|
||||
override def id: String = "ShowDogsEvent"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class ShowPlayersOutEvent(out: List[AbstractPlayer]) extends SimpleEvent {
|
||||
|
||||
override def id: String = "ShowPlayersOutEvent"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TrickEndEvent(winner: AbstractPlayer) extends SimpleEvent {
|
||||
override def id: String = s"TrickEndEvent"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TrumpSelectEvent(player: AbstractPlayer) extends SimpleEvent{
|
||||
|
||||
override def id: String = "TrumpSelectEvent"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.cards.Suit
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TrumpSelectedEvent(suit: Suit) extends SimpleEvent{
|
||||
|
||||
override def id: String = "TrumpSelectEvent"
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TurnEvent(player: AbstractPlayer) extends SimpleEvent {
|
||||
override def id: String = s"TurnEvent"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global.tie
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TieAllPlayersSelectedEvent() extends SimpleEvent {
|
||||
override def id: String = s"TieAllPlayersSelectedEvent"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global.tie
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TieEvent(players: List[AbstractPlayer]) extends SimpleEvent {
|
||||
override def id: String = s"TieEvent"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global.tie
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TieShowPlayerCardsEvent() extends SimpleEvent {
|
||||
override def id: String = s"TieShowPlayerCardsEvent"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global.tie
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TieTieEvent(players: List[AbstractPlayer]) extends SimpleEvent {
|
||||
override def id: String = s"TieTieEvent"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.knockoutwhist.events.global.tie
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TieTurnEvent(player: AbstractPlayer) extends SimpleEvent {
|
||||
override def id: String = s"TieTurnEvent"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.knockoutwhist.events.global.tie
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class TieWinningPlayersEvent(winners: List[AbstractPlayer]) extends SimpleEvent {
|
||||
override def id: String = s"TieWinningPlayersEvent"
|
||||
|
||||
def isSingleWinner: Boolean = winners.size == 1
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package de.knockoutwhist.events.player
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
abstract class PlayerEvent(player: AbstractPlayer) extends SimpleEvent {
|
||||
|
||||
def playerId: UUID = player.id
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.events.player
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
|
||||
case class ReceivedHandEvent(player: AbstractPlayer) extends PlayerEvent(player) {
|
||||
override def id: String = "ReceivedHandEvent"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.events.player
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
|
||||
case class RequestCardEvent(player: AbstractPlayer) extends PlayerEvent(player) {
|
||||
override def id: String = "PlayCardEvent"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.events.player
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
|
||||
case class RequestTieChoiceEvent(player: AbstractPlayer, maxNumber: Int) extends PlayerEvent(player) {
|
||||
override def id: String = "RequestTieChoiceEvent"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.events.player
|
||||
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
|
||||
case class RequestTrumpSuitEvent(player: AbstractPlayer) extends PlayerEvent(player) {
|
||||
override def id: String = "RequestTrumpSuitEvent"
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package de.knockoutwhist.events.round
|
||||
|
||||
import de.knockoutwhist.rounds.{Round, Trick}
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class ShowCurrentTrickEvent(round: Round, trick: Trick) extends SimpleEvent {
|
||||
override def id: String = "ShowCurrentTrickEvent"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package de.knockoutwhist.events.ui
|
||||
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
enum GameState:
|
||||
case NO_SET
|
||||
case MAIN_MENU
|
||||
case PLAYERS
|
||||
case INGAME
|
||||
case TRUMPSUIT
|
||||
case TIE
|
||||
end GameState
|
||||
|
||||
|
||||
case class GameStateUpdateEvent(gameState: GameState) extends SimpleEvent {
|
||||
override def id: String = s"GameStateUpdateEvent($gameState)"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.events.util
|
||||
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class ReloadAllEvent() extends SimpleEvent {
|
||||
override def id: String = "ReloadAllEvent"
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
package de.knockoutwhist.persistence
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.control.{ControlHandler, ControlThread}
|
||||
import de.knockoutwhist.events.ui.{GameState, GameStateUpdateEvent}
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogic
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.BasePlayerTieLogic
|
||||
import de.knockoutwhist.control.sublogic.PlayerTieLogic
|
||||
import de.knockoutwhist.control.{ControlThread, GameLogic, LogicSnapshot}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
enum MethodEntryPoint:
|
||||
case EnterPlayers
|
||||
case ControlMatch
|
||||
case ControlRound
|
||||
case ControlTrick
|
||||
@@ -15,32 +16,10 @@ end MethodEntryPoint
|
||||
|
||||
|
||||
case class MatchSnapshot(
|
||||
matchImpl: Option[Match] = None,
|
||||
round: Option[Round] = None,
|
||||
trick: Option[Trick] = None,
|
||||
currentIndex: Option[Int] = None,
|
||||
gameState: GameState = GameState.MAIN_MENU,
|
||||
methodEntryPoint: Option[MethodEntryPoint] = None
|
||||
entryPoint: Option[MethodEntryPoint] = None,
|
||||
gameLogicSnapShot: Option[LogicSnapshot[GameLogic]] = None
|
||||
) {
|
||||
|
||||
def withMatchImpl(matchImpl: Match): MatchSnapshot = copy(matchImpl = Some(matchImpl))
|
||||
def withRound(round: Round): MatchSnapshot = copy(round = Some(round))
|
||||
def withTrick(trick: Trick): MatchSnapshot = copy(trick = Some(trick))
|
||||
def withCurrentIndex(currentIndex: Int): MatchSnapshot = copy(currentIndex = Some(currentIndex))
|
||||
def withGameState(gameState: GameState): MatchSnapshot = copy(gameState = gameState)
|
||||
def withMethodEntryPoint(methodEntryPoint: MethodEntryPoint): MatchSnapshot = copy(methodEntryPoint = Some(methodEntryPoint))
|
||||
|
||||
def restoreSnapshot(): Unit = {
|
||||
ControlThread.runLater {
|
||||
ControlHandler.invoke(GameStateUpdateEvent(gameState))
|
||||
methodEntryPoint match {
|
||||
case Some(MethodEntryPoint.EnterPlayers) => KnockOutWhist.config.maincomponent.enteredPlayers(matchImpl.get.totalplayers)
|
||||
case Some(MethodEntryPoint.ControlMatch) => KnockOutWhist.config.maincomponent.controlMatch(matchImpl.get)
|
||||
case Some(MethodEntryPoint.ControlRound) => KnockOutWhist.config.maincomponent.controlRound(matchImpl.get, round.get)
|
||||
case Some(MethodEntryPoint.ControlTrick) => KnockOutWhist.config.maincomponent.controlTrick(matchImpl.get, round.get, trick.get, currentIndex.get)
|
||||
case _ => throw new RuntimeException("MethodEntryPoint not found")
|
||||
}
|
||||
}
|
||||
}
|
||||
def withMethodEntryPoint(newEntryPoint: MethodEntryPoint): MatchSnapshot = this.copy(entryPoint = Some(newEntryPoint))
|
||||
def withGameLogicSnapShot(newGameLogicSnapShot: LogicSnapshot[GameLogic]): MatchSnapshot = this.copy(gameLogicSnapShot = Some(newGameLogicSnapShot))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
package de.knockoutwhist.persistence
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.control.ControlHandler
|
||||
import de.knockoutwhist.events.ui.{GameState, GameStateUpdateEvent}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.events.{EventListener, SimpleEvent}
|
||||
|
||||
import scala.Unit
|
||||
|
||||
trait PersistenceManager extends EventListener {
|
||||
|
||||
def updateGameState(gameState: GameState): MatchSnapshot
|
||||
def updateMatch(matchImpl: Match): MatchSnapshot
|
||||
def updateRound(round: Round): MatchSnapshot
|
||||
def updateTrick(trick: Trick): MatchSnapshot
|
||||
def updateCurrentIndex(currentIndex: Int): MatchSnapshot
|
||||
def updateMethodEntryPoint(methodEntryPoint: MethodEntryPoint): MatchSnapshot
|
||||
|
||||
def saveFile(path: String): Unit
|
||||
def loadFile(path: String): Unit
|
||||
|
||||
def canLoadfile(path: String): Boolean = {
|
||||
val file = new java.io.File(path + "." + KnockOutWhist.config.fileFormatter.fileEnding)
|
||||
file.exists() && file.isFile && file.canRead
|
||||
}
|
||||
|
||||
override def listen(event: SimpleEvent): Unit = {
|
||||
event match {
|
||||
case event: GameStateUpdateEvent =>
|
||||
updateGameState(event.gameState)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
def loadManager(): Unit = {
|
||||
ControlHandler.addListener(this)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.knockoutwhist.persistence.formats
|
||||
|
||||
import de.knockoutwhist.cards.Card
|
||||
|
||||
object CardFormatUtil {
|
||||
|
||||
def grabSpecificCard(card: Card, cc: List[Card]): Card = {
|
||||
cc.filter(c => c.suit == card.suit && c.cardValue == card.cardValue).head
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,9 +38,9 @@ trait FileFormatter {
|
||||
players.get(id) match {
|
||||
case Some(player) => player
|
||||
case None =>
|
||||
var player = PlayerFactory.createPlayer(name, id, player_type)
|
||||
if(hand.isDefined) player = player.provideHand(hand.get)
|
||||
if(dog_life) player = player.setDogLife()
|
||||
val player = PlayerFactory.createPlayer(name, id, player_type)
|
||||
if(hand.isDefined) player.provideHand(hand.get)
|
||||
if(dog_life) player.setDogLife()
|
||||
players.put(id, player)
|
||||
player
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package de.knockoutwhist.persistence.formats
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.*
|
||||
import de.knockoutwhist.events.ui.GameState
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogicSnapshot
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.{BasePlayerTieLogic, BasePlayerTieLogicSnapshot}
|
||||
import de.knockoutwhist.control.{GameLogic, GameState, LogicSnapshot}
|
||||
import de.knockoutwhist.persistence.{MatchSnapshot, MethodEntryPoint}
|
||||
import de.knockoutwhist.player.{AbstractPlayer, PlayerFactory, Playertype}
|
||||
import de.knockoutwhist.player.{AbstractPlayer, PlayerData, PlayerFactory, Playertype}
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import play.api.libs.json
|
||||
import play.api.libs.json.*
|
||||
@@ -22,64 +24,140 @@ class JSONFormatter extends FileFormatter {
|
||||
|
||||
override def createFormat(matchSnapshot: MatchSnapshot): Array[Byte] = {
|
||||
val js = Json.obj(
|
||||
"gamestate" -> matchSnapshot.gameState.toString,
|
||||
matchSnapshot.methodEntryPoint match {
|
||||
case None => "methodEntryPoint" -> JsString("None")
|
||||
case Some(methodEntryPoint) => "methodEntryPoint" -> JsString(methodEntryPoint.toString)
|
||||
matchSnapshot.entryPoint match {
|
||||
case None => "entryPoint" -> JsString("None")
|
||||
case Some(entryPoint) => "entryPoint" -> JsString(entryPoint.toString)
|
||||
},
|
||||
matchSnapshot.matchImpl match {
|
||||
case None => "match" -> JsString("None")
|
||||
case Some(matchImpl) => "match" -> MatchJsonFormatter.createMatchJson(matchImpl)
|
||||
matchSnapshot.gameLogicSnapShot match {
|
||||
case None => "gameLogic" -> JsString("None")
|
||||
case Some(gameLogic) => "gameLogic" -> BaseGameLogicJsonFormatter.createBaseGameLogicJson(gameLogic.asInstanceOf[BaseGameLogicSnapshot])
|
||||
},
|
||||
matchSnapshot.matchImpl match {
|
||||
case None => "cardManager" -> JsString("None")
|
||||
case Some(matchImpl) => "cardManager" -> CardManagerJsonFormatter.createCardManagerJson(matchImpl.cardManager)
|
||||
},
|
||||
matchSnapshot.round match {
|
||||
case None => "round" -> JsString("None")
|
||||
case Some(round) => "round" -> RoundJsonFormatter.createRoundJson(round)
|
||||
},
|
||||
matchSnapshot.trick match {
|
||||
case None => "trick" -> JsString("None")
|
||||
case Some(trick) => "trick" -> TrickJsonFormatter.createTrickJson(trick)
|
||||
},
|
||||
matchSnapshot.currentIndex match {
|
||||
case None => "currentIndex" -> JsString("None")
|
||||
case Some(index) => "currentIndex" -> JsNumber(index)
|
||||
}
|
||||
)
|
||||
js.toString().getBytes
|
||||
}
|
||||
|
||||
override def parseFormat(bytes: Array[Byte]): MatchSnapshot = {
|
||||
val json = Json.parse(new String(bytes))
|
||||
val gameState = GameState.valueOf((json \ "gamestate").get.asInstanceOf[JsString].value)
|
||||
val methodEntryPoint = (json \ "methodEntryPoint").get match {
|
||||
val methodEntryPoint = (json \ "entryPoint").get match {
|
||||
case JsString("None") => None
|
||||
case JsString(methodEntryPoint) => Some(MethodEntryPoint.valueOf(methodEntryPoint))
|
||||
case default => None
|
||||
}
|
||||
val matchImpl = (json \ "match").get match {
|
||||
val gameLogic = (json \ "gameLogic").get match {
|
||||
case JsString("None") => None
|
||||
case matchJson => Some(MatchJsonFormatter.parseMatchJson(matchJson.asInstanceOf[JsObject], playerUtil, CardManagerJsonFormatter.parseCardManagerJson((json \ "cardManager").get.asInstanceOf[JsObject])))
|
||||
case gameLogicJson: JsObject => Some(BaseGameLogicJsonFormatter.createBaseGameLogicFromJson(gameLogicJson, playerUtil))
|
||||
case default => None
|
||||
}
|
||||
val round = (json \ "round").get match {
|
||||
case JsString("None") => None
|
||||
case roundJson => Some(RoundJsonFormatter.parseRoundJson(roundJson.asInstanceOf[JsObject], playerUtil, CardManagerJsonFormatter.parseCardManagerJson((json \ "cardManager").get.asInstanceOf[JsObject])))
|
||||
case default => None
|
||||
|
||||
MatchSnapshot(methodEntryPoint, gameLogic.asInstanceOf[Option[LogicSnapshot[GameLogic]]])
|
||||
}
|
||||
val trick = (json \ "trick").get match {
|
||||
case JsString("None") => None
|
||||
case trickJson => Some(TrickJsonFormatter.parseTrickJson(trickJson.asInstanceOf[JsObject], playerUtil, CardManagerJsonFormatter.parseCardManagerJson((json \ "cardManager").get.asInstanceOf[JsObject])))
|
||||
case default => None
|
||||
|
||||
private object BaseGameLogicJsonFormatter {
|
||||
|
||||
def createBaseGameLogicJson(baseGameLogic: BaseGameLogicSnapshot): JsValue = {
|
||||
Json.obj(
|
||||
"gameState" -> JsString(baseGameLogic.savedState.toString),
|
||||
|
||||
"cardManagerContainer" -> Json.obj(
|
||||
"cardContainer" -> Json.obj(
|
||||
"card" ->
|
||||
(if (baseGameLogic.cardContainer.isDefined) JsArray(
|
||||
baseGameLogic.cardContainer.get
|
||||
.map(card => CardJsonFormatter.createCardJson(card)))
|
||||
else JsString("None"))
|
||||
),
|
||||
"currentIdx" ->
|
||||
(if (baseGameLogic.cardIndex.isDefined) JsNumber(baseGameLogic.cardIndex.get) else JsString("None"))
|
||||
),
|
||||
|
||||
"match" -> (if (baseGameLogic.currentMatch.isDefined) MatchJsonFormatter.createMatchJson(baseGameLogic.currentMatch.get) else JsString("None")),
|
||||
"round" -> (if (baseGameLogic.currentRound.isDefined) RoundJsonFormatter.createRoundJson(baseGameLogic.currentRound.get) else JsString("None")),
|
||||
"trick" -> (if (baseGameLogic.currentTrick.isDefined) TrickJsonFormatter.createTrickJson(baseGameLogic.currentTrick.get) else JsString("None")),
|
||||
"player" -> (if (baseGameLogic.currentPlayer.isDefined) PlayerJsonFormatter.createPlayerJson(baseGameLogic.currentPlayer.get) else JsString("None")),
|
||||
|
||||
"queue" -> Json.obj(
|
||||
"currentIndx" -> (if (baseGameLogic.playerIndex.isDefined) JsNumber(baseGameLogic.playerIndex.get) else JsString("None")),
|
||||
"players" ->
|
||||
(if (baseGameLogic.players.isDefined) JsArray(
|
||||
baseGameLogic.players.get
|
||||
.map(player => PlayerJsonFormatter.createPlayerJson(player)))
|
||||
else JsString("None"))
|
||||
),
|
||||
)
|
||||
}
|
||||
val currentIndex = (json \ "currentIndex").get match {
|
||||
case JsString("None") => None
|
||||
case JsNumber(index) => Some(index.toInt)
|
||||
case default => None
|
||||
|
||||
def createBaseGameLogicFromJson(baseGameLogicJson: JsObject, playerUtil: PlayerUtil): BaseGameLogicSnapshot = {
|
||||
val gameState = GameState.valueOf((baseGameLogicJson \ "gameState").get.asInstanceOf[JsString].value)
|
||||
|
||||
val cardContainerJson = (baseGameLogicJson \ "cardManagerContainer" \ "cardContainer" \ "card").get
|
||||
val cardContainer = if (cardContainerJson.isInstanceOf[JsString]) {
|
||||
None
|
||||
} else {
|
||||
Some(cardContainerJson.asInstanceOf[JsArray].value.map(cardJson => CardJsonFormatter.parseCardJson(cardJson.asInstanceOf[JsObject])).toList)
|
||||
}
|
||||
val cc = cardContainer match {
|
||||
case Some(cards) => cards
|
||||
case None => List.empty[Card]
|
||||
}
|
||||
|
||||
val cardIndex = (baseGameLogicJson \ "cardManagerContainer" \ "currentIdx").get match {
|
||||
case JsString("None") => None
|
||||
case JsNumber(idx) => Some(idx.toInt)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
val matchImpl = (baseGameLogicJson \ "match").get match {
|
||||
case JsString("None") => None
|
||||
case matchJson: JsObject => Some(MatchJsonFormatter.parseMatchJson(matchJson, playerUtil, cc))
|
||||
case _ => None
|
||||
}
|
||||
|
||||
val round = (baseGameLogicJson \ "round").get match {
|
||||
case JsString("None") => None
|
||||
case roundJson: JsObject => Some(RoundJsonFormatter.parseRoundJson(roundJson, playerUtil, cc))
|
||||
case _ => None
|
||||
}
|
||||
|
||||
val trick = (baseGameLogicJson \ "trick").get match {
|
||||
case JsString("None") => None
|
||||
case trickJson: JsObject => Some(TrickJsonFormatter.parseTrickJson(trickJson, playerUtil, cc))
|
||||
case _ => None
|
||||
}
|
||||
|
||||
val player = (baseGameLogicJson \ "player").get match {
|
||||
case JsString("None") => None
|
||||
case playerJson: JsObject => Some(PlayerJsonFormatter.parsePlayerJson(playerJson, playerUtil, cc))
|
||||
case _ => None
|
||||
}
|
||||
|
||||
val queueJson = (baseGameLogicJson \ "queue").get
|
||||
val playerIndex = (queueJson \ "currentIndx").get match {
|
||||
case JsString("None") => None
|
||||
case JsNumber(idx) => Some(idx.toInt)
|
||||
case _ => None
|
||||
}
|
||||
val playersJson = (queueJson \ "players").get
|
||||
val players = if (playersJson.isInstanceOf[JsString]) {
|
||||
None
|
||||
} else {
|
||||
Some(playersJson.asInstanceOf[JsArray].value.map(playerJson => PlayerJsonFormatter.parsePlayerJson(playerJson.asInstanceOf[JsObject], playerUtil, cc)).toList)
|
||||
}
|
||||
BaseGameLogicSnapshot(
|
||||
gameState,
|
||||
cardContainer,
|
||||
cardIndex,
|
||||
matchImpl,
|
||||
round,
|
||||
trick,
|
||||
player,
|
||||
playerIndex,
|
||||
players,
|
||||
matchImpl match {
|
||||
case Some(m) => m.totalplayers.map(p => (p.id, p.generatePlayerData())).toMap
|
||||
case None => Map.empty[UUID, PlayerData]
|
||||
}
|
||||
)
|
||||
}
|
||||
MatchSnapshot(matchImpl, round, trick, currentIndex, gameState, methodEntryPoint)
|
||||
}
|
||||
|
||||
private object PlayerJsonFormatter {
|
||||
@@ -87,8 +165,8 @@ class JSONFormatter extends FileFormatter {
|
||||
Json.obj(
|
||||
"id" -> abstractPlayer.id.toString,
|
||||
"name" -> abstractPlayer.name,
|
||||
"hand" -> createHandJson(abstractPlayer.hand),
|
||||
"doglife" -> abstractPlayer.doglife,
|
||||
"hand" -> createHandJson(abstractPlayer.currentHand()),
|
||||
"doglife" -> abstractPlayer.isInDogLife,
|
||||
"playerType" -> PlayerFactory.parsePlayerType(abstractPlayer).toString
|
||||
)
|
||||
}
|
||||
@@ -105,26 +183,26 @@ class JSONFormatter extends FileFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
def parsePlayerJson(playerJson: JsObject, playerUtil: PlayerUtil, cardManager: CardManager): AbstractPlayer = {
|
||||
def parsePlayerJson(playerJson: JsObject, playerUtil: PlayerUtil, cards: List[Card]): AbstractPlayer = {
|
||||
val id = UUID.fromString((playerJson \ "id").get.asInstanceOf[JsString].value)
|
||||
val name = (playerJson \ "name").get.asInstanceOf[JsString].value
|
||||
val handJson = playerJson \ "hand"
|
||||
val doglife = (playerJson \ "doglife").get.asInstanceOf[JsBoolean].value
|
||||
val playerType = Playertype.valueOf((playerJson \ "playerType").get.asInstanceOf[JsString].value)
|
||||
|
||||
val hand = if (handJson.isInstanceOf[JsString]) {
|
||||
val hand = if (handJson.isEmpty || !handJson.get.isInstanceOf[JsObject]) {
|
||||
None
|
||||
} else {
|
||||
Some(parseHandJson(handJson.get.asInstanceOf[JsObject], cardManager))
|
||||
Some(parseHandJson(handJson.get.asInstanceOf[JsObject], cards))
|
||||
}
|
||||
|
||||
playerUtil.handlePlayer(id, name, hand, doglife, playerType)
|
||||
}
|
||||
|
||||
private def parseHandJson(handJson: JsObject, cardManager: CardManager): Hand = {
|
||||
private def parseHandJson(handJson: JsObject, cc: List[Card]): Hand = {
|
||||
val cards = (handJson \ "cards").get.asInstanceOf[JsArray].value.map(cardJson => {
|
||||
val card = CardJsonFormatter.parseCardJson(cardJson.asInstanceOf[JsObject])
|
||||
cardManager.grabSpecificCard(card)
|
||||
CardFormatUtil.grabSpecificCard(card, cc)
|
||||
})
|
||||
Hand(cards.toList)
|
||||
}
|
||||
@@ -138,19 +216,19 @@ class JSONFormatter extends FileFormatter {
|
||||
trick.cards.map { case (card, player) => Json.obj(
|
||||
"card" -> CardJsonFormatter.createCardJson(card),
|
||||
"player" -> PlayerJsonFormatter.createPlayerJson(player)
|
||||
)}.toList
|
||||
)
|
||||
}.toList
|
||||
),
|
||||
"firstCard" -> (if (trick.firstCard.isDefined) CardJsonFormatter.createCardJson(trick.firstCard.get) else JsString("")),
|
||||
"winner" -> (if (trick.winner != null) PlayerJsonFormatter.createPlayerJson(trick.winner) else JsString("")),
|
||||
"finished" -> JsBoolean(trick.finished)
|
||||
"winner" -> (if (trick.winner.isDefined) PlayerJsonFormatter.createPlayerJson(trick.winner.get) else JsString("")),
|
||||
)
|
||||
}
|
||||
|
||||
def parseTrickJson(trickJson: JsObject, playerUtil: PlayerUtil, cardManager: CardManager): Trick = {
|
||||
def parseTrickJson(trickJson: JsObject, playerUtil: PlayerUtil, cc: List[Card]): Trick = {
|
||||
val plays = (trickJson \ "plays").get
|
||||
val playsList = plays.asInstanceOf[JsArray].value.map(playJson => {
|
||||
val card = CardJsonFormatter.parseCardJson((playJson \ "card").get.asInstanceOf[JsObject])
|
||||
val player = PlayerJsonFormatter.parsePlayerJson((playJson \ "player").get.asInstanceOf[JsObject], playerUtil, cardManager)
|
||||
val player = PlayerJsonFormatter.parsePlayerJson((playJson \ "player").get.asInstanceOf[JsObject], playerUtil, cc)
|
||||
(card, player)
|
||||
}).groupBy(_._1).map((card, list) => (card, list.map(_._2).head))
|
||||
val firstCard = if ((trickJson \ "firstCard").get.isInstanceOf[JsString]) {
|
||||
@@ -159,13 +237,12 @@ class JSONFormatter extends FileFormatter {
|
||||
Some(CardJsonFormatter.parseCardJson((trickJson \ "firstCard").get.asInstanceOf[JsObject]))
|
||||
}
|
||||
val winner = if ((trickJson \ "winner").get.isInstanceOf[JsString]) {
|
||||
null
|
||||
None
|
||||
} else {
|
||||
PlayerJsonFormatter.parsePlayerJson((trickJson \ "winner").get.asInstanceOf[JsObject], playerUtil, cardManager)
|
||||
Some(PlayerJsonFormatter.parsePlayerJson((trickJson \ "winner").get.asInstanceOf[JsObject], playerUtil, cc))
|
||||
}
|
||||
val finished = (trickJson \ "finished").get.asInstanceOf[JsBoolean].value
|
||||
val hashed = HashMap(playsList.toSeq*)
|
||||
Trick(hashed, winner, finished, firstCard)
|
||||
val hashed = HashMap(playsList.toSeq *)
|
||||
Trick(hashed, winner, firstCard)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,46 +253,23 @@ class JSONFormatter extends FileFormatter {
|
||||
"tricks" -> JsArray(
|
||||
round.tricklist.map(trick => TrickJsonFormatter.createTrickJson(trick))
|
||||
),
|
||||
"playersin" -> JsArray(
|
||||
round.playersin.map(player => PlayerJsonFormatter.createPlayerJson(player))
|
||||
),
|
||||
round.playersout match {
|
||||
case null => "playersout" -> JsString("None")
|
||||
case default =>
|
||||
"playersout" -> JsArray(
|
||||
round.playersout.map(player => PlayerJsonFormatter.createPlayerJson(player))
|
||||
)
|
||||
},
|
||||
"queue" -> Json.obj(
|
||||
"currentIndx" -> round.playerQueue.currentIndex,
|
||||
"players" -> JsArray(
|
||||
round.playerQueue.convertToArray().map(player => PlayerJsonFormatter.createPlayerJson(player))
|
||||
)
|
||||
),
|
||||
"trumpSuit" -> JsNumber(round.trumpSuit.ordinal),
|
||||
"startingPlayer" -> JsNumber(round.playerQueue.currentIndex),
|
||||
"winner" -> (if (round.winner != null) PlayerJsonFormatter.createPlayerJson(round.winner) else JsString("None")),
|
||||
"winner" -> (if (round.winner.isDefined) PlayerJsonFormatter.createPlayerJson(round.winner.get) else JsString("None")),
|
||||
"firstRound" -> JsBoolean(round.firstRound)
|
||||
)
|
||||
}
|
||||
|
||||
def parseRoundJson(roundJson: JsObject, playerUtil: PlayerUtil, cardManager: CardManager): Round = {
|
||||
def parseRoundJson(roundJson: JsObject, playerUtil: PlayerUtil, cc: List[Card]): Round = {
|
||||
val tricks = (roundJson \ "tricks").get
|
||||
val tricksList = tricks.asInstanceOf[JsArray].value.map(trickJson => TrickJsonFormatter.parseTrickJson(trickJson.asInstanceOf[JsObject], playerUtil, cardManager)).toList
|
||||
val playersin = (roundJson \ "playersin").get.asInstanceOf[JsArray].value.map(playerJson => PlayerJsonFormatter.parsePlayerJson(playerJson.asInstanceOf[JsObject], playerUtil, cardManager)).toList
|
||||
val playersout = (roundJson \ "playersout").get match {
|
||||
case JsString("None") => List()
|
||||
case default => (roundJson \ "playersout").get.asInstanceOf[JsArray].value.map(playerJson => PlayerJsonFormatter.parsePlayerJson(playerJson.asInstanceOf[JsObject], playerUtil, cardManager)).toList
|
||||
}
|
||||
val tricksList = tricks.asInstanceOf[JsArray].value.map(trickJson => TrickJsonFormatter.parseTrickJson(trickJson.asInstanceOf[JsObject], playerUtil, cc)).toList
|
||||
val trumpSuit = Suit.fromOrdinal((roundJson \ "trumpSuit").get.asInstanceOf[JsNumber].value.toInt)
|
||||
val startingPlayer = (roundJson \ "startingPlayer").get.asInstanceOf[JsNumber].value.toInt
|
||||
val winner = if ((roundJson \ "winner").get.isInstanceOf[JsString]) {
|
||||
null
|
||||
None
|
||||
} else {
|
||||
PlayerJsonFormatter.parsePlayerJson((roundJson \ "winner").get.asInstanceOf[JsObject], playerUtil, cardManager)
|
||||
Some(PlayerJsonFormatter.parsePlayerJson((roundJson \ "winner").get.asInstanceOf[JsObject], playerUtil, cc))
|
||||
}
|
||||
val firstRound = (roundJson \ "firstRound").get.asInstanceOf[JsBoolean].value
|
||||
Round(trumpSuit = trumpSuit, tricklist = tricksList, playersin = playersin, playersout = playersout, startingPlayer = startingPlayer, winner = winner, firstRound = firstRound)
|
||||
Round(trumpSuit = trumpSuit, tricklist = tricksList, winner = winner, firstRound = firstRound)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +280,9 @@ class JSONFormatter extends FileFormatter {
|
||||
"totalplayers" -> JsArray(
|
||||
matchImpl.totalplayers.map(player => PlayerJsonFormatter.createPlayerJson(player))
|
||||
),
|
||||
"playerIn" -> JsArray(
|
||||
matchImpl.playersIn.map(player => PlayerJsonFormatter.createPlayerJson(player))
|
||||
),
|
||||
"numberofcards" -> JsNumber(matchImpl.numberofcards),
|
||||
"dogLife" -> JsBoolean(matchImpl.dogLife),
|
||||
"roundlist" -> JsArray(
|
||||
@@ -234,12 +291,13 @@ class JSONFormatter extends FileFormatter {
|
||||
)
|
||||
}
|
||||
|
||||
def parseMatchJson(matchJson: JsObject, playerUtil: PlayerUtil, cardManager: CardManager): Match = {
|
||||
val totalplayers = (matchJson \ "totalplayers").get.asInstanceOf[JsArray].value.map(playerJson => PlayerJsonFormatter.parsePlayerJson(playerJson.asInstanceOf[JsObject], playerUtil, cardManager)).toList
|
||||
def parseMatchJson(matchJson: JsObject, playerUtil: PlayerUtil, cc: List[Card]): Match = {
|
||||
val totalplayers = (matchJson \ "totalplayers").get.asInstanceOf[JsArray].value.map(playerJson => PlayerJsonFormatter.parsePlayerJson(playerJson.asInstanceOf[JsObject], playerUtil, cc)).toList
|
||||
val playersIn = (matchJson \ "playerIn").get.asInstanceOf[JsArray].value.map(playerJson => PlayerJsonFormatter.parsePlayerJson(playerJson.asInstanceOf[JsObject], playerUtil, cc)).toList
|
||||
val numberofcards = (matchJson \ "numberofcards").get.asInstanceOf[JsNumber].value.toInt
|
||||
val dogLife = (matchJson \ "dogLife").get.asInstanceOf[JsBoolean].value
|
||||
val roundlist = (matchJson \ "roundlist").get.asInstanceOf[JsArray].value.map(roundJson => RoundJsonFormatter.parseRoundJson(roundJson.asInstanceOf[JsObject], playerUtil, cardManager)).toList
|
||||
Match(totalplayers, numberofcards, dogLife, roundlist, cardManager)
|
||||
val roundlist = (matchJson \ "roundlist").get.asInstanceOf[JsArray].value.map(roundJson => RoundJsonFormatter.parseRoundJson(roundJson.asInstanceOf[JsObject], playerUtil, cc)).toList
|
||||
Match(totalplayers, playersIn, numberofcards, dogLife, roundlist)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -261,27 +319,4 @@ class JSONFormatter extends FileFormatter {
|
||||
|
||||
}
|
||||
|
||||
private object CardManagerJsonFormatter {
|
||||
def createCardManagerJson(cardManager: CardManager): JsObject = {
|
||||
Json.obj(
|
||||
"cardContainer" -> Json.obj(
|
||||
"card" -> JsArray(
|
||||
cardManager.cardContainer.map(card => CardJsonFormatter.createCardJson(card))
|
||||
)
|
||||
),
|
||||
"currentIdx" -> JsNumber(cardManager.currentIndx)
|
||||
)
|
||||
}
|
||||
|
||||
def parseCardManagerJson(cardManagerJson: JsObject): CardManager = {
|
||||
val cardContainer = (cardManagerJson \ "cardContainer").get.asInstanceOf[JsObject]
|
||||
val cards = (cardContainer \ "card").get.asInstanceOf[JsArray].value.map(cardJson => CardJsonFormatter.parseCardJson(cardJson.asInstanceOf[JsObject])).toList
|
||||
val currentIdx = (cardManagerJson \ "currentIdx").get.asInstanceOf[JsNumber].value.toInt
|
||||
val cardManager = KnockOutWhist.config.cardManager
|
||||
cardManager.setState(cards, currentIdx)
|
||||
cardManager
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,263 +0,0 @@
|
||||
package de.knockoutwhist.persistence.formats
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.CardValue.Ten
|
||||
import de.knockoutwhist.cards.{Card, CardManager, CardValue, Hand, Suit}
|
||||
import de.knockoutwhist.events.ui.GameState
|
||||
import de.knockoutwhist.persistence.{MatchSnapshot, MethodEntryPoint}
|
||||
import de.knockoutwhist.player.{AbstractPlayer, PlayerFactory, Playertype}
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
import scala.xml.{Elem, Node}
|
||||
import de.knockoutwhist.utils.Implicits.*
|
||||
|
||||
import java.util.UUID
|
||||
import scala.collection.immutable.HashMap
|
||||
|
||||
class XMLFormatter extends FileFormatter {
|
||||
override def formatName: String = "XML"
|
||||
|
||||
override def fileEnding: String = "xml"
|
||||
|
||||
override def createFormat(matchSnapshot: MatchSnapshot): Array[Byte] = {
|
||||
val xml =
|
||||
<gamesave>
|
||||
<gameState>{matchSnapshot.gameState.toString}</gameState>
|
||||
{matchSnapshot.methodEntryPoint.isDefined ? <methodEntryPoint>{matchSnapshot.methodEntryPoint.get.toString}</methodEntryPoint> |: ""}
|
||||
{matchSnapshot.matchImpl.isDefined ? CardManagerXMLFormatter.createCardManagerXML(matchSnapshot.matchImpl.get.cardManager) |: ""}
|
||||
{matchSnapshot.matchImpl.isDefined ? MatchXMLFormatter.createMatchXML(matchSnapshot.matchImpl.get) |: ""}
|
||||
{matchSnapshot.round.isDefined ? RoundXMLFormatter.createRoundXML(matchSnapshot.round.get) |: ""}
|
||||
{matchSnapshot.trick.isDefined ? TrickXMLFormatter.createTrickXML(matchSnapshot.trick.get) |: ""}
|
||||
{matchSnapshot.currentIndex.isDefined ? <currentIndex>{matchSnapshot.currentIndex.get}</currentIndex> |: ""}
|
||||
</gamesave>
|
||||
xml.toString().getBytes
|
||||
}
|
||||
|
||||
override def parseFormat(bytes: Array[Byte]): MatchSnapshot = {
|
||||
val xml = scala.xml.XML.loadString(new String(bytes))
|
||||
val gameState = GameState.valueOf((xml \ "gameState").text)
|
||||
val methodEntryPoint = if ((xml \ "methodEntryPoint").isEmpty) {
|
||||
None
|
||||
} else {
|
||||
Some(MethodEntryPoint.valueOf((xml \ "methodEntryPoint").text))
|
||||
}
|
||||
val playerHelp = PlayerUtil()
|
||||
val cardManager = if ((xml \ "cardManager").isEmpty) {
|
||||
KnockOutWhist.config.cardManager
|
||||
} else {
|
||||
CardManagerXMLFormatter.parseCardManagerXML((xml \ "cardManager").head)
|
||||
}
|
||||
val matchImpl = if ((xml \ "match").isEmpty) {
|
||||
None
|
||||
} else {
|
||||
Some(MatchXMLFormatter.parseMatchXML((xml \ "match").head, playerHelp, cardManager))
|
||||
}
|
||||
val round = if ((xml \ "round").isEmpty) {
|
||||
None
|
||||
} else {
|
||||
Some(RoundXMLFormatter.parseRoundXML((xml \ "round").head, playerHelp, cardManager))
|
||||
}
|
||||
val trick = if ((xml \ "trick").isEmpty) {
|
||||
None
|
||||
} else {
|
||||
Some(TrickXMLFormatter.parseTrickXML((xml \ "trick").head, playerHelp, cardManager))
|
||||
}
|
||||
val currentIndex = if ((xml \ "currentIndex").isEmpty) {
|
||||
None
|
||||
} else {
|
||||
Some((xml \ "currentIndex").text.toInt)
|
||||
}
|
||||
MatchSnapshot(matchImpl, round, trick, currentIndex, gameState, methodEntryPoint)
|
||||
}
|
||||
|
||||
|
||||
private object PlayerXMLFormatter {
|
||||
def createPlayerXML(abstractPlayer: AbstractPlayer): Elem = {
|
||||
<player>
|
||||
<id>{abstractPlayer.id.toString}</id>
|
||||
<name>{abstractPlayer.name}</name>
|
||||
{createHandXML(abstractPlayer.hand)}
|
||||
<doglife>{abstractPlayer.doglife}</doglife>
|
||||
<playerType>{PlayerFactory.parsePlayerType(abstractPlayer).toString}</playerType>
|
||||
</player>
|
||||
}
|
||||
|
||||
private def createHandXML(hand: Option[Hand]): Elem = {
|
||||
if (hand.isDefined) {
|
||||
<hand>
|
||||
{hand.get.cards.map(card => CardXMLFormatter.createCardXML(card))}
|
||||
</hand>
|
||||
} else {
|
||||
<hand></hand>
|
||||
}
|
||||
}
|
||||
|
||||
def parsePlayerXML(playerXML: Node, playerUtil: PlayerUtil, cardManager: CardManager): AbstractPlayer = {
|
||||
val id = UUID.fromString((playerXML \ "id").text)
|
||||
val name = (playerXML \ "name").text
|
||||
val handXML = playerXML \ "hand"
|
||||
val doglife = (playerXML \ "doglife").text.toBoolean
|
||||
val playerType = Playertype.valueOf((playerXML \ "playerType").text)
|
||||
|
||||
val hand = if (handXML.text.isEmpty) {
|
||||
None
|
||||
} else {
|
||||
Some(parseHandXML(handXML.head, cardManager))
|
||||
}
|
||||
|
||||
playerUtil.handlePlayer(id, name, hand, doglife, playerType)
|
||||
}
|
||||
|
||||
private def parseHandXML(handXML: Node, cardManager: CardManager): Hand = {
|
||||
val cards = (handXML \ "card").map(cardXML => {
|
||||
val card = CardXMLFormatter.parseCardXML(cardXML)
|
||||
cardManager.grabSpecificCard(card)
|
||||
})
|
||||
Hand(cards.toList)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private object TrickXMLFormatter {
|
||||
def createTrickXML(trick: Trick): Elem = {
|
||||
<trick>
|
||||
<plays>
|
||||
{trick.cards.map { case (card, player) => <play>{CardXMLFormatter.createCardXML(card)}{PlayerXMLFormatter.createPlayerXML(player)}</play> }}
|
||||
</plays>
|
||||
<firstCard>{(trick.firstCard.isDefined) ? CardXMLFormatter.createCardXML(trick.firstCard.get) |: ""}</firstCard>
|
||||
<winner>{(trick.winner != null) ? PlayerXMLFormatter.createPlayerXML(trick.winner) |: ""}</winner>
|
||||
<finished>{trick.finished}</finished>
|
||||
</trick>
|
||||
}
|
||||
|
||||
def parseTrickXML(trickXML: Node, playerUtil: PlayerUtil, cardManager: CardManager): Trick = {
|
||||
val plays = (trickXML \ "plays").head
|
||||
val tricks = (plays \ "play").map(playXML => {
|
||||
val card = CardXMLFormatter.parseCardXML((playXML \ "card").head)
|
||||
val player = PlayerXMLFormatter.parsePlayerXML((playXML \ "player").head, playerUtil, cardManager)
|
||||
card -> player
|
||||
}).groupBy(_._1).map((card, list) => (card, list.map(_._2).head))
|
||||
val firstCard = if ((trickXML \ "firstCard").text.isEmpty) {
|
||||
None
|
||||
} else {
|
||||
val c = CardXMLFormatter.parseCardXML((trickXML \ "firstCard" \ "card").head)
|
||||
Some(cardManager.grabSpecificCard(c))
|
||||
}
|
||||
val winner = if ((trickXML \ "winner").text.isEmpty) {
|
||||
null
|
||||
} else {
|
||||
PlayerXMLFormatter.parsePlayerXML((trickXML \ "winner" \ "player").head, playerUtil, cardManager)
|
||||
}
|
||||
val finished = (trickXML \ "finished").text.toBoolean
|
||||
val hashed = HashMap(tricks.toSeq*)
|
||||
Trick(hashed, winner, finished, firstCard)
|
||||
}
|
||||
}
|
||||
|
||||
private object RoundXMLFormatter {
|
||||
|
||||
def createRoundXML(round: Round): Elem = {
|
||||
<round>
|
||||
<tricks>
|
||||
{round.tricklist.map(trick => TrickXMLFormatter.createTrickXML(trick))}
|
||||
</tricks>
|
||||
<playersin>
|
||||
{round.playersin.map(player => PlayerXMLFormatter.createPlayerXML(player))}
|
||||
</playersin>
|
||||
<playersout>
|
||||
{(round.playersout != null) ? round.playersout.map(player => PlayerXMLFormatter.createPlayerXML(player)) |: ""}
|
||||
</playersout>
|
||||
<trumpSuit>{round.trumpSuit.ordinal}</trumpSuit>
|
||||
<startingPlayer>{round.playerQueue.currentIndex}</startingPlayer>
|
||||
<winner>{(round.winner != null) ? PlayerXMLFormatter.createPlayerXML(round.winner) |: ""}</winner>
|
||||
<firstRound>{round.firstRound}</firstRound>
|
||||
</round>
|
||||
}
|
||||
|
||||
def parseRoundXML(roundXML: Node, playerUtil: PlayerUtil, cardManager: CardManager): Round = {
|
||||
val tricks = (roundXML \ "tricks").head
|
||||
val tricklist = tricks \ "trick"
|
||||
val tricksList = tricklist.map(trickXML => TrickXMLFormatter.parseTrickXML(trickXML, playerUtil, cardManager)).toList
|
||||
val playersin = (roundXML \ "playersin").head \ "player"
|
||||
val playersInList = playersin.map(playerXML => PlayerXMLFormatter.parsePlayerXML(playerXML, playerUtil, cardManager)).toList
|
||||
val playersout = (roundXML \ "playersout").head \ "player"
|
||||
val playersOutList = playersout.map(playerXML => PlayerXMLFormatter.parsePlayerXML(playerXML, playerUtil, cardManager)).toList
|
||||
val trumpSuit = Suit.fromOrdinal((roundXML \ "trumpSuit").text.toInt)
|
||||
val startingPlayer = (roundXML \ "startingPlayer").text.toInt
|
||||
val winner = if ((roundXML \ "winner").text.isEmpty) {
|
||||
null
|
||||
} else {
|
||||
PlayerXMLFormatter.parsePlayerXML((roundXML \ "winner" \ "player").head, playerUtil, cardManager)
|
||||
}
|
||||
val firstRound = (roundXML \ "firstRound").text.toBoolean
|
||||
Round(trumpSuit, tricksList, playersInList, playersOutList, startingPlayer, winner, firstRound)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private object MatchXMLFormatter {
|
||||
|
||||
def createMatchXML(matchImpl: Match): Elem = {
|
||||
<match>
|
||||
<totalplayers>
|
||||
{matchImpl.totalplayers.map(player => PlayerXMLFormatter.createPlayerXML(player))}
|
||||
</totalplayers>
|
||||
<numberofcards>{matchImpl.numberofcards}</numberofcards>
|
||||
<dogLife>{matchImpl.dogLife}</dogLife>
|
||||
<roundlist>
|
||||
{matchImpl.roundlist.map(round => RoundXMLFormatter.createRoundXML(round))}
|
||||
</roundlist>
|
||||
</match>
|
||||
}
|
||||
|
||||
def parseMatchXML(matchXML: Node, playerUtil: PlayerUtil, cardManager: CardManager): Match = {
|
||||
val totalplayers = (matchXML \ "totalplayers").head \ "player"
|
||||
val totalPlayersList = totalplayers.map(playerXML => PlayerXMLFormatter.parsePlayerXML(playerXML, playerUtil, cardManager)).toList
|
||||
val numberofcards = (matchXML \ "numberofcards").text.toInt
|
||||
val dogLife = (matchXML \ "dogLife").text.toBoolean
|
||||
val roundlist = (matchXML \ "roundlist").head \ "round"
|
||||
val roundList = roundlist.map(roundXML => RoundXMLFormatter.parseRoundXML(roundXML, playerUtil, cardManager)).toList
|
||||
Match(totalPlayersList, numberofcards, dogLife, roundList, cardManager)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private object CardXMLFormatter {
|
||||
|
||||
def createCardXML(card: Card): Elem = {
|
||||
<card>
|
||||
<value>{card.cardValue.ordinal}</value>
|
||||
<suit>{card.suit.ordinal}</suit>
|
||||
</card>
|
||||
}
|
||||
|
||||
def parseCardXML(cardXML: Node): Card = {
|
||||
val value = (cardXML \ "value").text.toInt
|
||||
val suit = (cardXML \ "suit").text.toInt
|
||||
Card(CardValue.fromOrdinal(value), Suit.fromOrdinal(suit))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private object CardManagerXMLFormatter {
|
||||
def createCardManagerXML(cardManager: CardManager): Elem = {
|
||||
<cardManager>
|
||||
<cardContainer>
|
||||
{cardManager.cardContainer.map(card => CardXMLFormatter.createCardXML(card))}
|
||||
</cardContainer>
|
||||
<currentIdx>{cardManager.currentIndx}</currentIdx>
|
||||
</cardManager>
|
||||
}
|
||||
|
||||
def parseCardManagerXML(cardManagerXML: Node): CardManager = {
|
||||
val cardContainer = (cardManagerXML \ "cardContainer").head \ "card"
|
||||
val cardContainerList = cardContainer.map(cardXML => CardXMLFormatter.parseCardXML(cardXML)).toList
|
||||
val currentIdx = (cardManagerXML \ "currentIdx").text.toInt
|
||||
val cardManager = KnockOutWhist.config.cardManager
|
||||
cardManager.setState(cardContainerList, currentIdx)
|
||||
cardManager
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package de.knockoutwhist.persistence.stub
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.events.ui.GameState
|
||||
import de.knockoutwhist.persistence.formats.{JSONFormatter, XMLFormatter}
|
||||
import de.knockoutwhist.persistence.{MatchSnapshot, MethodEntryPoint, PersistenceManager}
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
object PersistenceBaseManager extends PersistenceManager {
|
||||
|
||||
private var currentSnapshot: MatchSnapshot = MatchSnapshot()
|
||||
|
||||
override def updateGameState(gameState: GameState): MatchSnapshot = {
|
||||
currentSnapshot = currentSnapshot.withGameState(gameState)
|
||||
currentSnapshot
|
||||
}
|
||||
|
||||
override def updateMatch(matchImpl: Match): MatchSnapshot = {
|
||||
currentSnapshot = currentSnapshot.withMatchImpl(matchImpl)
|
||||
currentSnapshot
|
||||
}
|
||||
|
||||
override def updateRound(round: Round): MatchSnapshot = {
|
||||
currentSnapshot = currentSnapshot.withRound(round)
|
||||
currentSnapshot
|
||||
}
|
||||
|
||||
override def updateTrick(trick: Trick): MatchSnapshot = {
|
||||
currentSnapshot = currentSnapshot.withTrick(trick)
|
||||
currentSnapshot
|
||||
}
|
||||
|
||||
override def updateCurrentIndex(currentIndex: Int): MatchSnapshot = {
|
||||
currentSnapshot = currentSnapshot.withCurrentIndex(currentIndex)
|
||||
currentSnapshot
|
||||
}
|
||||
|
||||
override def updateMethodEntryPoint(methodEntryPoint: MethodEntryPoint): MatchSnapshot = {
|
||||
currentSnapshot = currentSnapshot.withMethodEntryPoint(methodEntryPoint)
|
||||
currentSnapshot
|
||||
}
|
||||
|
||||
override def saveFile(path: String): Unit = {
|
||||
KnockOutWhist.config.fileFormatter.writeToFile(currentSnapshot, path + "." + KnockOutWhist.config.fileFormatter.fileEnding)
|
||||
}
|
||||
|
||||
override def loadFile(path: String): Unit = {
|
||||
currentSnapshot = KnockOutWhist.config.fileFormatter.readFromFile(path + "." + KnockOutWhist.config.fileFormatter.fileEnding)
|
||||
currentSnapshot.restoreSnapshot()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package de.knockoutwhist.player
|
||||
import de.knockoutwhist.cards.{Card, Hand, Suit}
|
||||
import de.knockoutwhist.control.AILogic
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
import java.util.UUID
|
||||
import scala.collection.immutable
|
||||
import scala.util.Try
|
||||
|
||||
class AIPlayer private[player](name: String, hand: Option[Hand], id: UUID = UUID.randomUUID(), doglife: Boolean = false) extends AbstractPlayer(name, hand, id, doglife) {
|
||||
override def provideHand(hand: Hand): AbstractPlayer = {
|
||||
AIPlayer(name, Some(hand), id, doglife)
|
||||
}
|
||||
|
||||
override def removeCard(card: Card): AbstractPlayer = {
|
||||
AIPlayer(name, Some(hand.get.removeCard(card)), id, doglife)
|
||||
}
|
||||
|
||||
override def setDogLife(): AbstractPlayer = AIPlayer(name, hand, id, true)
|
||||
|
||||
override def handlePlayCard(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int): Unit = {
|
||||
AILogic.decideCard(this, round, trick)
|
||||
}
|
||||
|
||||
override def handleDogPlayCard(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, needstoplay: Boolean): Unit = {
|
||||
AILogic.decideDogCard(this, round, trick, needstoplay)
|
||||
}
|
||||
|
||||
override def handlePickTrumpsuit(matchImpl: Match, remaining_players: List[AbstractPlayer], firstRound: Boolean): Unit = {
|
||||
AILogic.decideTrumpSuit(this)
|
||||
}
|
||||
|
||||
override def handlePickTieCard(winner: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit = {
|
||||
AILogic.decideTie(1, remaining)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +1,63 @@
|
||||
package de.knockoutwhist.player
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Hand, Suit}
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.cards.{Card, Hand}
|
||||
|
||||
import java.util.UUID
|
||||
import scala.collection.immutable
|
||||
import scala.util.Try
|
||||
|
||||
//If you get an uuid conflict, go play the lottery!!!
|
||||
abstract case class AbstractPlayer private[player](var name: String, hand: Option[Hand], id: UUID = UUID.randomUUID(), doglife: Boolean = false) {
|
||||
abstract case class AbstractPlayer private[player](name: String, id: UUID = UUID.randomUUID()) {
|
||||
|
||||
protected var hand: Option[Hand] = None
|
||||
protected var dogLife: Boolean = false
|
||||
|
||||
def currentHand(): Option[Hand] = hand
|
||||
|
||||
def provideHand(hand: Hand): AbstractPlayer
|
||||
def setDogLife(): AbstractPlayer
|
||||
def removeCard(card: Card): AbstractPlayer
|
||||
def isInDogLife: Boolean = dogLife
|
||||
|
||||
def handlePlayCard(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int): Unit
|
||||
def handleDogPlayCard(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, needstoplay: Boolean): Unit
|
||||
def handlePickTrumpsuit(matchImpl: Match, remaining_players: List[AbstractPlayer], firstRound: Boolean): Unit
|
||||
def handlePickTieCard(winner: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit
|
||||
def provideHand(hand: Hand): Unit = {
|
||||
this.hand = Some(hand)
|
||||
}
|
||||
def setDogLife(): Unit = {
|
||||
this.dogLife = true
|
||||
}
|
||||
def resetDogLife(): Unit = {
|
||||
this.dogLife = false
|
||||
}
|
||||
def removeCard(card: Card): Unit = {
|
||||
this.hand = this.hand.map(_.removeCard(card))
|
||||
}
|
||||
|
||||
override def toString: String = {
|
||||
name
|
||||
}
|
||||
|
||||
override def canEqual(that: Any): Boolean = that.isInstanceOf[AbstractPlayer]
|
||||
|
||||
override def equals(obj: Any): Boolean = {
|
||||
obj match {
|
||||
case that: AbstractPlayer => this.id.equals(that.id)
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def generatePlayerData(): PlayerData = {
|
||||
PlayerData(id, name, hand, dogLife)
|
||||
}
|
||||
|
||||
def receivePlayerData(data: PlayerData): Unit = {
|
||||
if (this.id != data.id) {
|
||||
throw new IllegalArgumentException("Cannot receive PlayerData for a different player!")
|
||||
}
|
||||
if (this.name != data.name) {
|
||||
throw new IllegalArgumentException("Cannot change player name via PlayerData!")
|
||||
}
|
||||
this.hand = data.hand
|
||||
this.dogLife = data.dogLife
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case class PlayerData(id: UUID, name: String, hand: Option[Hand], dogLife: Boolean) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package de.knockoutwhist.player
|
||||
|
||||
import de.knockoutwhist.player.Playertype.{AI, HUMAN, STUB}
|
||||
import de.knockoutwhist.player.Playertype.{HUMAN, STUB}
|
||||
import de.knockoutwhist.player.baseImpl.HumanPlayer
|
||||
import de.knockoutwhist.player.builder.*
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.util.UUID
|
||||
|
||||
enum Playertype:
|
||||
case HUMAN
|
||||
case AI
|
||||
case STUB
|
||||
end Playertype
|
||||
|
||||
@@ -17,8 +16,6 @@ object PlayerFactory {
|
||||
val buildType: PlayerBuilder = playertype match {
|
||||
case HUMAN =>
|
||||
new HumanoidBuilder()
|
||||
case AI =>
|
||||
new AIPlayerBuilder()
|
||||
case STUB =>
|
||||
new StubPlayerBuilder
|
||||
}
|
||||
@@ -41,8 +38,6 @@ object PlayerFactory {
|
||||
player match {
|
||||
case _: HumanPlayer =>
|
||||
HUMAN
|
||||
case _: AIPlayer =>
|
||||
AI
|
||||
case _: StubPlayer =>
|
||||
STUB
|
||||
}
|
||||
|
||||
@@ -1,42 +1,7 @@
|
||||
package de.knockoutwhist.player
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.CardValue.Ten
|
||||
import de.knockoutwhist.cards.Suit.Spades
|
||||
import de.knockoutwhist.cards.{Card, Hand}
|
||||
import de.knockoutwhist.control.ControlHandler
|
||||
import de.knockoutwhist.control.controllerBaseImpl.{PlayerLogic, TrickLogic}
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
import java.util.UUID
|
||||
import scala.collection.immutable
|
||||
import scala.util.Try
|
||||
|
||||
class StubPlayer private[player](name: String, hand: Option[Hand], id: UUID = UUID.randomUUID(), doglife: Boolean = false) extends AbstractPlayer(name, hand, id, doglife) {
|
||||
class StubPlayer (name: String, id: UUID = UUID.randomUUID()) extends AbstractPlayer(name, id) {
|
||||
|
||||
override def provideHand(hand: Hand): AbstractPlayer = {
|
||||
StubPlayer(name, Some(hand), id, doglife)
|
||||
}
|
||||
|
||||
override def removeCard(card: Card): AbstractPlayer = {
|
||||
StubPlayer(name, Some(hand.get.removeCard(card)), id, doglife)
|
||||
}
|
||||
|
||||
override def setDogLife(): AbstractPlayer = StubPlayer(name, hand, id, true)
|
||||
|
||||
override def handlePlayCard(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int): Unit = {
|
||||
KnockOutWhist.config.trickcomponent.controlSuitplayed(Try{Card(Ten, Spades)}, matchImpl, round, trick, currentIndex, this)
|
||||
}
|
||||
|
||||
override def handleDogPlayCard(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, needstoplay: Boolean): Unit = {
|
||||
KnockOutWhist.config.trickcomponent.controlDogPlayed(Try{None}, matchImpl, round, trick, currentIndex, this)
|
||||
}
|
||||
|
||||
override def handlePickTrumpsuit(matchImpl: Match, remaining_players: List[AbstractPlayer], firstRound: Boolean): Unit = {
|
||||
KnockOutWhist.config.playerlogcomponent.trumpSuitSelected(matchImpl, Try{Spades}, remaining_players, firstRound, this)
|
||||
}
|
||||
|
||||
override def handlePickTieCard(winner: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit = {
|
||||
KnockOutWhist.config.playerlogcomponent.selectedTie(winner, matchImpl, round, playersout, cut, Try{1}, currentStep, remaining, currentIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,10 @@
|
||||
package de.knockoutwhist.player.baseImpl
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Hand, Suit}
|
||||
import de.knockoutwhist.control.ControlHandler
|
||||
import de.knockoutwhist.events.directional.{RequestCardEvent, RequestDogPlayCardEvent, RequestPickTrumpsuitEvent, RequestTieNumberEvent}
|
||||
import de.knockoutwhist.events.ui.GameState.TRUMPSUIT
|
||||
import de.knockoutwhist.events.ui.GameStateUpdateEvent
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
|
||||
import java.util.UUID
|
||||
import scala.collection.immutable
|
||||
import scala.util.Try
|
||||
|
||||
|
||||
class HumanPlayer private[player](name: String, hand: Option[Hand], id: UUID = UUID.randomUUID(), doglife: Boolean = false) extends AbstractPlayer(name, hand, id, doglife) {
|
||||
override def provideHand(hand: Hand): AbstractPlayer = {
|
||||
HumanPlayer(name, Some(hand), id, doglife)
|
||||
}
|
||||
|
||||
override def setDogLife(): AbstractPlayer = HumanPlayer(name, hand, id, true)
|
||||
|
||||
override def removeCard(card: Card): AbstractPlayer = {
|
||||
HumanPlayer(name, Some(hand.get.removeCard(card)), id, doglife)
|
||||
}
|
||||
|
||||
override def handlePlayCard(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int): Unit = {
|
||||
ControlHandler.invoke(RequestCardEvent(hand, matchImpl, round, trick, currentIndex, this))
|
||||
}
|
||||
|
||||
override def handleDogPlayCard(hand: Hand, matchImpl: Match, round: Round, trick: Trick, currentIndex: Int, needstoplay: Boolean): Unit = {
|
||||
ControlHandler.invoke(RequestDogPlayCardEvent(hand, matchImpl, round, trick, currentIndex, this, needstoplay))
|
||||
}
|
||||
|
||||
override def handlePickTrumpsuit(matchImpl: Match, remaining_players: List[AbstractPlayer], firstRound: Boolean): Unit = {
|
||||
ControlHandler.invoke(GameStateUpdateEvent(TRUMPSUIT))
|
||||
ControlHandler.invoke(RequestPickTrumpsuitEvent(matchImpl, remaining_players, firstRound, this))
|
||||
}
|
||||
|
||||
override def handlePickTieCard(winner: List[AbstractPlayer], matchImpl: Match, round: Round, playersout: List[AbstractPlayer], cut: immutable.HashMap[AbstractPlayer, Card], currentStep: Int, remaining: Int, currentIndex: Int = 0): Unit = {
|
||||
ControlHandler.invoke(RequestTieNumberEvent(winner, matchImpl, round, playersout, cut, currentStep, remaining, currentIndex))
|
||||
}
|
||||
class HumanPlayer (name: String, id: UUID = UUID.randomUUID()) extends AbstractPlayer(name, id) {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package de.knockoutwhist.player.builder
|
||||
|
||||
import de.knockoutwhist.player.{AIPlayer, AbstractPlayer}
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class AIPlayerBuilder extends PlayerBuilder {
|
||||
private var name: Option[String] = None
|
||||
private var id: Option[UUID] = Some(UUID.randomUUID())
|
||||
|
||||
override def setName(name: String): PlayerBuilder = {
|
||||
this.name = Some(name)
|
||||
this
|
||||
}
|
||||
|
||||
override def setID(id: UUID): PlayerBuilder = {
|
||||
this.id = Some(id)
|
||||
this
|
||||
}
|
||||
|
||||
override def reset(): PlayerBuilder = {
|
||||
this.name = None
|
||||
this.id = Some(UUID.randomUUID())
|
||||
this
|
||||
}
|
||||
|
||||
override def build(): AbstractPlayer = {
|
||||
if (this.name.isDefined && this.id.isDefined) {
|
||||
val player = new AIPlayer(this.name.get, None, id.get, false)
|
||||
reset()
|
||||
return player
|
||||
}
|
||||
throw new IllegalStateException("Trying to build non-existing AI")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,7 +28,7 @@ class HumanoidBuilder extends PlayerBuilder {
|
||||
|
||||
override def build(): AbstractPlayer = {
|
||||
if (this.name.isDefined && this.id.isDefined) {
|
||||
val player = new HumanPlayer(this.name.get, None, id.get, false)
|
||||
val player = new HumanPlayer(this.name.get, id.get)
|
||||
reset()
|
||||
return player
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class StubPlayerBuilder extends PlayerBuilder {
|
||||
|
||||
override def build(): AbstractPlayer = {
|
||||
if (this.name.isDefined && this.id.isDefined) {
|
||||
val player = new StubPlayer(this.name.get, None, id.get, false)
|
||||
val player = new StubPlayer(this.name.get, id.get)
|
||||
reset()
|
||||
return player
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@ import de.knockoutwhist.cards.CardManager
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.utils.Implicits.*
|
||||
|
||||
import java.util.UUID
|
||||
import scala.collection.immutable.List
|
||||
|
||||
case class Match(totalplayers: List[AbstractPlayer],numberofcards: Int = 7, dogLife: Boolean = false, roundlist: List[Round] = List[Round](), cardManager: CardManager) {
|
||||
case class Match(totalplayers: List[AbstractPlayer], playersIn: List[AbstractPlayer] = List(), numberofcards: Int = 7, dogLife: Boolean = false, roundlist: List[Round] = List[Round]()) {
|
||||
|
||||
def addRound(round: Round): Match = {
|
||||
this.copy(roundlist = roundlist :+ round)
|
||||
@@ -20,8 +21,16 @@ case class Match(totalplayers: List[AbstractPlayer],numberofcards: Int = 7, dogL
|
||||
this.copy(dogLife = true)
|
||||
}
|
||||
|
||||
def updatePlayers(totalplayers: List[AbstractPlayer]): Match = {
|
||||
this.copy(totalplayers = totalplayers)
|
||||
def updatePlayersIn(playersIn: List[AbstractPlayer]): Match = {
|
||||
this.copy(playersIn = playersIn)
|
||||
}
|
||||
|
||||
def playersOut: List[AbstractPlayer] = {
|
||||
totalplayers.diff(playersIn)
|
||||
}
|
||||
|
||||
def isOver: Boolean = {
|
||||
playersIn.size <= 1
|
||||
}
|
||||
|
||||
override def toString: String = {
|
||||
|
||||
@@ -10,26 +10,14 @@ import scala.collection.immutable
|
||||
import scala.collection.immutable.List
|
||||
import scala.util.Random
|
||||
|
||||
case class Round (trumpSuit: Suit, tricklist: List[Trick], playersin: List[AbstractPlayer], playersout: List[AbstractPlayer] = null, startingPlayer: Int = -1, winner: AbstractPlayer = null, firstRound: Boolean) {
|
||||
def this(trumpSuit: Suit, playersin: List[AbstractPlayer], firstRound: Boolean) = {
|
||||
this(trumpSuit, List[Trick](), playersin, firstRound = firstRound)
|
||||
}
|
||||
|
||||
val playerQueue: CustomPlayerQueue[AbstractPlayer] = KnockOutWhist.config.createRightQueue(
|
||||
playersin.toArray,
|
||||
(startingPlayer == -1) ? Random.nextInt(playersin.length) |: startingPlayer
|
||||
)
|
||||
case class Round (trumpSuit: Suit, firstRound: Boolean, tricklist: List[Trick] = List(), winner: Option[AbstractPlayer] = None) {
|
||||
|
||||
def addTrick(trick: Trick): Round = {
|
||||
Round(trumpSuit, tricklist :+ trick, playersin, playersout, playerQueue.currentIndex, winner, firstRound)
|
||||
}
|
||||
|
||||
def updatePlayersIn(playersin: List[AbstractPlayer]): Round = {
|
||||
Round(trumpSuit, tricklist, playersin, playersout, playerQueue.currentIndex, winner, firstRound)
|
||||
Round(trumpSuit, firstRound, tricklist :+ trick, winner)
|
||||
}
|
||||
|
||||
override def toString: String = {
|
||||
s"$trumpSuit, $tricklist, $playersin, $playersout, $winner, $firstRound"
|
||||
s"$trumpSuit, $tricklist, $winner, $firstRound"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,18 +5,20 @@ import de.knockoutwhist.player.AbstractPlayer
|
||||
|
||||
import scala.collection.immutable
|
||||
|
||||
case class Trick (cards: immutable.HashMap[Card, AbstractPlayer] = immutable.HashMap[Card, AbstractPlayer](), winner: AbstractPlayer = null, finished: Boolean = false, firstCard: Option[Card] = None) {
|
||||
case class Trick (cards: immutable.HashMap[Card, AbstractPlayer] = immutable.HashMap[Card, AbstractPlayer](), winner: Option[AbstractPlayer] = None, firstCard: Option[Card] = None) {
|
||||
|
||||
def finished: Boolean = winner.isDefined
|
||||
|
||||
def addCard(card: Card, player: AbstractPlayer): Trick = {
|
||||
Trick(cards + (card -> player), winner, finished, firstCard)
|
||||
Trick(cards + (card -> player), winner, firstCard)
|
||||
}
|
||||
|
||||
def setfirstcard(card: Card): Trick = {
|
||||
Trick(cards, winner, finished, Some(card))
|
||||
Trick(cards, winner, Some(card))
|
||||
}
|
||||
|
||||
override def toString: String = {
|
||||
s"$cards, $winner, $finished"
|
||||
s"$cards, $winner"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package de.knockoutwhist.ui
|
||||
|
||||
import de.knockoutwhist.control.GameLogic
|
||||
|
||||
trait UI {
|
||||
|
||||
def initial: Boolean
|
||||
def initial(gameLogic: GameLogic): Boolean
|
||||
|
||||
}
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
package de.knockoutwhist.ui.gui
|
||||
|
||||
import atlantafx.base.theme.PrimerDark
|
||||
import de.knockoutwhist.events.GLOBAL_STATUS.{SHOW_FINISHED_MATCH, SHOW_TIE_TIE, SHOW_TIE_WINNER}
|
||||
import de.knockoutwhist.events.PLAYER_STATUS.{SHOW_TIE_NUMBERS, SHOW_TURN, SHOW_WON_PLAYER_TRICK}
|
||||
import de.knockoutwhist.events.ROUND_STATUS.WON_ROUND
|
||||
import de.knockoutwhist.events.cards.ShowTieCardsEvent
|
||||
import de.knockoutwhist.events.directional.{RequestCardEvent, RequestDogPlayCardEvent, RequestPickTrumpsuitEvent, RequestTieNumberEvent}
|
||||
import de.knockoutwhist.events.round.ShowCurrentTrickEvent
|
||||
import de.knockoutwhist.events.ui.GameState.{INGAME, MAIN_MENU, NO_SET, PLAYERS, TIE, TRUMPSUIT}
|
||||
import de.knockoutwhist.events.ui.{GameState, GameStateUpdateEvent}
|
||||
import de.knockoutwhist.events.{ShowGlobalStatus, ShowPlayerStatus, ShowRoundStatus}
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.control.GameLogic
|
||||
import de.knockoutwhist.control.GameState.*
|
||||
import de.knockoutwhist.events.global.*
|
||||
import de.knockoutwhist.events.global.tie.{TieShowPlayerCardsEvent, TieTieEvent, TieTurnEvent, TieWinningPlayersEvent}
|
||||
import de.knockoutwhist.events.player.{RequestCardEvent, RequestTieChoiceEvent, RequestTrumpSuitEvent}
|
||||
import de.knockoutwhist.events.util.ReloadAllEvent
|
||||
import de.knockoutwhist.ui.UI
|
||||
import de.knockoutwhist.utils.CustomThread
|
||||
import de.knockoutwhist.utils.events.{EventListener, SimpleEvent}
|
||||
import javafx.application as jfxa
|
||||
import scalafx.application.JFXApp3.PrimaryStage
|
||||
import scalafx.application.{JFXApp3, Platform}
|
||||
import scalafx.beans.property.ObjectProperty
|
||||
@@ -22,11 +17,22 @@ import scalafx.scene.{Parent, Scene}
|
||||
|
||||
import scala.compiletime.uninitialized
|
||||
|
||||
object GUIMain extends JFXApp3 with EventListener with UI {
|
||||
class GUIMain extends JFXApp3 with EventListener with UI {
|
||||
|
||||
private var platformReady: Boolean = false
|
||||
private var internState: GameState = NO_SET
|
||||
private var currentRoot: Parent = uninitialized
|
||||
private var _logic: Option[GameLogic] = None
|
||||
|
||||
//UIS
|
||||
private var _mainMenu: MainMenu = uninitialized
|
||||
private var _game: Game = uninitialized
|
||||
private var _tieMenu: TieMenu = uninitialized
|
||||
private var _pickTrumpsuit: PickTrumsuit = uninitialized
|
||||
private var _winnerScreen: WinnerScreen = uninitialized
|
||||
|
||||
def mainMenu: MainMenu = _mainMenu
|
||||
|
||||
def logic: Option[GameLogic] = _logic
|
||||
|
||||
override def listen(event: SimpleEvent): Unit = {
|
||||
while (!platformReady) {
|
||||
@@ -34,80 +40,84 @@ object GUIMain extends JFXApp3 with EventListener with UI {
|
||||
}
|
||||
Platform.runLater {
|
||||
event match {
|
||||
case event: GameStateUpdateEvent =>
|
||||
if (internState != event.gameState) {
|
||||
internState = event.gameState
|
||||
if (event.gameState == INGAME) {
|
||||
Game.createGame()
|
||||
} else if (event.gameState == MAIN_MENU) {
|
||||
MainMenu.createMainMenu
|
||||
} else if (event.gameState == PLAYERS) {
|
||||
MainMenu.createPlayeramountmenu()
|
||||
} else if (event.gameState == TIE) {
|
||||
TieMenu.spawnTieMain()
|
||||
case event: GameStateChangeEvent =>
|
||||
if (event.newState == InGame) {
|
||||
_game.createGame()
|
||||
} else if (event.newState == MainMenu) {
|
||||
_mainMenu.createMainMenu
|
||||
} else if (event.newState == Lobby) {
|
||||
_mainMenu.createPlayeramountmenu()
|
||||
} else if (event.newState == TieBreak) {
|
||||
_tieMenu.spawnTieMain()
|
||||
}
|
||||
}
|
||||
case event: ShowGlobalStatus =>
|
||||
event.status match
|
||||
case SHOW_TIE_WINNER =>
|
||||
TieMenu.updateWinnerLabel(event)
|
||||
case SHOW_TIE_TIE =>
|
||||
TieMenu.showTieAgain(event)
|
||||
case SHOW_FINISHED_MATCH =>
|
||||
WinnerScreen.spawnWinnerScreen(event.objects.head.asInstanceOf[AbstractPlayer])
|
||||
case _ =>
|
||||
case event: ShowPlayerStatus =>
|
||||
event.status match
|
||||
case SHOW_TURN =>
|
||||
Game.updateStatus(event.player)
|
||||
case SHOW_WON_PLAYER_TRICK =>
|
||||
Game.showFinishedTrick(event)
|
||||
case SHOW_TIE_NUMBERS =>
|
||||
TieMenu.updatePlayerLabel(event.player)
|
||||
TieMenu.changeSlider(event.objects.head.asInstanceOf[Int])
|
||||
case _ =>
|
||||
case event: ShowCurrentTrickEvent =>
|
||||
Game.updatePlayedCards(event.trick)
|
||||
case event: ShowRoundStatus =>
|
||||
event.status match
|
||||
case WON_ROUND =>
|
||||
Game.showWon(event.currentRound)
|
||||
case _ =>
|
||||
case event: TieWinningPlayersEvent =>
|
||||
_tieMenu.updateWinnerLabel(event)
|
||||
|
||||
case event: TieTieEvent =>
|
||||
_tieMenu.showTieAgain(event)
|
||||
case event: MatchEndEvent =>
|
||||
_winnerScreen.spawnWinnerScreen(event.winner)
|
||||
case event: TrickEndEvent =>
|
||||
_game.showFinishedTrick(event)
|
||||
case event: TieTurnEvent =>
|
||||
_tieMenu.updatePlayerLabel(event.player)
|
||||
_tieMenu.changeSlider(logic.get.playerTieLogic.highestAllowedNumber())
|
||||
case event: NewRoundEvent =>
|
||||
_game.updateTrumpSuit(logic.get.getCurrentRound.get.trumpSuit)
|
||||
case event: NewTrickEvent =>
|
||||
_game.resetFirstCard()
|
||||
case event: RoundEndEvent =>
|
||||
_game.showWon(event.winner, event.amountOfTricks)
|
||||
case event: TurnEvent =>
|
||||
_game.updateStatus(event.player)
|
||||
_game.updateNextPlayer(_logic.get.getPlayerQueue.get, _logic.get.getPlayerQueue.get.currentIndex)
|
||||
case event: TieShowPlayerCardsEvent =>
|
||||
val cards = logic.get.playerTieLogic.getSelectedCard
|
||||
_tieMenu.addCutCards(cards.map((p, c) => (p, c)).toList)
|
||||
case event: CardPlayedEvent =>
|
||||
_game.updatePlayedCards()
|
||||
if (event.trick.firstCard.isDefined)
|
||||
_game.updateFirstCard(event.trick.firstCard.get)
|
||||
case event: TrumpSelectedEvent =>
|
||||
_game.updateTrumpSuit(event.suit)
|
||||
case event: RequestCardEvent =>
|
||||
Game.requestCard = Some(event)
|
||||
Game.requestDogCard = None
|
||||
Game.updateNextPlayer(event.round.playerQueue, event.currentIndex)
|
||||
Game.updateTrumpSuit(event.round.trumpSuit)
|
||||
if(event.trick.firstCard.isDefined) Game.updateFirstCard(event.trick.firstCard.get)
|
||||
else Game.resetFirstCard()
|
||||
Game.updatePlayerCards(event.player.hand.get)
|
||||
case event: RequestPickTrumpsuitEvent =>
|
||||
PickTrumsuit.showPickTrumpsuit(event)
|
||||
case event: RequestDogPlayCardEvent =>
|
||||
Game.requestCard = None
|
||||
Game.requestDogCard = Some(event)
|
||||
Game.updateNextPlayer(event.round.playerQueue, event.currentIndex)
|
||||
Game.updateTrumpSuit(event.round.trumpSuit)
|
||||
if(event.trick.firstCard.isDefined) Game.updateFirstCard(event.trick.firstCard.get)
|
||||
else Game.resetFirstCard()
|
||||
Game.updatePlayerCards(event.player.hand.get)
|
||||
case event: RequestTieNumberEvent =>
|
||||
TieMenu.showNeccessary()
|
||||
TieMenu.requestInfo = Some(event)
|
||||
case event: ShowTieCardsEvent =>
|
||||
TieMenu.addCutCards(event.card)
|
||||
_game.updatePlayerCards(event.player)
|
||||
case event: RequestTieChoiceEvent =>
|
||||
_tieMenu.showNeccessary()
|
||||
case event: RequestTrumpSuitEvent =>
|
||||
_pickTrumpsuit.showPickTrumpsuit(event.player)
|
||||
case event: ReloadAllEvent =>
|
||||
if (_logic.isEmpty) throw new Exception("Logic is not initialized!")
|
||||
val logicImpl = _logic.get
|
||||
if (logicImpl.getCurrentState == MainMenu)
|
||||
_mainMenu.createMainMenu
|
||||
else if (logicImpl.getCurrentState == Lobby)
|
||||
_mainMenu.createPlayeramountmenu()
|
||||
else if (logicImpl.getCurrentState == InGame)
|
||||
_game.reloadAll()
|
||||
else if (logicImpl.getCurrentState == TieBreak)
|
||||
_tieMenu.reloadAll()
|
||||
else if (logicImpl.getCurrentState == SelectTrump)
|
||||
_pickTrumpsuit.reloadAll()
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def initial: Boolean = {
|
||||
GUIThread.start()
|
||||
override def initial(logic: GameLogic): Boolean = {
|
||||
this._logic = Some(logic)
|
||||
new GUIThread(this).start()
|
||||
true
|
||||
}
|
||||
|
||||
override def start(): Unit = {
|
||||
currentRoot = MainMenu.current_root
|
||||
_game = new Game(this)
|
||||
_mainMenu = new MainMenu(this)
|
||||
_tieMenu = new TieMenu(this)
|
||||
_pickTrumpsuit = new PickTrumsuit(this)
|
||||
_winnerScreen = new WinnerScreen(this)
|
||||
|
||||
currentRoot = mainMenu.current_root
|
||||
val cont = ObjectProperty(currentRoot)
|
||||
JFXApp3.userAgentStylesheet_=(new PrimerDark().getUserAgentStylesheet)
|
||||
stage = new PrimaryStage {
|
||||
@@ -121,6 +131,8 @@ object GUIMain extends JFXApp3 with EventListener with UI {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_mainMenu.createMainMenu
|
||||
stage.show()
|
||||
platformReady = true
|
||||
}
|
||||
@@ -131,14 +143,14 @@ object GUIMain extends JFXApp3 with EventListener with UI {
|
||||
|
||||
}
|
||||
|
||||
object GUIThread extends CustomThread {
|
||||
class GUIThread(gui: GUIMain) extends CustomThread {
|
||||
|
||||
setName("GUIThread")
|
||||
|
||||
override def instance: CustomThread = GUIThread
|
||||
override def instance: CustomThread = this
|
||||
|
||||
override def run(): Unit = {
|
||||
GUIMain.main(new Array[String](_length = 0))
|
||||
gui.main(new Array[String](_length = 0))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package de.knockoutwhist.ui.gui
|
||||
|
||||
import atlantafx.base.theme.Styles
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.{Card, Hand, Suit}
|
||||
import de.knockoutwhist.control.ControlThread
|
||||
import de.knockoutwhist.events.ShowPlayerStatus
|
||||
import de.knockoutwhist.events.directional.{RequestCardEvent, RequestDogPlayCardEvent}
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.{MatchUtil, PlayerUtil}
|
||||
import de.knockoutwhist.events.global.TrickEndEvent
|
||||
import de.knockoutwhist.player.AbstractPlayer
|
||||
import de.knockoutwhist.rounds.{Round, Trick}
|
||||
import de.knockoutwhist.undo.UndoManager
|
||||
import de.knockoutwhist.rounds.Trick
|
||||
import de.knockoutwhist.undo.commands.{PlayCardCommand, PlayDogCardCommand}
|
||||
import de.knockoutwhist.utils.CustomPlayerQueue
|
||||
import de.knockoutwhist.utils.Implicits.*
|
||||
import de.knockoutwhist.utils.gui.Animations
|
||||
@@ -27,10 +26,32 @@ import scalafx.util.Duration
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.util.Try
|
||||
|
||||
|
||||
object Game {
|
||||
class Game(gui: GUIMain) {
|
||||
|
||||
private[ui] def reloadAll(): Unit = {
|
||||
if (gui.logic.isEmpty) throw new IllegalStateException("Logic is not initialized!")
|
||||
val logic = gui.logic.get
|
||||
if (logic.getCurrentRound.isEmpty) throw new IllegalStateException("No current round available!")
|
||||
val currentRound = logic.getCurrentRound.get
|
||||
if (logic.getCurrentTrick.isEmpty) throw new IllegalStateException("No current trick available!")
|
||||
val currentTrick = logic.getCurrentTrick.get
|
||||
if (logic.getCurrentPlayer.isEmpty) throw new IllegalStateException("No current player available!")
|
||||
val currentPlayer = logic.getCurrentPlayer.get
|
||||
|
||||
updateStatus(currentPlayer)
|
||||
updateNextPlayer(logic.getPlayerQueue.get, logic.getPlayerQueue.get.currentIndex)
|
||||
updatePlayedCards()
|
||||
if (currentTrick.firstCard.isDefined) {
|
||||
updateFirstCard(currentTrick.firstCard.get)
|
||||
} else {
|
||||
resetFirstCard()
|
||||
}
|
||||
updateTrumpSuit(currentRound.trumpSuit)
|
||||
updatePlayerCards(currentPlayer)
|
||||
createGame()
|
||||
}
|
||||
|
||||
private val statusLabel: Label = new Label {
|
||||
alignment = Center
|
||||
@@ -96,8 +117,8 @@ object Game {
|
||||
}
|
||||
|
||||
def createGame(): Unit = {
|
||||
GUIMain.stage.maximized = true
|
||||
MainMenu.changeChild(new BorderPane {
|
||||
gui.stage.maximized = true
|
||||
gui.mainMenu.changeChild(new BorderPane {
|
||||
val myBI = new BackgroundImage(new Image("/background.png", 32, 32, false, true),
|
||||
BackgroundRepeat.REPEAT, BackgroundRepeat.REPEAT, BackgroundPosition.DEFAULT,
|
||||
BackgroundSize.DEFAULT)
|
||||
@@ -124,7 +145,7 @@ object Game {
|
||||
font = Font.font(20)
|
||||
styleClass += Styles.WARNING
|
||||
onMouseClicked = _ => {
|
||||
KnockOutWhist.config.persistenceManager.saveFile("currentSnapshot")
|
||||
gui.logic.get.persistenceManager.saveFile("currentSnapshot")
|
||||
new Alert(AlertType.Information) {
|
||||
title = "Game Saved"
|
||||
headerText = "Game Saved"
|
||||
@@ -140,7 +161,7 @@ object Game {
|
||||
font = Font.font(20)
|
||||
styleClass += Styles.WARNING
|
||||
onMouseClicked = _ => {
|
||||
UndoManager.undoStep()
|
||||
gui.logic.get.undoManager.undoStep()
|
||||
}
|
||||
},
|
||||
new Button {
|
||||
@@ -149,7 +170,9 @@ object Game {
|
||||
text = "Exit Game"
|
||||
font = Font.font(20)
|
||||
styleClass += Styles.DANGER
|
||||
onMouseClicked = _ => System.exit(0)
|
||||
onMouseClicked = _ => {
|
||||
gui.logic.get.endSession()
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
@@ -219,7 +242,7 @@ object Game {
|
||||
playerCards.visible = visible
|
||||
}
|
||||
|
||||
def firstCardvisible(visible: Boolean): Unit = {
|
||||
private def firstCardvisible(visible: Boolean): Unit = {
|
||||
firstCard.visible = visible
|
||||
}
|
||||
|
||||
@@ -232,7 +255,16 @@ object Game {
|
||||
firstCard.image = new Image("cards/1B.png")
|
||||
}
|
||||
|
||||
def updatePlayerCards(hand: Hand): Unit = {
|
||||
def updatePlayerCards(player: AbstractPlayer): Unit = {
|
||||
if (gui.logic.isEmpty) throw new IllegalStateException("Logic is not initialized!")
|
||||
val logic = gui.logic.get
|
||||
if (logic.getCurrentMatch.isEmpty) throw new IllegalStateException("No current match available!")
|
||||
val currentMatch = logic.getCurrentMatch.get
|
||||
if (logic.getCurrentRound.isEmpty) throw new IllegalStateException("No current round available!")
|
||||
val currentRound = logic.getCurrentRound.get
|
||||
if (player.currentHand().isEmpty) throw new IllegalStateException("Player has no hand!")
|
||||
val hand: Hand = player.currentHand().get
|
||||
|
||||
val cards = ListBuffer[Node]()
|
||||
playerCards.children.clear()
|
||||
for (card <- hand.cards) {
|
||||
@@ -242,45 +274,37 @@ object Game {
|
||||
fitWidth = 170
|
||||
fitHeight = 250
|
||||
onMouseClicked = _ => {
|
||||
if (requestCard.isDefined) {
|
||||
val event = requestCard.get
|
||||
if (KnockOutWhist.config.trickcomponent.alternativeCards(card, event.round, event.trick, event.player).nonEmpty) {
|
||||
if (logic.getCurrentTrick.isEmpty) throw new IllegalStateException("No current trick available!")
|
||||
val currentTrick = logic.getCurrentTrick.get
|
||||
if (logic.getCurrentPlayer.isDefined && logic.isWaitingForInput) {
|
||||
val currentPlayer = logic.getCurrentPlayer.get
|
||||
if (!currentPlayer.isInDogLife) {
|
||||
if (!PlayerUtil.canPlayCard(card, currentRound, currentTrick, currentPlayer)) {
|
||||
val pulse = Animations.pulse(this, Duration(400))
|
||||
pulse.play()
|
||||
} else {
|
||||
requestCard = None
|
||||
hideCards(this)
|
||||
val slideOut = Animations.slideOutUp(this, Duration(400), -350)
|
||||
slideOut.onFinished = _ => {
|
||||
visible = false
|
||||
ControlThread.runLater {
|
||||
KnockOutWhist.config.trickcomponent.controlSuitplayed(Try {
|
||||
logic.undoManager.doStep(
|
||||
PlayCardCommand(
|
||||
logic.createSnapshot(),
|
||||
logic.playerTieLogic.createSnapshot(),
|
||||
card
|
||||
}, event.matchImpl, event.round, event.trick, event.currentIndex, event.player)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
slideOut.play()
|
||||
}
|
||||
} else if(requestDogCard.isDefined) {
|
||||
val event = requestDogCard.get
|
||||
requestDogCard = None
|
||||
hideCards(this)
|
||||
val slideOutDog = Animations.slideOutUp(this, Duration(400), -350)
|
||||
slideOutDog.onFinished = _ => {
|
||||
visible = false
|
||||
ControlThread.runLater {
|
||||
KnockOutWhist.config.trickcomponent.controlDogPlayed(Try {Some(
|
||||
card)
|
||||
}, event.matchImpl, event.round, event.trick, event.currentIndex, event.player)
|
||||
}
|
||||
}
|
||||
slideOutDog.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (requestDogCard.isDefined && !requestDogCard.get.needstoplay) {
|
||||
//if (requestDogCard.get.player.doglife) {
|
||||
}
|
||||
if (player.isInDogLife && !MatchUtil.dogNeedsToPlay(currentMatch, currentRound)) {
|
||||
cards += new Button {
|
||||
alignmentInParent = BottomCenter
|
||||
styleClass += Styles.SUCCESS
|
||||
@@ -290,29 +314,36 @@ object Game {
|
||||
minHeight = 250
|
||||
maxHeight = 250
|
||||
onMouseClicked = _ => {
|
||||
if (requestDogCard.isDefined) {
|
||||
val event = requestDogCard.get
|
||||
requestDogCard = None
|
||||
hideCards(this)
|
||||
val slideOutDog = Animations.slideOutUp(this, Duration(400), -350)
|
||||
slideOutDog.onFinished = _ => {
|
||||
visible = false
|
||||
ControlThread.runLater {
|
||||
KnockOutWhist.config.trickcomponent.controlDogPlayed(Try(None), event.matchImpl, event.round, event.trick, event.currentIndex, event.player)
|
||||
logic.undoManager.doStep(
|
||||
PlayDogCardCommand(
|
||||
logic.createSnapshot(),
|
||||
logic.playerTieLogic.createSnapshot(),
|
||||
None
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
slideOutDog.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
playerCards.children = cards.toList
|
||||
}
|
||||
|
||||
def visibilityPlayedCards(visible: Boolean): Unit = {
|
||||
private def visibilityPlayedCards(visible: Boolean): Unit = {
|
||||
playedCards.visible = visible
|
||||
}
|
||||
def updatePlayedCards(trick: Trick): Unit = {
|
||||
|
||||
def updatePlayedCards(): Unit = {
|
||||
if (gui.logic.isEmpty) throw new IllegalStateException("Logic is not initialized!")
|
||||
val logic = gui.logic.get
|
||||
if (logic.getCurrentTrick.isEmpty) throw new IllegalStateException("No current trick available!")
|
||||
val trick: Trick = logic.getCurrentTrick.get
|
||||
visibilityPlayedCards(true)
|
||||
val cards = ListBuffer[Node]()
|
||||
for (card <- trick.cards) {
|
||||
@@ -355,14 +386,12 @@ object Game {
|
||||
def updateNextPlayer(queue: CustomPlayerQueue[AbstractPlayer], currendIndx: Int): Unit = {
|
||||
val queueDupli = queue.duplicate()
|
||||
nextPlayers.children = queueDupli.iteratorWithStart(currendIndx).map(player => new Label {
|
||||
text = !player.doglife ? player.name |: s"${player.name} (Doglife)"
|
||||
text = !player.isInDogLife ? player.name |: s"${player.name} (Doglife)"
|
||||
font = Font.font(20)
|
||||
}).toSeq
|
||||
}
|
||||
private[gui] var requestCard: Option[RequestCardEvent] = None
|
||||
private[gui] var requestDogCard: Option[RequestDogPlayCardEvent] = None
|
||||
def showWon(round: Round): Unit = {
|
||||
val playerwon = round.winner
|
||||
|
||||
def showWon(winner: AbstractPlayer, amountOfTricks: Int): Unit = {
|
||||
nextPlayers.visible = false
|
||||
playerCards.visible = false
|
||||
yourCardslabel.visible = false
|
||||
@@ -371,16 +400,16 @@ object Game {
|
||||
firstCard.visible = false
|
||||
suitLabel.visible = false
|
||||
nextPlayers.visible = false
|
||||
val wontricks = round.tricklist.count(trick => trick.winner == round.winner)
|
||||
if (wontricks == 1) statusLabel.text = s"${playerwon.name} won the round with $wontricks trick!"
|
||||
else statusLabel.text = s"${playerwon.name} won the round with $wontricks tricks!"
|
||||
if (amountOfTricks == 1) statusLabel.text = s"${winner.name} won the round with $amountOfTricks trick!"
|
||||
else statusLabel.text = s"${winner.name} won the round with $amountOfTricks tricks!"
|
||||
}
|
||||
def showFinishedTrick(event: ShowPlayerStatus): Unit = {
|
||||
|
||||
def showFinishedTrick(event: TrickEndEvent): Unit = {
|
||||
nextPlayers.visible = false
|
||||
playerCards.visible = false
|
||||
yourCardslabel.visible = false
|
||||
playedCardslabel.visible = false
|
||||
statusLabel.text = s"${event.player} won the trick"
|
||||
Game.updatePlayedCards(event.objects.head.asInstanceOf[Trick])
|
||||
statusLabel.text = s"${event.winner.name} won the trick"
|
||||
updatePlayedCards()
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,8 @@ package de.knockoutwhist.ui.gui
|
||||
|
||||
import atlantafx.base.theme.Styles
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.control.{ControlHandler, ControlThread}
|
||||
import de.knockoutwhist.events.ui.GameState.MAIN_MENU
|
||||
import de.knockoutwhist.events.ui.GameStateUpdateEvent
|
||||
import de.knockoutwhist.persistence.stub.PersistenceBaseManager
|
||||
import de.knockoutwhist.control.ControlThread
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.BasePersistenceManager
|
||||
import de.knockoutwhist.player.Playertype.HUMAN
|
||||
import de.knockoutwhist.player.{AbstractPlayer, PlayerFactory}
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
@@ -15,27 +13,27 @@ import scalafx.animation.Timeline
|
||||
import scalafx.geometry.Insets
|
||||
import scalafx.geometry.Pos.{BottomCenter, Center, TopCenter, TopLeft, TopRight}
|
||||
import scalafx.scene.Parent
|
||||
import scalafx.scene.control.*
|
||||
import scalafx.scene.control.Alert.AlertType
|
||||
import scalafx.scene.control.{Alert, Button, Label, Slider, TextField}
|
||||
import scalafx.scene.image.{Image, ImageView}
|
||||
import scalafx.scene.layout.Priority.Always
|
||||
import scalafx.scene.layout.{BorderPane, HBox, StackPane, VBox}
|
||||
import scalafx.scene.text.{Font, TextAlignment}
|
||||
import scalafx.util.Duration
|
||||
|
||||
import java.awt.Taskbar.Feature
|
||||
import java.awt.Taskbar.{Feature, getTaskbar}
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
object MainMenu {
|
||||
class MainMenu(gui: GUIMain) {
|
||||
|
||||
private val mainMenu: StackPane = new StackPane()
|
||||
|
||||
def current_root: Parent = mainMenu
|
||||
|
||||
def createMainMenu: StackPane = {
|
||||
GUIMain.stage.maximized = false
|
||||
GUIMain.stage.resizable = true
|
||||
gui.stage.maximized = false
|
||||
gui.stage.resizable = true
|
||||
changeChild(new VBox {
|
||||
alignment = Center
|
||||
spacing = 10
|
||||
@@ -54,7 +52,7 @@ object MainMenu {
|
||||
styleClass += Styles.SUCCESS
|
||||
onMouseClicked = _ => {
|
||||
ControlThread.runLater {
|
||||
KnockOutWhist.config.maincomponent.startMatch()
|
||||
gui.logic.get.createSession()
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -72,8 +70,8 @@ object MainMenu {
|
||||
text = "Load Game"
|
||||
font = Font.font(20)
|
||||
styleClass += Styles.ACCENT
|
||||
disable = !KnockOutWhist.config.persistenceManager.canLoadfile("currentSnapshot")
|
||||
onMouseClicked = _ => KnockOutWhist.config.persistenceManager.loadFile("currentSnapshot")
|
||||
disable = gui.logic.isDefined && !gui.logic.get.persistenceManager.canLoadfile("currentSnapshot")
|
||||
onMouseClicked = _ => gui.logic.get.persistenceManager.loadFile("currentSnapshot")
|
||||
}
|
||||
)
|
||||
}, Duration(1000))
|
||||
@@ -95,8 +93,7 @@ object MainMenu {
|
||||
}
|
||||
}
|
||||
def createPlayeramountmenu(): Unit = {
|
||||
GUIMain.stage.maximized = true
|
||||
GUIMain.stage.resizable = false
|
||||
gui.stage.maximized = true
|
||||
changeChild(new BorderPane {
|
||||
margin = Insets(50, 50, 50, 50)
|
||||
val players: VBox = new VBox {
|
||||
@@ -126,7 +123,7 @@ object MainMenu {
|
||||
}
|
||||
onMouseClicked = _ => {
|
||||
ControlThread.runLater {
|
||||
ControlHandler.invoke(GameStateUpdateEvent(MAIN_MENU))
|
||||
gui.logic.get.endSession()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,7 +157,8 @@ object MainMenu {
|
||||
}.showAndWait()
|
||||
}else {
|
||||
ControlThread.runLater {
|
||||
KnockOutWhist.config.maincomponent.enteredPlayers(playerNamesList.toList)
|
||||
gui.logic.get.createMatch(playerNamesList.toList)
|
||||
gui.logic.get.controlMatch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user