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 16 — Diamonds
This is project 16 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
Run it with:
ek9 diamonds.ek9
It prints:
Diamonds, by Al Sweigart al@inventwithpython.com
/\
\/
/\
\/
/\
/ \
\ /
\/
/\
//\\
\\//
\/
/\
/ \
/ \
\ /
\ /
\/
/\
//\\
///\\\
\\\///
\\//
\/
/\
/ \
/ \
/ \
\ /
\ /
\ /
\/
/\
//\\
///\\\
////\\\\
\\\\////
\\\///
\\//
\/
/\
/ \
/ \
/ \
/ \
\ /
\ /
\ /
\ /
\/
/\
//\\
///\\\
////\\\\
/////\\\\\
\\\\\/////
\\\\////
\\\///
\\//
\/
The program
#!ek9 defines module bigbook.diamonds defines constant LargestSize <- 5 Slash <- '/' Backslash <- '\\' defines class //THE OUTPUT: everything the reader sees goes through here, worded by Say. The drawing reads //no input, so there is no LineInput. Console stdout as Stdout: Stdout() say as Say: Say("en") Console() -> words as Say say: words showIntroduction() stdout.println(say.introduction()) //A diamond is computed, not worded: it is shown as the game drew it. The blank line //after each one is layout, so the Console prints it. showDiamond() -> lines as List of String for line in lines stdout.println(line) stdout.println("") override operator ? as pure <- rtn as Boolean: true defines function //THE GAME: the drawing, as lines, with no output or words. //The two diamond styles differ only in how one row of the top half looks, so that row is //a function TYPE: each style is a function that extends it, and diamond() takes either. RowShape() as pure abstract -> size as Integer row as Integer <- rtn as String? //Row `row` (1 = the tip) of an outline diamond's top half: "/", a gap, "\". outlineRow() is RowShape as pure -> size as Integer row as Integer <- rtn as String: `${run(' ', size - row)}${Slash}${run(' ', (row - 1) * 2)}${Backslash}` //Row `row` of a filled diamond's top half: `row` slashes, then `row` backslashes. filledRow() is RowShape as pure -> size as Integer row as Integer <- rtn as String: `${run(' ', size - row)}${run(Slash, row)}${run(Backslash, row)}` //EK9 has no `text * n`: padding an empty String out with a fill character makes a run. run() as pure -> fill as Character times as Integer <- rtn as String: String("").rightPadded(times, fill) flipped() as pure -> ch as Character <- rtn as Character: ch == Slash <- Backslash : ch == Backslash <- Slash : ch //The bottom half is the top half read upwards with every slash turned the other way. mirrored() as pure -> line as String <- rtn as String: cat line | map with flipped | collect as String //'by 1' matters: a bare `1 ... 0` would count DOWN, but a size-0 diamond has no rows. diamond() -> size as Integer shape as RowShape <- rtn as List of String: List() of String for row in 1 ... size by 1 rtn += shape(size, row) for row in size ... 1 by -1 rtn += mirrored(shape(size, row)) 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 reader sees - only the title. The diamonds are not here: the game //draws them. defines text for "en" Say introduction() "Diamonds, by Al Sweigart al@inventwithpython.com" defines program //Diamonds (Big Book project 16). Draws an outline and a filled diamond for each size 0..5. //The game decides; the Console shows, in the reader's words. Diamonds() //A language with no words of its own is unset: ?: falls back to English. console <- Console(Say(language()) ?: Say("en")) console.showIntroduction() for size in 0 ... LargestSize for shape in [outlineRow, filledRow] console.showDiamond(diamond(size, shape))
About this port
- Behaviour: for sizes 0 to 5, an outline diamond (
/ \) then a filled one (//\\), each followed by a blank line. Size 0 draws nothing, as in the book. - Idioms:
- The two styles differ only in one row of the top half, so
RowShapeis an abstract function type andoutlineRow/filledRowextend it.diamond(size, shape)takes either, and the program loops over[outlineRow, filledRow]- functions are values. - The bottom half is not drawn separately: it is the top half's rows in reverse order,
mirroredby a stream (cat line | map with flipped | collect as String). - EK9 has no
text * n.run(fill, times)pads an empty String with the fill character (rightPadded(times, fill)). for row in 1 ... size by 1: a range counts in whichever direction its ends point, so1 ... 0would yield 1 and 0; the explicit step makes the size-0 range empty.- The row builders are
as pure;diamondaccumulates into its result, so it is not.
- The two styles differ only in one row of the top half, so