package snake package pong import PongModel.initialPong /** m11 pong app: the same wiring as App.scala (streams in, drawings out), reusing the course's modules. */ object PongApp: val FRAME_MS_PONG: Long = 30 private def paddleKey(key: String): Option[Paddle] = key match case "ArrowUp" | "w" | "W" => Some(Paddle.Up) case "ArrowDown" | "s" | "S" => Some(Paddle.Down) case _ => None def pongKey(isDown: Boolean, key: String): Option[PongAction] = paddleKey(key) match case Some(p) => Some(if isDown then PongAction.Press(p) else PongAction.Release(p)) case None => if isDown && (key == "r" || key == "R") then Some(PongAction.Restart) else None lazy val pongActions: Stream[PongAction] = Stream .interval(FRAME_MS_PONG) .map(_ => PongAction.Frame) .merge(Stream.keyDowns.filterMap(pongKey(true, _))) .merge(Stream.keyUps.filterMap(pongKey(false, _))) def pongStates(seed: Long, actions: Stream[PongAction]): Stream[PongState] = actions.scan(initialPong(seed))(PongRules.pongUpdate).startWith(initialPong(seed)) lazy val pongMain: IO[Stream[IO[Unit]]] = IO.randomSeed.map(seed => pongStates(seed, pongActions).map(state => IO.drawScene(PongView.pongView(state))))