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