Compare commits
28 Commits
archive/te
...
b9e896fc0b
| Author | SHA1 | Date | |
|---|---|---|---|
| b9e896fc0b | |||
|
a0e2eadc93
|
|||
| 0b5bfc69e5 | |||
|
ad0494f0ba
|
|||
| 355addf8a5 | |||
|
efd5e0fae6
|
|||
|
8cb5012c8f
|
|||
|
|
6304ce44b9 | ||
|
ee44f6940b
|
|||
|
|
0c6de4b86f | ||
|
094afc5631
|
|||
| bb0ad578be | |||
|
ce5efd7a05
|
|||
|
174fe3c993
|
|||
|
03ab3f3650
|
|||
|
|
a7f839d01c | ||
|
a7e84b9815
|
|||
|
4c7fb1c8bc
|
|||
|
ef1eb29fe3
|
|||
|
|
619cbcfaac | ||
|
fe46690fb4
|
|||
|
24bfd7925c
|
|||
|
11c0b61933
|
|||
|
0cc7756556
|
|||
|
153d028959
|
|||
|
|
177ec3772e | ||
|
c397d079bf
|
|||
|
a99182beaf
|
13
build.sbt
13
build.sbt
@@ -1,5 +1,5 @@
|
||||
ThisBuild / version := "0.1.0-SNAPSHOT"
|
||||
ThisBuild / scalaVersion := "3.5.1"
|
||||
|
||||
|
||||
|
||||
Compile/mainClass := Some("de.knockoutwhist.KnockOutWhist")
|
||||
|
||||
@@ -10,11 +10,16 @@ version := {
|
||||
val buildNR = sys.env.getOrElse("BUI_COUNTER", "1")
|
||||
s"$major.$minor.$buildNR"
|
||||
}
|
||||
organization := "de.knockoutwhist"
|
||||
|
||||
ThisBuild / organization := "de.knockoutwhist"
|
||||
ThisBuild / version := version.value
|
||||
ThisBuild / scalaVersion := "3.5.1"
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.settings(
|
||||
name := "Projekt-zu-SE"
|
||||
name := "Projekt-zu-SE",
|
||||
assembly / mainClass := Some("de.knockoutwhist.KnockOutWhist"),
|
||||
assembly / assemblyJarName := s"KnockOutWhist-${version.value}.jar",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.2.1")
|
||||
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,5 +0,0 @@
|
||||
import de.knockoutwhist.cards.CardManager
|
||||
|
||||
val originalDeck = List(CardManager.cardContainer)
|
||||
CardManager.shuffleAndReset()
|
||||
val shuffledDeck = CardManager.cardContainer
|
||||
@@ -2,23 +2,22 @@ package de.knockoutwhist
|
||||
|
||||
|
||||
import de.knockoutwhist.control.MatchControl
|
||||
import de.knockoutwhist.control.text.TextMatchControl
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
|
||||
|
||||
object KnockOutWhist {
|
||||
|
||||
val matchControl: MatchControl = TextMatchControl
|
||||
|
||||
/*
|
||||
Debug mode:
|
||||
|
||||
- Disables the random shuffle of the cards
|
||||
*/
|
||||
private[knockoutwhist] var DEBUG_MODE_VAR: Boolean = true
|
||||
private[knockoutwhist] var DEBUG_MODE_VAR: Boolean = false
|
||||
|
||||
def DEBUG_MODE = DEBUG_MODE_VAR
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
if(!matchControl.initial()) throw new IllegalStateException("Game could not be started.")
|
||||
if(!TUIMain.initial) throw new IllegalStateException("Game could not be started.")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package de.knockoutwhist.cards
|
||||
|
||||
import de.knockoutwhist.cards.CardValue.Ten
|
||||
import de.knockoutwhist.cards.Suit
|
||||
|
||||
enum Suit(identifier: String):
|
||||
|
||||
def cardType(): String = identifier
|
||||
@@ -34,34 +31,6 @@ enum CardValue(identifier: String):
|
||||
end CardValue
|
||||
|
||||
case class Card(cardValue: CardValue, suit: Suit) {
|
||||
|
||||
def cardColour(suit: Suit): String = suit match {
|
||||
case Suit.Hearts | Suit.Diamonds => Console.RED
|
||||
case Suit.Clubs | Suit.Spades => Console.BLACK
|
||||
}
|
||||
|
||||
def renderAsString(): Vector[String] = {
|
||||
if (cardValue == Ten) {
|
||||
return Vector(
|
||||
s"┌─────────┐",
|
||||
s"│${cardColour(suit)}${Console.BOLD}${cardValue.cardType()}${Console.RESET} │",
|
||||
"│ │",
|
||||
s"│ ${cardColour(suit)}${Console.BOLD}${suit.cardType()}${Console.RESET} │",
|
||||
"│ │",
|
||||
s"│ ${cardColour(suit)}${Console.BOLD}${cardValue.cardType()}${Console.RESET}│",
|
||||
s"└─────────┘"
|
||||
)
|
||||
}
|
||||
Vector(
|
||||
s"┌─────────┐",
|
||||
s"│${cardColour(suit)}${Console.BOLD}${cardValue.cardType()}${Console.RESET} │",
|
||||
"│ │",
|
||||
s"│ ${cardColour(suit)}${Console.BOLD}${suit.cardType()}${Console.RESET} │",
|
||||
"│ │",
|
||||
s"│ ${cardColour(suit)}${Console.BOLD}${cardValue.cardType()}${Console.RESET}│",
|
||||
s"└─────────┘"
|
||||
)
|
||||
}
|
||||
override def toString: String = s"$cardValue of $suit"
|
||||
//Combined String
|
||||
|
||||
override def toString: String = s"$cardValue of $suit"
|
||||
}
|
||||
|
||||
@@ -19,11 +19,5 @@ case class Hand(cards: List[Card]) {
|
||||
def hasTrumpSuit(trumpSuit: Suit): Boolean = {
|
||||
cards.exists(_.suit == trumpSuit)
|
||||
}
|
||||
|
||||
def renderAsString() : List[String] = {
|
||||
val cardStrings = cards.map(_.renderAsString())
|
||||
val zipped = cardStrings.transpose
|
||||
zipped.map(_.mkString(" "))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
12
src/main/scala/de/knockoutwhist/control/ControlHandler.scala
Normal file
12
src/main/scala/de/knockoutwhist/control/ControlHandler.scala
Normal file
@@ -0,0 +1,12 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
import de.knockoutwhist.utils.DelayHandler
|
||||
import de.knockoutwhist.utils.events.EventHandler
|
||||
|
||||
object ControlHandler extends EventHandler {
|
||||
|
||||
addListener(TUIMain)
|
||||
addListener(DelayHandler)
|
||||
|
||||
}
|
||||
@@ -1,24 +1,77 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.{Card, CardManager}
|
||||
import de.knockoutwhist.control.RoundControl.controlRound
|
||||
import de.knockoutwhist.events.*
|
||||
import de.knockoutwhist.events.ERROR_STATUS.{IDENTICAL_NAMES, INVALID_NAME_FORMAT, INVALID_NUMBER_OF_PLAYERS, WRONG_CARD}
|
||||
import de.knockoutwhist.events.GLOBAL_STATUS.*
|
||||
import de.knockoutwhist.events.PLAYER_STATUS.{SHOW_NOT_PLAYED, SHOW_WON_PLAYER_TRICK}
|
||||
import de.knockoutwhist.events.ROUND_STATUS.{PLAYERS_OUT, SHOW_START_ROUND, WON_ROUND}
|
||||
import de.knockoutwhist.events.round.ShowCurrentTrickEvent
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.CustomPlayerQueue
|
||||
import de.knockoutwhist.utils.Implicits.*
|
||||
|
||||
trait MatchControl {
|
||||
|
||||
def initial(): Boolean
|
||||
def start(): Unit
|
||||
def playerControl: PlayerControl
|
||||
|
||||
/**
|
||||
* Start the next round
|
||||
* @return the next round or null if the match is over
|
||||
*/
|
||||
def nextRound(matchImpl: Match): Round
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.io.StdIn
|
||||
import scala.util.Random
|
||||
|
||||
/**
|
||||
* Start the next trick
|
||||
* @return the last trick or null if the round is over
|
||||
*/
|
||||
def nextTrick(roundImpl: Round): Trick
|
||||
object MatchControl {
|
||||
|
||||
private[control] var playerQueue: CustomPlayerQueue[Player] = uninitialized
|
||||
|
||||
def startMatch(): Player = {
|
||||
ControlHandler.invoke(ShowGlobalStatus(SHOW_START_MATCH))
|
||||
val players = enterPlayers()
|
||||
playerQueue = CustomPlayerQueue[Player](players, Random.nextInt(players.length))
|
||||
controlMatch()
|
||||
}
|
||||
|
||||
def enterPlayers(): Array[Player] = {
|
||||
ControlHandler.invoke(ShowGlobalStatus(SHOW_TYPE_PLAYERS))
|
||||
val names = StdIn.readLine().split(",")
|
||||
if (names.length < 2) {
|
||||
ControlHandler.invoke(ShowErrorStatus(INVALID_NUMBER_OF_PLAYERS))
|
||||
return enterPlayers()
|
||||
}
|
||||
if (names.distinct.length != names.length) {
|
||||
ControlHandler.invoke(ShowErrorStatus(IDENTICAL_NAMES))
|
||||
return enterPlayers()
|
||||
}
|
||||
if (names.count(_.trim.isBlank) > 0 || names.count(_.trim.length <= 2) > 0 || names.count(_.trim.length > 10) > 0) {
|
||||
ControlHandler.invoke(ShowErrorStatus(INVALID_NAME_FORMAT))
|
||||
return enterPlayers()
|
||||
}
|
||||
names.map(s => Player(s))
|
||||
}
|
||||
|
||||
def controlMatch(): Player = {
|
||||
val matchImpl = Match(playerQueue.toList)
|
||||
while (!isOver(matchImpl)) {
|
||||
val roundImpl = controlRound(matchImpl)
|
||||
}
|
||||
val winner = finalizeMatch(matchImpl)
|
||||
val playerwinner = winner.name
|
||||
ControlHandler.invoke(ShowGlobalStatus(SHOW_FINISHED_MATCH, winner))
|
||||
winner
|
||||
}
|
||||
|
||||
def isOver(matchImpl: Match): Boolean = {
|
||||
if (matchImpl.roundlist.isEmpty) {
|
||||
false
|
||||
} else {
|
||||
RoundControl.remainingPlayers(matchImpl.roundlist.last).size == 1
|
||||
}
|
||||
}
|
||||
|
||||
def finalizeMatch(matchImpl: Match): Player = {
|
||||
if (!isOver(matchImpl)) {
|
||||
throw new IllegalStateException("Match is not over yet.")
|
||||
}
|
||||
RoundControl.remainingPlayers(matchImpl.roundlist.last).head
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,126 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Suit}
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.{Card, CardManager, Suit}
|
||||
import de.knockoutwhist.control.PlayerControl
|
||||
import de.knockoutwhist.events.ERROR_STATUS.{INVALID_INPUT, 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_DOG_PLAY_CARD, SHOW_PLAY_CARD, SHOW_TIE_NUMBERS, SHOW_TRUMPSUIT_OPTIONS, SHOW_TURN}
|
||||
import de.knockoutwhist.events.cards.{RenderHandEvent, ShowTieCardsEvent}
|
||||
import de.knockoutwhist.events.directional.{RequestCardEvent, RequestDogPlayCardEvent, RequestNumberEvent, RequestPickTrumpsuitEvent}
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.events.{ShowErrorStatus, ShowGlobalStatus, ShowPlayerStatus}
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.rounds.Round
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
import de.knockoutwhist.utils.DelayHandler
|
||||
import de.knockoutwhist.utils.events.EventHandler
|
||||
|
||||
trait PlayerControl {
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.io.StdIn.readLine
|
||||
import scala.util.{Failure, Success}
|
||||
import scala.util.control.Breaks.*
|
||||
|
||||
def playCard(player: Player): Card
|
||||
def dogplayCard(player: Player, round: Round): Option[Card]
|
||||
def determineWinnerTie(players: List[Player]): Player
|
||||
def pickNextTrumpsuit(player: Player): Suit
|
||||
def showCards(player: Player): Boolean
|
||||
def showWon(player: Player, round: Round): String
|
||||
|
||||
object PlayerControl {
|
||||
|
||||
def playCard(player: Player): Card = {
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_TURN, player))
|
||||
ControlHandler.invoke(DelayEvent(3000L))
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_PLAY_CARD, player))
|
||||
ControlHandler.invoke(RenderHandEvent(player.currentHand().get, true))
|
||||
ControlHandler.invoke(RequestCardEvent(player.currentHand().get)) match {
|
||||
case Success(value) => {
|
||||
value
|
||||
}
|
||||
case Failure(exception) => {
|
||||
ControlHandler.invoke(ShowErrorStatus(INVALID_NUMBER))
|
||||
playCard(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def dogplayCard(player: Player, round: Round): Option[Card] = {
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_TURN, player))
|
||||
ControlHandler.invoke(DelayEvent(3000L))
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_DOG_PLAY_CARD, player, RoundControl.dogNeedsToPlay(round)))
|
||||
ControlHandler.invoke(RenderHandEvent(player.currentHand().get, false))
|
||||
ControlHandler.invoke(RequestDogPlayCardEvent(player.currentHand().get, RoundControl.dogNeedsToPlay(round))) match {
|
||||
case Success(value) => {
|
||||
value
|
||||
}
|
||||
case Failure(exception) => {
|
||||
ControlHandler.invoke(ShowErrorStatus(INVALID_INPUT))
|
||||
dogplayCard(player, round)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def determineWinnerTie(players: List[Player]): Player = {
|
||||
determineWinnerTieText(players, true)
|
||||
}
|
||||
|
||||
@tailrec
|
||||
private def determineWinnerTieText(players: List[Player], tieMessage: Boolean): Player = {
|
||||
if (!KnockOutWhist.DEBUG_MODE) CardManager.shuffleAndReset()
|
||||
if (tieMessage) ControlHandler.invoke(ShowGlobalStatus(SHOW_TIE))
|
||||
var currentStep = 0
|
||||
var remaining = CardManager.cardContainer.size - (players.length - 1)
|
||||
val cut: mutable.HashMap[Player, Card] = mutable.HashMap()
|
||||
for (player <- players) {
|
||||
var selCard: Card = null
|
||||
while (selCard == null) {
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_TIE_NUMBERS, player, remaining))
|
||||
ControlHandler.invoke(RequestNumberEvent(1, remaining)) match {
|
||||
case Success(value) =>
|
||||
selCard = CardManager.cardContainer(currentStep + (value-1))
|
||||
cut.put(player, selCard)
|
||||
currentStep += value
|
||||
remaining -= (value-1)
|
||||
case Failure(exception) =>
|
||||
ControlHandler.invoke(ShowErrorStatus(NOT_A_NUMBER))
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlHandler.invoke(ShowTieCardsEvent(cut.toList))
|
||||
|
||||
var currentHighest: Card = null
|
||||
val winner: ListBuffer[Player] = ListBuffer()
|
||||
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))
|
||||
return winner.head
|
||||
}
|
||||
ControlHandler.invoke(ShowGlobalStatus(SHOW_TIE_TIE))
|
||||
determineWinnerTieText(winner.toList, false)
|
||||
}
|
||||
|
||||
def pickNextTrumpsuit(player: Player): Suit = {
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_TRUMPSUIT_OPTIONS, player))
|
||||
ControlHandler.invoke(RenderHandEvent(player.currentHand().get, false))
|
||||
ControlHandler.invoke(RequestPickTrumpsuitEvent()) match {
|
||||
case Success(value) => {
|
||||
value
|
||||
}
|
||||
case Failure(exception) => {
|
||||
ControlHandler.invoke(ShowErrorStatus(INVALID_NUMBER))
|
||||
pickNextTrumpsuit(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
124
src/main/scala/de/knockoutwhist/control/RoundControl.scala
Normal file
124
src/main/scala/de/knockoutwhist/control/RoundControl.scala
Normal file
@@ -0,0 +1,124 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.CardManager
|
||||
import de.knockoutwhist.control.MatchControl.playerQueue
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.Implicits.*
|
||||
import de.knockoutwhist.control.RoundControl
|
||||
import de.knockoutwhist.control.TrickControl.controlTrick
|
||||
import de.knockoutwhist.events.ROUND_STATUS.{PLAYERS_OUT, SHOW_START_ROUND, WON_ROUND}
|
||||
import de.knockoutwhist.events.ShowRoundStatus
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
|
||||
object RoundControl {
|
||||
|
||||
def isOver(round: Round): Boolean = {
|
||||
round.players_in.map(_.currentHand()).count(_.get.cards.isEmpty) == round.players_in.size
|
||||
}
|
||||
|
||||
def dogNeedsToPlay(round: Round): Boolean = {
|
||||
round.players_in.filter(!_.doglife).map(_.currentHand()).exists(_.get.cards.isEmpty)
|
||||
}
|
||||
|
||||
def finalizeRound(round: Round, matchImpl: Match,force: Boolean = false): (Player, Round) = {
|
||||
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.players_in.filter(!tricksMapped.contains(_))
|
||||
|
||||
if (playersOut.nonEmpty && !matchImpl.dogLife) {
|
||||
matchImpl.dogLife = true
|
||||
playersOut.foreach(p => p.doglife = true)
|
||||
playersOut = List()
|
||||
}
|
||||
|
||||
tricksMapped.keys.foreach(p => {
|
||||
p.doglife = false
|
||||
})
|
||||
|
||||
val winner = (winners.size == 1)
|
||||
? winners.head
|
||||
|: PlayerControl.determineWinnerTie(winners.toList)
|
||||
|
||||
val finalRound = Round(round.trumpSuit, matchImpl, round.tricklist, round.players_in, playersOut, winner, round.firstRound)
|
||||
matchImpl.roundlist += finalRound
|
||||
(winner, finalRound)
|
||||
}
|
||||
|
||||
def remainingPlayers(round: Round): List[Player] = {
|
||||
if (round.players_out == null) {
|
||||
return round.players_in
|
||||
}
|
||||
round.players_in.filter(!round.players_out.contains(_))
|
||||
}
|
||||
|
||||
def create_round(matchImpl: Match): Round = {
|
||||
val remainingPlayer = matchImpl.roundlist.isEmpty ? matchImpl.totalplayers |: RoundControl.remainingPlayers(matchImpl.roundlist.last)
|
||||
provideCards(matchImpl, remainingPlayer)
|
||||
if (matchImpl.roundlist.isEmpty) {
|
||||
val random_trumpsuit = CardManager.nextCard().suit
|
||||
matchImpl.current_round = Some(new Round(random_trumpsuit, matchImpl, remainingPlayer, true))
|
||||
} else {
|
||||
val winner = matchImpl.roundlist.last.winner
|
||||
val trumpsuit = PlayerControl.pickNextTrumpsuit(winner)
|
||||
|
||||
matchImpl.current_round = Some(new Round(trumpsuit, matchImpl, remainingPlayer, false))
|
||||
}
|
||||
matchImpl.number_of_cards -= 1
|
||||
matchImpl.current_round.get
|
||||
}
|
||||
|
||||
def nextRound(matchImpl: Match): Round = {
|
||||
if (MatchControl.isOver(matchImpl)) {
|
||||
return null
|
||||
}
|
||||
create_round(matchImpl)
|
||||
}
|
||||
|
||||
|
||||
def controlRound(matchImpl: Match): Round = {
|
||||
val roundImpl = nextRound(matchImpl)
|
||||
ControlHandler.invoke(ShowRoundStatus(SHOW_START_ROUND, roundImpl))
|
||||
while (!RoundControl.isOver(roundImpl)) {
|
||||
TrickControl.controlTrick(roundImpl)
|
||||
}
|
||||
val (roundWinner, finalRound) = RoundControl.finalizeRound(roundImpl, matchImpl)
|
||||
ControlHandler.invoke(ShowRoundStatus(WON_ROUND, finalRound, roundWinner))
|
||||
ControlHandler.invoke(DelayEvent(5000L))
|
||||
if (finalRound.players_out.nonEmpty) {
|
||||
ControlHandler.invoke(ShowRoundStatus(PLAYERS_OUT, finalRound))
|
||||
finalRound.players_out.foreach(p => {
|
||||
playerQueue.remove(p)
|
||||
})
|
||||
}
|
||||
playerQueue.resetAndSetStart(roundWinner)
|
||||
finalRound
|
||||
}
|
||||
|
||||
|
||||
private def provideCards(matchImpl: Match, players: List[Player]): Int = {
|
||||
if (!KnockOutWhist.DEBUG_MODE) CardManager.shuffleAndReset()
|
||||
var hands = 0
|
||||
for (player <- players) {
|
||||
if (!player.doglife) {
|
||||
player.provideHand(CardManager.createHand(matchImpl.number_of_cards))
|
||||
} else {
|
||||
player.provideHand(CardManager.createHand(1))
|
||||
}
|
||||
hands += 1
|
||||
}
|
||||
hands
|
||||
}
|
||||
}
|
||||
111
src/main/scala/de/knockoutwhist/control/TrickControl.scala
Normal file
111
src/main/scala/de/knockoutwhist/control/TrickControl.scala
Normal file
@@ -0,0 +1,111 @@
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.control.MatchControl.playerQueue
|
||||
import de.knockoutwhist.events.ERROR_STATUS.WRONG_CARD
|
||||
import de.knockoutwhist.events.PLAYER_STATUS.{SHOW_NOT_PLAYED, SHOW_WON_PLAYER_TRICK}
|
||||
import de.knockoutwhist.events.{ShowErrorStatus, ShowPlayerStatus}
|
||||
import de.knockoutwhist.events.round.ShowCurrentTrickEvent
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.rounds.{Round, Trick}
|
||||
import de.knockoutwhist.player.Player
|
||||
|
||||
object TrickControl {
|
||||
|
||||
def playCard(trick: Trick, round: Round, card: Card, player: Player): Boolean = {
|
||||
if (trick.finished) {
|
||||
throw new IllegalStateException("This trick is already finished")
|
||||
} else {
|
||||
if (trick.get_first_card().isEmpty) {
|
||||
trick.set_first_card(card)
|
||||
trick.cards += (card -> player)
|
||||
true
|
||||
} else if (card.suit == trick.get_first_card().getOrElse(card).suit) { // Wert aus Option extrahieren
|
||||
trick.cards += (card -> player)
|
||||
true
|
||||
} else if (card.suit == round.trumpSuit) {
|
||||
trick.cards += (card -> player)
|
||||
true
|
||||
} else {
|
||||
trick.cards += (card -> player)
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def wonTrick(trick: Trick, round: Round): (Player, 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.get_first_card().get.suit).maxBy(_.cardValue.ordinal) //stream
|
||||
}
|
||||
}
|
||||
val winningPlayer = trick.cards(winningCard)
|
||||
val finalTrick = Trick(round, trick.cards, winningPlayer, true)
|
||||
round.tricklist += finalTrick
|
||||
(winningPlayer, finalTrick)
|
||||
}
|
||||
|
||||
def create_trick(round: Round): Trick = {
|
||||
val trick = new Trick(round)
|
||||
round.set_current_trick(trick)
|
||||
trick
|
||||
}
|
||||
|
||||
def controlTrick(round: Round): Trick = {
|
||||
val trick = nextTrick(round)
|
||||
for (player <- playerQueue) {
|
||||
ControlHandler.invoke(ShowCurrentTrickEvent(round, trick))
|
||||
if (!player.doglife) {
|
||||
val rightCard = controlSuitplayed(trick, player)
|
||||
player.removeCard(rightCard)
|
||||
TrickControl.playCard(trick, round, rightCard, player)
|
||||
} else if (player.currentHand().exists(_.cards.nonEmpty)) {
|
||||
val card = PlayerControl.dogplayCard(player, round)
|
||||
if (card.isEmpty) {
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_NOT_PLAYED, player))
|
||||
} else {
|
||||
player.removeCard(card.get)
|
||||
TrickControl.playCard(trick, round, card.get, player)
|
||||
}
|
||||
}
|
||||
}
|
||||
val (winner, finalTrick) = TrickControl.wonTrick(trick, round)
|
||||
ControlHandler.invoke(ShowCurrentTrickEvent(round, finalTrick))
|
||||
ControlHandler.invoke(ShowPlayerStatus(SHOW_WON_PLAYER_TRICK, winner))
|
||||
playerQueue.resetAndSetStart(winner)
|
||||
ControlHandler.invoke(DelayEvent(3000L))
|
||||
finalTrick
|
||||
}
|
||||
|
||||
def nextTrick(roundImpl: Round): Trick = {
|
||||
if (RoundControl.isOver(roundImpl)) {
|
||||
return null
|
||||
}
|
||||
create_trick(roundImpl)
|
||||
}
|
||||
|
||||
private[control] def controlSuitplayed(trick: Trick, player: Player): Card = {
|
||||
var card = PlayerControl.playCard(player)
|
||||
if (trick.get_first_card().isDefined) {
|
||||
val firstCard = trick.get_first_card().get
|
||||
while (!(firstCard.suit == card.suit)) {
|
||||
var hasSuit = false
|
||||
for (cardInHand <- player.currentHand().get.cards) {
|
||||
if (cardInHand.suit == firstCard.suit) {
|
||||
hasSuit = true
|
||||
}
|
||||
}
|
||||
if (!hasSuit) {
|
||||
return card
|
||||
} else {
|
||||
ControlHandler.invoke(ShowErrorStatus(WRONG_CARD, firstCard))
|
||||
card = PlayerControl.playCard(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
card
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
package de.knockoutwhist.control.text
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.control.{MatchControl, PlayerControl}
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.CustomPlayerQueue
|
||||
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.io.StdIn
|
||||
import scala.util.Random
|
||||
|
||||
object TextMatchControl extends MatchControl {
|
||||
|
||||
private[control] var playerQueue: CustomPlayerQueue[Player] = uninitialized
|
||||
private var init = false
|
||||
|
||||
override def initial(): Boolean = {
|
||||
if(init) {
|
||||
println("The game is already running.")
|
||||
return false
|
||||
}
|
||||
init = true
|
||||
println("Welcome to Knockout Whist!")
|
||||
start()
|
||||
true
|
||||
}
|
||||
|
||||
override def start(): Unit = {
|
||||
while(true) { //Main Gameplay Loop
|
||||
val input = printMenu()
|
||||
input match {
|
||||
case "1" =>
|
||||
startMatch()
|
||||
case "2" =>
|
||||
println("Exiting the game.")
|
||||
return
|
||||
case _ =>
|
||||
println("Invalid input. Please try again.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private[control] def startMatch(): Player = {
|
||||
clearConsole()
|
||||
println("Starting a new match.")
|
||||
val players = enterPlayers()
|
||||
playerQueue = CustomPlayerQueue[Player](players, Random.nextInt(players.length))
|
||||
clearConsole()
|
||||
controlMatch()
|
||||
}
|
||||
|
||||
private[control] def enterPlayers(): Array[Player] = {
|
||||
println("Please enter the names of the players, separated by a comma.")
|
||||
val names = StdIn.readLine().split(",")
|
||||
if(names.length < 2) {
|
||||
println("Please enter at least two names.")
|
||||
return enterPlayers()
|
||||
}
|
||||
if(names.distinct.length != names.length) {
|
||||
println("Please enter unique names.")
|
||||
return enterPlayers()
|
||||
}
|
||||
if(names.count(_.trim.isBlank) > 0 || names.count(_.trim.length <= 2) > 0 || names.count(_.trim.length > 10) > 0) {
|
||||
println("Please enter valid names. Those can not be empty, shorter than 2 or longer then 10 characters.")
|
||||
return enterPlayers()
|
||||
}
|
||||
names.map(s => Player(s))
|
||||
}
|
||||
|
||||
private[control] def controlMatch(): Player = {
|
||||
val matchImpl = Match(playerQueue.toList)
|
||||
while (!matchImpl.isOver) {
|
||||
val roundImpl = controlRound(matchImpl)
|
||||
}
|
||||
clearConsole()
|
||||
println(s"The match is over. The winner is ${matchImpl.finalizeMatch().name}.")
|
||||
matchImpl.finalizeMatch()
|
||||
}
|
||||
|
||||
private[control] def controlRound(matchImpl: Match): Round = {
|
||||
val roundImpl = nextRound(matchImpl)
|
||||
clearConsole(10)
|
||||
println(s"Starting a new round. The trump suit is ${roundImpl.trumpSuit}.")
|
||||
clearConsole(2)
|
||||
while (!roundImpl.isOver) {
|
||||
controlTrick(roundImpl)
|
||||
}
|
||||
val (roundWinner, finalRound) = roundImpl.finalizeRound()
|
||||
println(s"${roundWinner.name} won the round.")
|
||||
if(!KnockOutWhist.DEBUG_MODE) Thread.sleep(5000L)
|
||||
if(finalRound.players_out.nonEmpty) {
|
||||
println("The following players are out of the game:")
|
||||
finalRound.players_out.foreach(p => {
|
||||
println(p.name)
|
||||
playerQueue.remove(p)
|
||||
})
|
||||
}
|
||||
playerQueue.resetAndSetStart(roundWinner)
|
||||
finalRound
|
||||
}
|
||||
|
||||
private[control] def controlTrick(round: Round): Trick = {
|
||||
val trick = nextTrick(round)
|
||||
for (player <- playerQueue) {
|
||||
clearConsole()
|
||||
println(printTrick(round))
|
||||
if (!player.doglife) {
|
||||
val rightCard = controlSuitplayed(trick, player)
|
||||
player.removeCard(rightCard)
|
||||
trick.playCard(rightCard, player)
|
||||
} else if (player.currentHand().exists(_.cards.nonEmpty)) {
|
||||
val card = playerControl.dogplayCard(player, round)
|
||||
if (card.isEmpty) {
|
||||
println(f"Player $player decided to not play his card")
|
||||
} else {
|
||||
player.removeCard(card.get)
|
||||
trick.playCard(card.get, player)
|
||||
}
|
||||
}
|
||||
}
|
||||
val (winner, finalTrick) = trick.wonTrick()
|
||||
clearConsole()
|
||||
println(printTrick(round))
|
||||
println(s"${winner.name} won the trick.")
|
||||
clearConsole(2)
|
||||
playerQueue.resetAndSetStart(winner)
|
||||
if(!KnockOutWhist.DEBUG_MODE) Thread.sleep(3000L)
|
||||
finalTrick
|
||||
}
|
||||
private[control] def controlSuitplayed(trick: Trick, player: Player): Card = {
|
||||
var card = playerControl.playCard(player)
|
||||
if (trick.get_first_card().isDefined) {
|
||||
while (!(trick.get_first_card().get.suit == card.suit)) {
|
||||
var hasSuit = false
|
||||
for (cardInHand <- player.currentHand().get.cards) {
|
||||
if (cardInHand.suit == trick.get_first_card().get.suit) {
|
||||
hasSuit = true
|
||||
}
|
||||
}
|
||||
if(!hasSuit) {
|
||||
return card
|
||||
}else {
|
||||
println(f"You have to play a card of suit: ${trick.get_first_card().get.suit}\n")
|
||||
card = playerControl.playCard(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
card
|
||||
}
|
||||
|
||||
private[control] def printMenu(): String = {
|
||||
println("Please select an option:")
|
||||
println("1. Start a new match")
|
||||
println("2. Exit")
|
||||
StdIn.readLine()
|
||||
}
|
||||
|
||||
private[control] def printTrick(round: Round): String = {
|
||||
val sb = new StringBuilder()
|
||||
sb.append("Current Trick:\n")
|
||||
sb.append("Trump-Suit: " + round.trumpSuit + "\n")
|
||||
if(round.get_current_trick().get_first_card().isDefined) {
|
||||
sb.append(s"Suit to play: ${round.get_current_trick().get_first_card().get.suit}\n")
|
||||
}
|
||||
for((card, player) <- round.get_current_trick().cards) {
|
||||
sb.append(s"${player.name} played ${card.toString}\n")
|
||||
}
|
||||
sb.toString()
|
||||
}
|
||||
|
||||
private def clearConsole(lines: Int = 32): Int = {
|
||||
var l = 0
|
||||
for(_ <- 0 until lines) {
|
||||
println()
|
||||
l += 1
|
||||
}
|
||||
l
|
||||
}
|
||||
|
||||
override def playerControl: PlayerControl = {
|
||||
TextPlayerControl
|
||||
}
|
||||
|
||||
override def nextRound(matchImpl: Match): Round = {
|
||||
if(matchImpl.isOver) {
|
||||
println(s"The match is over. The winner is ${matchImpl.finalizeMatch().name}.")
|
||||
return null
|
||||
}
|
||||
matchImpl.create_round()
|
||||
}
|
||||
|
||||
override def nextTrick(roundImpl: Round): Trick = {
|
||||
if(roundImpl.isOver) {
|
||||
println("The round is over.")
|
||||
return null
|
||||
}
|
||||
roundImpl.create_trick()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
package de.knockoutwhist.control.text
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.{Card, CardManager, Suit}
|
||||
import de.knockoutwhist.control.PlayerControl
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.rounds.Round
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.io.StdIn.readLine
|
||||
import scala.util.control.Breaks.*
|
||||
|
||||
object TextPlayerControl extends PlayerControl {
|
||||
|
||||
override def playCard(player: Player): Card = {
|
||||
println("It's your turn, " + player.name + ".")
|
||||
if(!KnockOutWhist.DEBUG_MODE) Thread.sleep(3000L)
|
||||
println("Which card do you want to play?")
|
||||
showCards(player)
|
||||
try {
|
||||
val card = readLine().toInt-1
|
||||
val handCard = player.currentHand()
|
||||
if (handCard.isEmpty) {
|
||||
println("You don't have any cards.")
|
||||
throw new IllegalStateException("Trying to play a card without any cards.")
|
||||
} else if(card < 0 || card >= handCard.get.cards.length) {
|
||||
println("Please enter a valid number.")
|
||||
playCard(player)
|
||||
} else {
|
||||
handCard.get.cards(card)
|
||||
}
|
||||
} catch {
|
||||
case e: NumberFormatException =>
|
||||
println("Please enter a valid number.")
|
||||
playCard(player)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override def dogplayCard(player: Player, round: Round): Option[Card] = {
|
||||
println("It's your turn, " + player.name + ".")
|
||||
if (!KnockOutWhist.DEBUG_MODE) Thread.sleep(3000L)
|
||||
println("You are using your dog life. Do you want to play your final card now?")
|
||||
if(round.dogNeedsToPlay) {
|
||||
println("You have to play your final card this round!")
|
||||
println("Please enter y to play your final card.")
|
||||
}else {
|
||||
println("Please enter y/n to play your final card.")
|
||||
}
|
||||
|
||||
showCards(player)
|
||||
val card = readLine()
|
||||
val handCard = player.currentHand()
|
||||
if (handCard.isEmpty) {
|
||||
println("You don't have any cards.")
|
||||
throw new IllegalStateException("Trying to play a card without any cards.")
|
||||
} else if(card.equalsIgnoreCase("y")) {
|
||||
Some(handCard.get.cards.head)
|
||||
} else if (card.equalsIgnoreCase("n") && !round.dogNeedsToPlay) {
|
||||
None
|
||||
} else {
|
||||
println("Please enter y or n to play your final card.")
|
||||
dogplayCard(player, round)
|
||||
}
|
||||
}
|
||||
|
||||
override def determineWinnerTie(players: List[Player]): Player = {
|
||||
determineWinnerTieText(players, true)
|
||||
}
|
||||
|
||||
@tailrec
|
||||
private def determineWinnerTieText(players: List[Player], tieMessage: Boolean): Player = {
|
||||
if (!KnockOutWhist.DEBUG_MODE) CardManager.shuffleAndReset()
|
||||
if (tieMessage) println("It's a tie! Let's cut to determine the winner.")
|
||||
var currentStep = 0
|
||||
var remaining = CardManager.cardContainer.size - (players.length - 1)
|
||||
val cut: mutable.HashMap[Player, Card] = mutable.HashMap()
|
||||
for (player <- players) {
|
||||
var selCard: Card = null
|
||||
while (selCard == null) {
|
||||
println(s"${player.name} enter a number between 1 and $remaining.")
|
||||
try {
|
||||
val selected = readLine().toInt - 1
|
||||
if (selected >= 0 && selected < remaining) {
|
||||
selCard = CardManager.cardContainer(currentStep + selected)
|
||||
cut.put(player, selCard)
|
||||
currentStep += selected + 1
|
||||
remaining -= selected
|
||||
} else {
|
||||
println("Please enter a valid number.")
|
||||
}
|
||||
} catch {
|
||||
case e: NumberFormatException =>
|
||||
println("Please enter a valid number.")
|
||||
}
|
||||
}
|
||||
}
|
||||
println("The cards are:")
|
||||
val a: Array[String] = Array("", "", "", "", "", "", "", "")
|
||||
for ((player, card) <- cut) {
|
||||
val playerNameLength = player.name.length
|
||||
a(0) += " " + player.name + ":" + (" " * (playerNameLength - 1))
|
||||
val rendered = card.renderAsString()
|
||||
a(1) += " " + rendered(0)
|
||||
a(2) += " " + rendered(1)
|
||||
a(3) += " " + rendered(2)
|
||||
a(4) += " " + rendered(3)
|
||||
a(5) += " " + rendered(4)
|
||||
a(6) += " " + rendered(5)
|
||||
a(7) += " " + rendered(6)
|
||||
}
|
||||
a.foreach(println)
|
||||
|
||||
var currentHighest: Card = null
|
||||
val winner: ListBuffer[Player] = ListBuffer()
|
||||
for ((player, card) <- cut) {
|
||||
breakable {
|
||||
if (currentHighest == null) {
|
||||
currentHighest = card
|
||||
winner += player
|
||||
break
|
||||
}
|
||||
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) {
|
||||
println(s"${winner.head.name} wins the cut!")
|
||||
return winner.head
|
||||
}
|
||||
println("It's a tie again! Let's cut again.")
|
||||
determineWinnerTieText(winner.toList, false)
|
||||
}
|
||||
|
||||
override def pickNextTrumpsuit(player: Player): Suit = {
|
||||
println("Which suit do you want to pick as the next trump suit?")
|
||||
println("1: Hearts")
|
||||
println("2: Diamonds")
|
||||
println("3: Clubs")
|
||||
println("4: Spades")
|
||||
println()
|
||||
|
||||
player.currentHand().get.renderAsString().foreach(println)
|
||||
|
||||
try {
|
||||
val suit = readLine().toInt
|
||||
suit match {
|
||||
case 1 => Suit.Hearts
|
||||
case 2 => Suit.Diamonds
|
||||
case 3 => Suit.Clubs
|
||||
case 4 => Suit.Spades
|
||||
case _ =>
|
||||
println("Please enter a valid number.")
|
||||
pickNextTrumpsuit(player)
|
||||
}
|
||||
} catch {
|
||||
case e: NumberFormatException =>
|
||||
println("Please enter a valid number.")
|
||||
pickNextTrumpsuit(player)
|
||||
}
|
||||
}
|
||||
|
||||
override def showCards(player: Player): Boolean = {
|
||||
val hand = player.currentHand()
|
||||
if (hand.isEmpty) {
|
||||
println("You don't have any cards.")
|
||||
return false
|
||||
}
|
||||
println("Your cards:")
|
||||
var rendered = hand.get.renderAsString()
|
||||
rendered ::= {
|
||||
var s = ""
|
||||
for (i <- hand.get.cards.indices) {
|
||||
s += s" ${i+1} " + " "
|
||||
}
|
||||
s
|
||||
}
|
||||
rendered.foreach(println)
|
||||
true
|
||||
}
|
||||
|
||||
override def showWon(player: Player, round: Round): String = {
|
||||
s"$player won this round."
|
||||
}
|
||||
|
||||
}
|
||||
58
src/main/scala/de/knockoutwhist/events/ShowStatusEvent.scala
Normal file
58
src/main/scala/de/knockoutwhist/events/ShowStatusEvent.scala
Normal file
@@ -0,0 +1,58 @@
|
||||
package de.knockoutwhist.events
|
||||
|
||||
import de.knockoutwhist.player.Player
|
||||
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: Player, 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"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
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"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.knockoutwhist.events.cards
|
||||
|
||||
import de.knockoutwhist.cards.Card
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class ShowTieCardsEvent(card: List[(Player, Card)]) extends SimpleEvent {
|
||||
override def id: String = "ShowTieCardsEvent"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.knockoutwhist.events.directional
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Hand}
|
||||
import de.knockoutwhist.utils.events.ReturnableEvent
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
case class RequestCardEvent(hand: Hand) extends ReturnableEvent[Try[Card]] {
|
||||
override def id: String = "RequestCardEvent"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.knockoutwhist.events.directional
|
||||
|
||||
import de.knockoutwhist.cards.{Card, Hand}
|
||||
import de.knockoutwhist.utils.events.ReturnableEvent
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
case class RequestDogPlayCardEvent(hand: Hand, needs_to_play: Boolean) extends ReturnableEvent[Try[Option[Card]]] {
|
||||
override def id: String = "RequestDogPlayCardEvent"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.knockoutwhist.events.directional
|
||||
|
||||
import de.knockoutwhist.utils.events.{SimpleEvent, ReturnableEvent}
|
||||
|
||||
import scala.io.StdIn
|
||||
import scala.util.Try
|
||||
|
||||
case class RequestNumberEvent(min: Int, max: Int) extends ReturnableEvent[Try[Int]] {
|
||||
override def id: String = "RequestNumberEvent"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.knockoutwhist.events.directional
|
||||
|
||||
import de.knockoutwhist.cards.Suit
|
||||
import de.knockoutwhist.utils.events.ReturnableEvent
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
case class RequestPickTrumpsuitEvent() extends ReturnableEvent[Try[Suit]] {
|
||||
override def id: String = "RequestPickTrumpsuitEvent"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
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"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.events.util
|
||||
|
||||
import de.knockoutwhist.utils.events.SimpleEvent
|
||||
|
||||
case class DelayEvent (delay: Long) extends SimpleEvent {
|
||||
override def id: String = "DelayEvent"
|
||||
}
|
||||
@@ -14,9 +14,7 @@ case class Player(name: String) {
|
||||
this.hand = Some(hand)
|
||||
true
|
||||
}
|
||||
def pickTrumpsuit(): Suit = {
|
||||
KnockOutWhist.matchControl.playerControl.pickNextTrumpsuit(this)
|
||||
}
|
||||
|
||||
def removeCard(card: Card): Int = {
|
||||
hand = Some(hand.get.removeCard(card))
|
||||
hand.get.cards.size
|
||||
|
||||
@@ -7,56 +7,11 @@ import de.knockoutwhist.player.Player
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import de.knockoutwhist.utils.Implicits._
|
||||
|
||||
case class Match(totalplayers: List[Player], private[rounds] var number_of_cards: Int = 7) {
|
||||
case class Match(totalplayers: List[Player], var number_of_cards: Int = 7) {
|
||||
|
||||
private[rounds] val roundlist: ListBuffer[Round] = ListBuffer[Round]()
|
||||
private var current_round: Option[Round] = None
|
||||
private[rounds] var dogLife = false
|
||||
|
||||
def create_round(): Round = {
|
||||
val remainingPlayer = roundlist.isEmpty ? totalplayers |: roundlist.last.remainingPlayers()
|
||||
provideCards(remainingPlayer)
|
||||
if (roundlist.isEmpty) {
|
||||
val random_trumpsuit = CardManager.nextCard().suit
|
||||
current_round = Some(new Round(random_trumpsuit, this, remainingPlayer, true))
|
||||
} else {
|
||||
val winner = roundlist.last.winner
|
||||
val trumpsuit = winner.pickTrumpsuit()
|
||||
|
||||
current_round = Some(new Round(trumpsuit, this, remainingPlayer, false))
|
||||
}
|
||||
number_of_cards -= 1
|
||||
current_round.get
|
||||
}
|
||||
|
||||
def isOver: Boolean = {
|
||||
if(roundlist.isEmpty) {
|
||||
false
|
||||
} else {
|
||||
roundlist.last.remainingPlayers().size == 1
|
||||
}
|
||||
}
|
||||
|
||||
private def provideCards(players: List[Player]): Int = {
|
||||
if(!KnockOutWhist.DEBUG_MODE) CardManager.shuffleAndReset()
|
||||
var hands = 0
|
||||
for (player <- players) {
|
||||
if(!player.doglife) {
|
||||
player.provideHand(CardManager.createHand(number_of_cards))
|
||||
} else {
|
||||
player.provideHand(CardManager.createHand(1))
|
||||
}
|
||||
hands += 1
|
||||
}
|
||||
hands
|
||||
}
|
||||
|
||||
def finalizeMatch(): Player = {
|
||||
if(!isOver) {
|
||||
throw new IllegalStateException("Match is not over yet.")
|
||||
}
|
||||
roundlist.last.remainingPlayers().head
|
||||
}
|
||||
val roundlist: ListBuffer[Round] = ListBuffer[Round]()
|
||||
var current_round: Option[Round] = None
|
||||
var dogLife = false
|
||||
|
||||
override def toString: String = {
|
||||
s"${totalplayers}, ${number_of_cards}"
|
||||
|
||||
@@ -2,77 +2,26 @@ package de.knockoutwhist.rounds
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.{CardManager, Suit}
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.utils.Implicits._
|
||||
import de.knockoutwhist.utils.Implicits.*
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
case class Round private[rounds](trumpSuit: Suit, matchImpl: Match, private[rounds] val tricklist: ListBuffer[Trick], players_in: List[Player], players_out: List[Player] = null, winner: Player = null, firstRound: Boolean) {
|
||||
case class Round (trumpSuit: Suit, matchImpl: Match, tricklist: ListBuffer[Trick], players_in: List[Player], players_out: List[Player] = null, winner: Player = null, firstRound: Boolean) {
|
||||
def this(trumpSuit: Suit, matchImpl: Match, players_in: List[Player], firstRound: Boolean) = {
|
||||
this(trumpSuit, matchImpl, ListBuffer[Trick](), players_in, firstRound = firstRound)
|
||||
}
|
||||
|
||||
private var current_trick: Option[Trick] = None
|
||||
|
||||
def get_current_trick(): Trick = {
|
||||
current_trick.getOrElse(create_trick())
|
||||
def get_current_trick(): Option[Trick] = {
|
||||
current_trick
|
||||
}
|
||||
|
||||
def get_tricks(): List[Trick] = tricklist.toList
|
||||
|
||||
def create_trick(): Trick = {
|
||||
val trick = new Trick(this)
|
||||
def set_current_trick(trick: Trick): Unit = {
|
||||
current_trick = Some(trick)
|
||||
trick
|
||||
}
|
||||
|
||||
def isOver: Boolean = {
|
||||
players_in.map(_.currentHand()).count(_.get.cards.isEmpty) == players_in.size
|
||||
}
|
||||
|
||||
def dogNeedsToPlay: Boolean = {
|
||||
players_in.filter(!_.doglife).map(_.currentHand()).exists(_.get.cards.isEmpty)
|
||||
}
|
||||
|
||||
def finalizeRound(force: Boolean = false): (Player, Round) = {
|
||||
if(!force && tricklist.isEmpty)
|
||||
throw new IllegalStateException("No tricks played in this round")
|
||||
if(!force && !isOver)
|
||||
throw new IllegalStateException("Not all tricks were played in this round")
|
||||
val tricksMapped = 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 = firstRound
|
||||
? List()
|
||||
|: players_in.filter(!tricksMapped.contains(_))
|
||||
|
||||
if(playersOut.nonEmpty && !matchImpl.dogLife) {
|
||||
matchImpl.dogLife = true
|
||||
playersOut.foreach(p => p.doglife = true)
|
||||
playersOut = List()
|
||||
}
|
||||
|
||||
tricksMapped.keys.foreach(p => {p.doglife = false})
|
||||
|
||||
val winner = (winners.size == 1)
|
||||
? winners.head
|
||||
|: KnockOutWhist.matchControl.playerControl.determineWinnerTie(winners.toList)
|
||||
|
||||
val finalRound = Round(trumpSuit, matchImpl, tricklist, players_in, playersOut, winner, firstRound)
|
||||
matchImpl.roundlist += finalRound
|
||||
(winner, finalRound)
|
||||
}
|
||||
|
||||
def remainingPlayers(): List[Player] = {
|
||||
if (players_out == null) {
|
||||
return players_in
|
||||
}
|
||||
players_in.filter(!players_out.contains(_))
|
||||
}
|
||||
|
||||
override def toString: String = {
|
||||
s"$trumpSuit, $tricklist, $players_in, $players_out, $winner, $firstRound"
|
||||
}
|
||||
|
||||
@@ -7,54 +7,21 @@ import de.knockoutwhist.player.Player
|
||||
import scala.collection.mutable
|
||||
|
||||
|
||||
case class Trick private(round: Round, cards: mutable.HashMap[Card, Player], winner: Player = null, finished: Boolean = false) {
|
||||
case class Trick (round: Round, cards: mutable.HashMap[Card, Player], winner: Player = null, finished: Boolean = false) {
|
||||
|
||||
def this(round: Round) = {
|
||||
this(round, mutable.HashMap[Card, Player]())
|
||||
}
|
||||
private var first_card: Option[Card] = None // statt als Parameter im Konstruktor
|
||||
|
||||
def get_first_card(): Option[Card] = first_card
|
||||
|
||||
/**
|
||||
* Play a card in the trick
|
||||
* @param card The card to play
|
||||
* @return True if the card has a chance of winning the trick, false otherwise
|
||||
*/
|
||||
def playCard(card: Card, player: Player): Boolean = {
|
||||
if (finished) {
|
||||
def set_first_card(card: Card): Option[Card] = {
|
||||
if(first_card.isDefined) {
|
||||
throw new IllegalStateException("This trick is already finished")
|
||||
} else {
|
||||
if (first_card.isEmpty) {
|
||||
first_card = Some(card)
|
||||
cards += (card -> player)
|
||||
true
|
||||
} else if (card.suit == first_card.getOrElse(card).suit) { // Wert aus Option extrahieren
|
||||
cards += (card -> player)
|
||||
true
|
||||
} else if (card.suit == round.trumpSuit) {
|
||||
cards += (card -> player)
|
||||
true
|
||||
} else {
|
||||
cards += (card -> player)
|
||||
false
|
||||
}
|
||||
}
|
||||
first_card = Some(card)
|
||||
first_card
|
||||
}
|
||||
|
||||
def wonTrick(): (Player, Trick) = {
|
||||
val winningCard = {
|
||||
if (cards.keys.exists(_.suit == round.trumpSuit)) {
|
||||
cards.keys.filter(_.suit == round.trumpSuit).maxBy(_.cardValue.ordinal) //stream
|
||||
} else {
|
||||
cards.keys.filter(_.suit == first_card.get.suit).maxBy(_.cardValue.ordinal) //stream
|
||||
}
|
||||
}
|
||||
val winningPlayer = cards(winningCard)
|
||||
val finalTrick = Trick(round, cards, winningPlayer, true)
|
||||
round.tricklist += finalTrick
|
||||
(winningPlayer, finalTrick)
|
||||
}
|
||||
def get_first_card(): Option[Card] = first_card
|
||||
|
||||
override def toString: String = {
|
||||
s"$cards, $winner, $finished"
|
||||
|
||||
7
src/main/scala/de/knockoutwhist/ui/UI.scala
Normal file
7
src/main/scala/de/knockoutwhist/ui/UI.scala
Normal file
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.ui
|
||||
|
||||
trait UI {
|
||||
|
||||
def initial: Boolean
|
||||
|
||||
}
|
||||
319
src/main/scala/de/knockoutwhist/ui/tui/TUIMain.scala
Normal file
319
src/main/scala/de/knockoutwhist/ui/tui/TUIMain.scala
Normal file
@@ -0,0 +1,319 @@
|
||||
package de.knockoutwhist.ui.tui
|
||||
|
||||
import de.knockoutwhist.cards.{Card, CardValue, Hand, Suit}
|
||||
import de.knockoutwhist.control.{ControlHandler, MatchControl}
|
||||
import de.knockoutwhist.events.*
|
||||
import de.knockoutwhist.events.ERROR_STATUS.*
|
||||
import de.knockoutwhist.events.GLOBAL_STATUS.*
|
||||
import de.knockoutwhist.events.PLAYER_STATUS.*
|
||||
import de.knockoutwhist.events.ROUND_STATUS.{PLAYERS_OUT, SHOW_START_ROUND, WON_ROUND}
|
||||
import de.knockoutwhist.events.cards.{RenderHandEvent, ShowTieCardsEvent}
|
||||
import de.knockoutwhist.events.directional.{RequestCardEvent, RequestDogPlayCardEvent, RequestNumberEvent, RequestPickTrumpsuitEvent}
|
||||
import de.knockoutwhist.events.round.ShowCurrentTrickEvent
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.ui.UI
|
||||
import de.knockoutwhist.utils.events.{EventListener, ReturnableEvent}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.io.StdIn.readLine
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
object TUIMain extends EventListener with UI {
|
||||
|
||||
var init = false
|
||||
|
||||
override def listen[R](event: ReturnableEvent[R]): Option[R] = {
|
||||
event match {
|
||||
case event: RenderHandEvent =>
|
||||
TUICards.renderHandEvent(event.hand, event.showNumbers).foreach(println)
|
||||
Some(true)
|
||||
case event: ShowTieCardsEvent =>
|
||||
val a: Array[String] = Array("", "", "", "", "", "", "", "")
|
||||
for ((player,card) <- event.card) {
|
||||
val playerNameLength = player.name.length
|
||||
a(0) += " " + player.name + ":" + (" " * (playerNameLength - 1))
|
||||
val rendered = TUICards.renderCardAsString(card)
|
||||
a(1) += " " + rendered(0)
|
||||
a(2) += " " + rendered(1)
|
||||
a(3) += " " + rendered(2)
|
||||
a(4) += " " + rendered(3)
|
||||
a(5) += " " + rendered(4)
|
||||
a(6) += " " + rendered(5)
|
||||
a(7) += " " + rendered(6)
|
||||
}
|
||||
a.foreach(println)
|
||||
Some(true)
|
||||
case event: ShowGlobalStatus =>
|
||||
event.status match {
|
||||
case SHOW_TIE =>
|
||||
println("It's a tie! Let's cut to determine the winner.")
|
||||
Some(true)
|
||||
case SHOW_TIE_WINNER =>
|
||||
if(event.objects.length != 1 || !event.objects.head.isInstanceOf[Player]) {
|
||||
None
|
||||
} else {
|
||||
println(s"${event.objects.head.asInstanceOf[Player].name} wins the cut!")
|
||||
Some(true)
|
||||
}
|
||||
case SHOW_TIE_TIE =>
|
||||
println("It's a tie again! Let's cut again.")
|
||||
Some(true)
|
||||
case SHOW_START_MATCH =>
|
||||
TUIUtil.clearConsole()
|
||||
println("Starting a new match...")
|
||||
TUIUtil.clearConsole(2)
|
||||
Some(true)
|
||||
case SHOW_TYPE_PLAYERS =>
|
||||
println("Please enter the names of the players, separated by a comma.")
|
||||
Some(true)
|
||||
case SHOW_FINISHED_MATCH =>
|
||||
if (event.objects.length != 1 || !event.objects.head.isInstanceOf[Player]) {
|
||||
None
|
||||
} else {
|
||||
TUIUtil.clearConsole()
|
||||
println(s"The match is over. The winner is ${event.objects.head.asInstanceOf[Player]}")
|
||||
Some(true)
|
||||
}
|
||||
}
|
||||
case event: ShowPlayerStatus =>
|
||||
val player = event.player
|
||||
event.status match {
|
||||
case SHOW_TURN =>
|
||||
println("It's your turn, " + player.name + ".")
|
||||
Some(true)
|
||||
case SHOW_PLAY_CARD =>
|
||||
println("Which card do you want to play?")
|
||||
Some(true)
|
||||
case SHOW_DOG_PLAY_CARD =>
|
||||
if(event.objects.length != 1 || !event.objects.head.isInstanceOf[Boolean]) {
|
||||
None
|
||||
} else {
|
||||
println("You are using your dog life. Do you want to play your final card now?")
|
||||
if (event.objects.head.asInstanceOf[Boolean]) {
|
||||
println("You have to play your final card this round!")
|
||||
println("Please enter y to play your final card.")
|
||||
Some(true)
|
||||
} else {
|
||||
println("Please enter y/n to play your final card.")
|
||||
Some(true)
|
||||
}
|
||||
}
|
||||
case SHOW_TIE_NUMBERS =>
|
||||
if(event.objects.length != 1 || !event.objects.head.isInstanceOf[Int]) {
|
||||
None
|
||||
} else {
|
||||
println(s"${player.name} enter a number between 1 and ${event.objects.head.asInstanceOf[Int]}.")
|
||||
Some(true)
|
||||
}
|
||||
case SHOW_TRUMPSUIT_OPTIONS =>
|
||||
println("Which suit do you want to pick as the next trump suit?")
|
||||
println("1: Hearts")
|
||||
println("2: Diamonds")
|
||||
println("3: Clubs")
|
||||
println("4: Spades")
|
||||
println()
|
||||
Some(true)
|
||||
case SHOW_NOT_PLAYED =>
|
||||
println(s"Player ${event.player} decided to not play his card")
|
||||
Some(true)
|
||||
case SHOW_WON_PLAYER_TRICK =>
|
||||
println(s"${event.player.name} won the trick.")
|
||||
TUIUtil.clearConsole(2)
|
||||
Some(true)
|
||||
}
|
||||
case event: ShowRoundStatus =>
|
||||
event.status match {
|
||||
case SHOW_START_ROUND =>
|
||||
TUIUtil.clearConsole()
|
||||
println(s"Starting a new round. The trump suit is ${event.currentRound.trumpSuit}.")
|
||||
TUIUtil.clearConsole(2)
|
||||
Some(true)
|
||||
case WON_ROUND =>
|
||||
if (event.objects.length != 1 || !event.objects.head.isInstanceOf[Player]) {
|
||||
None
|
||||
} else {
|
||||
println(s"${event.objects.head.asInstanceOf[Player].name} won the round.")
|
||||
Some(true)
|
||||
}
|
||||
case PLAYERS_OUT =>
|
||||
println("The following players are out of the game:")
|
||||
event.currentRound.players_out.foreach(p => {
|
||||
println(p.name)
|
||||
})
|
||||
Some(true)
|
||||
}
|
||||
case event: ShowErrorStatus =>
|
||||
event.status match {
|
||||
case INVALID_NUMBER =>
|
||||
println("Please enter a valid number.")
|
||||
Some(true)
|
||||
case NOT_A_NUMBER =>
|
||||
println("Please enter a valid number.")
|
||||
Some(true)
|
||||
case INVALID_INPUT =>
|
||||
println("Please enter a valid input")
|
||||
Some(true)
|
||||
case INVALID_NUMBER_OF_PLAYERS =>
|
||||
println("Please enter at least two names.")
|
||||
Some(true)
|
||||
case IDENTICAL_NAMES =>
|
||||
println("Please enter unique names.")
|
||||
Some(true)
|
||||
case INVALID_NAME_FORMAT =>
|
||||
println("Please enter valid names. Those can not be empty, shorter than 2 or longer then 10 characters.")
|
||||
Some(true)
|
||||
case WRONG_CARD =>
|
||||
if(event.objects.length != 1 || !event.objects.head.isInstanceOf[Card]) {
|
||||
None
|
||||
} else {
|
||||
println(f"You have to play a card of suit: ${event.objects.head.asInstanceOf[Card].suit}\n")
|
||||
Some(true)
|
||||
}
|
||||
}
|
||||
case event: RequestNumberEvent =>
|
||||
Some(Try {
|
||||
val input = readLine()
|
||||
val number = input.toInt
|
||||
if (number < event.min || number > event.max) {
|
||||
throw new IllegalArgumentException(s"Number must be between ${event.min} and ${event.max}")
|
||||
}
|
||||
number
|
||||
})
|
||||
case event: RequestCardEvent =>
|
||||
Some(Try {
|
||||
val card = readLine().toInt - 1
|
||||
if (card < 0 || card >= event.hand.cards.length) {
|
||||
throw new IllegalArgumentException(s"Number has to be between 1 and ${event.hand.cards.length}")
|
||||
} else {
|
||||
event.hand.cards(card)
|
||||
}
|
||||
})
|
||||
case event: RequestDogPlayCardEvent =>
|
||||
Some(Try {
|
||||
val card = readLine()
|
||||
if (card.equalsIgnoreCase("y")) {
|
||||
Some(event.hand.cards.head)
|
||||
} else if (card.equalsIgnoreCase("n") && !event.needs_to_play) {
|
||||
None
|
||||
} else {
|
||||
throw new IllegalArgumentException("Didn't want to play card but had to")
|
||||
}
|
||||
}
|
||||
)
|
||||
case event: RequestPickTrumpsuitEvent =>
|
||||
Some(Try {
|
||||
val suit = readLine().toInt
|
||||
suit match {
|
||||
case 1 => Suit.Hearts
|
||||
case 2 => Suit.Diamonds
|
||||
case 3 => Suit.Clubs
|
||||
case 4 => Suit.Spades
|
||||
case _ => throw IllegalArgumentException("Didn't enter a number between 1 and 4")
|
||||
}
|
||||
})
|
||||
case event: ShowCurrentTrickEvent =>
|
||||
TUIUtil.clearConsole()
|
||||
val sb = new StringBuilder()
|
||||
sb.append("Current Trick:\n")
|
||||
sb.append("Trump-Suit: " + event.round.trumpSuit + "\n")
|
||||
if (event.trick.get_first_card().isDefined) {
|
||||
sb.append(s"Suit to play: ${event.trick.get_first_card().get.suit}\n")
|
||||
}
|
||||
for ((card, player) <- event.trick.cards) {
|
||||
sb.append(s"${player.name} played ${card.toString}\n")
|
||||
}
|
||||
println(sb.toString())
|
||||
Some(true)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object TUICards {
|
||||
def renderCardAsString(card: Card): Vector[String] = {
|
||||
if (card.cardValue == CardValue.Ten) {
|
||||
return Vector(
|
||||
s"┌─────────┐",
|
||||
s"│${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET} │",
|
||||
"│ │",
|
||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.suit.cardType()}${Console.RESET} │",
|
||||
"│ │",
|
||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET}│",
|
||||
s"└─────────┘"
|
||||
)
|
||||
}
|
||||
Vector(
|
||||
s"┌─────────┐",
|
||||
s"│${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET} │",
|
||||
"│ │",
|
||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.suit.cardType()}${Console.RESET} │",
|
||||
"│ │",
|
||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET}│",
|
||||
s"└─────────┘"
|
||||
)
|
||||
}
|
||||
|
||||
private[ui] def cardColour(suit: Suit): String = suit match {
|
||||
case Suit.Hearts | Suit.Diamonds => Console.RED
|
||||
case Suit.Clubs | Suit.Spades => Console.BLACK
|
||||
}
|
||||
|
||||
def renderHandEvent(hand: Hand, showNumbers: Boolean): Vector[String] = {
|
||||
val cardStrings = hand.cards.map(TUICards.renderCardAsString)
|
||||
var zipped = cardStrings.transpose
|
||||
if (showNumbers) zipped = {
|
||||
List.tabulate(hand.cards.length) { i =>
|
||||
s" ${i + 1} "
|
||||
}
|
||||
} :: zipped
|
||||
zipped.map(_.mkString(" ")).toVector
|
||||
}
|
||||
}
|
||||
private object TUIUtil {
|
||||
def clearConsole(lines: Int = 32): Int = {
|
||||
var l = 0
|
||||
for (_ <- 0 until lines) {
|
||||
println()
|
||||
l += 1
|
||||
}
|
||||
l
|
||||
}
|
||||
}
|
||||
|
||||
@tailrec
|
||||
override def initial: Boolean = {
|
||||
if (init) {
|
||||
return false
|
||||
}
|
||||
init = true
|
||||
TUIUtil.clearConsole()
|
||||
println("Welcome to Knockout Whist!")
|
||||
println()
|
||||
println("Please select an option:")
|
||||
println("1. Start a new match")
|
||||
println("2. Exit")
|
||||
Try{
|
||||
readLine().toInt
|
||||
} match {
|
||||
case Success(value) =>
|
||||
value match {
|
||||
case 1 =>
|
||||
MatchControl.startMatch()
|
||||
init = false
|
||||
initial
|
||||
case 2 =>
|
||||
println("Exiting the game.")
|
||||
true
|
||||
case _ =>
|
||||
ControlHandler.invoke(ShowErrorStatus(INVALID_NUMBER))
|
||||
init = false
|
||||
initial
|
||||
}
|
||||
case Failure(_) =>
|
||||
ControlHandler.invoke(ShowErrorStatus(NOT_A_NUMBER))
|
||||
init = false
|
||||
initial
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package de.knockoutwhist.utils
|
||||
|
||||
|
||||
class CustomPlayerQueue[A] (protected var players: Array[A], val start: Int = 0) extends Iterable[A] {
|
||||
|
||||
private var current = start
|
||||
|
||||
|
||||
def nextPlayer(): A = {
|
||||
val player = players(current)
|
||||
current = (current + 1) % players.length
|
||||
|
||||
18
src/main/scala/de/knockoutwhist/utils/DelayHandler.scala
Normal file
18
src/main/scala/de/knockoutwhist/utils/DelayHandler.scala
Normal file
@@ -0,0 +1,18 @@
|
||||
package de.knockoutwhist.utils
|
||||
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.utils.events.{EventListener, ReturnableEvent}
|
||||
|
||||
object DelayHandler extends EventListener {
|
||||
|
||||
private[knockoutwhist] var activateDelay: Boolean = true
|
||||
|
||||
override def listen[R](event: ReturnableEvent[R]): Option[R] = {
|
||||
event match {
|
||||
case event: DelayEvent =>
|
||||
if(activateDelay) Thread.sleep(event.delay)
|
||||
Some(true)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package de.knockoutwhist.utils.events
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
abstract class EventHandler {
|
||||
private[events] var listeners: mutable.ListBuffer[EventListener] = mutable.ListBuffer[EventListener]()
|
||||
|
||||
def addListener(listener: EventListener): Int = {
|
||||
listeners = (listeners += listener).sorted
|
||||
listeners.size
|
||||
}
|
||||
|
||||
def removeListener(listener: EventListener): Int = {
|
||||
listeners = (listeners -= listener).sorted
|
||||
listeners.size
|
||||
}
|
||||
|
||||
def invoke[R](event: ReturnableEvent[R]): R = {
|
||||
event match {
|
||||
case simpleEvent: SimpleEvent =>
|
||||
val result = listeners.map(_.listen(simpleEvent)).filter(_.isDefined).map(_.get).toList
|
||||
if(result.isEmpty) return false
|
||||
result.reduce((a,b) => a && b)
|
||||
case returnableEvent: ReturnableEvent[R] =>
|
||||
val result = listeners.view.map(_.listen(returnableEvent)).find(_.isDefined).flatten
|
||||
result.getOrElse(throw new IllegalStateException("No listener returned a result"))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package de.knockoutwhist.utils.events
|
||||
|
||||
enum Priority extends Ordered[Priority] :
|
||||
case High, Normal, Low
|
||||
|
||||
override def compare(that: Priority): Int = {
|
||||
if this == that then 0
|
||||
else if this == High then 1
|
||||
else if that == High then -1
|
||||
else if this == Low then -1
|
||||
else 1
|
||||
}
|
||||
end Priority
|
||||
|
||||
|
||||
trait EventListener extends Ordered[EventListener] {
|
||||
def priority: Priority = Priority.Normal
|
||||
def listen[R](event: ReturnableEvent[R]): Option[R]
|
||||
|
||||
override def compare(that: EventListener): Int = that.priority.compare(priority)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.knockoutwhist.utils.events
|
||||
|
||||
trait ReturnableEvent[R] {
|
||||
|
||||
def id: String
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package de.knockoutwhist.utils.events
|
||||
|
||||
trait SimpleEvent extends ReturnableEvent[Boolean]
|
||||
37
src/test/scala/de/knockoutwhist/DelayHandlerTests.scala
Normal file
37
src/test/scala/de/knockoutwhist/DelayHandlerTests.scala
Normal file
@@ -0,0 +1,37 @@
|
||||
package de.knockoutwhist
|
||||
|
||||
import de.knockoutwhist.events.util.DelayEvent
|
||||
import de.knockoutwhist.utils.DelayHandler
|
||||
import de.knockoutwhist.utils.events.EventHandler
|
||||
import org.scalatest.concurrent.*
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.time.SpanSugar.*
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
import scala.language.postfixOps
|
||||
|
||||
class DelayHandlerTests extends AnyWordSpec with TimeLimits with Matchers {
|
||||
|
||||
private val eventHandler = new EventHandler() {}
|
||||
eventHandler.addListener(DelayHandler)
|
||||
|
||||
"A delay event" should {
|
||||
val delayEvent = DelayEvent(100)
|
||||
"be able to be created" in {
|
||||
delayEvent should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
delayEvent.id should be ("DelayEvent")
|
||||
}
|
||||
"have the correct delay" in {
|
||||
delayEvent.delay should be (100)
|
||||
}
|
||||
"not be longer than 120ms if it's set to 100ms" in {
|
||||
DelayHandler.activateDelay = true
|
||||
failAfter(200 millis) {
|
||||
eventHandler.invoke(delayEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +1,21 @@
|
||||
package de.knockoutwhist
|
||||
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
import org.scalatest.funsuite.AnyFunSuite
|
||||
|
||||
class MainTests extends AnyFunSuite {
|
||||
|
||||
test("Main should be able to go to the main menu") {
|
||||
TestUtil.disableDelay()
|
||||
TUIMain.init = false
|
||||
TestUtil.simulateInput("2\n") {
|
||||
KnockOutWhist.main(Array())
|
||||
}
|
||||
}
|
||||
|
||||
test("Main should be able to be executed twice") {
|
||||
TestUtil.disableDelay()
|
||||
TestUtil.simulateInput("2\n") {
|
||||
assertThrows[IllegalStateException] {
|
||||
KnockOutWhist.main(Array())
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package de.knockoutwhist
|
||||
|
||||
import de.knockoutwhist.cards.{CardTests, DeckTests, HandTests}
|
||||
import de.knockoutwhist.control.text.{TextMatchControllerTests, TextPlayerControllerTests}
|
||||
import de.knockoutwhist.control.{MatchControllerTests, PlayerControllerTests}
|
||||
import de.knockoutwhist.events.TestAllEvent
|
||||
import de.knockoutwhist.player.PlayerTests
|
||||
import de.knockoutwhist.rounds.{GameplayTests, MatchTests, TrickTests}
|
||||
import de.knockoutwhist.utils.events.EventTests
|
||||
import de.knockoutwhist.utils.{ImplicitTests, QueueTests}
|
||||
import org.scalatest.Sequential
|
||||
|
||||
@@ -15,10 +17,12 @@ class TestSequence extends Sequential(
|
||||
new QueueTests(),
|
||||
new ImplicitTests(),
|
||||
new PlayerTests(),
|
||||
new TextPlayerControllerTests(),
|
||||
new TextMatchControllerTests(),
|
||||
new PlayerControllerTests(),
|
||||
new MatchControllerTests(),
|
||||
new CardTests(),
|
||||
new DeckTests(),
|
||||
new HandTests(),
|
||||
|
||||
) {}
|
||||
new EventTests(),
|
||||
new TestAllEvent(),
|
||||
new DelayHandlerTests()
|
||||
)
|
||||
@@ -1,11 +1,16 @@
|
||||
package de.knockoutwhist.cards
|
||||
|
||||
import de.knockoutwhist.utils.events.EventHandler
|
||||
import de.knockoutwhist.cards.CardValue.{Ace, Ten}
|
||||
import de.knockoutwhist.events.cards.RenderHandEvent
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import de.knockoutwhist.ui.tui.TUIMain.TUICards.renderCardAsString
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
class CardTests extends AnyWordSpec with Matchers{
|
||||
|
||||
"A card" should {
|
||||
TestUtil.disableDelay()
|
||||
"be displayed with correct value and Suit" in {
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val e = "Ace of Spades"
|
||||
@@ -22,7 +27,7 @@ class CardTests extends AnyWordSpec with Matchers{
|
||||
s"│ ${Console.BLACK}${Console.BOLD}A${Console.RESET}│",
|
||||
"└─────────┘"
|
||||
)
|
||||
card.renderAsString() shouldBe expectedResult
|
||||
renderCardAsString(Card(CardValue.Ace, Suit.Spades)) shouldBe expectedResult
|
||||
}
|
||||
"can be rendered for CardValue Ten" in {
|
||||
val card = Card(CardValue.Ten, Suit.Spades)
|
||||
@@ -35,7 +40,7 @@ class CardTests extends AnyWordSpec with Matchers{
|
||||
s"│ ${Console.BLACK}${Console.BOLD}10${Console.RESET}│",
|
||||
"└─────────┘"
|
||||
)
|
||||
card.renderAsString() shouldBe expectedResult
|
||||
renderCardAsString(Card(CardValue.Ten, Suit.Spades)) shouldBe expectedResult
|
||||
}
|
||||
"be able to reset the order" in {
|
||||
CardManager.shuffleAndReset()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.knockoutwhist.cards
|
||||
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import org.scalatest.matchers.must.Matchers
|
||||
import org.scalatest.matchers.should.Matchers.{should, shouldBe}
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
@@ -7,6 +8,7 @@ import org.scalatest.wordspec.AnyWordSpec
|
||||
class DeckTests extends AnyWordSpec with Matchers{
|
||||
|
||||
"A deck" should {
|
||||
TestUtil.disableDelay()
|
||||
"not be empty" in {
|
||||
CardManager.cardContainer must not be empty
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package de.knockoutwhist.cards
|
||||
|
||||
import de.knockoutwhist.cards.{Card, CardValue, Hand, Suit}
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import de.knockoutwhist.ui.tui.TUIMain.TUICards.renderHandEvent
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
@@ -9,6 +11,7 @@ import scala.collection.mutable.ListBuffer
|
||||
class HandTests extends AnyWordSpec with Matchers {
|
||||
|
||||
"The hand" should {
|
||||
TestUtil.disableDelay()
|
||||
"be able to remove cards from its hand" in {
|
||||
val handholder = ListBuffer[Card]()
|
||||
handholder.addOne(Card(CardValue.Ace, Suit.Spades))
|
||||
@@ -48,7 +51,7 @@ class HandTests extends AnyWordSpec with Matchers {
|
||||
s"│ ${Console.BLACK}${Console.BOLD}A${Console.RESET}│ │ ${Console.RED}${Console.BOLD}Q${Console.RESET}│",
|
||||
"└─────────┘ └─────────┘"
|
||||
)
|
||||
hand.renderAsString() shouldBe expectedResult
|
||||
renderHandEvent(Hand(List(Card(CardValue.Ace, Suit.Spades), Card(CardValue.Queen, Suit.Diamonds))), false) shouldBe expectedResult
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,68 +1,63 @@
|
||||
package de.knockoutwhist.control.text
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.cards.CardManager
|
||||
import de.knockoutwhist.cards.CardValue.Ace
|
||||
import de.knockoutwhist.cards.Suit.Hearts
|
||||
import de.knockoutwhist.cards.{Card, CardValue, Hand, Suit}
|
||||
import de.knockoutwhist.control.{MatchControl, RoundControl, TrickControl}
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
import de.knockoutwhist.utils.CustomPlayerQueue
|
||||
import org.scalatest.matchers.must.Matchers
|
||||
import org.scalatest.matchers.should.Matchers.{should, shouldBe}
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
class TextMatchControllerTests extends AnyWordSpec with Matchers {
|
||||
"The start function" should {
|
||||
"throw no exception" in {
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("a\n2\n") {
|
||||
TextMatchControl.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class MatchControllerTests extends AnyWordSpec with Matchers {
|
||||
|
||||
"The enter players function" should {
|
||||
TestUtil.disableDelay()
|
||||
"throw no exception" in {
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("foo,bar\n") {
|
||||
TextMatchControl.enterPlayers() should be (List(Player("foo"), Player("bar")))
|
||||
MatchControl.enterPlayers() should be (List(Player("foo"), Player("bar")))
|
||||
}
|
||||
}
|
||||
}
|
||||
"not accept less than 2 players" in {
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("foo\nbar,foo2\n") {
|
||||
TextMatchControl.enterPlayers() should be (List(Player("bar"), Player("foo2")))
|
||||
MatchControl.enterPlayers() should be (List(Player("bar"), Player("foo2")))
|
||||
}
|
||||
}
|
||||
}
|
||||
"not accept players with the same name" in {
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("foo,foo\nbar,foo\n") {
|
||||
TextMatchControl.enterPlayers() should be (List(Player("bar"), Player("foo")))
|
||||
MatchControl.enterPlayers() should be (List(Player("bar"), Player("foo")))
|
||||
}
|
||||
}
|
||||
}
|
||||
"not accept player names less than 2 or greater than 10 characters" in {
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("f,b\nbarrrrrrrrrrrrrrrrr,foooooooooooooooooooo\nbar,foo\n") {
|
||||
TextMatchControl.enterPlayers() should be (List(Player("bar"), Player("foo")))
|
||||
MatchControl.enterPlayers() should be (List(Player("bar"), Player("foo")))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The control round function" should {
|
||||
TestUtil.disableDelay()
|
||||
"throw no exception and return a winner" in {
|
||||
val players = List(Player("foo"), Player("bar"))
|
||||
val matchImpl = Match(players, 1)
|
||||
TestUtil.disableDebugMode()
|
||||
TextMatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
MatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("1\n1\n1\n") {
|
||||
TextMatchControl.controlRound(matchImpl).winner should be (players.head).or(be (players(1)))
|
||||
RoundControl.controlRound(matchImpl).winner should be (players.head).or(be (players(1)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,45 +68,48 @@ class TextMatchControllerTests extends AnyWordSpec with Matchers {
|
||||
CardManager.shuffleAndReset()
|
||||
CardManager.resetOrder()
|
||||
|
||||
TextMatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
MatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n") {
|
||||
TextMatchControl.controlRound(matchImpl).winner should be(players.head).or(be(players(1)))
|
||||
RoundControl.controlRound(matchImpl).winner should be(players.head).or(be(players(1)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The next round function" should {
|
||||
TestUtil.disableDelay()
|
||||
"return null if the match is over" in {
|
||||
val players = List(Player("foo"))
|
||||
val matchImpl = Match(players, 2)
|
||||
TestUtil.enableDebugMode()
|
||||
TextMatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
MatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("1\n1\n1\n") {
|
||||
TextMatchControl.controlRound(matchImpl)
|
||||
TextMatchControl.nextRound(matchImpl) should be (null)
|
||||
RoundControl.controlRound(matchImpl)
|
||||
RoundControl.nextRound(matchImpl) should be (null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The next trick function" should {
|
||||
TestUtil.disableDelay()
|
||||
"return null if the round is over" in {
|
||||
val players = List(Player("foo"))
|
||||
val matchImpl = Match(players, 2)
|
||||
TestUtil.enableDebugMode()
|
||||
TextMatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
MatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("1\n1\n1\n") {
|
||||
val round = TextMatchControl.controlRound(matchImpl)
|
||||
TextMatchControl.nextTrick(round) should be (null)
|
||||
val round = RoundControl.controlRound(matchImpl)
|
||||
TrickControl.nextTrick(round) should be (null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"The controlSuit function" should {
|
||||
TestUtil.disableDelay()
|
||||
"check if a player can play from the correct suit but doesnt" in {
|
||||
val player1 = Player("Gunter")
|
||||
val player2 = Player("Peter")
|
||||
@@ -121,18 +119,19 @@ class TextMatchControllerTests extends AnyWordSpec with Matchers {
|
||||
val matchImpl = Match(players, 2)
|
||||
val round = new Round(Suit.Clubs, matchImpl, players, false)
|
||||
val trick = new Trick(round)
|
||||
trick.playCard(Card(Ace, Suit.Hearts), player2)
|
||||
TrickControl.playCard(trick, round, Card(Ace, Suit.Hearts), player2)
|
||||
TestUtil.enableDebugMode()
|
||||
TextMatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
MatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("1\n2\n") {
|
||||
val card = TextMatchControl.controlSuitplayed(trick, player1)
|
||||
val card = TrickControl.controlSuitplayed(trick, player1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The control Trick function" should {
|
||||
TestUtil.disableDelay()
|
||||
"return the other player if the dog decides not to play" in {
|
||||
val foo = Player("foo")
|
||||
foo.doglife = true
|
||||
@@ -142,11 +141,11 @@ class TextMatchControllerTests extends AnyWordSpec with Matchers {
|
||||
val players = List(foo, bar)
|
||||
val matchImpl = Match(players, 2)
|
||||
TestUtil.enableDebugMode()
|
||||
TextMatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
MatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
val round = new Round(Hearts,matchImpl,players,false)
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("n\n1\n") {
|
||||
val finalTrick = TextMatchControl.controlTrick(round)
|
||||
val finalTrick = TrickControl.controlTrick(round)
|
||||
finalTrick.winner should be(bar)
|
||||
}
|
||||
}
|
||||
@@ -164,11 +163,11 @@ class TextMatchControllerTests extends AnyWordSpec with Matchers {
|
||||
bar.provideHand(CardManager.createHand(3))
|
||||
val players = List(foo, bar)
|
||||
val matchImpl = Match(players, 2)
|
||||
TextMatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
MatchControl.playerQueue = CustomPlayerQueue[Player](players.toArray[Player], 0)
|
||||
val round = new Round(foo.currentHand().get.cards.head.suit, matchImpl, players, false)
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("y\n1\n") {
|
||||
val finalTrick = TextMatchControl.controlTrick(round)
|
||||
val finalTrick = TrickControl.controlTrick(round)
|
||||
finalTrick.winner should be(bar)
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,24 @@
|
||||
package de.knockoutwhist.control.text
|
||||
package de.knockoutwhist.control
|
||||
|
||||
import de.knockoutwhist.cards.{CardManager, Hand}
|
||||
import de.knockoutwhist.cards.Suit._
|
||||
import de.knockoutwhist.cards.Suit.*
|
||||
import de.knockoutwhist.control.PlayerControl
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.rounds.Round
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
class PlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
|
||||
"The text player controller play function" should {
|
||||
TestUtil.disableDelay()
|
||||
CardManager.shuffleAndReset()
|
||||
TestUtil.cancelOut() {
|
||||
"throw an exception of the player has no hand" in {
|
||||
assertThrows[IllegalStateException] {
|
||||
assertThrows[NoSuchElementException] {
|
||||
TestUtil.simulateInput("1\n") {
|
||||
TextPlayerControl.playCard(Player("Foo"))
|
||||
PlayerControl.playCard(Player("Foo"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +28,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val hand = CardManager.createHand(1)
|
||||
player.provideHand(hand)
|
||||
val card = TestUtil.simulateInput("0\na\n1\n") {
|
||||
TextPlayerControl.playCard(player)
|
||||
PlayerControl.playCard(player)
|
||||
}
|
||||
card should be(hand.cards.head)
|
||||
}
|
||||
@@ -36,7 +38,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val hand = CardManager.createHand(1)
|
||||
player.provideHand(hand)
|
||||
val card = TestUtil.simulateInput("1\n") {
|
||||
TextPlayerControl.playCard(player)
|
||||
PlayerControl.playCard(player)
|
||||
}
|
||||
card should be(hand.cards.head)
|
||||
}
|
||||
@@ -51,10 +53,10 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val round = new Round(Spades, null, List(player), false)
|
||||
TestUtil.cancelOut() {
|
||||
"throw an exception of the player has no hand" in {
|
||||
assertThrows[IllegalStateException] {
|
||||
assertThrows[NoSuchElementException] {
|
||||
TestUtil.simulateInput("y\n") {
|
||||
TestUtil.disableDebugMode()
|
||||
TextPlayerControl.dogplayCard(Player("Foo"), round)
|
||||
PlayerControl.dogplayCard(Player("Foo"), round)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +67,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val hand = CardManager.createHand(1)
|
||||
player.provideHand(hand)
|
||||
val card = TestUtil.simulateInput("a\ny\n") {
|
||||
TextPlayerControl.dogplayCard(player, round)
|
||||
PlayerControl.dogplayCard(player, round)
|
||||
}
|
||||
card should be(Some(hand.cards.head))
|
||||
}
|
||||
@@ -76,7 +78,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val hand = CardManager.createHand(1)
|
||||
player.provideHand(hand)
|
||||
val card = TestUtil.simulateInput("y\n") {
|
||||
TextPlayerControl.dogplayCard(player, round)
|
||||
PlayerControl.dogplayCard(player, round)
|
||||
}
|
||||
card should be(Some(hand.cards.head))
|
||||
}
|
||||
@@ -87,7 +89,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val hand = CardManager.createHand(1)
|
||||
player.provideHand(hand)
|
||||
val card = TestUtil.simulateInput("n\n") {
|
||||
TextPlayerControl.dogplayCard(player, round)
|
||||
PlayerControl.dogplayCard(player, round)
|
||||
}
|
||||
card should be(None)
|
||||
}
|
||||
@@ -101,7 +103,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
player2.provideHand(Hand(List()))
|
||||
val round2 = new Round(Spades, null, List(player1,player2), true)
|
||||
val card = TestUtil.simulateInput("n\ny\n") {
|
||||
TextPlayerControl.dogplayCard(player1, round2)
|
||||
PlayerControl.dogplayCard(player1, round2)
|
||||
}
|
||||
card should be(Some(player1.currentHand().get.cards.head))
|
||||
}
|
||||
@@ -116,7 +118,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val player2 = Player("Bar")
|
||||
val players = List(player1, player2)
|
||||
val winner = TestUtil.simulateInput("1\n2\n") {
|
||||
TextPlayerControl.determineWinnerTie(players)
|
||||
PlayerControl.determineWinnerTie(players)
|
||||
}
|
||||
winner should be(player2).or(be(player1))
|
||||
}
|
||||
@@ -127,7 +129,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val player2 = Player("Bar")
|
||||
val players = List(player1, player2)
|
||||
val winner = TestUtil.simulateInput("1\n13\n5\n1\n") {
|
||||
TextPlayerControl.determineWinnerTie(players)
|
||||
PlayerControl.determineWinnerTie(players)
|
||||
}
|
||||
winner should be(player2)
|
||||
}
|
||||
@@ -138,7 +140,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val player2 = Player("Bar")
|
||||
val players = List(player1, player2)
|
||||
val winner = TestUtil.simulateInput("13\n1\n") {
|
||||
TextPlayerControl.determineWinnerTie(players)
|
||||
PlayerControl.determineWinnerTie(players)
|
||||
}
|
||||
winner should be(player1)
|
||||
}
|
||||
@@ -149,7 +151,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val player2 = Player("Bar")
|
||||
val players = List(player1, player2)
|
||||
val winner = TestUtil.simulateInput("a\n200\n1\n2\n") {
|
||||
TextPlayerControl.determineWinnerTie(players)
|
||||
PlayerControl.determineWinnerTie(players)
|
||||
}
|
||||
winner should be(player2)
|
||||
}
|
||||
@@ -163,7 +165,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val player = Player("Foo")
|
||||
player.provideHand(CardManager.createHand(4))
|
||||
val suit = TestUtil.simulateInput("4\n") {
|
||||
TextPlayerControl.pickNextTrumpsuit(player)
|
||||
PlayerControl.pickNextTrumpsuit(player)
|
||||
}
|
||||
suit should be(Spades)
|
||||
}
|
||||
@@ -172,7 +174,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val player = Player("Foo")
|
||||
player.provideHand(CardManager.createHand(4))
|
||||
val suit = TestUtil.simulateInput("1\n") {
|
||||
TextPlayerControl.pickNextTrumpsuit(player)
|
||||
PlayerControl.pickNextTrumpsuit(player)
|
||||
}
|
||||
suit should be(Hearts)
|
||||
}
|
||||
@@ -181,7 +183,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val player = Player("Foo")
|
||||
player.provideHand(CardManager.createHand(4))
|
||||
val suit = TestUtil.simulateInput("2\n") {
|
||||
TextPlayerControl.pickNextTrumpsuit(player)
|
||||
PlayerControl.pickNextTrumpsuit(player)
|
||||
}
|
||||
suit should be(Diamonds)
|
||||
}
|
||||
@@ -190,7 +192,7 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val player = Player("Foo")
|
||||
player.provideHand(CardManager.createHand(4))
|
||||
val suit = TestUtil.simulateInput("3\n") {
|
||||
TextPlayerControl.pickNextTrumpsuit(player)
|
||||
PlayerControl.pickNextTrumpsuit(player)
|
||||
}
|
||||
suit should be(Clubs)
|
||||
}
|
||||
@@ -199,37 +201,37 @@ class TextPlayerControllerTests extends AnyWordSpec with Matchers {
|
||||
val player = Player("Foo")
|
||||
player.provideHand(CardManager.createHand(4))
|
||||
val suit = TestUtil.simulateInput("a\n10\n1\n") {
|
||||
TextPlayerControl.pickNextTrumpsuit(player)
|
||||
PlayerControl.pickNextTrumpsuit(player)
|
||||
}
|
||||
suit should be(Hearts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The text player controller showCards function" should {
|
||||
TestUtil.cancelOut() {
|
||||
"return true if the player wants to show their cards" in {
|
||||
TestUtil.disableDebugMode()
|
||||
val player = Player("Foo")
|
||||
player.provideHand(CardManager.createHand(4))
|
||||
TextPlayerControl.showCards(player) should be(true)
|
||||
}
|
||||
"return false if the player does not want to show their cards" in {
|
||||
TestUtil.disableDebugMode()
|
||||
val player = Player("Foo")
|
||||
TextPlayerControl.showCards(player) should be(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The text player controller showWon function" should {
|
||||
TestUtil.cancelOut() {
|
||||
"print the winner of the match" in {
|
||||
TestUtil.disableDebugMode()
|
||||
val player = Player("Foo")
|
||||
TextPlayerControl.showWon(player, null) should be("Foo won this round.")
|
||||
}
|
||||
}
|
||||
}
|
||||
// "The text player controller showCards function" should {
|
||||
// TestUtil.cancelOut() {
|
||||
// "return true if the player wants to show their cards" in {
|
||||
// TestUtil.disableDebugMode()
|
||||
// val player = Player("Foo")
|
||||
// player.provideHand(CardManager.createHand(4))
|
||||
// TextPlayerControl.showCards(player) should be(true)
|
||||
// }
|
||||
// "return false if the player does not want to show their cards" in {
|
||||
// TestUtil.disableDebugMode()
|
||||
// val player = Player("Foo")
|
||||
// TextPlayerControl.showCards(player) should be(false)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// "The text player controller showWon function" should {
|
||||
// TestUtil.cancelOut() {
|
||||
// "print the winner of the match" in {
|
||||
// TestUtil.disableDebugMode()
|
||||
// val player = Player("Foo")
|
||||
// TextPlayerControl.showWon(player, null) should be("Foo won this round.")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
497
src/test/scala/de/knockoutwhist/events/TestAllEvent.scala
Normal file
497
src/test/scala/de/knockoutwhist/events/TestAllEvent.scala
Normal file
@@ -0,0 +1,497 @@
|
||||
package de.knockoutwhist.events
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.CardValue.{Queen, Two}
|
||||
import de.knockoutwhist.cards.Suit.Hearts
|
||||
import de.knockoutwhist.cards.{Card, CardManager, CardValue, Hand, Suit}
|
||||
import de.knockoutwhist.control.{RoundControl, TrickControl}
|
||||
import de.knockoutwhist.events.GLOBAL_STATUS.*
|
||||
import de.knockoutwhist.events.PLAYER_STATUS.*
|
||||
import de.knockoutwhist.events.ERROR_STATUS.*
|
||||
import de.knockoutwhist.events.ROUND_STATUS.*
|
||||
import de.knockoutwhist.events.cards.{RenderHandEvent, ShowTieCardsEvent}
|
||||
import de.knockoutwhist.events.directional.{RequestCardEvent, RequestDogPlayCardEvent, RequestNumberEvent, RequestPickTrumpsuitEvent}
|
||||
import de.knockoutwhist.events.round.ShowCurrentTrickEvent
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.rounds.{Match, Round}
|
||||
import de.knockoutwhist.testutils.{TestUtil, TestUtil as shouldBe}
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
import de.knockoutwhist.utils.events.{EventHandler, SimpleEvent}
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.compiletime.uninitialized
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
class TestAllEvent extends AnyWordSpec with Matchers {
|
||||
|
||||
private val eventHandler = new EventHandler() {}
|
||||
eventHandler.addListener(TUIMain)
|
||||
|
||||
"The render hand event" should {
|
||||
TestUtil.disableDelay()
|
||||
CardManager.resetOrder()
|
||||
val event1 = RenderHandEvent(CardManager.createHand(1), true)
|
||||
val event2 = RenderHandEvent(CardManager.createHand(1), false)
|
||||
"be able to be created" in {
|
||||
event1 should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
event1.id should be ("RenderHandEvent")
|
||||
}
|
||||
"have the correct parameter (showing numbers)" in {
|
||||
event1.showNumbers should be (true)
|
||||
}
|
||||
"have the correct parameter (not showing numbers)" in {
|
||||
event2.showNumbers should be (false)
|
||||
}
|
||||
"be able to be handled" in {
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event1) should be(true)
|
||||
eventHandler.invoke(event2) should be(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
"The show tie cards event" should {
|
||||
TestUtil.disableDelay()
|
||||
val event = ShowTieCardsEvent(List((Player("Foo"), Card(Two,Suit.Hearts))))
|
||||
"be able to be created" in {
|
||||
event should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
event.id should be ("ShowTieCardsEvent")
|
||||
}
|
||||
"have the correct player" in {
|
||||
event.card.head._1 should be (Player("Foo"))
|
||||
}
|
||||
"have the correct card" in {
|
||||
event.card.head._2.cardValue should be (Two)
|
||||
event.card.head._2.suit should be (Suit.Hearts)
|
||||
}
|
||||
"be able to be handled" in {
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The request card event" should {
|
||||
TestUtil.disableDelay()
|
||||
val hand = CardManager.createHand(1)
|
||||
val event = RequestCardEvent(hand)
|
||||
"be able to be created" in {
|
||||
event should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
event.id should be("RequestCardEvent")
|
||||
}
|
||||
"have the correct hand" in {
|
||||
event.hand should be(hand)
|
||||
}
|
||||
"be able to be handled" in {
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("0\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a [Failure[?]]
|
||||
TestUtil.simulateInput("5\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a[Failure[?]]
|
||||
val result = TestUtil.simulateInput("1\n") {
|
||||
eventHandler.invoke(event)
|
||||
}
|
||||
result should be (Success(hand.cards.head))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The request number event" should {
|
||||
TestUtil.disableDelay()
|
||||
val event = RequestNumberEvent(6, 12)
|
||||
"be able to be created" in {
|
||||
event should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
event.id should be("RequestNumberEvent")
|
||||
}
|
||||
"have the correct min & max" in {
|
||||
event.min should be(6)
|
||||
event.max should be(12)
|
||||
}
|
||||
"be able to be handled" in {
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("0\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a [Failure[?]]
|
||||
TestUtil.simulateInput("28\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a[Failure[?]]
|
||||
val result = TestUtil.simulateInput("8\n") {
|
||||
eventHandler.invoke(event)
|
||||
}
|
||||
result should be (Success(8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The RequestDogPlayCardEvent" should {
|
||||
TestUtil.disableDelay()
|
||||
val hand = Hand(List(Card(CardValue.Ten, Suit.Spades)))
|
||||
val event = RequestDogPlayCardEvent(hand, true)
|
||||
"be able to get created" in {
|
||||
event should not be null
|
||||
}
|
||||
"have the correct ID" in {
|
||||
event.id should be("RequestDogPlayCardEvent")
|
||||
}
|
||||
"return the card played if it was played" in {
|
||||
TestUtil.simulateInput("y\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a[Success[?]]
|
||||
}
|
||||
"return an exception if player doesn't want to play but has to" in {
|
||||
TestUtil.simulateInput("n\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a [Failure[?]]
|
||||
}
|
||||
"return None when a player doesn't play a card and is able to do so" in {
|
||||
val hand2 = Hand(List(Card(CardValue.Ten, Suit.Spades), Card(CardValue.Nine, Suit.Spades)))
|
||||
val event2 = RequestDogPlayCardEvent(hand2, false)
|
||||
TestUtil.simulateInput("n\n") {
|
||||
eventHandler.invoke(event2)
|
||||
} shouldBe a [Success[?]]
|
||||
}
|
||||
}
|
||||
"The RequestPickTrumpsuitEvent" should {
|
||||
TestUtil.disableDelay()
|
||||
val event = RequestPickTrumpsuitEvent()
|
||||
"be able to get created" in {
|
||||
event should not be null
|
||||
}
|
||||
"have an ID" in {
|
||||
event.id should be("RequestPickTrumpsuitEvent")
|
||||
}
|
||||
"be a Success if the player picks a trumpsuit" in {
|
||||
TestUtil.simulateInput("1\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a [Success[?]]
|
||||
TestUtil.simulateInput("2\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a[Success[?]]
|
||||
TestUtil.simulateInput("3\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a[Success[?]]
|
||||
TestUtil.simulateInput("4\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a[Success[?]]
|
||||
}
|
||||
"fail if the player doesn't pick a trumpsuit" in {
|
||||
TestUtil.simulateInput("5\n") {
|
||||
eventHandler.invoke(event)
|
||||
} shouldBe a [Failure[?]]
|
||||
}
|
||||
}
|
||||
"The ShowCurrentTrickEvent" should {
|
||||
TestUtil.disableDelay()
|
||||
val player1 = Player("Gunter")
|
||||
val player2 = Player("Peter")
|
||||
val listplayers = List(player1, player2)
|
||||
val match1 = Match(listplayers)
|
||||
val round = RoundControl.create_round(match1)
|
||||
val trick = TrickControl.create_trick(round)
|
||||
TrickControl.playCard(trick, round, Card(CardValue.Ten, Suit.Spades), player1)
|
||||
val event = ShowCurrentTrickEvent(round, trick)
|
||||
"be able to get created" in {
|
||||
event should not be null
|
||||
}
|
||||
"have an ID" in {
|
||||
event.id should be("ShowCurrentTrickEvent")
|
||||
}
|
||||
"should be true if a trick can be displayed" in {
|
||||
eventHandler.invoke(event) shouldBe true
|
||||
}
|
||||
}
|
||||
|
||||
"The show global status event" should {
|
||||
TestUtil.disableDelay()
|
||||
var event: ShowGlobalStatus = null
|
||||
"be able to be created" in {
|
||||
event = ShowGlobalStatus(SHOW_TIE)
|
||||
event should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
event = ShowGlobalStatus(SHOW_TIE)
|
||||
event.id should be ("ShowGlobalStatus")
|
||||
}
|
||||
"have the correct status" in {
|
||||
event = ShowGlobalStatus(SHOW_TIE)
|
||||
event.status should be (SHOW_TIE)
|
||||
}
|
||||
"be able to be handled with status SHOW_TIE" in {
|
||||
event = ShowGlobalStatus(SHOW_TIE)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to return false with status SHOW_TIE_WINNER if arguments mismatch" in {
|
||||
event = ShowGlobalStatus(SHOW_TIE_WINNER)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(false)
|
||||
}
|
||||
}
|
||||
"be able to return true with status SHOW_TIE_WINNER if arguments match" in {
|
||||
event = ShowGlobalStatus(SHOW_TIE_WINNER, Player("Foo"))
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status SHOW_TIE_TIE" in {
|
||||
event = ShowGlobalStatus(SHOW_TIE_TIE)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status SHOW_START_MATCH" in {
|
||||
event = ShowGlobalStatus(SHOW_START_MATCH)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status SHOW_TYPE_PLAYERS" in {
|
||||
event = ShowGlobalStatus(SHOW_TYPE_PLAYERS)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to return false with status SHOW_FINISHED_MATCH if arguments mismatch" in {
|
||||
event = ShowGlobalStatus(SHOW_FINISHED_MATCH)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(false)
|
||||
}
|
||||
}
|
||||
"be able to return true with status SHOW_FINISHED_MATCH if arguments match" in {
|
||||
event = ShowGlobalStatus(SHOW_FINISHED_MATCH, Player("Foo"))
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The show player status event" should {
|
||||
TestUtil.disableDelay()
|
||||
val player = Player("Foo")
|
||||
var event: ShowPlayerStatus = null
|
||||
"be able to be created" in {
|
||||
event = ShowPlayerStatus(SHOW_TURN, player)
|
||||
event should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
event = ShowPlayerStatus(SHOW_TURN, player)
|
||||
event.id should be ("ShowPlayerStatus")
|
||||
}
|
||||
"have the correct status" in {
|
||||
event = ShowPlayerStatus(SHOW_TURN, player)
|
||||
event.status should be (SHOW_TURN)
|
||||
}
|
||||
"have the correct player" in {
|
||||
event = ShowPlayerStatus(SHOW_TURN, player)
|
||||
event.player should be (player)
|
||||
}
|
||||
"be able to be handled with status SHOW_TURN" in {
|
||||
event = ShowPlayerStatus(SHOW_TURN, player)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status SHOW_PLAY_CARD" in {
|
||||
event = ShowPlayerStatus(SHOW_PLAY_CARD, player)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to return false with status SHOW_DOG_PLAY_CARD if arguments mismatch" in {
|
||||
event = ShowPlayerStatus(SHOW_DOG_PLAY_CARD, player)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(false)
|
||||
}
|
||||
}
|
||||
"be able to return true with status SHOW_DOG_PLAY_CARD if arguments match" in {
|
||||
event = ShowPlayerStatus(SHOW_DOG_PLAY_CARD, player, true)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to return false with status SHOW_TIE_NUMBERS if arguments mismatch" in {
|
||||
event = ShowPlayerStatus(SHOW_TIE_NUMBERS, player)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(false)
|
||||
}
|
||||
}
|
||||
"be able to return true with status SHOW_TIE_NUMBERS if arguments match" in {
|
||||
event = ShowPlayerStatus(SHOW_TIE_NUMBERS, player, 5)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status SHOW_TRUMPSUIT_OPTIONS" in {
|
||||
event = ShowPlayerStatus(SHOW_TRUMPSUIT_OPTIONS, player)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status SHOW_NOT_PLAYED" in {
|
||||
event = ShowPlayerStatus(SHOW_NOT_PLAYED, player)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status SHOW_WON_PLAYER_TRICK" in {
|
||||
event = ShowPlayerStatus(SHOW_WON_PLAYER_TRICK, player)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The show round status event" should {
|
||||
TestUtil.disableDelay()
|
||||
val round = Round(trumpSuit = Hearts, matchImpl = null, tricklist = ListBuffer(), players_in = null, firstRound = false, players_out = List(Player("Foo")))
|
||||
var event: ShowRoundStatus = null
|
||||
"be able to be created" in {
|
||||
event = ShowRoundStatus(SHOW_START_ROUND, round)
|
||||
event should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
event = ShowRoundStatus(SHOW_START_ROUND, round)
|
||||
event.id should be ("ShowRoundStatus")
|
||||
}
|
||||
"have the correct status" in {
|
||||
event = ShowRoundStatus(SHOW_START_ROUND, round)
|
||||
event.status should be (SHOW_START_ROUND)
|
||||
}
|
||||
"have the correct round" in {
|
||||
event = ShowRoundStatus(SHOW_START_ROUND, round)
|
||||
event.currentRound should be (round)
|
||||
}
|
||||
"be able to be handled with status SHOW_START_ROUND" in {
|
||||
event = ShowRoundStatus(SHOW_START_ROUND, round)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to return false with status WON_ROUND if arguments mismatch" in {
|
||||
event = ShowRoundStatus(WON_ROUND, round)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(false)
|
||||
}
|
||||
}
|
||||
"be able to return true with status WON_ROUND if arguments match" in {
|
||||
event = ShowRoundStatus(WON_ROUND, round, Player("Foo"))
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status PLAYERS_OUT" in {
|
||||
event = ShowRoundStatus(PLAYERS_OUT, round)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"The error status event" should {
|
||||
TestUtil.disableDelay()
|
||||
var event: ShowErrorStatus = null
|
||||
"be able to be created" in {
|
||||
event = ShowErrorStatus(INVALID_NUMBER)
|
||||
event should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
event = ShowErrorStatus(INVALID_NUMBER)
|
||||
event.id should be ("ShowErrorStatus")
|
||||
}
|
||||
"have the correct status" in {
|
||||
event = ShowErrorStatus(INVALID_NUMBER)
|
||||
event.status should be (INVALID_NUMBER)
|
||||
}
|
||||
"be able to be handled with status INVALID_NUMBER" in {
|
||||
event = ShowErrorStatus(INVALID_NUMBER)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status NOT_A_NUMBER" in {
|
||||
event = ShowErrorStatus(NOT_A_NUMBER)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status INVALID_INPUT" in {
|
||||
event = ShowErrorStatus(INVALID_INPUT)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status INVALID_NUMBER_OF_PLAYERS" in {
|
||||
event = ShowErrorStatus(INVALID_NUMBER_OF_PLAYERS)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status IDENTICAL_NAMES" in {
|
||||
event = ShowErrorStatus(IDENTICAL_NAMES)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to be handled with status INVALID_NAME_FORMAT" in {
|
||||
event = ShowErrorStatus(INVALID_NAME_FORMAT)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
"be able to return false with status WRONG_CARD if arguments mismatch" in {
|
||||
event = ShowErrorStatus(WRONG_CARD)
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(false)
|
||||
}
|
||||
}
|
||||
"be able to return true with status WRONG_CARD if arguments match" in {
|
||||
event = ShowErrorStatus(WRONG_CARD, Card(CardValue.Queen, Suit.Hearts))
|
||||
TestUtil.cancelOut() {
|
||||
eventHandler.invoke(event) should be(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"An Event" should {
|
||||
TestUtil.disableDelay()
|
||||
"return None if it doesn't exist" in {
|
||||
val event = new SimpleEvent {
|
||||
override def id: String = "ShowEnte"
|
||||
}
|
||||
eventHandler.invoke(event) shouldBe false
|
||||
}
|
||||
}
|
||||
/*"The pick next trumpsuit event" should {
|
||||
val event = PickNextTrumpsuitEvent(Player("Foo"))
|
||||
"be able to be created" in {
|
||||
event should not be null
|
||||
}
|
||||
"have the correct id" in {
|
||||
event.id should be ("PickNextTrumpsuitEvent")
|
||||
}
|
||||
"have the correct player" in {
|
||||
event.player should be (Player("Foo"))
|
||||
}
|
||||
"be able to be handled" in {
|
||||
TestUtil.enableDebugMode()
|
||||
CardManager.resetOrder()
|
||||
TestUtil.simulateInput("1\n") {
|
||||
eventHandler.invoke(event)
|
||||
} should be (Suit.Hearts)
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package de.knockoutwhist.player
|
||||
|
||||
import de.knockoutwhist.cards.{Card, CardValue, Hand, Suit}
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
class PlayerTests extends AnyWordSpec with Matchers {
|
||||
|
||||
"A player" should {
|
||||
TestUtil.disableDelay()
|
||||
"be able to have a hand" in {
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val card2 = Card(CardValue.Ten, Suit.Spades)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package de.knockoutwhist.rounds
|
||||
|
||||
import de.knockoutwhist.cards.CardManager
|
||||
import de.knockoutwhist.control.text.TextMatchControl
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import de.knockoutwhist.ui.tui.TUIMain
|
||||
import org.scalatest.matchers.must.Matchers
|
||||
import org.scalatest.matchers.should.Matchers.{should, shouldBe}
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
@@ -14,11 +14,12 @@ class GameplayTests extends AnyWordSpec with Matchers {
|
||||
"The Match Control" must {
|
||||
"not throw an exception" in {
|
||||
TestUtil.enableDebugMode()
|
||||
TestUtil.disableDelay()
|
||||
CardManager.shuffleAndReset()
|
||||
CardManager.resetOrder()
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.simulateInput("1\nLeon,Janis\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\ny\n1\n1\n1\n2\n") {
|
||||
TextMatchControl.start()
|
||||
TestUtil.simulateInput("a\n5\n1\nLeon,Janis\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\ny\n1\n1\n1\n2\n") {
|
||||
TUIMain.initial
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.knockoutwhist.rounds
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.cards.{Card, CardManager, CardValue, Suit}
|
||||
import de.knockoutwhist.control.{MatchControl, PlayerControl, RoundControl, TrickControl}
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import org.scalatest.matchers.must.Matchers
|
||||
@@ -15,82 +16,74 @@ import scala.collection.mutable.ListBuffer
|
||||
class MatchTests extends AnyWordSpec with Matchers{
|
||||
|
||||
"A Match" should {
|
||||
TestUtil.disableDelay()
|
||||
TestUtil.cancelOut() {
|
||||
TestUtil.disableDebugMode()
|
||||
val player1 = Player("Gunter")
|
||||
val player2 = Player("Peter")
|
||||
val player_list = List(player1, player2)
|
||||
val match1 = Match(player_list)
|
||||
val round1 = match1.create_round()
|
||||
val round1 = RoundControl.create_round(match1)
|
||||
val trumpsuit = round1.trumpSuit
|
||||
val trick1 = round1.create_trick()
|
||||
val trick1 = TrickControl.create_trick(round1)
|
||||
val playedcard1 = TestUtil.simulateInput("1\n") {
|
||||
KnockOutWhist.matchControl.playerControl.playCard(player1)
|
||||
PlayerControl.playCard(player1)
|
||||
}
|
||||
trick1.playCard(playedcard1, player1)
|
||||
TrickControl.playCard(trick1, round1, playedcard1, player1)
|
||||
val playedcard2 = TestUtil.simulateInput("1\n") {
|
||||
KnockOutWhist.matchControl.playerControl.playCard(player2)
|
||||
PlayerControl.playCard(player2)
|
||||
}
|
||||
trick1.playCard(playedcard2, player2)
|
||||
TrickControl.playCard(trick1, round1, playedcard2, player2)
|
||||
"return the players ingame in players_remaining" in {
|
||||
round1.remainingPlayers() should be(player_list)
|
||||
RoundControl.remainingPlayers(round1) should be(player_list)
|
||||
}
|
||||
val rtrick1 = trick1.wonTrick()
|
||||
round1.finalizeRound(true)
|
||||
val rtrick1 = TrickControl.wonTrick(trick1, round1)
|
||||
RoundControl.finalizeRound(round1, match1, true)
|
||||
val round2 = TestUtil.simulateInput("1\n") {
|
||||
match1.create_round()
|
||||
RoundControl.create_round(match1)
|
||||
}
|
||||
TestUtil.enableDebugMode()
|
||||
var trick2: Trick = null
|
||||
"should be able to create a trick with requesting the current trick" in {
|
||||
trick2 = round2.get_current_trick()
|
||||
}
|
||||
if (trick2 == null) {
|
||||
trick2 = round2.get_current_trick()
|
||||
}
|
||||
val trick2: Trick = TrickControl.create_trick(round2)
|
||||
val playedcard3 = TestUtil.simulateInput("1\n") {
|
||||
KnockOutWhist.matchControl.playerControl.playCard(player1)
|
||||
PlayerControl.playCard(player1)
|
||||
}
|
||||
trick1.playCard(playedcard3, player1)
|
||||
TrickControl.playCard(trick1, round2, playedcard3, player1)
|
||||
val playedcard4 = TestUtil.simulateInput("1\n") {
|
||||
KnockOutWhist.matchControl.playerControl.playCard(player2)
|
||||
PlayerControl.playCard(player2)
|
||||
}
|
||||
trick2.playCard(playedcard4, player2)
|
||||
TrickControl.playCard(trick2, round2, playedcard4, player2)
|
||||
"be able to return the current trick of the round" in {
|
||||
round2.get_current_trick() should be(trick2)
|
||||
round2.get_current_trick().get should be(trick2)
|
||||
}
|
||||
val rtrick2 = trick2.wonTrick()
|
||||
val rtrick2 = TrickControl.wonTrick(trick2, round2)
|
||||
"return false if the round isn't over" in {
|
||||
round2.isOver shouldBe false
|
||||
}
|
||||
"be able to return all the tricks of the round" in {
|
||||
round1.get_tricks() should be(List(rtrick1._2))
|
||||
RoundControl.isOver(round2) shouldBe false
|
||||
}
|
||||
"be able to tell if a dog needs to play" in {
|
||||
round2.dogNeedsToPlay shouldBe false
|
||||
RoundControl.dogNeedsToPlay(round2) shouldBe false
|
||||
}
|
||||
"error out if a round is finalized without all tricks played" in {
|
||||
assertThrows[IllegalStateException] {
|
||||
round2.finalizeRound()
|
||||
RoundControl.finalizeRound(round2, match1)
|
||||
}
|
||||
}
|
||||
round2.finalizeRound(true)
|
||||
RoundControl.finalizeRound(round2, match1, true)
|
||||
val round3 = TestUtil.simulateInput("1\n") {
|
||||
match1.create_round()
|
||||
RoundControl.create_round(match1)
|
||||
}
|
||||
val trick3 = round3.create_trick()
|
||||
val trick3 = TrickControl.create_trick(round3)
|
||||
val playedcard5 = TestUtil.simulateInput("1\n") {
|
||||
KnockOutWhist.matchControl.playerControl.playCard(player1)
|
||||
PlayerControl.playCard(player1)
|
||||
}
|
||||
trick1.playCard(playedcard5, player1)
|
||||
TrickControl.playCard(trick1, round3, playedcard5, player1) //stand trick1
|
||||
val playedcard6 = TestUtil.simulateInput("1\n") {
|
||||
KnockOutWhist.matchControl.playerControl.playCard(player2)
|
||||
PlayerControl.playCard(player2)
|
||||
}
|
||||
trick3.playCard(playedcard6, player2)
|
||||
trick3.wonTrick()
|
||||
TrickControl.playCard(trick3, round3, playedcard6, player2)
|
||||
TrickControl.wonTrick(trick3, round3)
|
||||
"throw an exception if a match gets finalized before it is finished" in {
|
||||
assertThrows[IllegalStateException] { //If exception is thrown, assertThrows returns succeeded
|
||||
match1.finalizeMatch()
|
||||
MatchControl.finalizeMatch(match1)
|
||||
}
|
||||
}
|
||||
"be able to create a random trumpsuit for first round" in {
|
||||
@@ -99,38 +92,38 @@ class MatchTests extends AnyWordSpec with Matchers{
|
||||
"return false when no round has been completed" in {
|
||||
CardManager.shuffleAndReset()
|
||||
val match3 = Match(List(Player("Gunter")))
|
||||
match3.create_round()
|
||||
match3.isOver shouldBe false
|
||||
RoundControl.create_round(match3)
|
||||
MatchControl.isOver(match3) shouldBe false
|
||||
}
|
||||
"return true if one player is remaining after a round has been played" in {
|
||||
round3.finalizeRound(true)
|
||||
match1.isOver shouldBe true
|
||||
RoundControl.finalizeRound(round3, match1, true)
|
||||
MatchControl.isOver(match1) shouldBe true
|
||||
}
|
||||
val round4 = TestUtil.simulateInput("1\n") {
|
||||
match1.create_round()
|
||||
RoundControl.create_round(match1)
|
||||
}
|
||||
val trick4 = round4.create_trick()
|
||||
val trick4 = TrickControl.create_trick(round4)
|
||||
val playedcard7 = Card(CardValue.Ace, Suit.Hearts)
|
||||
val playedcard8 = Card(CardValue.Two, Suit.Hearts)
|
||||
trick4.playCard(playedcard7, player1)
|
||||
trick4.playCard(playedcard8, player2)
|
||||
trick4.wonTrick()
|
||||
TrickControl.playCard(trick4, round4, playedcard7, player1)
|
||||
TrickControl.playCard(trick4, round4, playedcard8, player2)
|
||||
TrickControl.wonTrick(trick4, round4)
|
||||
|
||||
val trick5 = round4.create_trick()
|
||||
trick5.playCard(playedcard8, player1)
|
||||
trick5.playCard(playedcard7, player2)
|
||||
trick5.wonTrick()
|
||||
val trick5 = TrickControl.create_trick(round4)
|
||||
TrickControl.playCard(trick5, round4, playedcard8, player1)
|
||||
TrickControl.playCard(trick5, round4, playedcard7, player2)
|
||||
TrickControl.wonTrick(trick5, round4)
|
||||
CardManager.shuffleAndReset()
|
||||
val roundResult = TestUtil.simulateInput("1\n13\n") {
|
||||
round4.finalizeRound(true)
|
||||
RoundControl.finalizeRound(round4, match1, true)
|
||||
}
|
||||
|
||||
val round5 = TestUtil.simulateInput("1\n") {
|
||||
match1.create_round()
|
||||
RoundControl.create_round(match1)
|
||||
}
|
||||
"error out if a round is finalized without any tricks played" in {
|
||||
assertThrows[IllegalStateException] {
|
||||
round5.finalizeRound()
|
||||
RoundControl.finalizeRound(round5, match1)
|
||||
}
|
||||
}
|
||||
"be able to finalize a round" in {
|
||||
@@ -141,7 +134,7 @@ class MatchTests extends AnyWordSpec with Matchers{
|
||||
round5.toString should be(s"${Suit.Hearts}, ${ListBuffer()}, $player_list, null, null, false")
|
||||
}
|
||||
"show the winner of the match when it has ended" in {
|
||||
match1.finalizeMatch() shouldBe Player("Peter")
|
||||
MatchControl.finalizeMatch(match1) shouldBe Player("Peter")
|
||||
}
|
||||
"have a working toString Method" in {
|
||||
match1.toString shouldBe "List(Gunter, Peter), 2"
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package de.knockoutwhist.rounds
|
||||
|
||||
import de.knockoutwhist.cards.{Card, CardValue, Suit}
|
||||
import de.knockoutwhist.control.TrickControl
|
||||
import de.knockoutwhist.player.Player
|
||||
import de.knockoutwhist.testutils.TestUtil
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
class TrickTests extends AnyWordSpec with Matchers {
|
||||
|
||||
"A trick" should {
|
||||
TestUtil.disableDelay()
|
||||
"be able to return the first card after it was played" in {
|
||||
val player = Player("Gunter")
|
||||
val player2 = Player("Peter")
|
||||
@@ -16,7 +19,7 @@ class TrickTests extends AnyWordSpec with Matchers {
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val card2 = Card(CardValue.Two, Suit.Clubs)
|
||||
val trick = new Trick(round)
|
||||
trick.playCard(card, player)
|
||||
TrickControl.playCard(trick, round, card, player)
|
||||
trick.get_first_card().isEmpty shouldBe false
|
||||
trick.get_first_card().get shouldBe card
|
||||
}
|
||||
@@ -35,9 +38,9 @@ class TrickTests extends AnyWordSpec with Matchers {
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val trick = new Trick(round)
|
||||
|
||||
trick.playCard(card, player)
|
||||
TrickControl.playCard(trick, round, card, player)
|
||||
|
||||
val won = trick.wonTrick()
|
||||
val won = TrickControl.wonTrick(trick, round)
|
||||
|
||||
won(0) shouldBe player
|
||||
won(1).cards should equal(trick.cards)
|
||||
@@ -50,11 +53,11 @@ class TrickTests extends AnyWordSpec with Matchers {
|
||||
val round = new Round(Suit.Spades, Match(playerlist), playerlist, false)
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val trick = new Trick(round)
|
||||
trick.playCard(card, player)
|
||||
TrickControl.playCard(trick, round, card, player)
|
||||
|
||||
val won = trick.wonTrick()
|
||||
val won = TrickControl.wonTrick(trick, round)
|
||||
assertThrows[IllegalStateException] { //If exception is thrown, assertThrows returns succeeded
|
||||
won(1).playCard(card, player)
|
||||
TrickControl.playCard(won(1), round, card, player)
|
||||
}
|
||||
}
|
||||
"filter the cards by suit correctly if no trump was played" in {
|
||||
@@ -65,9 +68,9 @@ class TrickTests extends AnyWordSpec with Matchers {
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val card2 = Card(CardValue.Ten, Suit.Spades)
|
||||
val trick = new Trick(round)
|
||||
trick.playCard(card, player)
|
||||
trick.playCard(card2, player2)
|
||||
val won = trick.wonTrick()
|
||||
TrickControl.playCard(trick, round, card, player)
|
||||
TrickControl.playCard(trick, round, card2, player2)
|
||||
val won = TrickControl.wonTrick(trick, round)
|
||||
won(0) shouldBe player
|
||||
|
||||
}
|
||||
@@ -77,7 +80,7 @@ class TrickTests extends AnyWordSpec with Matchers {
|
||||
val round = new Round(Suit.Spades, Match(playerlist), playerlist, false)
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val trick = new Trick(round)
|
||||
trick.playCard(card, player) shouldBe true
|
||||
TrickControl.playCard(trick, round, card, player) shouldBe true
|
||||
}
|
||||
"return true if the suit matches the first card played" in {
|
||||
val player = Player("Gunter")
|
||||
@@ -86,9 +89,9 @@ class TrickTests extends AnyWordSpec with Matchers {
|
||||
val round = new Round(Suit.Diamonds, Match(playerlist), playerlist, false)
|
||||
val card = Card(CardValue.Two, Suit.Spades)
|
||||
val card2 = Card(CardValue.Ace, Suit.Spades)
|
||||
val trick = round.create_trick()
|
||||
trick.playCard(card, player)
|
||||
trick.playCard(card2, player2) shouldBe true
|
||||
val trick = TrickControl.create_trick(round)
|
||||
TrickControl.playCard(trick, round, card, player)
|
||||
TrickControl.playCard(trick, round, card2, player2) shouldBe true
|
||||
}
|
||||
"return true if the card matches the trump-card" in {
|
||||
val player = Player("Gunter")
|
||||
@@ -98,8 +101,8 @@ class TrickTests extends AnyWordSpec with Matchers {
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val card2 = Card(CardValue.Two, Suit.Diamonds)
|
||||
val trick = new Trick(round)
|
||||
trick.playCard(card, player)
|
||||
trick.playCard(card2, player2) shouldBe true
|
||||
TrickControl.playCard(trick, round, card, player)
|
||||
TrickControl.playCard(trick, round, card2, player2) shouldBe true
|
||||
}
|
||||
"return false if the card doesn't match the suit of the trump-card + first-card" in {
|
||||
val player = Player("Gunter")
|
||||
@@ -109,8 +112,8 @@ class TrickTests extends AnyWordSpec with Matchers {
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val card2 = Card(CardValue.Two, Suit.Clubs)
|
||||
val trick = new Trick(round)
|
||||
trick.playCard(card, player)
|
||||
trick.playCard(card2, player2) shouldBe false
|
||||
TrickControl.playCard(trick, round, card, player)
|
||||
TrickControl.playCard(trick, round, card2, player2) shouldBe false
|
||||
}
|
||||
"have a working to string" in {
|
||||
val player = Player("Gunter")
|
||||
@@ -120,10 +123,23 @@ class TrickTests extends AnyWordSpec with Matchers {
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val card2 = Card(CardValue.Two, Suit.Clubs)
|
||||
val trick = new Trick(round)
|
||||
trick.playCard(card, player)
|
||||
trick.playCard(card2, player2)
|
||||
TrickControl.playCard(trick, round, card, player)
|
||||
TrickControl.playCard(trick, round, card2, player2)
|
||||
trick.toString() shouldBe s"${trick.cards}, ${null}, ${false}"
|
||||
}
|
||||
"can't set a first card twice" in {
|
||||
val player = Player("Gunter")
|
||||
val player2 = Player("Peter")
|
||||
val playerlist = List(player, player2)
|
||||
val round = new Round(Suit.Diamonds, Match(playerlist), playerlist, false)
|
||||
val card = Card(CardValue.Ace, Suit.Spades)
|
||||
val card2 = Card(CardValue.Two, Suit.Clubs)
|
||||
val trick = new Trick(round)
|
||||
trick.set_first_card(card)
|
||||
assertThrows[IllegalStateException] {
|
||||
trick.set_first_card(card2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.knockoutwhist.testutils
|
||||
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.utils.DelayHandler
|
||||
|
||||
import java.io.{ByteArrayInputStream, OutputStream}
|
||||
|
||||
@@ -26,5 +27,9 @@ object TestUtil {
|
||||
def disableDebugMode(): Unit = {
|
||||
KnockOutWhist.DEBUG_MODE_VAR = false
|
||||
}
|
||||
|
||||
def disableDelay(): Unit = {
|
||||
DelayHandler.activateDelay = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.knockoutwhist.utils.events
|
||||
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
class EventTests extends AnyWordSpec with Matchers {
|
||||
|
||||
"An EventListener Priority" should {
|
||||
"have a working compare too" in {
|
||||
val event1 = Priority.High
|
||||
val event2 = Priority.Normal
|
||||
val event3 = Priority.Low
|
||||
event1 should be > event2
|
||||
event2 should be < event1
|
||||
event2 should be > event3
|
||||
event3 should be < event2
|
||||
event1 should be > event3
|
||||
event3 should be < event1
|
||||
}
|
||||
}
|
||||
|
||||
"The event handler" should {
|
||||
"add a listener" in {
|
||||
val eventHandler = new EventHandler() {}
|
||||
val listener = new EventListener {
|
||||
override def listen[R](event: ReturnableEvent[R]): Option[R] = None
|
||||
}
|
||||
eventHandler.addListener(listener)
|
||||
eventHandler.listeners should contain(listener)
|
||||
}
|
||||
"remove a listener" in {
|
||||
val eventHandler = new EventHandler() {}
|
||||
val listener = new EventListener {
|
||||
override def listen[R](event: ReturnableEvent[R]): Option[R] = None
|
||||
}
|
||||
eventHandler.addListener(listener)
|
||||
eventHandler.removeListener(listener)
|
||||
eventHandler.listeners should not contain listener
|
||||
}
|
||||
"throw an exception if an event is sent without anyone to listen" in {
|
||||
val eventHandler = new EventHandler() {}
|
||||
assertThrows[IllegalStateException] {
|
||||
eventHandler.invoke(new ReturnableEvent[String] {
|
||||
override def id: String = "testEvent"
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user