I am seeking a review of my command line wordle game.

Having only recently started exploring functional programming, I expect that there will be no shortage of areas to improve. This is my first simple project outside of reading textbooks and solving exercism puzzles.

I am keen to discuss all improvements, however some of my thoughts are listed below:

  1. Can the type declarations be improved/extended? Is it possible to introduce constraints? IE. Strings of length 5
  2. Can the nested if-statements be simplified using pattern matching?
  3. Is my solution considered readable? How can I improve?
  4. Is there a better pattern/approach I could use to handle game state? Should recursion be avoided?

Solution: NET6

open System

type Result = Incorrect | CorrectLetter | CorrectPosition

type Round = {
    Guess: string;
    Result: Result seq;

type Game = {
    Answer: string;
    Rounds: Round seq;

let loadWords path =
    IO.File.ReadAllLines path

let getRandomWord words =
    Array.get words (Random().Next(words.Length))

let checkGuess (answer: string) (guess: string) : Result seq =
    let grader (a: char, g: char) =
        if a = g then Result.CorrectPosition else
            if answer.Contains g then Result.CorrectLetter else Result.Incorrect
    Seq.map grader (Seq.zip answer guess)

let printColoured (colour: ConsoleColor) (letter: char) =
    Console.ForegroundColor <- colour
    printf "%c" letter

let outputResult (letter: char, result: Result) = 
    match result with 
    | Incorrect -> printColoured ConsoleColor.Red letter
    | CorrectLetter -> printColoured ConsoleColor.Yellow letter
    | CorrectPosition -> printColoured ConsoleColor.Green letter

let outputRound (round: Round) = 
    Seq.iter outputResult (Seq.zip round.Guess round.Result)
    printfn ""

let hasWon (results: Result seq) =
    Seq.forall (fun result -> result.Equals(Result.CorrectPosition)) results

let containsAlphabetsOnly (text: string) : bool =
    text |> Seq.forall (fun c -> System.Char.IsLetter(c))

let rec input (validWords: string seq) : string = 
    printf "Input your guess: "
    let guess = System.Console.ReadLine()

    if containsAlphabetsOnly guess && Seq.contains guess validWords then guess else input validWords

let main argv =
    let possibleAnswers = loadWords "answers.txt"

    let answer = getRandomWord possibleAnswers
    //printfn "Answer: %s" answer

    let (initialState: Game) = { Answer = answer; Rounds = []; }

    let rec play (state: Game) =

        let validGuesses = Seq.append possibleAnswers (loadWords "guesses.txt")
        let guess = input validGuesses

        let (round: Round) = { Guess = guess; Result = checkGuess answer guess; }
        outputRound round |> ignore

        let newRoundState = Seq.append state.Rounds [round]

        if hasWon round.Result then state else
            if Seq.length state.Rounds >= 5 then state
            else play { state with Rounds = newRoundState; }

    let result = play initialState

    printfn "Finished in: %d rounds" (Seq.length result.Rounds + 1)
    printfn "Answer: %s" result.Answer


The files referenced above were taken from this reddit post.



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.