Skip to content

Commit

Permalink
Merge pull request #4 from vaslabs/feature/enhanceStartingRules
Browse files Browse the repository at this point in the history
Feature/enhance starting rules
  • Loading branch information
vaslabs committed Aug 7, 2020
2 parents 721b579 + 9016ec5 commit e9716ca
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 44 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ lazy val service = (project in file("service"))

lazy val dockerSettings = Seq(
(packageName in Docker) := "cardgame-generator",
dockerBaseImage := "openjdk:8u191-jre-alpine3.8",
dockerBaseImage := "openjdk:14-jdk-alpine3.10",
dockerUsername := Some("vaslabs"),
dockerExposedPorts := List(8080)
)
Expand Down
87 changes: 49 additions & 38 deletions engine/src/main/scala/cardgame/engine/StartingGameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ object StartingGameOps {
if (startingGame.playersJoined.nonEmpty) {
val players = startingGame.playersJoined
val startingPlayer = Math.abs(randomizer.unsafeRunSync() % players.size)
val (startingDeck, gamePlayers) = shuffleHand(deck, players.map(j => PlayingPlayer(j.id, List.empty)))
val (startingDeck, gamePlayers, discardCards) = shuffleHand(deck, players.map(j => PlayingPlayer(j.id, List.empty)))
val startedGame =
StartedGame(
gamePlayers,
startingDeck,
startingPlayer,
Clockwise,
List.empty,
DiscardPile.empty
DiscardPile(discardCards)
)
startedGame -> GameStarted(gamePlayers(startingPlayer).id)
} else {
Expand All @@ -39,7 +39,7 @@ object StartingGameOps {
}
}

def shuffleHand(deck: Deck, players: List[PlayingPlayer]): (Deck, List[PlayingPlayer]) = {
def shuffleHand(deck: Deck, players: List[PlayingPlayer]): (Deck, List[PlayingPlayer], List[Card]) = {
def cardName(image: URI): String = {
val `/` = image.getPath.lastIndexOf("/")
val `.jpg` = image.getPath.lastIndexOf(".jpg")
Expand All @@ -54,52 +54,63 @@ object StartingGameOps {

val exactlyOneCards = deck.startingRules.exactlyOne
val exclude = deck.startingRules.no
val discard = deck.startingRules.discardAll
val handSize = deck.startingRules.hand

val guaranteed = deck.cards.filter(
c =>
exactlyOneCards.contains(cardName(c.image))
).take(players.size)
if (guaranteed.size < players.size && guaranteed.nonEmpty) {
println("players are more than the guaranteed cards, will not give starting hands")
deck -> players
} else {

val takenCards = mutable.HashSet.empty[CardId]

val playersWithGuaranteedCard = if (guaranteed.isEmpty)
players else
players.lazyZip(guaranteed).map {
case (player, card) =>
takenCards += card.id
player.copy(hand = player.hand :+ card)
}
val takenCards = mutable.HashSet.empty[CardId]


val playerWithGuaranteedCards = if (exactlyOneCards.isEmpty)
players
else {
val playerHands = for {
player <- players
guaranteedCard <- exactlyOneCards
takeFromDeck <- deck.cards.filterNot(c => takenCards.contains(c.id)).find(c => cardName(c.image) == guaranteedCard).toList
_ = takenCards.add(takeFromDeck.id)
playerWithGuaranteedCards = player.copy(hand = player.hand :+ takeFromDeck)
} yield playerWithGuaranteedCards

playerHands.groupBy(_.id).map {
case (id, player) =>
player.reduce[PlayingPlayer] {
case (p1, p2) =>
PlayingPlayer(id, p1.hand ++ p2.hand)
}
}.toList
}

val deckWithoutGuaranteedCards = deck.cards.filterNot(
c => takenCards.contains(c.id)
)
val deckWithoutGuaranteedCards = deck.cards.filterNot(c => takenCards.contains(c.id))

val deckWithoutExclusionCards = deckWithoutGuaranteedCards.filterNot(
c =>
exclude.contains(cardName(c.image))
)
val deckWithoutExclusionCards = deckWithoutGuaranteedCards.filterNot(
c => exclude.contains(cardName(c.image))
)

val discardCards = deckWithoutExclusionCards.filter(c => discard.contains(cardName(c.image)))

val shuffledCards = Random.shuffle(deckWithoutExclusionCards)
val deckWithoutDiscardedCards = deckWithoutExclusionCards.filterNot(
c => discard.contains(cardName(c.image))
)

val playersWithHand = playersWithGuaranteedCard.zipWithIndex.map {
case (player, index) =>
val cards = shuffledCards.slice(index * handSize, index * handSize + handSize)
takenCards ++= cards.map(_.id).toSet
player.copy(hand = Random.shuffle(player.hand ++ cards))
}
println(playersWithGuaranteedCard)
val shuffledCards = Random.shuffle(deckWithoutDiscardedCards)

Deck(Random.shuffle(deck.cards.filterNot(c => takenCards.contains(c.id))), None, deck.startingRules) ->
playersWithHand
val playersWithHand = playerWithGuaranteedCards.zipWithIndex.map {
case (player, index) =>
val cards = shuffledCards.slice(index * handSize, index * handSize + handSize)
takenCards ++= cards.map(_.id).toSet
player.copy(hand = Random.shuffle(player.hand ++ cards))
}

val excludedCards = deck.cards.filter(c => exclude.contains(cardName(c.image)))

val remainingCards = shuffledCards.filterNot(c => takenCards.contains(c.id))


(
Deck(Random.shuffle(excludedCards ++ remainingCards), None, deck.startingRules),
playersWithHand,
discardCards.map(c => VisibleCard(c.id, c.image))
)

}

Expand Down
5 changes: 3 additions & 2 deletions model/src/main/scala/cardgame/model/Model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ case class CardId(value: UUID)
case class StartingRules(
no: List[String],
exactlyOne: List[String],
hand: Int
hand: Int,
discardAll: List[String]
)
object StartingRules {
def empty = StartingRules(List.empty, List.empty, 0)
def empty = StartingRules(List.empty, List.empty, 0, List.empty)
}
case class BorrowedCards(playerId: PlayerId, cards: List[Card]) {
def take(cardId: CardId): Option[BorrowedCards] = {
Expand Down
17 changes: 15 additions & 2 deletions processor/src/main/scala/cardgame/processor/GameLoader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import akka.actor.typed.{ActorRef, Behavior}
import cardgame.model.{CardId, Deck, DeckId, HiddenCard, RemoteClock, StartGame, StartingRules}
import cardgame.processor.GameProcessor.FireAndForgetCommand
import cats.effect.{IO, Resource}
import io.circe.Decoder

import scala.io.Source
import io.circe.parser._
import io.circe.generic.auto._

import cats.implicits._
object GameLoader {

def ephemeralBehaviour(
Expand Down Expand Up @@ -87,4 +87,17 @@ object GameLoader {

sealed trait Protocol
case class DeckReady(deck: Deck) extends Protocol

implicit val startingRulesDecoder: Decoder[StartingRules] = Decoder.instance {
hcursor =>
(
hcursor.downField("no").as[List[String]].orElse(Right(List.empty)),
hcursor.downField("exactlyOne").as[List[String]].orElse(Right(List.empty)),
hcursor.downField("hand").as[Int],
hcursor.downField("discardAll").as[List[String]].orElse(Right(List.empty))
).mapN(
(no, exactlyOne, hand, discardAll) =>
StartingRules(no = no, exactlyOne = exactlyOne, hand = hand, discardAll = discardAll)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ object GameProcessorSpec {
Deck(
(0 to size).map(n => HiddenCard(CardId(UUID.randomUUID()), localUri(n))).toList,
None,
StartingRules(List.empty, List.empty, 0)
StartingRules(List.empty, List.empty, 0, List.empty)
)
}

Expand Down

0 comments on commit e9716ca

Please sign in to comment.