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 42 — Magic Fortune Ball
This is project 42 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 program is random, so the run fixes it by setting BIGBOOK_SEED=3. The player's answers are piped in:
Will this port compile?
Run it with:
BIGBOOK_SEED=3 ek9 magicfortuneball.ek9 < input.txt
It prints:
ANSWER SPHERE, GIVE US THE (VAGUE) TRUTH!
Ask a yes/no question:
You asked: Will this port compile?
Thinking...
My reply is no.
The program
#!ek9 defines module bigbook.magicfortuneball 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 showIntroduction() stdout.println(say.introduction()) //The question the player asks; unset when the input ends before they ask one. nextQuestion() <- rtn as String: String() stdout.println(say.askQuestion()) rtn: input.next() showQuestion() -> question as String stdout.println(say.youAsked(question)) //The original's time.sleep dot animation is a single line here. showThinking() stdout.println(say.thinking()) //The answer is the toy's own data, shown as it is. showAnswer() -> answer as String stdout.println(answer) override operator ? as pure <- rtn as Boolean: true defines function //THE GAME: the toy's answers and the draw, with no input or output. //The answers of the classic toy: data the ball draws from, not words the program says. sphereAnswers() as pure <- rtn as List of String: [ "It is certain.", "It is decidedly so.", "Without a doubt.", "Yes, definitely.", "You may rely on it.", "As I see it, yes.", "Most likely.", "Outlook good.", "Yes.", "Signs point to yes.", "Reply hazy, try again.", "Ask again later.", "Better not tell you now.", "Cannot predict now.", "Concentrate and ask again.", "Don't count on it.", "My reply is no.", "My sources say no.", "Outlook not so good.", "Very doubtful." ] //Random.next(low, high) includes both ends, so the last index is the upper bound. sphereAnswer() -> rng as Random <- rtn as String: String() answers <- sphereAnswers() rtn: answers.getOrDefault(rng.next(0, length answers - 1), String()) defines function //THE source of randomness, copied unchanged from lib/RandomSource.ek9: SystemRandom(), or //SeededRandom(seed) when BIGBOOK_SEED holds a number (run-and-diff.sh sets it from seed.txt). randomSource() <- rtn as Random: SeededRandom(Integer(EnvVars().get("BIGBOOK_SEED"))) ?: SystemRandom() //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, apart from the toy's answers. defines text for "en" Say introduction() "ANSWER SPHERE, GIVE US THE (VAGUE) TRUTH!" askQuestion() "Ask a yes/no question:" youAsked() -> question as String `You asked: ${question}` thinking() "Thinking..." defines program //Magic Fortune Ball (Big Book project 42). A Magic 8-Ball: ask it a yes/no question and it //draws an answer. The game decides; the Console asks and tells, in the player's words. The //golden replays a seeded game (seed.txt). MagicFortuneBall() //A language with no words of its own is unset: ?: falls back to English. console <- Console(Say(language()) ?: Say("en")) rng <- randomSource() console.showIntroduction() //The guard: the sphere answers only once a question has actually been asked, so the //end of input (an unset line) ends the program quietly. if question <- console.nextQuestion() console.showQuestion(question) console.showThinking() console.showAnswer(sphereAnswer(rng))
About this port
- Idioms:
- The pick is
rng.next(0, length answers - 1);Random.nextincludes both bounds. - The question is read in an
ifguard: the sphere answers only when a line was actually read, and the end of input ends the program quietly.
- The pick is
- Divergences: the original reads the question and discards it. This port echoes it
(
You asked: ...) so the transcript shows what was asked. Thetime.sleep"Thinking..." dot animation is one line.