import { Terminal } from "@effect/platform"
import type { PlatformError } from "@effect/platform/Error"
import { Effect, Option, Random } from "effect"
import { NodeRuntime, NodeTerminal } from "@effect/platform-node"
// Generate a secret random number between 1 and 100
const secret = Random.nextIntBetween(1, 100)
// Parse the user's input into a valid number
const parseGuess = (input: string) => {
const n = parseInt(input, 10)
return isNaN(n) || n < 1 || n > 100 ? Option.none() : Option.some(n)
// Display a message on the terminal
const display = (message: string) =>
Effect.gen(function* () {
const terminal = yield* Terminal.Terminal
yield* terminal.display(`${message}\n`)
// Prompt the user for a guess
const prompt = Effect.gen(function* () {
const terminal = yield* Terminal.Terminal
yield* terminal.display("Enter a guess: ")
return yield* terminal.readLine
// Get the user's guess, validating it as an integer between 1 and 100
const answer: Effect.Effect<
Terminal.QuitException | PlatformError,
> = Effect.gen(function* () {
const input = yield* prompt
const guess = parseGuess(input)
if (Option.isNone(guess)) {
yield* display("You must enter an integer from 1 to 100")
// Check if the guess is too high, too low, or correct
ok: Effect.Effect<A, E, R>,
ko: Effect.Effect<A, E, R>
Effect.gen(function* () {
yield* display("Too high")
} else if (guess < secret) {
yield* display("Too low")
// End the game with a success message
const end = display("You guessed it!")
Terminal.QuitException | PlatformError,
Effect.gen(function* () {
const guess = yield* answer
Effect.suspend(() => loop(secret))
// Full game setup and execution
const game = Effect.gen(function* () {
`We have selected a random number between 1 and 100.
See if you can guess it in 10 turns or fewer.
We'll tell you if your guess was too high or too low.`
yield* loop(yield* secret)
NodeRuntime.runMain(game.pipe(Effect.provide(NodeTerminal.layer)))