Refactor Match class and rename WebUI to WebUIMain; update HomeController for new UI structure
This commit is contained in:
@@ -1,9 +1,13 @@
|
|||||||
package components
|
package components
|
||||||
|
|
||||||
|
import controllers.WebUIMain
|
||||||
import de.knockoutwhist.components.DefaultConfiguration
|
import de.knockoutwhist.components.DefaultConfiguration
|
||||||
|
import de.knockoutwhist.ui.UI
|
||||||
|
import de.knockoutwhist.utils.events.EventListener
|
||||||
|
|
||||||
//class WebApplicationConfiguration extends DefaultConfiguration {
|
class WebApplicationConfiguration extends DefaultConfiguration {
|
||||||
|
|
||||||
|
override def uis: Set[UI] = super.uis + WebUIMain
|
||||||
|
override def listener: Set[EventListener] = super.listener + WebUIMain
|
||||||
|
|
||||||
|
}
|
||||||
//}
|
|
||||||
|
|||||||
8
knockoutwhistweb/app/controllers/GameManager.scala
Normal file
8
knockoutwhistweb/app/controllers/GameManager.scala
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
object GameManager {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import javax.inject.*
|
import com.google.inject.{Guice, Injector}
|
||||||
|
import de.knockoutwhist.KnockOutWhist
|
||||||
|
import de.knockoutwhist.components.Configuration
|
||||||
|
import di.KnockOutWebConfigurationModule
|
||||||
import play.api.*
|
import play.api.*
|
||||||
import play.api.mvc.*
|
import play.api.mvc.*
|
||||||
import de.knockoutwhist.KnockOutWhist
|
|
||||||
import de.knockoutwhist.control.ControlHandler
|
import javax.inject.*
|
||||||
import de.knockoutwhist.ui.tui.TUIMain
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller creates an `Action` to handle HTTP requests to the
|
* This controller creates an `Action` to handle HTTP requests to the
|
||||||
@@ -15,6 +17,7 @@ import de.knockoutwhist.ui.tui.TUIMain
|
|||||||
class HomeController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {
|
class HomeController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {
|
||||||
|
|
||||||
private var initial = false
|
private var initial = false
|
||||||
|
private val injector: Injector = Guice.createInjector(KnockOutWebConfigurationModule())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an Action to render an HTML page.
|
* Create an Action to render an HTML page.
|
||||||
@@ -26,8 +29,7 @@ class HomeController @Inject()(val controllerComponents: ControllerComponents) e
|
|||||||
def index(): Action[AnyContent] = {
|
def index(): Action[AnyContent] = {
|
||||||
if (!initial) {
|
if (!initial) {
|
||||||
initial = true
|
initial = true
|
||||||
ControlHandler.addListener(WebUI)
|
KnockOutWhist.entry(injector.getInstance(classOf[Configuration]))
|
||||||
KnockOutWhist.main(new Array[String](_length = 0))
|
|
||||||
}
|
}
|
||||||
Action { implicit request =>
|
Action { implicit request =>
|
||||||
Ok(views.html.index.apply())
|
Ok(views.html.index.apply())
|
||||||
@@ -36,11 +38,8 @@ class HomeController @Inject()(val controllerComponents: ControllerComponents) e
|
|||||||
|
|
||||||
def ingame(): Action[AnyContent] = {
|
def ingame(): Action[AnyContent] = {
|
||||||
Action { implicit request =>
|
Action { implicit request =>
|
||||||
Ok(views.html.tui.apply(WebUI.latestOutput))
|
Ok(views.html.tui.apply(WebUIMain.latestOutput))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def showTUI(): Action[AnyContent] = Action { implicit request =>
|
|
||||||
Ok(views.html.tui.render(WebUI.latestOutput))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,521 +0,0 @@
|
|||||||
package controllers
|
|
||||||
|
|
||||||
import de.knockoutwhist.events.directional.RequestPickTrumpsuitEvent
|
|
||||||
import de.knockoutwhist.events.round.ShowCurrentTrickEvent
|
|
||||||
import de.knockoutwhist.ui.UI
|
|
||||||
import de.knockoutwhist.ui.tui.TUIMain.{init, runLater, start}
|
|
||||||
import de.knockoutwhist.utils.events.{EventListener, SimpleEvent}
|
|
||||||
import de.knockoutwhist.KnockOutWhist
|
|
||||||
import de.knockoutwhist.cards.{Card, CardValue, Hand, Suit}
|
|
||||||
import de.knockoutwhist.control.controllerBaseImpl.{PlayerLogic, TrickLogic}
|
|
||||||
import de.knockoutwhist.control.{ControlHandler, ControlThread}
|
|
||||||
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.*
|
|
||||||
import de.knockoutwhist.events.round.ShowCurrentTrickEvent
|
|
||||||
import de.knockoutwhist.events.ui.GameState.MAIN_MENU
|
|
||||||
import de.knockoutwhist.events.ui.{GameState, GameStateUpdateEvent}
|
|
||||||
import de.knockoutwhist.events.util.DelayEvent
|
|
||||||
import de.knockoutwhist.player.Playertype.HUMAN
|
|
||||||
import de.knockoutwhist.player.{AbstractPlayer, PlayerFactory}
|
|
||||||
import de.knockoutwhist.ui.UI
|
|
||||||
import de.knockoutwhist.undo.{UndoManager, UndoneException}
|
|
||||||
import de.knockoutwhist.utils.CustomThread
|
|
||||||
import de.knockoutwhist.utils.events.{EventListener, SimpleEvent}
|
|
||||||
|
|
||||||
import java.io.{BufferedReader, InputStreamReader}
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
|
||||||
import scala.annotation.tailrec
|
|
||||||
import scala.util.{Failure, Success, Try}
|
|
||||||
|
|
||||||
object WebUI extends CustomThread with EventListener with UI {
|
|
||||||
|
|
||||||
override def initial: Boolean = {
|
|
||||||
if (init) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
init = true
|
|
||||||
start()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
setName("WebUI")
|
|
||||||
|
|
||||||
override def instance: CustomThread = WebUI
|
|
||||||
|
|
||||||
var init = false
|
|
||||||
override def runLater[R](op: => R): Unit = {
|
|
||||||
interrupted.set(true)
|
|
||||||
super.runLater(op)
|
|
||||||
}
|
|
||||||
var latestOutput: String = ""
|
|
||||||
private var internState: GameState = GameState.NO_SET
|
|
||||||
override def listen(event: SimpleEvent): Unit = {
|
|
||||||
runLater {
|
|
||||||
event match {
|
|
||||||
case event: RenderHandEvent =>
|
|
||||||
renderhandmethod(event)
|
|
||||||
case event: ShowTieCardsEvent =>
|
|
||||||
showtiecardseventmethod(event)
|
|
||||||
case event: ShowGlobalStatus =>
|
|
||||||
showglobalstatusmethod(event)
|
|
||||||
case event: ShowPlayerStatus =>
|
|
||||||
showplayerstatusmethod(event)
|
|
||||||
case event: ShowRoundStatus =>
|
|
||||||
showroundstatusmethod(event)
|
|
||||||
case event: ShowErrorStatus =>
|
|
||||||
showerrstatmet(event)
|
|
||||||
case event: RequestTieNumberEvent =>
|
|
||||||
reqnumbereventmet(event)
|
|
||||||
case event: RequestCardEvent =>
|
|
||||||
reqcardeventmet(event)
|
|
||||||
case event: RequestDogPlayCardEvent =>
|
|
||||||
reqdogeventmet(event)
|
|
||||||
case event: RequestPickTrumpsuitEvent =>
|
|
||||||
reqpicktevmet(event)
|
|
||||||
case event: ShowCurrentTrickEvent =>
|
|
||||||
showcurtrevmet(event)
|
|
||||||
case event: GameStateUpdateEvent =>
|
|
||||||
if (internState != event.gameState) {
|
|
||||||
internState = event.gameState
|
|
||||||
if (event.gameState == GameState.MAIN_MENU) {
|
|
||||||
mainMenu()
|
|
||||||
} else if (event.gameState == GameState.PLAYERS) {
|
|
||||||
reqplayersevent()
|
|
||||||
}
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
object WebUICards {
|
|
||||||
def renderCardAsString(card: Card): Vector[String] = {
|
|
||||||
val lines = "│ │"
|
|
||||||
if (card.cardValue == CardValue.Ten) {
|
|
||||||
latestOutput += Vector(
|
|
||||||
s"┌─────────┐",
|
|
||||||
s"│${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET} │",
|
|
||||||
lines,
|
|
||||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.suit.cardType()}${Console.RESET} │",
|
|
||||||
lines,
|
|
||||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET}│",
|
|
||||||
s"└─────────┘"
|
|
||||||
)
|
|
||||||
return Vector(
|
|
||||||
s"┌─────────┐",
|
|
||||||
s"│${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET} │",
|
|
||||||
lines,
|
|
||||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.suit.cardType()}${Console.RESET} │",
|
|
||||||
lines,
|
|
||||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET}│",
|
|
||||||
s"└─────────┘"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
latestOutput += Vector(
|
|
||||||
s"┌─────────┐",
|
|
||||||
s"│${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET} │",
|
|
||||||
lines,
|
|
||||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.suit.cardType()}${Console.RESET} │",
|
|
||||||
lines,
|
|
||||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET}│",
|
|
||||||
s"└─────────┘"
|
|
||||||
)
|
|
||||||
return Vector(
|
|
||||||
s"┌─────────┐",
|
|
||||||
s"│${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET} │",
|
|
||||||
lines,
|
|
||||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.suit.cardType()}${Console.RESET} │",
|
|
||||||
lines,
|
|
||||||
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET}│",
|
|
||||||
s"└─────────┘"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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(WebUICards.renderCardAsString)
|
|
||||||
var zipped = cardStrings.transpose
|
|
||||||
if (showNumbers) zipped = {
|
|
||||||
List.tabulate(hand.cards.length) { i =>
|
|
||||||
s" ${i + 1} "
|
|
||||||
}
|
|
||||||
} :: zipped
|
|
||||||
latestOutput += zipped.map(_.mkString(" ")).toVector
|
|
||||||
zipped.map(_.mkString(" ")).toVector
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//override def initial: Boolean = {
|
|
||||||
//if (init) {
|
|
||||||
//return false
|
|
||||||
//}
|
|
||||||
//init = true
|
|
||||||
//start()
|
|
||||||
//true
|
|
||||||
//}
|
|
||||||
|
|
||||||
@tailrec
|
|
||||||
private def mainMenu(): Unit = {
|
|
||||||
latestOutput = ""
|
|
||||||
latestOutput += "Welcome to Knockout Whist\n"
|
|
||||||
latestOutput += "Please select an option:\n"
|
|
||||||
latestOutput += "1. Start a new match\n"
|
|
||||||
latestOutput += "2. Exit\n"
|
|
||||||
Try {
|
|
||||||
input().toInt
|
|
||||||
} match {
|
|
||||||
case Success(value) =>
|
|
||||||
value match {
|
|
||||||
case 1 =>
|
|
||||||
ControlThread.runLater {
|
|
||||||
KnockOutWhist.config.maincomponent.startMatch()
|
|
||||||
}
|
|
||||||
case 2 =>
|
|
||||||
println("Exiting the game.")
|
|
||||||
System.exit(0)
|
|
||||||
case _ =>
|
|
||||||
showerrstatmet(ShowErrorStatus(INVALID_NUMBER))
|
|
||||||
ControlThread.runLater {
|
|
||||||
ControlHandler.invoke(DelayEvent(500))
|
|
||||||
ControlHandler.invoke(GameStateUpdateEvent(MAIN_MENU))
|
|
||||||
}
|
|
||||||
mainMenu()
|
|
||||||
}
|
|
||||||
case Failure(exception) =>
|
|
||||||
exception match {
|
|
||||||
case undo: UndoneException =>
|
|
||||||
case _ =>
|
|
||||||
showerrstatmet(ShowErrorStatus(NOT_A_NUMBER))
|
|
||||||
ControlThread.runLater {
|
|
||||||
ControlHandler.invoke(DelayEvent(500))
|
|
||||||
ControlHandler.invoke(GameStateUpdateEvent(MAIN_MENU))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def renderhandmethod(event: RenderHandEvent): Option[Boolean] = {
|
|
||||||
WebUICards.renderHandEvent(event.hand, event.showNumbers).foreach(println)
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def showtiecardseventmethod(event: ShowTieCardsEvent): Option[Boolean] = {
|
|
||||||
val a: Array[String] = Array("", "", "", "", "", "", "", "")
|
|
||||||
for ((player, card) <- event.card) {
|
|
||||||
val playerNameLength = player.name.length
|
|
||||||
a(0) += " " + player.name + ":" + (" " * (playerNameLength - 1))
|
|
||||||
val rendered = WebUICards.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def showglobalstatusmethod(event: ShowGlobalStatus): Option[Boolean] = {
|
|
||||||
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[AbstractPlayer]) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
println(s"${event.objects.head.asInstanceOf[AbstractPlayer].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 =>
|
|
||||||
latestOutput = ""
|
|
||||||
println("Starting a new match...")
|
|
||||||
wait(1000)
|
|
||||||
latestOutput = ""
|
|
||||||
Some(true)
|
|
||||||
case SHOW_TYPE_PLAYERS =>
|
|
||||||
latestOutput += "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[AbstractPlayer]) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
latestOutput = ""
|
|
||||||
latestOutput += s"The match is over. The winner is ${event.objects.head.asInstanceOf[AbstractPlayer]}"
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def showplayerstatusmethod(event: ShowPlayerStatus): Option[Boolean] = {
|
|
||||||
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.")
|
|
||||||
wait(2000)
|
|
||||||
latestOutput = ""
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def showroundstatusmethod(event: ShowRoundStatus): Option[Boolean] = {
|
|
||||||
event.status match {
|
|
||||||
case SHOW_START_ROUND =>
|
|
||||||
latestOutput = ""
|
|
||||||
println(s"Starting a new round. The trump suit is ${event.currentRound.trumpSuit}.")
|
|
||||||
wait(2000)
|
|
||||||
latestOutput = ""
|
|
||||||
Some(true)
|
|
||||||
case WON_ROUND =>
|
|
||||||
if (event.objects.length != 1 || !event.objects.head.isInstanceOf[AbstractPlayer]) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
println(s"${event.objects.head.asInstanceOf[AbstractPlayer].name} won the round.")
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
case PLAYERS_OUT =>
|
|
||||||
println("The following players are out of the game:")
|
|
||||||
event.currentRound.playersout.foreach(p => {
|
|
||||||
println(p.name)
|
|
||||||
})
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def showerrstatmet(event: ShowErrorStatus): Option[Boolean] = {
|
|
||||||
event.status match {
|
|
||||||
case INVALID_NUMBER =>
|
|
||||||
println("Please enter a valid number.")
|
|
||||||
Some(true)
|
|
||||||
case NOT_A_NUMBER =>
|
|
||||||
println("Please enter a number.")
|
|
||||||
Some(true)
|
|
||||||
case INVALID_INPUT =>
|
|
||||||
latestOutput += "Please enter a valid input"
|
|
||||||
Some(true)
|
|
||||||
case INVALID_NUMBER_OF_PLAYERS =>
|
|
||||||
latestOutput += "Please enter at least two names."
|
|
||||||
Some(true)
|
|
||||||
case IDENTICAL_NAMES =>
|
|
||||||
latestOutput += "Please enter unique names."
|
|
||||||
Some(true)
|
|
||||||
case INVALID_NAME_FORMAT =>
|
|
||||||
latestOutput += "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 {
|
|
||||||
latestOutput += f"You have to play a card of suit: ${event.objects.head.asInstanceOf[Card].suit}\n"
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def reqnumbereventmet(event: RequestTieNumberEvent): Option[Boolean] = {
|
|
||||||
val tryTie = Try {
|
|
||||||
val number = input().toInt
|
|
||||||
if (number < 1 || number > event.remaining) {
|
|
||||||
throw new IllegalArgumentException(s"Number must be between 1 and ${event.remaining}")
|
|
||||||
}
|
|
||||||
number
|
|
||||||
}
|
|
||||||
if (tryTie.isFailure && tryTie.failed.get.isInstanceOf[UndoneException]) {
|
|
||||||
return Some(true)
|
|
||||||
}
|
|
||||||
ControlThread.runLater {
|
|
||||||
KnockOutWhist.config.playerlogcomponent.selectedTie(event.winner, event.matchImpl, event.round, event.playersout, event.cut, tryTie, event.currentStep, event.remaining, event.currentIndex)
|
|
||||||
}
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def reqcardeventmet(event: RequestCardEvent): Option[Boolean] = {
|
|
||||||
val tryCard = Try {
|
|
||||||
val card = input().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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tryCard.isFailure && tryCard.failed.get.isInstanceOf[UndoneException]) {
|
|
||||||
return Some(true)
|
|
||||||
}
|
|
||||||
ControlThread.runLater {
|
|
||||||
KnockOutWhist.config.trickcomponent.controlSuitplayed(tryCard, event.matchImpl, event.round, event.trick, event.currentIndex, event.player)
|
|
||||||
}
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def reqdogeventmet(event: RequestDogPlayCardEvent): Option[Boolean] = {
|
|
||||||
val tryDogCard = Try {
|
|
||||||
val card = input()
|
|
||||||
if (card.equalsIgnoreCase("y")) {
|
|
||||||
Some(event.hand.cards.head)
|
|
||||||
} else if (card.equalsIgnoreCase("n") && !event.needstoplay) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Didn't want to play card but had to")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tryDogCard.isFailure && tryDogCard.failed.get.isInstanceOf[UndoneException]) {
|
|
||||||
return Some(true)
|
|
||||||
}
|
|
||||||
ControlThread.runLater {
|
|
||||||
KnockOutWhist.config.trickcomponent.controlDogPlayed(tryDogCard, event.matchImpl, event.round, event.trick, event.currentIndex, event.player)
|
|
||||||
}
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def reqplayersevent(): Option[Boolean] = {
|
|
||||||
showglobalstatusmethod(ShowGlobalStatus(SHOW_TYPE_PLAYERS))
|
|
||||||
val names = Try {
|
|
||||||
input().split(",")
|
|
||||||
}
|
|
||||||
if (names.isFailure && names.failed.get.isInstanceOf[UndoneException]) {
|
|
||||||
return Some(true)
|
|
||||||
}
|
|
||||||
if (names.get.length < 2) {
|
|
||||||
showerrstatmet(ShowErrorStatus(INVALID_NUMBER_OF_PLAYERS))
|
|
||||||
return reqplayersevent()
|
|
||||||
}
|
|
||||||
if (names.get.distinct.length != names.get.length) {
|
|
||||||
showerrstatmet(ShowErrorStatus(IDENTICAL_NAMES))
|
|
||||||
return reqplayersevent()
|
|
||||||
}
|
|
||||||
if (names.get.count(_.trim.isBlank) > 0
|
|
||||||
|| names.get.count(_.trim.length <= 2) > 0
|
|
||||||
|| names.get.count(_.trim.length > 10) > 0) {
|
|
||||||
showerrstatmet(ShowErrorStatus(INVALID_NAME_FORMAT))
|
|
||||||
return reqplayersevent()
|
|
||||||
}
|
|
||||||
ControlThread.runLater {
|
|
||||||
KnockOutWhist.config
|
|
||||||
.maincomponent
|
|
||||||
.enteredPlayers(names.get
|
|
||||||
.map(s => PlayerFactory.createPlayer(s, playertype = HUMAN))
|
|
||||||
.toList)
|
|
||||||
}
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def reqpicktevmet(event: RequestPickTrumpsuitEvent): Option[Boolean] = {
|
|
||||||
val trySuit = Try {
|
|
||||||
val suit = input().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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (trySuit.isFailure && trySuit.failed.get.isInstanceOf[UndoneException]) {
|
|
||||||
return Some(true)
|
|
||||||
}
|
|
||||||
ControlThread.runLater {
|
|
||||||
KnockOutWhist.config.playerlogcomponent.trumpSuitSelected(event.matchImpl, trySuit, event.remaining_players, event.firstRound, event.player)
|
|
||||||
}
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def showcurtrevmet(event: ShowCurrentTrickEvent): Option[Boolean] = {
|
|
||||||
latestOutput = ""
|
|
||||||
val sb = new StringBuilder()
|
|
||||||
sb.append("Current Trick:\n")
|
|
||||||
sb.append("Trump-Suit: " + event.round.trumpSuit + "\n")
|
|
||||||
if (event.trick.firstCard.isDefined) {
|
|
||||||
sb.append(s"Suit to play: ${event.trick.firstCard.get.suit}\n")
|
|
||||||
}
|
|
||||||
for ((card, player) <- event.trick.cards) {
|
|
||||||
sb.append(s"${player.name} played ${card.toString}\n")
|
|
||||||
}
|
|
||||||
latestOutput += sb.toString()
|
|
||||||
//println(sb.toString())
|
|
||||||
Some(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val isInIO: AtomicBoolean = new AtomicBoolean(false)
|
|
||||||
private val interrupted: AtomicBoolean = new AtomicBoolean(false)
|
|
||||||
|
|
||||||
private def input(): String = {
|
|
||||||
interrupted.set(false)
|
|
||||||
val reader = new BufferedReader(new InputStreamReader(System.in))
|
|
||||||
|
|
||||||
while (!interrupted.get()) {
|
|
||||||
if (reader.ready()) {
|
|
||||||
val in = reader.readLine()
|
|
||||||
if (in.equals("undo")) {
|
|
||||||
UndoManager.undoStep()
|
|
||||||
throw new UndoneException("Undo")
|
|
||||||
} else if (in.equals("redo")) {
|
|
||||||
UndoManager.redoStep()
|
|
||||||
throw new UndoneException("Redo")
|
|
||||||
} else if (in.equals("load")
|
|
||||||
&& KnockOutWhist.config.persistenceManager.canLoadfile("currentSnapshot")) {
|
|
||||||
KnockOutWhist.config.persistenceManager.loadFile("currentSnapshot.json")
|
|
||||||
throw new UndoneException("Load")
|
|
||||||
} else if (in.equals("save")) {
|
|
||||||
KnockOutWhist.config.persistenceManager.saveFile("currentSnapshot.json")
|
|
||||||
}
|
|
||||||
return in
|
|
||||||
}
|
|
||||||
Thread.sleep(50)
|
|
||||||
}
|
|
||||||
throw new UndoneException("Skipped")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
304
knockoutwhistweb/app/controllers/WebUIMain.scala
Normal file
304
knockoutwhistweb/app/controllers/WebUIMain.scala
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import de.knockoutwhist.cards.{Card, CardValue, Hand, Suit}
|
||||||
|
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.round.ShowCurrentTrickEvent
|
||||||
|
import de.knockoutwhist.events.ui.{GameState, GameStateUpdateEvent}
|
||||||
|
import de.knockoutwhist.player.AbstractPlayer
|
||||||
|
import de.knockoutwhist.ui.UI
|
||||||
|
import de.knockoutwhist.utils.CustomThread
|
||||||
|
import de.knockoutwhist.utils.events.{EventListener, SimpleEvent}
|
||||||
|
|
||||||
|
object WebUIMain extends CustomThread with EventListener with UI {
|
||||||
|
|
||||||
|
setName("WebUI")
|
||||||
|
|
||||||
|
var init = false
|
||||||
|
private var internState: GameState = GameState.NO_SET
|
||||||
|
|
||||||
|
var latestOutput: String = ""
|
||||||
|
|
||||||
|
override def instance: CustomThread = WebUIMain
|
||||||
|
|
||||||
|
override def listen(event: SimpleEvent): Unit = {
|
||||||
|
runLater {
|
||||||
|
event match {
|
||||||
|
case event: RenderHandEvent =>
|
||||||
|
renderhandmethod(event)
|
||||||
|
case event: ShowTieCardsEvent =>
|
||||||
|
showtiecardseventmethod(event)
|
||||||
|
case event: ShowGlobalStatus =>
|
||||||
|
showglobalstatusmethod(event)
|
||||||
|
case event: ShowPlayerStatus =>
|
||||||
|
showplayerstatusmethod(event)
|
||||||
|
case event: ShowRoundStatus =>
|
||||||
|
showroundstatusmethod(event)
|
||||||
|
case event: ShowErrorStatus =>
|
||||||
|
showerrstatmet(event)
|
||||||
|
case event: ShowCurrentTrickEvent =>
|
||||||
|
showcurtrevmet(event)
|
||||||
|
case event: GameStateUpdateEvent =>
|
||||||
|
if (internState != event.gameState) {
|
||||||
|
internState = event.gameState
|
||||||
|
if (event.gameState == GameState.MAIN_MENU) {
|
||||||
|
mainMenu()
|
||||||
|
}
|
||||||
|
Some(true)
|
||||||
|
}
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object TUICards {
|
||||||
|
def renderCardAsString(card: Card): Vector[String] = {
|
||||||
|
val lines = "│ │"
|
||||||
|
if (card.cardValue == CardValue.Ten) {
|
||||||
|
return Vector(
|
||||||
|
s"┌─────────┐",
|
||||||
|
s"│${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET} │",
|
||||||
|
lines,
|
||||||
|
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.suit.cardType()}${Console.RESET} │",
|
||||||
|
lines,
|
||||||
|
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} │",
|
||||||
|
lines,
|
||||||
|
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.suit.cardType()}${Console.RESET} │",
|
||||||
|
lines,
|
||||||
|
s"│ ${cardColour(card.suit)}${Console.BOLD}${card.cardValue.cardType()}${Console.RESET}│",
|
||||||
|
s"└─────────┘"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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() = {
|
||||||
|
latestOutput = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override def initial: Boolean = {
|
||||||
|
if (init) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
init = true
|
||||||
|
start()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
private def mainMenu(): Unit = {
|
||||||
|
TUIUtil.clearConsole()
|
||||||
|
println("Welcome to Knockout Whist!")
|
||||||
|
println()
|
||||||
|
println("Please select an option:")
|
||||||
|
println("1. Start a new match")
|
||||||
|
println("2. Exit")
|
||||||
|
}
|
||||||
|
|
||||||
|
private def renderhandmethod(event: RenderHandEvent): Option[Boolean] = {
|
||||||
|
TUICards.renderHandEvent(event.hand, event.showNumbers).foreach(println)
|
||||||
|
Some(true)
|
||||||
|
}
|
||||||
|
private def showtiecardseventmethod(event: ShowTieCardsEvent): Option[Boolean] = {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
private def showglobalstatusmethod(event: ShowGlobalStatus): Option[Boolean] = {
|
||||||
|
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[AbstractPlayer]) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
println(s"${event.objects.head.asInstanceOf[AbstractPlayer].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...")
|
||||||
|
latestOutput += "\n\n"
|
||||||
|
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[AbstractPlayer]) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
TUIUtil.clearConsole()
|
||||||
|
println(s"The match is over. The winner is ${event.objects.head.asInstanceOf[AbstractPlayer]}")
|
||||||
|
Some(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private def showplayerstatusmethod(event: ShowPlayerStatus): Option[Boolean] = {
|
||||||
|
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.")
|
||||||
|
latestOutput = "\n\n"
|
||||||
|
Some(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private def showroundstatusmethod(event: ShowRoundStatus): Option[Boolean] = {
|
||||||
|
event.status match {
|
||||||
|
case SHOW_START_ROUND =>
|
||||||
|
TUIUtil.clearConsole()
|
||||||
|
println(s"Starting a new round. The trump suit is ${event.currentRound.trumpSuit}.")
|
||||||
|
latestOutput = "\n\n"
|
||||||
|
Some(true)
|
||||||
|
case WON_ROUND =>
|
||||||
|
if (event.objects.length != 1 || !event.objects.head.isInstanceOf[AbstractPlayer]) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
println(s"${event.objects.head.asInstanceOf[AbstractPlayer].name} won the round.")
|
||||||
|
Some(true)
|
||||||
|
}
|
||||||
|
case PLAYERS_OUT =>
|
||||||
|
println("The following players are out of the game:")
|
||||||
|
event.currentRound.playersout.foreach(p => {
|
||||||
|
println(p.name)
|
||||||
|
})
|
||||||
|
Some(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private def showerrstatmet(event: ShowErrorStatus): Option[Boolean] = {
|
||||||
|
event.status match {
|
||||||
|
case INVALID_NUMBER =>
|
||||||
|
println("Please enter a valid number.")
|
||||||
|
Some(true)
|
||||||
|
case NOT_A_NUMBER =>
|
||||||
|
println("Please enter a 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def showcurtrevmet(event: ShowCurrentTrickEvent): Option[Boolean] = {
|
||||||
|
TUIUtil.clearConsole()
|
||||||
|
val sb = new StringBuilder()
|
||||||
|
sb.append("Current Trick:\n")
|
||||||
|
sb.append("Trump-Suit: " + event.round.trumpSuit + "\n")
|
||||||
|
if (event.trick.firstCard.isDefined) {
|
||||||
|
sb.append(s"Suit to play: ${event.trick.firstCard.get.suit}\n")
|
||||||
|
}
|
||||||
|
for ((card, player) <- event.trick.cards) {
|
||||||
|
sb.append(s"${player.name} played ${card.toString}\n")
|
||||||
|
}
|
||||||
|
println(sb.toString())
|
||||||
|
Some(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def println(s: String): Unit = {
|
||||||
|
latestOutput += s + "\n"
|
||||||
|
System.out.println(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def println(): Unit = {
|
||||||
|
latestOutput += "\n"
|
||||||
|
System.out.println()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
13
knockoutwhistweb/app/di/KnockOutWebConfigurationModule.scala
Normal file
13
knockoutwhistweb/app/di/KnockOutWebConfigurationModule.scala
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package di
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule
|
||||||
|
import components.WebApplicationConfiguration
|
||||||
|
import de.knockoutwhist.components.Configuration
|
||||||
|
|
||||||
|
class KnockOutWebConfigurationModule extends AbstractModule {
|
||||||
|
|
||||||
|
override def configure(): Unit = {
|
||||||
|
bind(classOf[Configuration]).to(classOf[WebApplicationConfiguration])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,10 +1,25 @@
|
|||||||
@(title: String)(content: play.twirl.api.Html)
|
@*
|
||||||
|
* This template is called from the `index` template. This template
|
||||||
|
* handles the rendering of the page header and body tags. It takes
|
||||||
|
* two arguments, a `String` for the title of the page and an `Html`
|
||||||
|
* object to insert into the body of the page.
|
||||||
|
*@
|
||||||
|
@(title: String)(content: Html)
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
@* Here's where we render the page title `String`. *@
|
||||||
<title>@title</title>
|
<title>@title</title>
|
||||||
|
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
|
||||||
|
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@* And here's where we render the `Html` object containing
|
||||||
|
* the page content. *@
|
||||||
@content
|
@content
|
||||||
|
|
||||||
|
<script src="@routes.Assets.versioned("javascripts/main.js")" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
@(renderTUI: String)
|
@(toRender: String)
|
||||||
|
|
||||||
@main("Welcome to Play") {
|
@main("Tui") {
|
||||||
<h1>@renderTUI</h1>
|
<div id="tui">
|
||||||
|
@for(line <- toRender.split('\n')) {
|
||||||
|
<p>@line</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,5 @@
|
|||||||
# An example controller showing a sample home page
|
# An example controller showing a sample home page
|
||||||
GET / controllers.HomeController.index()
|
GET / controllers.HomeController.index()
|
||||||
GET /ingame controllers.HomeController.ingame()
|
GET /ingame controllers.HomeController.ingame()
|
||||||
GET /showTUI controllers.HomeController.showTUI()
|
|
||||||
# Map static resources from the /public folder to the /assets URL path
|
# Map static resources from the /public folder to the /assets URL path
|
||||||
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
||||||
|
|||||||
Reference in New Issue
Block a user