The Big Book of Small EK9 Programs

Adapted from Al Sweigart's The Big Book of Small Python Projects: 81 Easy Practice Programs (No Starch Press, 2021; copyright © 2021 Al Sweigart), which he makes freely available under a Creative Commons Attribution-NonCommercial-ShareAlike licence at inventwithpython.com/bigbookpython. Changes were made: each program was ported from Python to EK9 and remodelled in EK9's idioms.

Project 32 — Gullible

This is project 32 of the book, ported to EK9. Its chapter is still being written; until then, this page shows the port itself: a run of it, the whole program, and how it keeps to the original.

A sample run

The player's answers are piped in:

maybe
yes
no

Run it with:

ek9 gullible.ek9 < input.txt

It prints:

Do you want to know how to keep a gullible person busy for hours? Y/N
"maybe" is not a valid yes/no response.
Do you want to know how to keep a gullible person busy for hours? Y/N
Do you want to know how to keep a gullible person busy for hours? Y/N
Thank you. Have a nice day!

The program

#!ek9
defines module bigbook.gullible

  defines type

    Answer
      Yes
      No

  defines class

    //THE input idiom of this book, copied unchanged from lib/LineInput.ek9 (the reasons are
    //there): read with next(), and every input loop also stops when ended() is true.
    LineInput
      stdin as Stdin: Stdin()
      inputEnded as Boolean: false

      next()
        <- rtn as String: stdin.next()
        if not rtn?
          inputEnded: true

      ended() as pure
        <- rtn as Boolean: Boolean(inputEnded)

      override operator ? as pure
        <- rtn as Boolean: true

    //THE INPUT AND OUTPUT: everything the player sees or types goes through here, worded by Say.
    Console
      stdout as Stdout: Stdout()
      input as LineInput: LineInput()
      say as Say: Say("en")

      Console()
        -> words as Say
        say: words

      //Asks until the reply is a yes or a no; unset only if the input ends first.
      nextAnswer()
        <- rtn as Answer: Answer()
        while not rtn? and not input.ended()
          stdout.println(say.askAnswer())
          if entry <- input.next()
            rtn: answerOf(entry.lowerCase())
            if not rtn?
              stdout.println(say.notYesOrNo(entry))

      showGoodbye()
        stdout.println(say.goodbye())

      ended() as pure
        <- rtn as Boolean: input.ended()

      //"yes" and "no" are words the player types, so they come from Say. Any other reply is an
      //unset Answer: the guard in nextAnswer, not a sentinel, says "not a yes or a no".
      private answerOf()
        -> reply as String
        <- rtn as Answer: Answer()
        if reply == say.yes() or reply == say.y()
          rtn: Answer.Yes
        else if reply == say.no() or reply == say.n()
          rtn: Answer.No

      override operator ? as pure
        <- rtn as Boolean: true

  defines function

    //THE GAME: the joke's one rule - only "no" stops the question.
    stopsAsking() as pure
      -> answer as Answer
      <- rtn as Boolean: answer == Answer.No

  defines function

    //THE language of the words, copied unchanged from lib/Language.ek9: BIGBOOK_LANG when it
    //is set (fr, zh, ...), otherwise en.
    language()
      <- rtn as String: EnvVars().get("BIGBOOK_LANG") ?: "en"

  //THE WORDS: every word the player sees or types.
  defines text for "en"

    Say

      askAnswer()
        "Do you want to know how to keep a gullible person busy for hours? Y/N"

      notYesOrNo()
        -> reply as String
        `"${reply}" is not a valid yes/no response.`

      yes()
        "yes"

      y()
        "y"

      no()
        "no"

      n()
        "n"

      goodbye()
        "Thank you. Have a nice day!"

  defines program

    //Gullible (Big Book project 32). Asks whether you want to know how to keep a gullible person
    //busy for hours, again and again, until you say no. The game decides; the Console asks and
    //tells, in the player's words.
    Gullible()
      //A language with no words of its own is unset: ?: falls back to English.
      console <- Console(Say(language()) ?: Say("en"))

      running <- true
      while running and not console.ended()
        if answer <- console.nextAnswer()
          running: not stopsAsking(answer)
      console.showGoodbye()

About this port