Skip to content

Instantly share code, notes, and snippets.

@r-wheeler
Last active January 31, 2017 15:31
Show Gist options
  • Save r-wheeler/f6f5b9de113841578092360d94992d4d to your computer and use it in GitHub Desktop.
Save r-wheeler/f6f5b9de113841578092360d94992d4d to your computer and use it in GitHub Desktop.
fp hang man
import cats._
import cats.data._
import cats.implicits._
trait IO[A]{self =>
def run: A
def map[B](f: A =>B): IO[B] = {
new IO[B]{def run = f(self.run)}
}
def flatMap[B](f: A => IO[B]): IO[B] = {
new IO[B] {def run = f(self.run).run}
}
}
implicit object IO extends Monad[IO] {
def pure[A](a: A) = new IO[A] {
def run = a
}
def flatMap[A, B](fa: IO[A])(f: A => IO[B]) = fa.flatMap(f)
def apply[A](a: => A): IO[A] = pure(a)
def tailRecM[A, B](a: A)(f: A => IO[Either[A, B]]): IO[B] = {
flatMap(f(a)) {
case Right(b) => pure(b)
case Left(nextA) => tailRecM(nextA)(f)
}
}
}
def getLine(): IO[String] = {
IO{scala.io.StdIn.readLine()}
}
def putStrLn(s: String): IO[Unit]={
IO{println(s)}
}
type Game[A] = StateT[IO,GameState, A]
sealed trait GameResult
final case object Won extends GameResult
final case object Lost extends GameResult
final case object InPlay extends GameResult
case class GameState(
theWord: String,
guesses: String,
lives: Int
)
implicit val gameShow: Show[GameState] = new Show[GameState]{
def show(f: GameState) = {
val wordIndicator = f.theWord.map(x => if (f.guesses.contains(x)) x else " _ ").mkString("")
val usedIndicator = s"Guessed: ${f.guesses}"
val livesIndicator = s"Lives: ${f.lives}"
s"$wordIndicator, $usedIndicator, lives remaining: $livesIndicator"
}
}
def evalGame(gameState: GameState): GameResult = { gameState match {
case GameState(theWord, guesses, lives) if theWord.toSet.diff(guesses.toSet).isEmpty => Won
case GameState(theWord, guesses, lives) if lives < 1 => Lost
case _ => InPlay
}
}
val initState = GameState("apples","",10)
def liftIO[A](ioa: IO[A]) = StateT.lift[IO, GameState,A](ioa)
def runGame(): Game[Unit] = {
for {
in <- StateT.get[IO, GameState]
_ <- StateT.get[IO, GameState].flatMapF(faf => putStrLn(faf.show))
_ <- liftIO(putStrLn(in.show))
guess <- StateT.lift[IO,GameState,String](getLine)
_ <- liftIO(putStrLn(guess))
updateLives = if (in.theWord.contains(guess)) (in.lives) else (in.lives -1)
newState = GameState(in.theWord,in.guesses ++ guess,updateLives)
_ <- liftIO(putStrLn(newState.show))
_ <- StateT.set[IO,GameState](newState)
status = evalGame(newState)
_ <- status match {
case Won => liftIO(putStrLn("You Won!"))
case Lost => liftIO(putStrLn("You Lost!"))
case _ => runGame
}
/*
_ <- status match {
case Won => StateT.lift[IO,GameState,Unit](putStrLn("youWon"))
//case Lost => StateT.lift[IO,GameState,Unit](putStrLn("youLost"))
case _ => runGame
}*/
} yield ()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment