Skip to content

Instantly share code, notes, and snippets.

@joshuakfarrar
Created January 20, 2022 18:15
Show Gist options
  • Save joshuakfarrar/88e9d6ce13db3d07094d7c3263f723c5 to your computer and use it in GitHub Desktop.
Save joshuakfarrar/88e9d6ce13db3d07094d7c3263f723c5 to your computer and use it in GitHub Desktop.
using the StateT Monad, we are able to interleave IO into our recursive simulation of State transitions
val scala3Version = "3.1.0"
lazy val root = project
.in(file("."))
.settings(
name := "cards n' stuff",
version := "0.1.0-SNAPSHOT",
scalaVersion := scala3Version,
libraryDependencies ++= Seq(
"com.novocode" % "junit-interface" % "0.11" % "test",
"org.typelevel" %% "cats-core" % "2.7.0",
"org.typelevel" %% "cats-effect" % "3.3.4"
)
)
import scala.util.Random
import cats.data.State
object Deck {
sealed trait Rank
case object Two extends Rank
case object Three extends Rank
case object Four extends Rank
case object Five extends Rank
case object Six extends Rank
case object Seven extends Rank
case object Eight extends Rank
case object Nine extends Rank
case object Ten extends Rank
case object Jack extends Rank
case object Queen extends Rank
case object King extends Rank
case object Ace extends Rank
sealed trait Suit
case object Hearts extends Suit
case object Clubs extends Suit
case object Diamonds extends Suit
case object Spades extends Suit
case class Card(rank: Rank, suit: Suit)
val standardDeck = Seq(
Card(Two, Hearts),
Card(Three, Hearts),
Card(Four, Hearts),
Card(Five, Hearts),
Card(Six, Hearts),
Card(Seven, Hearts),
Card(Eight, Hearts),
Card(Nine, Hearts),
Card(Ten, Hearts),
Card(Jack, Hearts),
Card(Queen, Hearts),
Card(King, Hearts),
Card(Ace, Hearts),
Card(Two, Clubs),
Card(Three, Clubs),
Card(Four, Clubs),
Card(Five, Clubs),
Card(Six, Clubs),
Card(Seven, Clubs),
Card(Eight, Clubs),
Card(Nine, Clubs),
Card(Ten, Clubs),
Card(Jack, Clubs),
Card(Queen, Clubs),
Card(King, Clubs),
Card(Ace, Clubs),
Card(Two, Diamonds),
Card(Three, Diamonds),
Card(Four, Diamonds),
Card(Five, Diamonds),
Card(Six, Diamonds),
Card(Seven, Diamonds),
Card(Eight, Diamonds),
Card(Nine, Diamonds),
Card(Ten, Diamonds),
Card(Jack, Diamonds),
Card(Queen, Diamonds),
Card(King, Diamonds),
Card(Ace, Diamonds),
Card(Two, Spades),
Card(Three, Spades),
Card(Four, Spades),
Card(Five, Spades),
Card(Six, Spades),
Card(Seven, Spades),
Card(Eight, Spades),
Card(Nine, Spades),
Card(Ten, Spades),
Card(Jack, Spades),
Card(Queen, Spades),
Card(King, Spades),
Card(Ace, Spades)
)
class Deck(val cards: Seq[Card] = standardDeck) {
def shuffle: Deck = new Deck(Random.shuffle(cards))
}
}
import cats.effect.{ExitCode, IO, IOApp}
import cats.data.{State, StateT}
object Main extends IOApp {
import Deck._
def describe(card: Card) =
s"${card.rank} of ${card.suit}"
def draw: StateT[IO, Deck, Option[Card]] = for {
deck <- StateT.get[IO, Deck]
_ <- StateT.modify[IO, Deck](_ => new Deck(deck.cards.drop(1)))
} yield deck.cards.headOption
def drawUntilEmpty(lastCard: Option[Card]): StateT[IO, Deck, Option[Card]] = for {
drawCard <- draw
_ <- StateT.liftF {
drawCard match {
case Some(card) => IO(println(s"got a card: ${describe(card)}"))
case None => IO(println("no more cards!"))
}
}
outcome <- drawCard match {
case Some(card) => drawUntilEmpty(Some(card))
case None => StateT.liftF(IO(lastCard))
}
} yield outcome
override def run(args: List[String]): IO[ExitCode] =
for {
_ <- drawUntilEmpty(None).run(new Deck().shuffle)
} yield ExitCode.Success
}
@joshuakfarrar
Copy link
Author

@merlinorg, @hrhino, @zackjp: pick a card, any card

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment