mirror of
https://github.com/Vale54321/schafkopf-bot.git
synced 2025-12-16 19:59:33 +01:00
added cmd playing mode
This commit is contained in:
122
Backend/schafkopf-client/src/main/kotlin/CmdSchafkopfMessager.kt
Normal file
122
Backend/schafkopf-client/src/main/kotlin/CmdSchafkopfMessager.kt
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
import de.heiserer.CmdPlayer
|
||||||
|
import de.heiserer.SchafkopfMessager
|
||||||
|
import de.heiserer.cards.Card
|
||||||
|
import de.heiserer.cards.CardColor
|
||||||
|
import de.heiserer.cards.CardSymbol
|
||||||
|
import de.heiserer.player.Player
|
||||||
|
|
||||||
|
class CmdSchafkopfMessager: SchafkopfMessager {
|
||||||
|
override fun sendPlayerTurn(player: Player) {
|
||||||
|
if(player !is CmdPlayer){
|
||||||
|
clearConsole()
|
||||||
|
}
|
||||||
|
|
||||||
|
println("${player.getName()} ist am Zug")
|
||||||
|
Thread.sleep(1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendPlayerWonTrick(player: Player) {
|
||||||
|
println("${player.getName()} hat den Stich gewonnen.")
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendPlayerWonGame(player: Player) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendCardPlayed(player: Player, card: Card) {
|
||||||
|
println("${player.getName()} hat ${card.displayName} gespielt.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sendTableCards(cards: List<Card>) {
|
||||||
|
println("Tischkarten:")
|
||||||
|
CmdCard.printCards(cards)
|
||||||
|
|
||||||
|
Thread.sleep(3000)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CmdCard(card: Card){
|
||||||
|
private val symbolMap = mapOf(
|
||||||
|
CardSymbol.SIEBEN to "7",
|
||||||
|
CardSymbol.ACHT to "8",
|
||||||
|
CardSymbol.NEUN to "9",
|
||||||
|
CardSymbol.ZEHN to "10",
|
||||||
|
CardSymbol.OBER to "O",
|
||||||
|
CardSymbol.UNTER to "U",
|
||||||
|
CardSymbol.KOENIG to "K",
|
||||||
|
CardSymbol.ASS to "A"
|
||||||
|
)
|
||||||
|
|
||||||
|
private val colorMap = mapOf(
|
||||||
|
CardColor.HERZ to "♥",
|
||||||
|
CardColor.SCHELL to "♦",
|
||||||
|
CardColor.EICHEL to "♣",
|
||||||
|
CardColor.BLATT to "♠"
|
||||||
|
)
|
||||||
|
|
||||||
|
private val symbol = symbolMap[card.symbol]?: "?"
|
||||||
|
private val color = colorMap[card.color]?: "?"
|
||||||
|
private val colorName = card.color.displayName
|
||||||
|
private val symbolName = card.symbol.displayName
|
||||||
|
|
||||||
|
private val cardWidth = 13
|
||||||
|
|
||||||
|
private val symbolLine = "│ ${symbol.padEnd(cardWidth-5)}$symbol │"
|
||||||
|
private val colorLine = "│ ${color.padEnd(cardWidth-5)}$color │"
|
||||||
|
|
||||||
|
private val cardLines = listOf(
|
||||||
|
"┌───────────┐",
|
||||||
|
symbolLine,
|
||||||
|
colorLine,
|
||||||
|
"│${colorName.padCenter(cardWidth-2)}│",
|
||||||
|
"│${symbolName.padCenter(cardWidth-2)}│",
|
||||||
|
colorLine,
|
||||||
|
symbolLine,
|
||||||
|
"└───────────┘"
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
fun print(){
|
||||||
|
cardLines.forEach {
|
||||||
|
println(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCardLines(): List<String> {
|
||||||
|
return cardLines
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.padCenter(totalWidth: Int, padChar: Char = ' '): String {
|
||||||
|
if (this.length >= totalWidth) return this
|
||||||
|
val padding = totalWidth - this.length
|
||||||
|
val padStart = this.length + padding / 2
|
||||||
|
return this.padStart(padStart, padChar).padEnd(totalWidth, padChar)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun printCards(cards: List<Card>) {
|
||||||
|
val lastCardLines = CmdCard(cards.last()).getCardLines()
|
||||||
|
|
||||||
|
val cardLines = cards.map { CmdCard(it).getCardLines() }
|
||||||
|
|
||||||
|
// Loop through the indices of the lines that are present in all cards
|
||||||
|
for (i in lastCardLines.indices) {
|
||||||
|
// For other lines, print up to the first 5 characters
|
||||||
|
var line = cardLines.joinToString(" ") { it[i].take(5) }
|
||||||
|
line += lastCardLines[i].drop(5)
|
||||||
|
println(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearConsole() {
|
||||||
|
for (i in 1..100) {
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package de.heiserer
|
||||||
|
|
||||||
|
import de.heiserer.cards.*
|
||||||
|
import de.heiserer.player.Player
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class CmdPlayer(name: String) : Player(name) {
|
||||||
|
private val scanner = Scanner(System.`in`)
|
||||||
|
|
||||||
|
override fun playCard(tableCards: UnsortedCardList, gameType: GameType): Card {
|
||||||
|
val cardsCopy = cards.getCopyOfCards()
|
||||||
|
|
||||||
|
println("Available cards:")
|
||||||
|
CmdSchafkopfMessager.CmdCard.printCards(cardsCopy)
|
||||||
|
|
||||||
|
// Print cards with their respective index
|
||||||
|
cardsCopy.forEachIndexed { index, card ->
|
||||||
|
println("(${index + 1}) ${card.name}") // Prints card with index starting from 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prompt the user to enter a card number
|
||||||
|
println("Please enter the number of the card you want to play:")
|
||||||
|
|
||||||
|
val userInput = scanner.nextLine()
|
||||||
|
val cardToPlay = getCardByUserInput(userInput, tableCards, gameType)
|
||||||
|
|
||||||
|
return cards.remove(cardToPlay)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCardByUserInput(
|
||||||
|
userInput: String,
|
||||||
|
tableCards: UnsortedCardList,
|
||||||
|
gameType: GameType
|
||||||
|
): Card {
|
||||||
|
val cardsCopy = cards.getCopyOfCards()
|
||||||
|
return try {
|
||||||
|
// Convert user input to an integer and adjust for zero-based index
|
||||||
|
val cardIndex = userInput.toInt() - 1
|
||||||
|
|
||||||
|
// Ensure the index is within bounds
|
||||||
|
if (cardIndex in cardsCopy.indices) {
|
||||||
|
cardsCopy[cardIndex] // Return the selected card
|
||||||
|
if(validateCard(cardsCopy[cardIndex], tableCards, gameType)){
|
||||||
|
cardsCopy[cardIndex]
|
||||||
|
} else {
|
||||||
|
println("Invalid card. Please try again.")
|
||||||
|
playCard(tableCards, gameType) // Retry if the card is invalid
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println("Invalid card number. Please try again.")
|
||||||
|
playCard(tableCards, gameType) // Retry if the input was invalid
|
||||||
|
}
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
println("Invalid input. Please enter a number.")
|
||||||
|
playCard(tableCards, gameType) // Retry on invalid input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
package de.heiserer
|
package de.heiserer
|
||||||
|
|
||||||
|
import CmdSchafkopfMessager
|
||||||
|
import de.heiserer.player.NPCPlayer
|
||||||
import de.heiserer.plugins.*
|
import de.heiserer.plugins.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.engine.*
|
import io.ktor.server.engine.*
|
||||||
import io.ktor.server.netty.*
|
import io.ktor.server.netty.*
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val test = SchafkopfGameController()
|
val test = SchafkopfGameController(listOf(NPCPlayer("NPC 1"), NPCPlayer("NPC 2"), CmdPlayer("Dev"), NPCPlayer("NPC 4")), CmdSchafkopfMessager())
|
||||||
|
|
||||||
test.playRound()
|
test.playRound()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package de.heiserer
|
package de.heiserer
|
||||||
|
|
||||||
class SchafkopfGameController {
|
import de.heiserer.cards.*
|
||||||
private val players = listOf(NPCPlayer("NPC 1"), NPCPlayer("NPC 2"), NPCPlayer("NPC 3"), NPCPlayer("NPC 4"))
|
import de.heiserer.player.Player
|
||||||
|
|
||||||
|
class SchafkopfGameController(palyers: List<Player>, private val messager: SchafkopfMessager) {
|
||||||
|
private val players = palyers
|
||||||
|
|
||||||
private lateinit var gameType: GameType
|
private lateinit var gameType: GameType
|
||||||
private val playedCards: CardList = UnsortedCardList()
|
private val playedCards: CardList = UnsortedCardList()
|
||||||
@@ -16,6 +19,7 @@ class SchafkopfGameController {
|
|||||||
|
|
||||||
for(i in 0 until 8){
|
for(i in 0 until 8){
|
||||||
startingPlayer = playTrick(startingPlayer)
|
startingPlayer = playTrick(startingPlayer)
|
||||||
|
messager.sendPlayerWonTrick(startingPlayer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,15 +28,17 @@ class SchafkopfGameController {
|
|||||||
|
|
||||||
for(i in 0 until 4){
|
for(i in 0 until 4){
|
||||||
val currentPlayer = calculatePlayerOffset(startingPlayer, i)
|
val currentPlayer = calculatePlayerOffset(startingPlayer, i)
|
||||||
currentPlayer.printName()
|
messager.sendPlayerTurn(currentPlayer)
|
||||||
|
|
||||||
val card = currentPlayer.playCard(tableCards, gameType)
|
val card = currentPlayer.playCard(tableCards, gameType)
|
||||||
|
messager.sendCardPlayed(currentPlayer, card)
|
||||||
tableCards.add(card)
|
tableCards.add(card)
|
||||||
|
messager.sendTableCards(tableCards.getCopyOfCards())
|
||||||
}
|
}
|
||||||
|
|
||||||
tableCards.print()
|
playedCards.add(tableCards)
|
||||||
|
|
||||||
return startingPlayer
|
val trickOffset = CardToolkit.whoTricks(gameType, tableCards)
|
||||||
|
return calculatePlayerOffset(startingPlayer, trickOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun calculatePlayerOffset(startingPlayer: Player, i: Int): Player = players[(players.indexOf(startingPlayer) + i) % 4]
|
private fun calculatePlayerOffset(startingPlayer: Player, i: Int): Player = players[(players.indexOf(startingPlayer) + i) % 4]
|
||||||
@@ -52,62 +58,3 @@ class SchafkopfGameController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Player(private var name: String){
|
|
||||||
protected var cards: SortedCardList = SortedCardList(GameType.SAU_SPIEL)
|
|
||||||
|
|
||||||
fun serveCards(cards: UnsortedCardList){
|
|
||||||
this.cards = cards.asSortedCardList(GameType.SAU_SPIEL)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sortCards(gameType: GameType){
|
|
||||||
cards = cards.asSortedCardList(gameType)
|
|
||||||
println("Spieler $name hat folgende Karten sortiert:")
|
|
||||||
cards.print()
|
|
||||||
println()
|
|
||||||
println("Trumpf:")
|
|
||||||
cards.getTrumpf().print()
|
|
||||||
println()
|
|
||||||
println("Farbe:")
|
|
||||||
cards.getCardsWithoutTrumpf().print()
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun playCard(tableCards: UnsortedCardList, gameType: GameType): Card
|
|
||||||
|
|
||||||
fun printName(){
|
|
||||||
println(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NPCPlayer(name: String) : Player(name){
|
|
||||||
override fun playCard(tableCards: UnsortedCardList, gameType: GameType): Card {
|
|
||||||
if(tableCards.size() == 0){
|
|
||||||
println("Erster Spieler")
|
|
||||||
val card = cards.removeLast()
|
|
||||||
println("Spielt ${card.displayName}")
|
|
||||||
println()
|
|
||||||
return card
|
|
||||||
}
|
|
||||||
|
|
||||||
val firstCard = tableCards.get(0)
|
|
||||||
if(cards.farbFreiOrTrumpf(firstCard, gameType)){
|
|
||||||
println("farbFrei Or Trumpf")
|
|
||||||
return playTrumpf()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun playTrumpf(): Card {
|
|
||||||
val trumpf = cards.getTrumpf()
|
|
||||||
if (trumpf.size() > 0) {
|
|
||||||
println("play Trumpf")
|
|
||||||
val card = trumpf.removeLast()
|
|
||||||
println("Spielt ${card.displayName}")
|
|
||||||
println()
|
|
||||||
return cards.remove(card)
|
|
||||||
} else {
|
|
||||||
println("abspatzen")
|
|
||||||
return cards.removeFirst()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package de.heiserer
|
||||||
|
|
||||||
|
import de.heiserer.cards.Card
|
||||||
|
import de.heiserer.player.Player
|
||||||
|
|
||||||
|
interface SchafkopfMessager {
|
||||||
|
fun sendPlayerTurn(player: Player)
|
||||||
|
fun sendPlayerWonTrick(player: Player)
|
||||||
|
fun sendPlayerWonGame(player: Player)
|
||||||
|
fun sendCardPlayed(player: Player, card: Card)
|
||||||
|
fun sendTableCards(cards: List<Card>)
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package de.heiserer.cards
|
||||||
|
|
||||||
|
class CardAlreadyAddedException(message: String, val card: Card) : RuntimeException(message) {
|
||||||
|
|
||||||
|
// You can add additional constructors or methods if needed, but for now, this is sufficient to handle the scenario of adding a card that's already in the list.
|
||||||
|
}
|
||||||
21
Backend/schafkopf-shared/src/main/kotlin/card/CardList.kt
Normal file
21
Backend/schafkopf-shared/src/main/kotlin/card/CardList.kt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package de.heiserer.cards
|
||||||
|
|
||||||
|
interface CardList {
|
||||||
|
fun add(card: Card)
|
||||||
|
fun add(cards: CardList)
|
||||||
|
|
||||||
|
fun remove(card: Card): Card
|
||||||
|
fun remove(cards: CardList)
|
||||||
|
fun removeLast(): Card
|
||||||
|
fun removeFirst(): Card
|
||||||
|
|
||||||
|
fun get(index: Int): Card
|
||||||
|
fun getLast(): Card
|
||||||
|
fun getCopyOfCards(): List<Card>
|
||||||
|
|
||||||
|
fun indexOf(card: Card): Int
|
||||||
|
operator fun contains(card: Card): Boolean
|
||||||
|
fun size(): Int
|
||||||
|
fun print()
|
||||||
|
fun asSortedCardList(type: GameType): SortedCardList
|
||||||
|
}
|
||||||
36
Backend/schafkopf-shared/src/main/kotlin/card/CardToolkit.kt
Normal file
36
Backend/schafkopf-shared/src/main/kotlin/card/CardToolkit.kt
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package de.heiserer.cards
|
||||||
|
|
||||||
|
class CardToolkit private constructor(private val gameType: GameType) {
|
||||||
|
private val sortedCardList = UnsortedCardList(true).asSortedCardList(gameType)
|
||||||
|
|
||||||
|
fun isTrumpf(card: Card): Boolean = card in sortedCardList.getTrumpf().getCopyOfCards()
|
||||||
|
|
||||||
|
fun whoTricks(cards: CardList): Int {
|
||||||
|
if(cards.size() != 4){
|
||||||
|
throw IllegalArgumentException("Es müssen 4 Karten auf dem Tisch liegen.")
|
||||||
|
}
|
||||||
|
|
||||||
|
val sortedCards = cards.asSortedCardList(gameType)
|
||||||
|
|
||||||
|
if(sortedCards.getTrumpf().size() > 0){
|
||||||
|
return cards.indexOf(sortedCards.getTrumpf().getLast())
|
||||||
|
} else {
|
||||||
|
val firstColor = cards.get(0).color
|
||||||
|
val colorCards = sortedCards.getCardsWithoutTrumpf(firstColor)
|
||||||
|
|
||||||
|
return cards.indexOf(colorCards.getLast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun isTrumpf(gameType: GameType, card: Card): Boolean {
|
||||||
|
val toolkit = CardToolkit(gameType)
|
||||||
|
return toolkit.isTrumpf(card)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun whoTricks(gameType: GameType, cards: CardList): Int {
|
||||||
|
val toolkit = CardToolkit(gameType)
|
||||||
|
return toolkit.whoTricks(cards)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package de.heiserer
|
package de.heiserer.cards
|
||||||
|
|
||||||
enum class Card(val color: CardColor, val symbol: CardSymbol) {
|
enum class Card(val color: CardColor, val symbol: CardSymbol) {
|
||||||
SCHELL_7(CardColor.SCHELL, CardSymbol.SIEBEN),
|
SCHELL_7(CardColor.SCHELL, CardSymbol.SIEBEN),
|
||||||
SCHELL_8(CardColor.SCHELL, CardSymbol.ACHT),
|
SCHELL_8(CardColor.SCHELL, CardSymbol.ACHT),
|
||||||
SCHELL_9(CardColor.SCHELL, CardSymbol.NINE),
|
SCHELL_9(CardColor.SCHELL, CardSymbol.NEUN),
|
||||||
SCHELL_U(CardColor.SCHELL, CardSymbol.UNTER),
|
SCHELL_U(CardColor.SCHELL, CardSymbol.UNTER),
|
||||||
SCHELL_O(CardColor.SCHELL, CardSymbol.OBER),
|
SCHELL_O(CardColor.SCHELL, CardSymbol.OBER),
|
||||||
SCHELL_K(CardColor.SCHELL, CardSymbol.KOENIG),
|
SCHELL_K(CardColor.SCHELL, CardSymbol.KOENIG),
|
||||||
@@ -11,7 +11,7 @@ enum class Card(val color: CardColor, val symbol: CardSymbol) {
|
|||||||
SCHELL_A(CardColor.SCHELL, CardSymbol.ASS),
|
SCHELL_A(CardColor.SCHELL, CardSymbol.ASS),
|
||||||
HERZ_7(CardColor.HERZ, CardSymbol.SIEBEN),
|
HERZ_7(CardColor.HERZ, CardSymbol.SIEBEN),
|
||||||
HERZ_8(CardColor.HERZ, CardSymbol.ACHT),
|
HERZ_8(CardColor.HERZ, CardSymbol.ACHT),
|
||||||
HERZ_9(CardColor.HERZ, CardSymbol.NINE),
|
HERZ_9(CardColor.HERZ, CardSymbol.NEUN),
|
||||||
HERZ_U(CardColor.HERZ, CardSymbol.UNTER),
|
HERZ_U(CardColor.HERZ, CardSymbol.UNTER),
|
||||||
HERZ_O(CardColor.HERZ, CardSymbol.OBER),
|
HERZ_O(CardColor.HERZ, CardSymbol.OBER),
|
||||||
HERZ_K(CardColor.HERZ, CardSymbol.KOENIG),
|
HERZ_K(CardColor.HERZ, CardSymbol.KOENIG),
|
||||||
@@ -19,7 +19,7 @@ enum class Card(val color: CardColor, val symbol: CardSymbol) {
|
|||||||
HERZ_A(CardColor.HERZ, CardSymbol.ASS),
|
HERZ_A(CardColor.HERZ, CardSymbol.ASS),
|
||||||
BLATT_7(CardColor.BLATT, CardSymbol.SIEBEN),
|
BLATT_7(CardColor.BLATT, CardSymbol.SIEBEN),
|
||||||
BLATT_8(CardColor.BLATT, CardSymbol.ACHT),
|
BLATT_8(CardColor.BLATT, CardSymbol.ACHT),
|
||||||
BLATT_9(CardColor.BLATT, CardSymbol.NINE),
|
BLATT_9(CardColor.BLATT, CardSymbol.NEUN),
|
||||||
BLATT_U(CardColor.BLATT, CardSymbol.UNTER),
|
BLATT_U(CardColor.BLATT, CardSymbol.UNTER),
|
||||||
BLATT_O(CardColor.BLATT, CardSymbol.OBER),
|
BLATT_O(CardColor.BLATT, CardSymbol.OBER),
|
||||||
BLATT_K(CardColor.BLATT, CardSymbol.KOENIG),
|
BLATT_K(CardColor.BLATT, CardSymbol.KOENIG),
|
||||||
@@ -27,7 +27,7 @@ enum class Card(val color: CardColor, val symbol: CardSymbol) {
|
|||||||
BLATT_A(CardColor.BLATT, CardSymbol.ASS),
|
BLATT_A(CardColor.BLATT, CardSymbol.ASS),
|
||||||
EICHEL_7(CardColor.EICHEL, CardSymbol.SIEBEN),
|
EICHEL_7(CardColor.EICHEL, CardSymbol.SIEBEN),
|
||||||
EICHEL_8(CardColor.EICHEL, CardSymbol.ACHT),
|
EICHEL_8(CardColor.EICHEL, CardSymbol.ACHT),
|
||||||
EICHEL_9(CardColor.EICHEL, CardSymbol.NINE),
|
EICHEL_9(CardColor.EICHEL, CardSymbol.NEUN),
|
||||||
EICHEL_U(CardColor.EICHEL, CardSymbol.UNTER),
|
EICHEL_U(CardColor.EICHEL, CardSymbol.UNTER),
|
||||||
EICHEL_O(CardColor.EICHEL, CardSymbol.OBER),
|
EICHEL_O(CardColor.EICHEL, CardSymbol.OBER),
|
||||||
EICHEL_K(CardColor.EICHEL, CardSymbol.KOENIG),
|
EICHEL_K(CardColor.EICHEL, CardSymbol.KOENIG),
|
||||||
@@ -49,7 +49,7 @@ enum class CardColor(val order: Int, val displayName: String) {
|
|||||||
enum class CardSymbol(val order: Int, val displayName: String, val value: Int) {
|
enum class CardSymbol(val order: Int, val displayName: String, val value: Int) {
|
||||||
SIEBEN(0,"7", 0),
|
SIEBEN(0,"7", 0),
|
||||||
ACHT(1,"8", 0),
|
ACHT(1,"8", 0),
|
||||||
NINE(2,"9", 0),
|
NEUN(2,"9", 0),
|
||||||
UNTER(3,"Unter", 2),
|
UNTER(3,"Unter", 2),
|
||||||
OBER(4,"Ober", 3),
|
OBER(4,"Ober", 3),
|
||||||
KOENIG(5,"König", 4),
|
KOENIG(5,"König", 4),
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package de.heiserer.cards
|
||||||
|
|
||||||
|
class SortedCardList(private val gameType: GameType, withAllCards: Boolean = false) : UnsortedCardList(withAllCards) {
|
||||||
|
override fun add(card: Card) {
|
||||||
|
super.add(card)
|
||||||
|
sort()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCardsWithoutTrumpf(color: CardColor? = null): SortedCardList {
|
||||||
|
val cardsWithoutTrumpf = SortedCardList(gameType)
|
||||||
|
|
||||||
|
color?.let { cardsWithoutTrumpf.add(get(it)) }?: cardsWithoutTrumpf.add(this)
|
||||||
|
try {
|
||||||
|
cardsWithoutTrumpf.remove(getTrumpf())
|
||||||
|
} catch (_: IllegalArgumentException) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return cardsWithoutTrumpf
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTrumpf(): SortedCardList {
|
||||||
|
val trumpf = SortedCardList(gameType)
|
||||||
|
|
||||||
|
gameType.symbol?.let {
|
||||||
|
trumpf.add(get(it))
|
||||||
|
} ?: run {
|
||||||
|
trumpf.add(get(CardSymbol.OBER))
|
||||||
|
trumpf.add(get(CardSymbol.UNTER))
|
||||||
|
}
|
||||||
|
|
||||||
|
gameType.color?.let {
|
||||||
|
try{ trumpf.add(get(it)) } catch (_: CardAlreadyAddedException) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trumpf
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sort() {
|
||||||
|
super.sortInternal(gameType.symbol, gameType.color)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,4 @@
|
|||||||
package de.heiserer
|
package de.heiserer.cards
|
||||||
|
|
||||||
interface CardList {
|
|
||||||
fun add(card: Card)
|
|
||||||
fun add(cards: CardList)
|
|
||||||
fun remove(card: Card): Card
|
|
||||||
fun remove(cards: CardList)
|
|
||||||
fun removeLast(): Card
|
|
||||||
fun get(index: Int): Card
|
|
||||||
fun getCopyOfCards(): List<Card>
|
|
||||||
fun size(): Int
|
|
||||||
fun print()
|
|
||||||
fun asSortedCardList(type: GameType): SortedCardList
|
|
||||||
fun removeFirst(): Card
|
|
||||||
}
|
|
||||||
|
|
||||||
open class UnsortedCardList(withAllCards: Boolean = false): CardList {
|
open class UnsortedCardList(withAllCards: Boolean = false): CardList {
|
||||||
private val cards: MutableList<Card> = if(withAllCards){
|
private val cards: MutableList<Card> = if(withAllCards){
|
||||||
@@ -21,6 +7,10 @@ open class UnsortedCardList(withAllCards: Boolean = false): CardList {
|
|||||||
mutableListOf()
|
mutableListOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override operator fun contains(card: Card): Boolean {
|
||||||
|
return cards.contains(card)
|
||||||
|
}
|
||||||
|
|
||||||
override fun add(card: Card) {
|
override fun add(card: Card) {
|
||||||
if (card !in cards) {
|
if (card !in cards) {
|
||||||
cards.add(card)
|
cards.add(card)
|
||||||
@@ -60,6 +50,10 @@ open class UnsortedCardList(withAllCards: Boolean = false): CardList {
|
|||||||
return cards.removeLast()
|
return cards.removeLast()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun indexOf(card: Card): Int {
|
||||||
|
return cards.indexOf(card)
|
||||||
|
}
|
||||||
|
|
||||||
override fun get(index: Int): Card {
|
override fun get(index: Int): Card {
|
||||||
if(index < 0 || index >= cards.size){
|
if(index < 0 || index >= cards.size){
|
||||||
throw IllegalArgumentException("Index $index is out of bounds.")
|
throw IllegalArgumentException("Index $index is out of bounds.")
|
||||||
@@ -67,6 +61,10 @@ open class UnsortedCardList(withAllCards: Boolean = false): CardList {
|
|||||||
return cards[index]
|
return cards[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getLast(): Card {
|
||||||
|
return cards[cards.size - 1]
|
||||||
|
}
|
||||||
|
|
||||||
protected fun get(color: CardColor): CardList {
|
protected fun get(color: CardColor): CardList {
|
||||||
val list = UnsortedCardList()
|
val list = UnsortedCardList()
|
||||||
cards.forEach { card ->
|
cards.forEach { card ->
|
||||||
@@ -129,52 +127,3 @@ open class UnsortedCardList(withAllCards: Boolean = false): CardList {
|
|||||||
}.thenComparing(compareBy({ it.color.order }, { it.symbol.order })))
|
}.thenComparing(compareBy({ it.color.order }, { it.symbol.order })))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SortedCardList(private val gameType: GameType, withAllCards: Boolean = false) : UnsortedCardList(withAllCards) {
|
|
||||||
private fun sort() {
|
|
||||||
super.sortInternal(gameType.symbol, gameType.color)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getCardsWithoutTrumpf(color: CardColor? = null): SortedCardList {
|
|
||||||
val cardsWithoutTrumpf = SortedCardList(gameType)
|
|
||||||
|
|
||||||
color?.let { cardsWithoutTrumpf.add(get(it)) }?: cardsWithoutTrumpf.add(this)
|
|
||||||
try {
|
|
||||||
cardsWithoutTrumpf.remove(getTrumpf())
|
|
||||||
} catch (_: IllegalArgumentException) {
|
|
||||||
}
|
|
||||||
|
|
||||||
return cardsWithoutTrumpf
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTrumpf():SortedCardList {
|
|
||||||
val trumpf = SortedCardList(gameType)
|
|
||||||
|
|
||||||
gameType.symbol?.let {
|
|
||||||
trumpf.add(get(it))
|
|
||||||
} ?: run {
|
|
||||||
trumpf.add(get(CardSymbol.OBER))
|
|
||||||
trumpf.add(get(CardSymbol.UNTER))
|
|
||||||
}
|
|
||||||
|
|
||||||
gameType.color?.let { try{
|
|
||||||
trumpf.add(get(it))
|
|
||||||
} catch (_: CardAlreadyAddedException) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
return trumpf
|
|
||||||
}
|
|
||||||
|
|
||||||
fun farbFreiOrTrumpf(firstCard: Card, gameType: GameType) =
|
|
||||||
firstCard.color == gameType.color || getCardsWithoutTrumpf(gameType.color).size() == 0
|
|
||||||
|
|
||||||
override fun add(card: Card) {
|
|
||||||
super.add(card)
|
|
||||||
sort()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CardAlreadyAddedException(message: String, val card: Card) : RuntimeException(message) {
|
|
||||||
|
|
||||||
// You can add additional constructors or methods if needed, but for now, this is sufficient to handle the scenario of adding a card that's already in the list.
|
|
||||||
}
|
|
||||||
38
Backend/schafkopf-shared/src/main/kotlin/player/NPCPlayer.kt
Normal file
38
Backend/schafkopf-shared/src/main/kotlin/player/NPCPlayer.kt
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package de.heiserer.player
|
||||||
|
|
||||||
|
import de.heiserer.cards.*
|
||||||
|
|
||||||
|
class NPCPlayer(name: String) : Player(name){
|
||||||
|
override fun playCard(tableCards: UnsortedCardList, gameType: GameType): Card {
|
||||||
|
if(tableCards.size() == 0){
|
||||||
|
return playTrumpf()
|
||||||
|
}
|
||||||
|
|
||||||
|
val firstCard = tableCards.get(0)
|
||||||
|
return if(CardToolkit.isTrumpf(gameType, firstCard)){
|
||||||
|
playTrumpf()
|
||||||
|
} else {
|
||||||
|
playColor(firstCard.color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun playTrumpf(): Card {
|
||||||
|
val trumpfCards = cards.getTrumpf()
|
||||||
|
if (trumpfCards.size() > 0) {
|
||||||
|
val card = trumpfCards.removeLast()
|
||||||
|
return cards.remove(card)
|
||||||
|
} else {
|
||||||
|
return cards.removeFirst()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun playColor(color: CardColor): Card {
|
||||||
|
val colorCards = cards.getCardsWithoutTrumpf(color)
|
||||||
|
if (colorCards.size() > 0) {
|
||||||
|
val card = colorCards.removeLast()
|
||||||
|
return cards.remove(card)
|
||||||
|
} else {
|
||||||
|
return cards.removeFirst()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
Backend/schafkopf-shared/src/main/kotlin/player/Player.kt
Normal file
35
Backend/schafkopf-shared/src/main/kotlin/player/Player.kt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package de.heiserer.player
|
||||||
|
|
||||||
|
import de.heiserer.cards.*
|
||||||
|
|
||||||
|
abstract class Player(private var name: String){
|
||||||
|
protected var cards: SortedCardList = SortedCardList(GameType.SAU_SPIEL)
|
||||||
|
|
||||||
|
fun serveCards(cards: UnsortedCardList){
|
||||||
|
this.cards = cards.asSortedCardList(GameType.SAU_SPIEL)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sortCards(gameType: GameType){
|
||||||
|
cards = cards.asSortedCardList(gameType)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun playCard(tableCards: UnsortedCardList, gameType: GameType): Card
|
||||||
|
|
||||||
|
fun getName(): String{
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun validateCard(card: Card, tableCards: UnsortedCardList, gameType: GameType): Boolean{
|
||||||
|
if(tableCards.size() == 0){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val firstCard = tableCards.get(0)
|
||||||
|
|
||||||
|
return if(CardToolkit.isTrumpf(gameType, firstCard)){
|
||||||
|
CardToolkit.isTrumpf(gameType, card) || cards.getTrumpf().size() == 0
|
||||||
|
} else {
|
||||||
|
card.color == firstCard.color || cards.getCardsWithoutTrumpf(firstCard.color).size() == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
import de.heiserer.*
|
import de.heiserer.cards.Card
|
||||||
|
import de.heiserer.cards.CardColor
|
||||||
|
import de.heiserer.cards.GameType
|
||||||
|
import de.heiserer.cards.UnsortedCardList
|
||||||
import org.junit.jupiter.api.Assertions.*
|
import org.junit.jupiter.api.Assertions.*
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.params.ParameterizedTest
|
import org.junit.jupiter.params.ParameterizedTest
|
||||||
|
|||||||
25
Backend/schafkopf-shared/src/test/kotlin/CardToolkitTest.kt
Normal file
25
Backend/schafkopf-shared/src/test/kotlin/CardToolkitTest.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import de.heiserer.cards.*
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class CardToolkitTest {
|
||||||
|
@Test
|
||||||
|
fun `test isTrumpf`() {
|
||||||
|
// ASSERT AND ACT
|
||||||
|
assertEquals(true, CardToolkit.isTrumpf(GameType.SAU_SPIEL, Card.HERZ_O))
|
||||||
|
assertEquals(false, CardToolkit.isTrumpf(GameType.SAU_SPIEL, Card.SCHELL_7))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whoTricks() {
|
||||||
|
// ARRANGE
|
||||||
|
val cards = UnsortedCardList()
|
||||||
|
cards.add(Card.SCHELL_7)
|
||||||
|
cards.add(Card.SCHELL_8)
|
||||||
|
cards.add(Card.SCHELL_K)
|
||||||
|
cards.add(Card.SCHELL_O)
|
||||||
|
|
||||||
|
// ASSERT AND ACT
|
||||||
|
assertEquals(3, CardToolkit.whoTricks(GameType.SAU_SPIEL, cards))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user