🎨 Render a colorized result

Wordle wouldn't be complete without the results being appropriately hued! 🧑🏼‍🎨 Fortunately, we can rely on a library for bulk of this functionality. Take a look at theTerminus library for ANSI terminal interactionsWe'll use that for producing green and yellow text.

Pull that library down and install it as a dependency with thepullcommand. It should look something like

wordle/main> pull @runarorama/terminus/releases/0.0.2 lib.terminus_0_0_2

See if you can write a function that renders thestubs.Resultof a user's guess appropriately.

  • A character that is in its proper location should be green
  • A character that exists in the target word should be yellow
  • All others can remain unchanged

Users will likely need to see the history of their guesses, so it would be nice if we also had a rendering function that could print out the grid of guesses too.

use stubs Result
renderChar : Result -> Text
renderChar = todo "render single character"
renderRow : [Result] -> Text
renderRow results = todo "render the guessed word"
renderGuesses : [[Result]] -> Text
renderGuesses guesses = todo "render the list of the user's guesses"

Then write a function which exercises all the functionality we've written thus far, including creating thestubs.Target,andstubs.Guessvalues, tallying up their results, and printing them to the console with theprintLinefunction found in base. You can call it whatever you'd like but you should use theruncommand to start it, and it should have the signature:

You may have to play around with different colors in the foreground or background to get a readable colorized letter depending on your console.

Terminus library usage help
Terminus library usage help

Here's an example of how you can set the foreground and background color of text using the library.

colorize = do
  style.fg (Bright IsoColor.Red)
  printLine "I am red"
  style.fg (Bright IsoColor.Green)
  printLine "I am green"
  style.bg (Bright IsoColor.Blue)
  printLine "I have a blue background"
  style.reset
  printLine "I am back to normal"

Enterrun colorizein the UCM to see the output.

These functions work by adding an ansi escape sequence to the given text argument. The terminal can interpet specific byte sequences as commands instead of text.

More on ANSI escape codes

📚printLineand the IO ability
📚printLineand the IO ability

The curly braces indicateprintLinehas twoability requirements.Abilities are one of the ways we encode computational effects in the Unison language. We can read this signature as "printLine is a function which performs the IO and Exception abilities in the process of returning unit."

If you'd like, you can pause here and check outan introduction to abilities.But for now you should know that abilities can be broken down into two things:

  1. An interface which specifies the abstract operations of an effectful computation
  2. Handlers which supply the specific implementation for how the effect should behave

The handler for theIOability is special because it can only be supplied by the Unison runtime itself. You can run a function which performs theIOandExceptionabilities with the UCMruncommand.Instead of wrapping the code that performs an ability with a handler function in the program, you'll issue theruncommand in the UCM console itself. The run command expects adelayed computation,which is commonly introduced by the keyword,do.

Resources

Solution

🔑Walk through rendering and running what we have so far
🔑Walk through rendering and running what we have so far

Thestubs.renderCharfunction uses an earlier ansi library to set the foreground and background colors with functions prefixedfgandbg,respectively. The terminus library implementation should work similarly. These functions operate onTextvalues so we first have to turn theCharback intoTextvalues first.

The pipe forward operator,|>is being used here to take the result of running the function on the left hand side and apply it as an argument to the function on the right.

Bothbasic.renderRowandbasic.renderGuessesmake use of thelib.base.Text.joinfunction to concatenateTextvalues with a character delimeter.

basic.renderRow : [basic.Result] -> Text
basic.renderRow results =
  lib.base.Text.join
    "" (lib.base.data.List.map basic.renderChar results)
basic.renderGuesses : [[basic.Result]] -> Text
basic.renderGuesses resultList =
  lib.base.data.List.map basic.renderRow resultList
    |> lib.base.Text.join "\n"

Here's what a running test of what we've written so far might look like:

basic.renderTest : '{IO, Exception} ()
basic.renderTest = do
  use basic Guess.fromText
  use basic.Guess score
  guess1 = Guess.fromText "hello"
  guess2 = Guess.fromText "there"
  target = basic.Target.fromText "world"
  results1 = score guess1 target
  results2 = score guess2 target
  printLine (basic.renderGuesses [results1, results2])
wordle/main> run renderTest

Next steps

👉Validation for user guesses