プログラミングhaskell 9章 version scala 〜後半(ライフゲーム)〜

type Board = List[Pos]

val width: Int = 5
val height: Int = 5

def showcells(b: Board): IO[Unit] = seqn(b.map(p => writeat(p)("○")))
def isAlive(b: Board)(p: Pos): Boolean = b.contains(p)
def isEmpty(b: Board)(p: Pos): Boolean = !isAlive(b)(p)
def neighbs(p: Pos) = List(
  (p._1 - 1, p._2 - 1), (p._1, p._2 - 1),
  (p._1 + 1, p._2 - 1), (p._1 - 1, p._2),
  (p._1 + 1, p._2), (p._1 - 1, p._2 + 1),
  (p._1, p._2 + 1), (p._1 + 1, p._2 + 1)
).map(wrap)
def wrap(p: Pos): Pos =
  (((p._1 - 1) % width) + 1, ((p._2 - 1) % height) + 1)
def liveneigbs(b: Board)(p: Pos): Int =
  neighbs(p).count(isAlive(b))
def survivers(b: Board): List[Pos] =
  b.filter(p => List(2, 3).contains(liveneigbs(b)(p)))
def births(b: Board): List[Pos] =
  b.flatMap(p => neighbs(p))
    .distinct
    .filter(p => isEmpty(b)(p))
    .filter(p => liveneigbs(b)(p) == 3)
def nextgen(b: Board): List[Pos] =
  survivers(b) ++ births(b)

def life(b: Board): IO[Unit] =
  for {
    _ <- cls
    _ <- showcells(b)
    _ <- IO(Thread.sleep(500L))
    _ <- life(nextgen(b))
  } yield ()

life(List((4, 2), (2, 3), (4, 3), (3, 4), (4, 4))).unsafeRunSync()