Add readLine and readInt operations to the Console effect for interactive input. Create a number guessing game project demonstrating ADTs, pattern matching, effects, and game state management. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
204 lines
5.8 KiB
Plaintext
204 lines
5.8 KiB
Plaintext
// Number Guessing Game
|
|
// The computer picks a random number, you try to guess it!
|
|
|
|
// Game configuration using ADTs
|
|
type Difficulty =
|
|
| Easy // 1-50, unlimited guesses
|
|
| Medium // 1-100, 10 guesses
|
|
| Hard // 1-200, 7 guesses
|
|
|
|
// GameConfig: minNum, maxNum, maxGuesses
|
|
type GameConfig =
|
|
| GameConfig(Int, Int, Option<Int>)
|
|
|
|
// GameState: secret, guesses, config
|
|
type GameState =
|
|
| GameState(Int, Int, GameConfig)
|
|
|
|
type GuessResult =
|
|
| TooLow
|
|
| TooHigh
|
|
| Correct
|
|
|
|
// Config helpers
|
|
fn getMinNum(config: GameConfig): Int =
|
|
match config { GameConfig(min, _, _) => min }
|
|
|
|
fn getMaxNum(config: GameConfig): Int =
|
|
match config { GameConfig(_, max, _) => max }
|
|
|
|
fn getMaxGuesses(config: GameConfig): Option<Int> =
|
|
match config { GameConfig(_, _, maxG) => maxG }
|
|
|
|
// State helpers
|
|
fn getSecret(state: GameState): Int =
|
|
match state { GameState(s, _, _) => s }
|
|
|
|
fn getGuessCount(state: GameState): Int =
|
|
match state { GameState(_, g, _) => g }
|
|
|
|
fn getConfig(state: GameState): GameConfig =
|
|
match state { GameState(_, _, c) => c }
|
|
|
|
fn difficultyConfig(d: Difficulty): GameConfig =
|
|
match d {
|
|
Easy => GameConfig(1, 50, None),
|
|
Medium => GameConfig(1, 100, Some(10)),
|
|
Hard => GameConfig(1, 200, Some(7))
|
|
}
|
|
|
|
fn difficultyName(d: Difficulty): String =
|
|
match d {
|
|
Easy => "Easy (1-50, unlimited guesses)",
|
|
Medium => "Medium (1-100, 10 guesses)",
|
|
Hard => "Hard (1-200, 7 guesses)"
|
|
}
|
|
|
|
// Core game logic (pure functions)
|
|
fn checkGuess(guess: Int, secret: Int): GuessResult =
|
|
if guess < secret then TooLow
|
|
else if guess > secret then TooHigh
|
|
else Correct
|
|
|
|
fn isGameOver(state: GameState, result: GuessResult): Bool =
|
|
match result {
|
|
Correct => true,
|
|
_ => match getMaxGuesses(getConfig(state)) {
|
|
Some(max) => getGuessCount(state) >= max,
|
|
None => false
|
|
}
|
|
}
|
|
|
|
fn guessesRemaining(state: GameState): Option<Int> =
|
|
match getMaxGuesses(getConfig(state)) {
|
|
Some(max) => Some(max - getGuessCount(state)),
|
|
None => None
|
|
}
|
|
|
|
// Game effects
|
|
fn printWelcome(): Unit with {Console} = {
|
|
Console.print("")
|
|
Console.print("========================================")
|
|
Console.print(" NUMBER GUESSING GAME")
|
|
Console.print("========================================")
|
|
Console.print("")
|
|
}
|
|
|
|
fn chooseDifficulty(): Difficulty with {Console} = {
|
|
Console.print("Choose difficulty:")
|
|
Console.print(" 1. " + difficultyName(Easy))
|
|
Console.print(" 2. " + difficultyName(Medium))
|
|
Console.print(" 3. " + difficultyName(Hard))
|
|
Console.print("")
|
|
Console.print("Enter choice (1-3): ")
|
|
|
|
let choice = Console.readInt()
|
|
match choice {
|
|
1 => Easy,
|
|
2 => Medium,
|
|
3 => Hard,
|
|
_ => {
|
|
Console.print("Invalid choice, defaulting to Medium")
|
|
Medium
|
|
}
|
|
}
|
|
}
|
|
|
|
fn initGame(difficulty: Difficulty): GameState with {Random} = {
|
|
let config = difficultyConfig(difficulty)
|
|
let secret = Random.int(getMinNum(config), getMaxNum(config))
|
|
GameState(secret, 0, config)
|
|
}
|
|
|
|
fn printGameStart(state: GameState): Unit with {Console} = {
|
|
let config = getConfig(state)
|
|
Console.print("")
|
|
Console.print("I'm thinking of a number between " +
|
|
toString(getMinNum(config)) + " and " +
|
|
toString(getMaxNum(config)) + "...")
|
|
match getMaxGuesses(config) {
|
|
Some(max) => Console.print("You have " + toString(max) + " guesses."),
|
|
None => Console.print("You have unlimited guesses.")
|
|
}
|
|
Console.print("")
|
|
}
|
|
|
|
fn getGuess(state: GameState): Int with {Console} = {
|
|
match guessesRemaining(state) {
|
|
Some(remaining) =>
|
|
Console.print("Guesses remaining: " + toString(remaining)),
|
|
None => ()
|
|
}
|
|
Console.print("Enter your guess: ")
|
|
Console.readInt()
|
|
}
|
|
|
|
fn printResult(result: GuessResult): Unit with {Console} =
|
|
match result {
|
|
TooLow => Console.print("Too low! Try higher."),
|
|
TooHigh => Console.print("Too high! Try lower."),
|
|
Correct => Console.print("")
|
|
}
|
|
|
|
fn printVictory(state: GameState): Unit with {Console} = {
|
|
Console.print("========================================")
|
|
Console.print(" CONGRATULATIONS! You got it!")
|
|
Console.print(" The number was: " + toString(getSecret(state)))
|
|
Console.print(" Guesses used: " + toString(getGuessCount(state)))
|
|
Console.print("========================================")
|
|
}
|
|
|
|
fn printDefeat(state: GameState): Unit with {Console} = {
|
|
Console.print("========================================")
|
|
Console.print(" GAME OVER - Out of guesses!")
|
|
Console.print(" The number was: " + toString(getSecret(state)))
|
|
Console.print("========================================")
|
|
}
|
|
|
|
// Main game loop
|
|
fn gameLoop(state: GameState): GameState with {Console} = {
|
|
let guess = getGuess(state)
|
|
let result = checkGuess(guess, getSecret(state))
|
|
let newState = GameState(getSecret(state), getGuessCount(state) + 1, getConfig(state))
|
|
|
|
printResult(result)
|
|
|
|
if isGameOver(newState, result) then {
|
|
match result {
|
|
Correct => printVictory(newState),
|
|
_ => printDefeat(newState)
|
|
}
|
|
newState
|
|
} else {
|
|
gameLoop(newState)
|
|
}
|
|
}
|
|
|
|
fn askPlayAgain(): Bool with {Console} = {
|
|
Console.print("")
|
|
Console.print("Play again? (1 = yes, 2 = no): ")
|
|
let choice = Console.readInt()
|
|
choice == 1
|
|
}
|
|
|
|
fn playGame(): Unit with {Console, Random} = {
|
|
let difficulty = chooseDifficulty()
|
|
let state = initGame(difficulty)
|
|
printGameStart(state)
|
|
let finalState = gameLoop(state)
|
|
()
|
|
}
|
|
|
|
fn mainLoop(): Unit with {Console, Random} = {
|
|
playGame()
|
|
if askPlayAgain() then mainLoop()
|
|
else Console.print("Thanks for playing! Goodbye!")
|
|
}
|
|
|
|
fn main(): Unit with {Console, Random} = {
|
|
printWelcome()
|
|
mainLoop()
|
|
}
|
|
|
|
let output = run main() with {}
|