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