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 49 — Multiplication Table
This is project 49 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 multiplicationtable.ek9
It prints:
Multiplication Table, by Al Sweigart al@inventwithpython.com
| 0 1 2 3 4 5 6 7 8 9 10 11 12
--+----------------------------------------------------
0| 0 0 0 0 0 0 0 0 0 0 0 0 0
1| 0 1 2 3 4 5 6 7 8 9 10 11 12
2| 0 2 4 6 8 10 12 14 16 18 20 22 24
3| 0 3 6 9 12 15 18 21 24 27 30 33 36
4| 0 4 8 12 16 20 24 28 32 36 40 44 48
5| 0 5 10 15 20 25 30 35 40 45 50 55 60
6| 0 6 12 18 24 30 36 42 48 54 60 66 72
7| 0 7 14 21 28 35 42 49 56 63 70 77 84
8| 0 8 16 24 32 40 48 56 64 72 80 88 96
9| 0 9 18 27 36 45 54 63 72 81 90 99 108
10| 0 10 20 30 40 50 60 70 80 90 100 110 120
11| 0 11 22 33 44 55 66 77 88 99 110 121 132
12| 0 12 24 36 48 60 72 84 96 108 120 132 144
The program
#!ek9 defines module bigbook.multiplicationtable defines constant Size <- 12 LabelWidth <- 2 CellWidth <- 3 //The marks the table is drawn with: a bar after each row's label, a corner where the bar //meets the rule under the header, and the rule itself. Bar <- "|" Corner <- "+" Rule <- '-' defines class //THE OUTPUT: everything the reader sees goes through here, worded by Say. The table 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()) //The table is computed, not worded: it is shown as the game drew it. showTable() -> lines as List of String for line in lines stdout.println(line) override operator ? as pure <- rtn as Boolean: true defines function //THE GAME: the table, as lines, with no output or words. //The book's str(n).rjust(3) + ' ': three wide is enough for the largest product, 144. cell() as pure -> number as Integer <- rtn as String: String() digits <- $number rtn: digits.leftPadded(CellWidth) + " " rowLabel() as pure -> number as Integer <- rtn as String: String() digits <- $number rtn: digits.leftPadded(LabelWidth) + Bar //The book types the header and the rule as fixed text; here they are built from the same //widths as the body, so a change to Size keeps them lined up. headerLine() as pure <- rtn as String: String() blank <- String("") header <- for column in 0 ... Size | map with cell | collect as String padding <- blank.leftPadded(LabelWidth) rtn: `${padding}${Bar}${header}` ruleLine() as pure <- rtn as String: String() blank <- String("") tableWidth <- LabelWidth + 1 + ((Size + 1) * (CellWidth + 1)) label <- blank.rightPadded(LabelWidth, Rule) + Corner rtn: label.rightPadded(tableWidth, Rule) productLine() -> number as Integer <- rtn as String: rowLabel(number) for other in 0 ... Size rtn += cell(number * other) tableLines() <- rtn as List of String: List() of String rtn += headerLine() rtn += ruleLine() for number in 0 ... Size rtn += productLine(number) 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 table is not here: the game //draws it. defines text for "en" Say introduction() "Multiplication Table, by Al Sweigart al@inventwithpython.com" defines program //Multiplication Table (Big Book project 49). Prints the multiplication table up to 12 x 12. //The game decides; the Console shows, in the reader's words. MultiplicationTable() //A language with no words of its own is unset: ?: falls back to English. console <- Console(Say(language()) ?: Say("en")) console.showIntroduction() console.showTable(tableLines())
About this port
- Faithful to the book: the title, a 0..12 table with row and column labels, a
--+---separator, and every cellstr(n).rjust(3) + ' ': right-justified to three, then a space. - Idioms:
- Ranges (
for number in 0 ... Size) instead of counters;0 ... 12includes both ends. - The header is a stream:
for column in 0 ... Size | map with cell | collect as String. leftPadded(width)right-justifies;rightPadded(width, '-')draws the separator.cell,rowLabel,headerLineandruleLineareas pure.productLineandtableLinesare not: they build their results with+=, and a pure scope may not mutate (E08120).- A method cannot be called on an interpolated or quoted literal (
`${n}`.leftPadded(3)does not parse), so the text is bound to a variable first.
- Ranges (