diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 09e42bff..efead2d0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,18 +5,37 @@ name: Build Documentation using MkDocs on: push: branches: [master] - paths: - - '**.yml' pull_request: branches: [master] +env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + +permissions: + contents: 'write' + id-token: 'write' + pull-requests: 'write' jobs: build: name: Build and Deploy Documentation runs-on: ubuntu-latest + steps: + - name: Checkout Branch + uses: actions/checkout@v3 + if: github.event_name == 'pull_request' + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref }} + persist-credentials: false + - name: Checkout Master - uses: actions/checkout@v2 + uses: actions/checkout@v3 + + if: github.event_name == 'push' + with: + fetch-depth: 0 + persist-credentials: false - name: Set up Python 3.7 uses: actions/setup-python@v2 @@ -27,7 +46,11 @@ jobs: run: | python -m pip install --upgrade pip pip install mkdocs-material - + + - name: Check + run: | + pwd + ls -la - name: Deploy run: | git pull diff --git a/.vscode/settings.json b/.vscode/settings.json index 9a49861c..59185018 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,37 @@ { "cSpell.words": [ - "Mojhave", - "Trinkit", "coderdojo", + "Colab", + "Docstrings", + "Dunder", + "elif", + "endswith", + "Falsiness", + "findall", + "Frozensets", + "isalnum", + "isalpha", + "isdigit", + "isinstance", + "itertools", "jupyter", - "randint" + "matplotlib", + "MNIST", + "Mojhave", + "nonlocal", + "onscreenclick", + "pendown", + "penup", + "randint", + "readlines", + "setheading", + "skulkt", + "Skulpt", + "Spyder", + "startswith", + "Thonny", + "Trinkit", + "xcor", + "ycor" ] } \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..9ab2fdca --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,84 @@ +# Beginning Python — Project Instructions + +## Core Teaching Philosophy + +**The primary teaching tool in Chapters 1–18 is inline interactive turtle graphics powered by Skulpt.** + +Every lesson in the early chapters must include at least one Skulpt lab where the student can: +1. **Read** a short, working Python program +2. **Run** it instantly in the browser (no install, no account) +3. **Modify** it — change a number, a color, a direction — and run it again + +This "see it, run it, modify it" cycle is the heartbeat of this textbook. It is what separates +it from a static reference and makes it usable in coding club or classroom setting. + +### Predict Before You Run + +Before every Skulpt lab, ask the student to **predict what the program will do** before +clicking Run. This one habit — pausing to reason through code before executing it — is +one of the most valuable skills a beginning programmer can build. + +Monty frames the prediction using `mascot-thinking`: + +```markdown +!!! mascot-thinking "What Do You Think Will Happen?" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + Before you click Run, look at the program below. + How many sides do you think the turtle will draw? + Make your guess, then run it to find out! +``` + +**Rules for prediction prompts:** +- Ask one specific, answerable question (shape drawn, number of lines printed, color used, how many times the loop repeats, etc.) — not an open-ended "what happens?" +- Place the `mascot-thinking` prediction prompt **immediately above** the Skulpt lab block, before the student can run the code +- After the lab, add a brief "Were you right?" sentence in prose to close the loop — no second admonition needed +- Keep the prediction question at a difficulty level where roughly half the students will guess correctly on their first try — too easy builds no habit, too hard discourages guessing + +### Learning Checks + +For every important concept, include at least one **Learning Check** — a Skulpt lab where: +- The program is **almost complete** but is missing one key line the student must add, OR +- The program contains a **small, deliberate bug** the student must find and fix + +Learning checks should be clearly labeled and framed by Monty so students know they are being +asked to think, not just read. Use `mascot-thinking` for "add the missing line" challenges and +`mascot-warning` for "find the bug" challenges. + +**Learning Check format:** +```markdown +!!! mascot-thinking "Your Turn — Add the Missing Line" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + The program below draws three sides of a square but stops short. + Add **one line** to make it draw the fourth side and complete the shape! +``` + +Followed immediately by a Skulpt lab whose textarea contains the incomplete or buggy program. + +## Content Generation Guidelines + +**Read `CONTENT-GENERATION-GUIDELINES.md` before generating any student-facing content.** + +That file is the authoritative source for: +- Monty the Python mascot usage (admonition types, image paths, placement rules, hard limits) +- Skulpt lab HTML block structure and required element IDs +- General writing style (audience ages 10–14, post-Scratch, encouraging tone) + +Key rules to keep in mind at all times: + +- **Mascot max 6 admonitions per lesson** — never back-to-back +- **Always open with `mascot-welcome`** and **close with `mascot-celebration`** +- **Image path depth matters**: chapters live two levels deep → use `../../img/mascot/` +- **Never use `` tags** — always `![alt](path){ class="mascot-admonition-img" }` +- **Skulpt element IDs are fixed** — `skulpt.js` depends on them; do not rename them +- Instructor-facing content (teachers' guide, course description) does NOT use the mascot + +## Chapter Structure + +38 chapters covering 450 concepts, all validated with 0 dependency violations. +Chapter files live in `docs/chapters/##-slug/index.md`. +The chapter concept assignment is the source of truth for which concepts belong where. + +## MkDocs + +- Do NOT add `- navigation.tabs` to mkdocs.yml. +- Do not start or kill `mkdocs serve` — the user runs it in their own terminal. diff --git a/CONTENT-GENERATION-GUIDELINES.md b/CONTENT-GENERATION-GUIDELINES.md new file mode 100644 index 00000000..8da7eb45 --- /dev/null +++ b/CONTENT-GENERATION-GUIDELINES.md @@ -0,0 +1,588 @@ +# Content Generation Guidelines — Beginning Python + +This file defines rules for generating student-facing content in this course. +All AI agents and human authors creating lessons, labs, quizzes, or other +student-facing pages must follow these guidelines. Instructor-facing content +(teacher's guide, course description) does not need to use the mascot. + +--- + +## Primary Teaching Tool: Inline Interactive Turtle Graphics + +**The core feature of this textbook is inline Skulpt turtle graphics that run directly in the browser.** + +In Chapters 1–18, every lesson must teach through interactive turtle programs, not static +code listings. Students click **Run**, watch Monty draw something on the canvas, then +immediately modify the code and run it again — all without installing anything or leaving +the page. This live feedback loop is what makes the textbook engaging for ages 10–14. + +### The "See It, Run It, Modify It" Cycle + +Every Skulpt lab follows this three-phase experience: + +1. **See it** — a short (5–15 line) working turtle program appears in the editable textarea, + accompanied by a prose explanation of what it does. +2. **Run it** — the student clicks Run and sees the turtle draw something on the canvas to + the right of the code. +3. **Modify it** — the Experiments section at the bottom of each lesson gives 3–5 specific + invitations to change the code: a different color, a different number of sides, a new + shape, a faster speed, etc. + +**This cycle is the heartbeat of the textbook.** Do not replace it with static code blocks, +output screenshots, or off-site links (e.g., Trinket) in any lesson for Chapters 1–18. + +### Predict Before You Run + +Before every Skulpt demo lab, Monty asks the student to **predict what the program will do +before clicking Run.** Pausing to reason through code before executing it is one of the most +transferable habits a beginning programmer can build — it trains the mental model that lets +students debug independently instead of changing things at random. + +**Placement:** the prediction prompt goes **immediately above** the Skulpt lab block, before +the student can run the code. + +**Format — use `mascot-thinking`:** + +```markdown +!!! mascot-thinking "What Do You Think Will Happen?" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + Before you click Run, look at the code below. + How many sides do you think the turtle will draw? Make your guess — then find out! +``` + +**Rules:** + +| Rule | Detail | +|------|--------| +| Ask one specific question | "How many sides?" / "What color?" / "How many times will the loop run?" — not vague "What happens?" | +| Calibrate difficulty | Aim for ~50% correct on a first guess — easy enough to attempt, surprising enough to build the habit | +| Close the loop | After the lab, add one short prose sentence ("Were you right?") — no second admonition needed | +| Skip in Learning Checks | Learning Check labs already give the student a task; stacking a prediction on top causes overload | +| Counts toward mascot cap | Prediction `mascot-thinking` and concept `mascot-thinking` both count in the 6-per-lesson limit | + +### Learning Checks + +For every important concept, include at least one **Learning Check** — a second Skulpt lab +(distinct from the main demo) where the student must actively produce or repair code: + +| Type | When to use | Admonition | +|------|-------------|------------| +| **Add the missing line** — program stops short or gives the wrong result until the student adds one key line | Introducing a new command or concept | `mascot-thinking` | +| **Find and fix the bug** — program has a small deliberate error (wrong method name, off-by-one in `range()`, missing `pendown()`, etc.) | After a concept has been introduced | `mascot-warning` | + +**Learning Check format — missing line:** + +```markdown +!!! mascot-thinking "Your Turn — Add the Missing Line" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + The program below draws three sides of a square and then stops. + Add **one line** so Monty completes the fourth side! + +[Skulpt lab block with the incomplete program in the textarea] +``` + +**Learning Check format — find the bug:** + +```markdown +!!! mascot-warning "Spot the Bug!" + ![Monty warning](../../img/mascot/warning.png){ class="mascot-admonition-img" } + Something is wrong with the program below — Monty draws a straight line + instead of a triangle. Can you find and fix the mistake? + +[Skulpt lab block with the buggy program in the textarea] +``` + +### Skulpt Lab Sizing for Turtle Programs + +Keep programs short enough that students can read the whole thing at a glance: + +- **Introductory labs (Chapters 1–5):** 4–8 lines of Python +- **Mid-course labs (Chapters 6–18):** 8–20 lines of Python +- **Advanced labs (Chapters 19+):** no strict limit, but prefer several short focused labs over one long one + +### When to Use Each Lab Type + +There are two Skulpt lab layouts. Choose based on whether the program uses turtle graphics: + +| Situation | Lab type | HTML class | +|-----------|----------|------------| +| Program uses `import turtle` or any turtle command | **Drawing lab** | *(no extra class — default)* | +| Program uses only `print()`, variables, loops, functions, etc. | **Text-only lab** | `class="skulpt-text-only"` | + +**Drawing labs** (Chapters 1–18 turtle lessons) show a 400 × 400 px canvas to the right of the +code editor where the turtle draws. + +**Text-only labs** hide the canvas panel entirely; the code editor stretches to fill the full +content width. Use these for any program that produces only text output — `print()` calls, +variable values, string results, etc. This layout is the default from Chapter 19 onward, and +can also appear in earlier chapters for the rare non-turtle concept (e.g., a `print()`-only +variable lesson). + +Never put a text-only lab in a lesson that also needs the canvas, and never put a drawing +lab in a lesson whose programs do not call any turtle commands — the empty canvas just +wastes space and confuses students. + +--- + +## Lesson Structure Requirements + +These rules apply to every student-facing lesson page regardless of chapter. + +### Learning Objectives + +Every lesson must open with 1–3 student-facing learning objectives written in plain English. +Place them **before** the `mascot-welcome` admonition so students know what they are working +toward before Monty speaks. + +**Format:** + +```markdown +By the end of this lesson you'll be able to: + +- Draw a square using a `for` loop with `forward()` and `right()` +- Explain why loops save you from writing the same line four times +- Change the number of sides to draw any regular polygon +``` + +**Rules:** + +- Write from the student's perspective: "you'll be able to…" +- Use concrete, observable verbs: *draw, write, fix, explain, change, build* — never "understand" or "know about" +- 1 objective = 1 new concept; if you have 4+ objectives the lesson is too broad — split it into two lessons +- Keep language at a 5th-grade reading level — no jargon in the objectives themselves; define it later in the lesson + +### Scratch Bridge + +For every new concept in Chapters 1–14 that has a Scratch analogue, include a **Scratch Bridge** +callout immediately after the concept is first introduced. This is the highest-leverage move for +this audience — students already have a working mental model from Scratch; connecting to it +explicitly saves significant cognitive effort. + +**Format — use `mascot-tip` with the label "Scratch Bridge":** + +```markdown +!!! mascot-tip "Scratch Bridge" + ![Monty with a tip](../../img/mascot/tip.png){ class="mascot-admonition-img" } + In Scratch you used the **"Move 10 steps"** block. + In Python, `forward(10)` does exactly the same thing — + it tells Monty to walk forward 10 steps! +``` + +**Common Scratch-to-Python bridges:** + +| Scratch block | Python equivalent | First appears | +|---------------|-------------------|---------------| +| Move ___ steps | `forward(n)` | Ch 5 | +| Turn ↻ ___ degrees | `right(n)` | Ch 5 | +| Turn ↺ ___ degrees | `left(n)` | Ch 5 | +| Pen down / Pen up | `pendown()` / `penup()` | Ch 5 | +| Set pen color | `pencolor("red")` | Ch 5 | +| Repeat ___ | `for i in range(n):` | Ch 7 | +| If ___ then | `if condition:` | Ch 9 | +| If ___ then / else | `if condition: … else:` | Ch 9 | +| Set ___ to ___ | `variable = value` | Ch 3 | +| Say ___ | `print(...)` | Ch 1 | +| Ask ___ and wait | `input(...)` | Ch 13 | + +**Rules:** + +- Required whenever a Scratch analogue exists (Chapters 1–10); optional but encouraged in Chapters 11–14 +- Skip in Chapter 15+ — students have moved past the Scratch mental model +- Always frame Python as the natural next step — never say "in Scratch you had to…" (sounds dismissive) +- Counts toward the 6-per-lesson mascot admonition cap + +### One New Concept Per Lab + +Each Skulpt **demo lab** must introduce exactly **one new concept**. If a lesson covers three +new turtle commands, write three short sequential labs — not one lab that introduces all three +at once. + +This is the single most important cognitive load rule in this textbook. A novice programmer +cannot simultaneously parse unfamiliar syntax, predict program behavior, and map it to prior +knowledge. Isolate each new idea in its own runnable chunk. + +**Correct pattern:** Lab A shows `penup()` alone → Lab B adds `goto()` → Lab C completes the +idea with `pendown()`, each building on the last. + +**Incorrect pattern:** One lab where `penup()`, `goto()`, and `pendown()` all appear for the +first time together. + +The demo lab for any concept should be the **simplest possible program** that demonstrates +only that concept. Save combinations and creative uses for the Experiments section. + +### New Vocabulary + +When a technical term appears **for the first time**, follow this three-step rule: + +1. **Bold** the term on first use: `**parameter**` +2. Define it immediately in one plain-English sentence using a concrete analogy +3. Show it in working code on the same page + +**Example:** +> A **parameter** is information you pass into a function when you call it — like telling +> a vending machine which button to press before it does anything. + +**Additional rules:** + +- Never introduce a term in the first sentence of an explanation — establish the concept in plain English first, then name it +- Do not define two new terms in the same sentence +- Reinforce the term at least once more in the same lesson (in the explanation table, an experiment prompt, or Monty's dialogue) +- Do not bold a term on its second or later appearance — bolding signals "this is new" + +### Spaced Repetition and Spiral Review + +Each lesson must naturally use at least 2–3 concepts from **previous chapters** as background +context in its demo labs — without re-teaching them. Students consolidate earlier learning by +encountering it in new situations. + +**How to apply:** + +- Teaching `for` loops (Ch 7)? Write the loop body using `forward()` and `right()` — reinforcing Ch 5 commands +- Teaching `if/else` (Ch 9)? Use a variable for the condition — reinforcing Ch 3 variables +- Teaching string methods (Ch 14)? Feed them from `input()` — reinforcing Ch 13 user input + +**What not to do:** + +- Do not add a "reminder" paragraph re-explaining a prior concept — just use it +- Do not re-introduce a prior concept as if new: "First, recall that `forward()` moves the turtle…" — trust that students read the earlier chapters + +### Handling Skulpt Error Messages + +Students will produce errors while modifying code. Skulpt prints tracebacks to +`
`. Lessons should prepare students to read errors calmly.
+
+**By chapter range:**
+
+| Chapters | Guidance |
+|----------|----------|
+| 1–5 | Add a short plain-text "If you see a red error message" note after the first lab. 2–3 sentences max. |
+| 6–12 | Fold error guidance into the `mascot-warning` admonition for the most likely mistake in that lesson. |
+| 13+ | Expect students to read tracebacks independently. Only add notes for genuinely tricky errors (e.g., `TypeError: can only concatenate str (not "int") to str`). |
+
+**Most common Skulpt errors by chapter range:**
+
+| Chapters | Common errors |
+|----------|---------------|
+| 1–4 | `NameError` from misspelled command, wrong indentation |
+| 5–8 | Missing `pendown()`, wrong argument type passed to `forward()` |
+| 9–12 | Missing colon after `if` / `for`, wrong indentation after colon |
+| 13–18 | `TypeError` mixing `str` + `int`, `ValueError` from bad `int()` conversion |
+
+**"If you see an error" note format (Chapters 1–5):**
+
+```markdown
+**If you see a red error message:** Check your spelling — Python is case-sensitive,
+so `Forward(100)` won't work but `forward(100)` will.
+Also make sure every line inside the loop is indented by exactly 4 spaces.
+```
+
+---
+
+## Learning Mascot: Monty the Python
+
+### Mascot File Index
+
+The canonical files for this mascot. When editing any of these, update the
+others in the same turn so they stay in sync.
+
+| File | Purpose |
+|------|---------|
+| [`docs/img/mascot/neutral.png`](docs/img/mascot/neutral.png) | Default / general-purpose pose |
+| [`docs/img/mascot/welcome.png`](docs/img/mascot/welcome.png) | Chapter-opening pose |
+| [`docs/img/mascot/thinking.png`](docs/img/mascot/thinking.png) | Key-concept / prediction / learning-check pose |
+| [`docs/img/mascot/tip.png`](docs/img/mascot/tip.png) | Hint / Scratch Bridge / helpful-guidance pose |
+| [`docs/img/mascot/warning.png`](docs/img/mascot/warning.png) | Common-mistake / bug-fix / pitfall pose |
+| [`docs/img/mascot/encouraging.png`](docs/img/mascot/encouraging.png) | Difficult-content / struggle pose |
+| [`docs/img/mascot/celebration.png`](docs/img/mascot/celebration.png) | End-of-lesson / achievement pose |
+| [`docs/css/mascot.css`](docs/css/mascot.css) | Custom admonition styles for the seven pose contexts |
+| [`docs/learning-graph/mascot-test.md`](docs/learning-graph/mascot-test.md) | Rendering test page that exercises every admonition style |
+
+### Character Overview
+
+- **Name**: Monty
+- **Species**: Python snake
+- **Personality**: Curious, encouraging, patient, playful, never sarcastic or intimidating
+- **Catchphrase**: "Let's code it together!"
+- **Visual**: Friendly cartoon python with bright emerald-green scales, oversized round wire-rim
+  glasses, large sparkling blue-green eyes, two small expressive arms, and a curling tail.
+  Flat vector style, transparent background, consistent across all poses.
+
+### Voice Characteristics
+
+- Uses simple, encouraging language appropriate for ages 10–14
+- Celebrates small wins — never dismisses a question as "easy"
+- Refers to students as "coders" or "programmers"
+- Occasionally uses Python puns ("Let's uncoil this problem!", "I've got a hiss-tory of coding!")
+- Never uses jargon without defining it first
+- Signature phrases: "Let's code it together!", "You've got this!", "Great question!"
+
+### Mascot Admonition Format
+
+**Always** place mascot images in the admonition body, never in the title bar.
+Use the Markdown image syntax with the `mascot-admonition-img` class:
+
+```markdown
+!!! mascot-welcome "Welcome to This Lesson!"
+    ![Monty waving welcome](../../img/mascot/welcome.png){ class="mascot-admonition-img" }
+    Admonition text goes here after the image. Keep it to 1–3 sentences.
+```
+
+**Image path depth:** The path `../../img/mascot/` is correct for pages two
+directories deep (e.g., `chapters/05-drawing-with-turtle/` or `skulpt/02-simple-square/`).
+For pages at the root of `docs/`, use `img/mascot/`.
+For pages one level deep (e.g., `docs/strategy/index.md`), use `../img/mascot/`.
+
+### Placement Rules
+
+| Context | Admonition Type | Image | Frequency |
+|---------|----------------|-------|-----------|
+| Lesson opening | `mascot-welcome` | `welcome.png` | Once per lesson — always first |
+| Prediction prompt | `mascot-thinking` | `thinking.png` | Once per demo lab |
+| Key concept or insight | `mascot-thinking` | `thinking.png` | 1–2 per lesson |
+| Scratch Bridge | `mascot-tip` | `tip.png` | Once per new concept with a Scratch analogue |
+| Helpful hint or shortcut | `mascot-tip` | `tip.png` | As needed |
+| Common mistake / pitfall | `mascot-warning` | `warning.png` | As needed |
+| Find-the-bug Learning Check | `mascot-warning` | `warning.png` | Once per learning check of this type |
+| Difficult content | `mascot-encourage` | `encouraging.png` | Where students may struggle |
+| End of lesson / experiments | `mascot-celebration` | `celebration.png` | Once per lesson — always last |
+| General sidebar | `mascot-neutral` | `neutral.png` | As needed |
+
+### Hard Limits
+
+- **Maximum 6 mascot admonitions per lesson** — more than this interrupts reading flow
+- **No back-to-back mascot admonitions** — always separate with at least one paragraph of content
+- **One `mascot-welcome` maximum per lesson** — always at the very start (after learning objectives)
+- **One `mascot-celebration` maximum per lesson** — always at the very end
+- Do not use mascot admonitions purely for decoration — every use must add instructional value
+
+### Do's and Don'ts
+
+**Do:**
+- Use Monty to introduce new topics warmly at the start of every lesson
+- Include the catchphrase "Let's code it together!" in welcome admonitions
+- Keep dialogue brief (1–3 sentences maximum)
+- Match the pose image to the content type (tip pose for Scratch Bridge and hints, warning pose for bugs and pitfalls)
+- Write in Monty's encouraging, kid-friendly voice
+
+**Don't:**
+- Use Monty more than 6 times in a single lesson
+- Put mascot admonitions back-to-back without intervening content
+- Change Monty's personality or make him sound sarcastic or intimidating
+- Use `` HTML tags — always use Markdown image syntax with `{ class="mascot-admonition-img" }`
+- Place images in the admonition title bar
+
+---
+
+## Skulpt Lab Format
+
+All Skulpt interactive labs share a common structure. Follow this template exactly
+when generating a new lesson page.
+
+### Page Structure
+
+```markdown
+# Lesson Title
+
+By the end of this lesson you'll be able to:
+
+- [Objective 1 — concrete, observable, student-facing]
+- [Objective 2]
+- [Objective 3 — maximum 3; if you need more, split the lesson]
+
+Brief intro paragraph (1–2 sentences setting up what problem the code solves or what
+the student will build).
+
+!!! mascot-welcome "Welcome to This Lesson!"
+    ![Monty waving welcome](../../img/mascot/welcome.png){ class="mascot-admonition-img" }
+    1–3 sentences from Monty introducing the lesson. Include "Let's code it together!"
+
+## [Concept Name]
+
+One short paragraph introducing the new concept in plain English **before** naming it
+technically. Bold the term on first use and define it with an analogy.
+
+[Scratch Bridge admonition here if a Scratch analogue exists — use mascot-tip]
+
+## Sample Code
+
+```python
+[working turtle program — as short as possible for this concept]
+```
+
+!!! mascot-thinking "What Do You Think Will Happen?"
+    ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" }
+    [One specific, answerable prediction question about the code above.]
+    Make your guess — then click Run to find out!
+
+## Try It Now
+
+Edit the code below and click **Run** to see the result right on this page.
+No account needed — everything runs in your browser.
+
+[Skulpt lab HTML block — see below]
+
+Were you right? [One sentence closing the prediction loop.]
+
+[Optional: "If you see a red error message" note for Chapters 1–5 only]
+
+## How It Works
+
+[Explanation of the key concept. Use the bolded term again here to reinforce it.]
+
+[Optional mascot-tip for a helpful shortcut, OR mascot-encourage for a hard idea]
+
+## Explanation Table
+
+| Line | What it does |
+|------|-------------|
+| `import turtle` | Loads the turtle library so Python knows how to draw |
+| ... | ... |
+
+[Optional mascot-warning for a common mistake — include brief "If you see…" guidance]
+
+## Learning Check
+
+!!! mascot-thinking "Your Turn!"
+    ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" }
+    [Clear task description — add one line, or spot the bug.]
+
+[Skulpt lab block with the incomplete or buggy program]
+
+## Experiments
+
+Try these changes to the code above. For each one, predict what will happen first,
+then run it to check!
+
+1. [Specific change to make.] **You'll know it worked when** [observable result].
+2. [Specific change to make.] **You'll know it worked when** [observable result].
+3. [Specific change to make.] **You'll know it worked when** [observable result].
+4. [Optional harder challenge.]
+5. [Optional creative challenge — no single right answer.]
+
+!!! mascot-celebration "Great Work!"
+    ![Monty celebrating](../../img/mascot/celebration.png){ class="mascot-admonition-img" }
+    You've completed this lesson — and that's something to celebrate!
+    Try the experiments above to go even further. Let's code it together!
+```
+
+### Skulpt HTML Block
+
+There are two lab templates. Pick based on whether the program uses turtle graphics
+(see [When to Use Each Lab Type](#when-to-use-each-lab-type)).
+
+The CDN `
+
+```
+
+#### Drawing Lab (turtle programs)
+
+Use when the program calls `import turtle` or any turtle command.
+The canvas appears to the right of the code editor.
+
+```html
+
+
+ +
+ + +
+

+  
+
+
+
+
+``` + +#### Text-Only Lab (print/variables/logic — no turtle) + +Use when the program produces only text output. Add `class="skulpt-text-only"` to +the outer div. The canvas container is hidden by CSS; the editor fills the full +content width. The `turtle-target` div must still be present so `runSkulpt()` can +initialise without errors — it just isn't visible. + +```html +
+
+ +
+ + +
+

+  
+
+
+
+
+``` + +#### Rules that apply to both templates + +- The Python code inside ` +
+ + +
+

+  
+  
+
+
+ + + +
+
+ +
+ + +
+

+  
+
+
+
+
+``` + +Do not add the ` + + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? You should see three lines of text appear, one for each `print()` call — Python runs them in order from top to bottom. + +**If you see a red error message:** Check your spelling carefully. Python is case-sensitive, so `Print("Hello")` with a capital P won't work — it must be `print("Hello")` in all lowercase. Also make sure you have both an opening `"` and a closing `"` around your text. + +## How print() Works + +Each `print()` line runs one at a time, from the top of the program to the bottom — exactly the same order Scratch runs blocks inside a script. When Python sees `print("Hello, world!")` it does three things: + +1. Reads the function name: `print` +2. Reads the text inside the parentheses: `"Hello, world!"` +3. Displays that text, then moves to the next line + +The quote marks around the text are important. They tell Python that `"Hello, world!"` is a piece of text — what programmers call a **string**. A string is any sequence of characters (letters, numbers, spaces, punctuation) wrapped in quote marks. Without the quotes, Python would think you are writing the name of a variable or a command it does not recognize. + +| Line | What it does | +|------|-------------| +| `print("Hello, world!")` | Displays the text: Hello, world! | +| `print("My name is Monty.")` | Displays the text: My name is Monty. | +| `print("Let's learn Python!")` | Displays the text: Let's learn Python! | + +## Writing Comments with # + +As your programs grow longer, it becomes helpful to leave notes for yourself and for anyone else who reads your code. In Python, a **comment** is a note that the interpreter completely ignores when running the program — it exists only for human readers. + +You start a comment by typing a `#` character (called a hash or pound sign). Everything on that line after the `#` is treated as a note, not as code. + +```python +# This line is a comment — Python ignores it completely +print("But Python runs this line!") + +# Comments explain the WHY behind your code +print("They make programs easier to read.") +``` + +Good programmers use comments constantly. A comment does not change what the program does — it just helps the next person (often you, six months later) understand what you were thinking. + +## Case Sensitivity + +Python is **case-sensitive**, which means uppercase and lowercase letters are treated as completely different things. The command `print` and the word `Print` are not the same. + +!!! mascot-warning "Capital Letters Matter!" + ![Monty warning](../../img/mascot/warning.png){ class="mascot-admonition-img" } + One of the most common first-week mistakes is typing `Print("Hello")` with a capital P. Python will respond with a `NameError: name 'Print' is not defined` message. The fix is simple: always use lowercase `print()`. This rule applies to every Python command — `Forward` is not the same as `forward`, and `Turtle` (capital T) refers to something different from `turtle` (lowercase t). When you are learning a new command, always double-check the capitalization. + +## Blank Lines Make Code Readable + +Python does not care about blank lines — you can add as many empty lines as you like between statements and the interpreter ignores them all. But *human readers* care a great deal. + +Blank lines divide your code into logical groups, the same way paragraph breaks divide a story into scenes. Two lines of code that do the same task belong together; two lines that do different tasks should be separated with a blank line (and optionally a comment label). + +```python +# --- Introduction --- +print("Welcome to my program!") +print("Let's get started.") + +# --- Main message --- +print("Python is fun to learn.") +print("You are doing great!") +``` + +Get into the habit early: if two chunks of code do different jobs, separate them with a blank line. Your programs will be much easier to read — and to fix when something goes wrong. + +## Importing Libraries with import + +One of Python's greatest strengths is its huge collection of pre-built tools. You can bring any of those tools into your program with an **`import` statement**. + +The keyword `import` tells the Python interpreter: "I need this extra toolkit — please load it before running the rest of my program." By itself Python knows how to do many things (`print`, basic math, and more), but libraries like `turtle`, `random`, and `math` must be imported before you can use them. + +An import statement always goes at the very **top** of your program — before any other code — so Python loads the library before it needs it. + +```python +import turtle # Load the turtle library +``` + +After that one line, everything in the turtle library is available to your program. + +## Drawing with import turtle + +The **turtle** library lets you draw pictures by moving a virtual pen around the screen. Imagine a tiny turtle holding a pen. When you tell the turtle `forward(100)`, it walks forward 100 steps and draws a line as it goes. When you tell it `right(90)`, it pivots 90 degrees clockwise. + +Every turtle program starts the same way: + +```python +import turtle +t = turtle.Turtle() +``` + +The first line loads the library. The second line creates a turtle and gives it the name `t`. Once you have a turtle, you direct it using dot notation — `t.forward(100)` means "tell turtle `t` to go forward 100 steps." + +## Sample Code: Drawing a Shape + +Here is a short turtle program. It calls `forward(100)` and `right(90)` several times in a row: + +```python +import turtle + +t = turtle.Turtle() +t.forward(100) +t.right(90) +t.forward(100) +t.right(90) +t.forward(100) +t.right(90) +t.forward(100) +``` + +!!! mascot-thinking "What Shape Will Monty Draw?" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + Look at the program above. The turtle calls `forward(100)` four times and `right(90)` three times in between. The number 90 is the number of degrees in each right turn. How many sides will the finished shape have, and what is the name of that shape? Make your guess — then click Run to find out! + +## Try It: Turtle Graphics + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? The turtle draws a **square** — four sides of equal length with a 90-degree right turn between each side. Four turns of 90 degrees adds up to 360 degrees, which is one full rotation, so the turtle ends up facing the same direction it started. + +## How the Turtle Program Works + +Let's trace through each line: + +| Line | What it does | +|------|-------------| +| `import turtle` | Loads the turtle graphics library | +| `t = turtle.Turtle()` | Creates a new turtle and names it `t` | +| `t.forward(100)` | Moves `t` forward 100 steps, drawing a line | +| `t.right(90)` | Turns `t` clockwise by 90 degrees | + +The number inside `forward()` controls how far the turtle walks — bigger numbers draw longer lines. The number inside `right()` controls how sharply the turtle turns — 90 degrees makes a square corner. Changing these two numbers is how you draw different shapes. + +## Learning Check + +!!! mascot-thinking "Your Turn — Complete the Triangle!" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + The program below draws **two sides** of a triangle and then stops. A triangle has three equal sides, with a 120-degree right turn at each corner. Add **one line** — `t.forward(100)` — to draw the missing third side and close the triangle! + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +When you add the missing line and click Run, the turtle should draw a closed triangle. If the shape does not close, double-check that your added line spells `forward` in all lowercase and uses parentheses with the number 100 inside. + +## Experiments + +Try these changes to the programs above. For each one, **predict what will happen first** — then run it to check! + +1. **Change a message in `print()`**. Replace `"Hello, world!"` with your own name, like `print("Hello, I'm Alex!")`. **You'll know it worked when** your name appears in the output box. + +2. **Add a fourth `print()` line** with a message of your choice. **You'll know it worked when** four lines of text appear in the output, not three. + +3. **Change `forward(100)` in the square to `forward(200)`**. **You'll know it worked when** the square is twice as wide and tall. + +4. **Draw a different shape**: change the square program to use `right(60)` and repeat `forward(100)` and `right(60)` six times. **You'll know it worked when** you see a six-sided hexagon. + +5. **Challenge — change the speed**: add the line `t.speed(1)` right after `t = turtle.Turtle()` in the square program. Run it and watch what happens. Then try `t.speed(10)`. **You'll know it worked when** the drawing speed visibly changes between the two runs. + +!!! mascot-celebration "Fantastic Work!" + ![Monty celebrating](../../img/mascot/celebration.png){ class="mascot-admonition-img" } + You just wrote your very first Python programs — and they actually ran! You used `print()` to display messages, `#` to write comments, `import` to load a library, and `import turtle` to draw a shape on screen. That is nine brand-new concepts in one chapter, and you handled every single one. You have got this — let's keep coding together! diff --git a/docs/chapters/02-python-code-structure/index.md b/docs/chapters/02-python-code-structure/index.md new file mode 100644 index 00000000..0c6f6bef --- /dev/null +++ b/docs/chapters/02-python-code-structure/index.md @@ -0,0 +1,360 @@ +--- +title: Python Code Structure +description: Learn how Python uses indentation to group code, discover Python keywords, and add named colors to your turtle drawings. +generated_by: claude skill chapter-content-generator +date: 2026-06-28 08:35:09 +version: 0.09 +--- + +# Python Code Structure + +## Summary + +Python has a very clean look: instead of curly braces or `begin/end` keywords, +it uses **indentation** (spaces) to group lines of code together. +This chapter explores those rules — indentation, code blocks, statements, +whitespace — plus Python keywords and named colors that you'll use with turtle. + +## Concepts Covered + +This chapter covers the following 7 concepts from the learning graph: + +1. Multi-Line Strings +2. Indentation as Syntax +3. Python Keywords +4. Code Block Structure +5. Statement vs Expression +6. Whitespace Rules +7. Named Colors + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 1: Welcome to Python and Skulpt](../01-welcome-to-python/index.md) + +--- + +By the end of this lesson you'll be able to: + +- Write multi-line text using triple quotes +- Explain why Python uses indentation to group lines of code together +- Recognize Python keywords and understand why they cannot be used as variable names +- Use named colors like `"red"` and `"forestgreen"` in turtle graphics programs + +In Chapter 1 you wrote your first Python lines: `print()`, comments, and a turtle drawing. Now you are ready to look at how Python is *structured* — the rules that govern how code is arranged on the page and what makes a Python program readable and correct. + +!!! mascot-welcome "Welcome Back, Coder!" + ![Monty waving welcome](../../img/mascot/welcome.png){ class="mascot-admonition-img" } + Ready to go deeper? This chapter is all about how Python code is organized — and the rules are simpler than you might think. By the end you will also make your turtle drawings way more colorful. Let's code it together! + +## Multi-Line Strings + +In Chapter 1 you used `print()` to display text surrounded by double quotes, like `"Hello, world!"`. That works great for short messages on one line. But what if you want to write several lines of text stored in a single variable? + +Python solves this with a **multi-line string** — a string that spans multiple lines, created by wrapping text in **triple quotes**: three double-quote marks (`"""`) or three single-quote marks (`'''`). Everything between the opening triple quotes and the closing triple quotes — including line breaks — becomes part of the string. + +```python +haiku = """An old silent pond. +A frog jumps into the pond. +Splash! Silence again.""" +print(haiku) +``` + +**Before you click Run:** how many lines do you think will appear in the output? Count the line breaks inside the triple quotes to make your prediction! + +## Try It: Multi-Line Strings + + + + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? Three lines appear — one for each line inside the triple quotes. The variable `haiku` holds all three lines as a single string, and `print()` displays them all at once with the line breaks preserved. + +## How Multi-Line Strings Work + +A regular string uses one pair of quotes: `"Hello"`. A multi-line string uses three pairs: `"""Hello"""`. The triple quotes tell Python: "keep reading until you see three more quotes — no matter how many line breaks are in between." + +| Syntax | Can span multiple lines? | Example | +|--------|-------------------------|---------| +| `"text"` | No — one line only | `"Hello, world!"` | +| `'text'` | No — one line only | `'Hello, world!'` | +| `"""text"""` | Yes | `"""Line one\nLine two"""` | +| `'''text'''` | Yes | `'''Line one\nLine two'''` | + +Multi-line strings are useful for writing poems, paragraphs, or any block of text you want to keep together in one variable. + +## Indentation as Syntax + +Most programming languages use **curly braces** `{ }` or the words `begin` and `end` to show that lines of code belong together. Python does something different — it uses **indentation**: the number of spaces at the start of each line. + +**Indentation** means pressing the spacebar (or the Tab key) before a line of code to push it to the right. In Python, indentation is not just for looks — it is part of the grammar of the language. Python reads the spaces at the start of a line to decide which lines belong together. + +!!! mascot-tip "Scratch Bridge" + ![Monty with a tip](../../img/mascot/tip.png){ class="mascot-admonition-img" } + In Scratch, you put blocks *inside* another block (like a Repeat block) by dragging them so they snap together inside it. In Python, you put lines *inside* a group by **indenting** them — adding 4 spaces at the start. The visual nesting you saw in Scratch now lives in those 4 spaces of whitespace. + +Here is a preview of what indentation looks like in action. You have not learned `for` loops yet — that is Chapter 7 — but look at the spacing pattern right now: + +```python +# PREVIEW — you will learn for loops in Chapter 7 +# For now, just notice the indentation pattern + +for i in range(4): # This line starts at the left edge + t.forward(100) # These two lines are indented 4 spaces + t.right(90) # They belong INSIDE the for loop +``` + +The two lines with 4 spaces before them are *inside* the loop. The `for` line itself is at the left edge. That difference in spacing is what Python uses to know which lines are part of the loop — not braces, not keywords, just spaces. + +!!! mascot-warning "IndentationError — The Most Common Python Mistake" + ![Monty warning](../../img/mascot/warning.png){ class="mascot-admonition-img" } + If you accidentally put too many spaces, too few spaces, or mix tabs with spaces, Python will stop and show you an `IndentationError`. This is one of the most common errors beginners see. The fix is always the same: use exactly **4 spaces** for each level of indentation, and never mix tabs and spaces. Most code editors (including Skulpt) automatically insert 4 spaces when you press Tab. + +## Code Block Structure + +A **code block** is a group of lines that belong together because they are all indented at the same level. Every block starts after a line that ends with a colon `:`, and every line in the block is indented by exactly 4 more spaces than the line that opened it. + +You will see this pattern constantly in Python: + +```python +some_statement: # colon opens a block + first line # 4 spaces — inside the block + second line # 4 spaces — still inside the block + third line # 4 spaces — still inside the block +back_to_normal # 0 spaces — block is over +``` + +Right now all your programs are a flat list of lines with no blocks. That changes when you reach loops (Chapter 7) and conditionals (Chapter 9). When you get there, you will already understand how blocks work — because you are learning it now. + +## Whitespace Rules + +Whitespace is the name for any invisible characters in your code: spaces, tabs, and blank lines. Python has clear rules about how whitespace is used: + +- **Inside a line:** add a single space around operators (`2 + 3`, not `2+3`) to make expressions easier to read. Python ignores extra spaces inside a line, but one space is the convention. +- **At the start of a line:** these spaces are *indentation* and they matter to Python (see above). +- **Blank lines:** Python ignores blank lines completely. Use them to separate logical sections of your program. + +Here is the same turtle program written two ways: + +```python +# Hard to read — no whitespace +import turtle +t=turtle.Turtle() +t.forward(100) +t.right(90) +t.forward(100) +``` + +```python +# Easy to read — good whitespace +import turtle + +t = turtle.Turtle() + +t.forward(100) +t.right(90) +t.forward(100) +``` + +Both programs do exactly the same thing. The second one is much easier to read at a glance. Good programmers always choose the second style. + +## Python Keywords + +Python reserves certain words for its own use. These are called **keywords** — words that already mean something specific in the Python language and cannot be used as names for your variables or functions. + +For example, `for` is a Python keyword. You cannot name a variable `for` because Python would be confused — it would not know whether you meant the loop command or a variable. The same is true for `if`, `while`, `def`, `class`, and all the others in the table below. + +Here is the complete list of Python keywords: + +| Keywords | | | | | +|---|---|---|---|---| +| `False` | `None` | `True` | `and` | `as` | +| `assert` | `async` | `await` | `break` | `class` | +| `continue` | `def` | `del` | `elif` | `else` | +| `except` | `finally` | `for` | `from` | `global` | +| `if` | `import` | `in` | `is` | `lambda` | +| `nonlocal` | `not` | `or` | `pass` | `raise` | +| `return` | `try` | `while` | `with` | `yield` | + +You do not need to memorize this list. As you write more Python programs, you will naturally come to recognize the keywords — most code editors highlight them in a different color to help you spot them at a glance. + +## Statement vs Expression + +Two words come up constantly when talking about Python code: **statement** and **expression**. They sound similar but they do different jobs. + +A **statement** is an instruction that *does* something. It performs an action. Statements do not produce a value you can store or pass around — they just act. + +An **expression** is a piece of code that *produces a value*. You can use an expression anywhere a value is expected — store it in a variable, pass it to a function, or print it. + +The table below shows examples side by side: + +| Type | Example | What it does | +|------|---------|-------------| +| Statement | `print("Hello")` | Displays text — does not produce a value | +| Statement | `import turtle` | Loads a library — does not produce a value | +| Expression | `2 + 3` | Produces the value `5` | +| Expression | `"Hello"` | Produces the string `"Hello"` | +| Expression | `100 * 2` | Produces the value `200` | + +In practice, many lines of Python combine both: `print(2 + 3)` is a *statement* (the print) that contains an *expression* (the addition). Knowing the difference helps you understand error messages — Python will tell you when it expected an expression and got a statement, or the other way around. + +## Named Colors + +The turtle library knows the names of hundreds of colors. Instead of describing a color mathematically, you can use a color's English name — a **named color** — as a string. Just pass it to `t.pencolor()` before you draw a line and the turtle will switch to that color. + +Some named colors you can use right away: + +- Common: `"red"`, `"blue"`, `"green"`, `"yellow"`, `"orange"`, `"purple"`, `"black"`, `"white"` +- Shades: `"forestgreen"`, `"skyblue"`, `"salmon"`, `"coral"`, `"gold"`, `"crimson"` +- Fun ones: `"hotpink"`, `"deepskyblue"`, `"limegreen"`, `"tomato"`, `"orchid"` + +The complete list of named colors comes from a standard called **X11 colors**, which includes 140 names. You can experiment freely — if a name does not work, you will see an error in the output box and you can try a different spelling. + +Here is a turtle program that draws a square with a different color on each side: + +```python +import turtle + +t = turtle.Turtle() + +t.pencolor("red") +t.forward(100) +t.right(90) + +t.pencolor("blue") +t.forward(100) +t.right(90) + +t.pencolor("forestgreen") +t.forward(100) +t.right(90) + +t.pencolor("orange") +t.forward(100) +``` + +!!! mascot-thinking "What Will You See?" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + Look at the program above. The turtle calls `pencolor()` four times — once before each side. How many different colors will you see in the drawing? What color will the very last side be? Make your predictions, then click Run! + +## Try It: Colored Turtle Drawing + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? Each side of the square is a different color — red, blue, forest green, and orange. Notice the blank lines in the code separating each color-change group: they do not affect how the program runs, but they make the structure immediately clear to a reader. + +## How pencolor() Works + +`t.pencolor("color name")` changes the color of the turtle's pen for all lines drawn after that call. It does not affect lines already drawn. Think of it like changing the color of a marker before drawing the next stroke. + +| Line | What it does | +|------|-------------| +| `t.pencolor("red")` | Switches the pen to red | +| `t.forward(100)` | Draws a red line 100 steps long | +| `t.pencolor("blue")` | Switches the pen to blue | +| `t.forward(100)` | Draws a blue line 100 steps long | + +The color stays set until you call `pencolor()` again with a different color. If you never call `pencolor()`, the turtle draws in black by default. + +## Learning Check + +!!! mascot-thinking "Your Turn — Add the Missing Color" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + The program below draws a three-sided shape, but the second side is missing its color change — it will draw in whatever color came before it. Add **one line** — a `t.pencolor()` call with the color `"purple"` — between the first `t.right(90)` and the second `t.forward(100)` to make the second side purple. + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +When you add the right line and click Run, you should see a triangle with sides in red, purple, and gold. If the second side is still red, check that you spelled `pencolor` in all lowercase and passed `"purple"` in quotes. + +## Experiments + +Try these changes to the programs above. For each one, predict what will happen first — then run it to check! + +1. **Write your own multi-line string.** Change the haiku in the first program to a three-line poem you make up yourself. **You'll know it worked when** your poem appears in the output, one line at a time. + +2. **Change the colors in the square program.** Replace `"red"` with `"hotpink"`, `"blue"` with `"deepskyblue"`, `"forestgreen"` with `"limegreen"`, and `"orange"` with `"gold"`. **You'll know it worked when** the square draws in your four new colors. + +3. **Add a fifth side.** In the square program, add `t.pencolor("purple")` and `t.right(90)` and `t.forward(100)` at the end. Does the result look like a square with an extra line? **You'll know it worked when** you see a fifth line drawn in purple. + +4. **Try a color that might not exist.** Change one `pencolor()` argument to `"neonblue"` and run the program. Read the error message carefully — it tells you what went wrong. Then switch it back to a valid color like `"cornflowerblue"`. + +5. **Challenge — draw a rainbow triangle.** Use three named colors of your choice to draw an equilateral triangle (three equal sides, `right(120)` at each corner). Add blank lines and comments in the code to label each side. **You'll know it worked when** you see a closed triangle with three distinct colors and clean, readable code. + +!!! mascot-celebration "Brilliant Work!" + ![Monty celebrating](../../img/mascot/celebration.png){ class="mascot-admonition-img" } + You just learned how Python organizes code — multi-line strings, indentation, keywords, code blocks, statements, expressions, and whitespace rules — and you made your turtle drawings colorful in the process. Seven concepts in one chapter, and you handled them all beautifully. Keep going — you are building real programming skills! Let's code it together! diff --git a/docs/chapters/03-variables-and-numbers/index.md b/docs/chapters/03-variables-and-numbers/index.md new file mode 100644 index 00000000..641c8dd4 --- /dev/null +++ b/docs/chapters/03-variables-and-numbers/index.md @@ -0,0 +1,378 @@ +--- +title: Variables and Numbers +description: Learn how to create variables, store integers and floats, follow Python naming conventions, and understand the None value. +generated_by: claude skill chapter-content-generator +date: 2026-06-28 08:55:45 +version: 0.09 +--- + +# Variables and Numbers + +By the end of this lesson you'll be able to: + +- Create a variable in Python and store a number inside it +- Name variables using `snake_case` and choose clear, descriptive names +- Explain the difference between an integer and a float + +Imagine you are playing a video game and you need to remember your score. +You could try to hold it in your head — but what if it changes? +What if you need that number in five different places in your code? +A **variable** solves this problem. +A variable is a labeled storage location in your program's memory. +You give it a name, put a value inside it, and Python remembers that value for you. + +!!! mascot-welcome "Welcome to Chapter 3!" + ![Monty waving welcome](../../img/mascot/welcome.png){ class="mascot-admonition-img" } + Variables are one of the most powerful ideas in all of programming — and you've already used them in Scratch! Today we learn how Python does the same thing with just a few keystrokes. Let's code it together! + +## What Is a Variable? + +Picture a sticky note on your desk. +The front has a name written on it — like **score** — and on the back you write the current value, like **10**. +Whenever you need to know the score, you flip it over and read it. +If the score changes, you erase the old number and write a new one — but the name on the front stays the same. + +In Python, a variable works exactly like that sticky note. +You create a variable by writing its name, then an equals sign, then the value you want to store. +This is called **variable assignment**: + +```python +score = 10 +``` + +- The name on the left (`score`) is the variable's label. +- The equals sign (`=`) means "store this value in this name." +- The value on the right (`10`) is what gets stored. + +Notice that `=` in Python does **not** mean "is equal to" the way it does in math. +It is a one-way instruction: "take the value on the right and put it in the box on the left." +The value flows from right to left, always. + +After you store a value, you can read it back using `print()`: + +```python +score = 10 +print(score) +``` + +!!! mascot-tip "Scratch Bridge" + ![Monty with a tip](../../img/mascot/tip.png){ class="mascot-admonition-img" } + In Scratch, you clicked the **"Set score to 10"** block to create a variable and give it a starting value. In Python, `score = 10` does exactly the same thing — same idea, just written as text instead of snapped together as blocks! + +## Sample Code + +Here is a short program that creates two variables and prints both of them. +Read through it before you run it. + +```python +score = 10 +lives = 3 +print(score) +print(lives) +``` + +!!! mascot-thinking "What Do You Think Will Happen?" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + Before you click Run, look at those four lines. The program stores two numbers and then prints them. What do you think the output will look like — will both numbers appear, or just one? And in what order? Make your prediction, then click Run to find out! + +## Try It Now + +Edit the code below and click **Run** to see the result right on this page. +No account needed — everything runs in your browser. + + + + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? +Python printed `10` on the first line and `3` on the second — one value per `print()` call, in the order they appeared. + +**If you see a red error message:** Check your spelling carefully. +Python is case-sensitive, so `Score = 10` and `score = 10` are two completely different variables. +Make sure there are no extra spaces around the `=` sign. + +## How It Works + +When Python runs `score = 10`, it sets aside a small storage location in memory, writes `10` into it, and attaches the label `score`. +When Python then sees `print(score)`, it looks up that label, retrieves the stored value, and displays it. + +The table below explains each line of the program: + +| Line | What it does | +|------|-------------| +| `score = 10` | Creates a variable named `score` and stores the integer `10` inside it | +| `lives = 3` | Creates a second variable named `lives` and stores `3` inside it | +| `print(score)` | Looks up the value in `score` and prints it | +| `print(lives)` | Looks up the value in `lives` and prints it | + +Each variable is independent. +Changing one does not affect the other. +You can have as many variables as you like — your program's memory can hold thousands of them. + +## Naming Your Variables + +Python lets you name a variable almost anything — but there are rules you must follow: + +- **Start with a letter or underscore** — not a digit. `score` is fine; `1score` causes an error. +- **Use only letters, digits, and underscores** — no spaces, hyphens, or symbols like `@` or `!`. +- **Avoid Python keywords** — words like `print`, `for`, `if`, and `while` are reserved. Python needs those words for itself. + +Python is also **case-sensitive**: `Score`, `SCORE`, and `score` are three completely separate variables. +Mixing upper and lower case accidentally is one of the most common sources of bugs for beginners. + +### Snake_case: Python's Naming Style + +When a variable name has more than one word, Python programmers join the words with underscores and keep all letters lowercase. +This style is called **snake_case** (picture the underscores as a snake lying flat between the words). + +The table below shows common naming mistakes and their snake_case fixes: + +| Problematic name | What's wrong | Better name | +|-----------------|-------------|-------------| +| `myscore` | Words run together — hard to read | `my_score` | +| `MyScore` | Capital letters belong to a different naming style | `my_score` | +| `my score` | Spaces are not allowed in variable names | `my_score` | +| `my-score` | Python reads the dash as **subtraction** — `my - score` — not a name! | `my_score` | +| `x` | Too vague — what does `x` mean? | `player_score` | +| `s` | Single letters give no information | `lives_remaining` | + +### Meaningful Variable Names + +The best variable names describe exactly what the variable holds. +A name like `player_score` tells you immediately what the number represents. +A name like `x` gives you no information at all. + +This matters because programs grow. +A program you write today might be 10 lines — easy to keep in your head. +But programs grow to hundreds and thousands of lines. +When that happens, a good name is the difference between code you can read and code that feels like a puzzle. + +!!! mascot-warning "Naming Pitfalls!" + ![Monty warning](../../img/mascot/warning.png){ class="mascot-admonition-img" } + Watch out for the dash! If you write `my-score` instead of `my_score`, Python reads the dash as a minus sign and thinks you are subtracting a variable called `score` from a variable called `my`. Use an **underscore** (`_`), never a dash (`-`), to join words in a name. Other common traps: single-letter names like `x` that tell you nothing, capital letters that break snake_case, and accidentally using a Python keyword as your variable name. + +## Integers: Whole Numbers + +Now that you know how to create and name variables, let's look more carefully at the kinds of numbers Python understands. + +A whole number — one with no decimal point — is called an **integer**, or `int` for short. +Integers can be positive, negative, or zero. +You use integers for things you count: the number of lives in a game, the number of sides on a shape, a player's score. + +```python +sides = 6 +lives = 3 +temperature = -5 +``` + +All three of those variables hold integers. + +## Floats: Decimal Numbers + +A number with a decimal point is called a **float** — short for "floating-point number." +Floats are used for measurements and values that don't land exactly on a whole number. + +```python +price = 4.99 +height = 1.75 +pi = 3.14159 +``` + +The name "float" comes from how computers store these numbers internally — the decimal point can "float" to different positions. +You don't need to know the internal details. +What matters is when to use each type: + +| Kind | Python type | When to use | Examples | +|------|-------------|-------------|---------| +| Whole number | `int` | Counting, game scores, number of repetitions | `0`, `7`, `-12`, `1000` | +| Decimal number | `float` | Measurements, money, percentages, averages | `3.14`, `0.5`, `-2.7`, `99.0` | + +One important detail: dividing two integers with `/` always gives you a float, even when the result is a whole number. + +```python +result = 10 / 2 +print(result) +``` + +That prints `5.0`, not `5` — note the decimal point. +Python uses `//` (floor division) if you want a whole-number result: `10 // 2` gives `5`. + +## Variable Reassignment + +One of the most powerful things about variables is that you can change them. +You **reassign** a variable by writing its name again on the left side of `=` with a new value on the right. +Python discards the old value and stores the new one under the same label. + +Here is a program that changes a score partway through: + +```python +score = 10 +print(score) + +score = 25 +print(score) +``` + +Read through that before you run it. +The first `print` shows the original value. +The second assignment replaces it. +The second `print` shows the updated value. + +## Sample Code — Reassignment + +```python +score = 10 +print(score) + +score = 25 +print(score) +``` + +## Try It Now — Reassignment + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Python printed `10` first and `25` second. +The name `score` stayed the same; only the value changed. + +You can also use the current value of a variable to calculate a new one: + +```python +score = 10 +score = score + 5 +print(score) +``` + +Python evaluates the right side first: `score + 5` is `10 + 5`, which equals `15`. +Then it stores `15` back into `score`. +This pattern — "take the old value, add something, store the result back" — appears constantly in real programs. + +## None: The "Nothing" Value + +Python has one special value that is neither an integer nor a float. +It is called **None**, and its type is called `NoneType`. + +None means "no value yet" or "nothing here." +You will see it in two common situations: + +1. When you want a variable to exist but you haven't decided its value yet. +2. When a function finishes without returning anything — Python automatically gives back `None` in that case. + +```python +winner = None +print(winner) +print(type(winner)) +``` + +Running that program prints: +``` +None + +``` + +None is not zero. +None is not an empty string. +None is its own special thing that means "the absence of a value." +Think of it like a sticky note that exists on your desk but has nothing written on the back yet. + +Later in the course you will use None to mark the start of a search, represent an empty box in a game board, or signal that a function didn't find what it was looking for. + +## What `type()` Tells You + +Python has a built-in function called `type()` that tells you what kind of value is stored in a variable. +You saw it used with `None` above. +Here it is with an integer and a float: + +```python +score = 10 +price = 4.99 + +print(type(score)) +print(type(price)) +``` + +Output: +``` + + +``` + +The word `class` in the output is how Python describes categories of values. +For now, just read `` as "this is an integer" and `` as "this is a float." +You will learn much more about classes later in the course. + +## Learning Check + +!!! mascot-thinking "Your Turn — Add the Missing Line" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + The program below creates two variables — `player_score` and `bonus_points`. It prints `player_score` just fine, but something is missing: `bonus_points` never gets printed. Add **one line** so the output shows both numbers, one on each line. + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +If your output shows `42` on the first line and `10` on the second, you got it! +The missing line was `print(bonus_points)`. + +## Experiments + +Try these changes in the labs above. +For each one, predict what will happen first — then run the code to check! + +1. In Lab 1, change `score = 10` to `score = 750`. **You'll know it worked when** the output shows `750` instead of `10`. +2. In Lab 1, add a third variable called `high_score` set to `100`. Add a `print(high_score)` line. **You'll know it worked when** you see three numbers in the output. +3. In Lab 2 (the reassignment lab), change `score = 25` to `score = score * 2`. **You'll know it worked when** the output shows `10` on the first line and `20` on the second. +4. Create a float variable called `average_score` and set it to `87.5`. Print it. **You'll know it worked when** the output shows `87.5`. +5. Create a variable called `champion` and set it to `None`. Print it. Then reassign `champion` to `1`. Print it again. **You'll know it worked when** the output shows `None` on one line and `1` on the next. + +!!! mascot-celebration "You've Got Variables!" + ![Monty celebrating](../../img/mascot/celebration.png){ class="mascot-admonition-img" } + Variables, integers, floats, snake_case naming, reassignment, None — you now have the building blocks every Python program is built on. Every chapter from here uses what you just learned. Brilliant work, coder! Let's code it together! diff --git a/docs/chapters/04-functions-and-objects/index.md b/docs/chapters/04-functions-and-objects/index.md new file mode 100644 index 00000000..f2b7919f --- /dev/null +++ b/docs/chapters/04-functions-and-objects/index.md @@ -0,0 +1,408 @@ +--- +title: Functions and Objects +description: Learn how to define and call functions using def, add positional parameters, return values, document code with docstrings, and get a first look at the Standard Library and Python objects. +generated_by: claude skill chapter-content-generator +date: 2026-06-28 09:19:38 +version: 0.09 +--- + +# Functions and Objects + +By the end of this lesson you'll be able to: + +- Define a function in Python using `def` and call it by name +- Add **parameters** so a function can work with different values each time you call it +- Use a `return` statement to send a result back from a function + +Imagine you have a task you need to do over and over — say hello to each person on a list, calculate the area of many different rectangles, or draw the same shape in ten different colors. +You could write out every step every single time. +Or you could give those steps a name, write them once, and use that name whenever you need the job done. +That is exactly what a **function** does in Python. + +!!! mascot-welcome "Welcome to Chapter 4!" + ![Monty waving welcome](../../img/mascot/welcome.png){ class="mascot-admonition-img" } + Functions are one of the biggest ideas in all of programming — they save you from writing the same code twice, keep your programs neat, and let you build bigger things from smaller pieces. You have already used functions every single lesson — `print()` is a function! Today you learn how to build your own. Let's code it together! + +## What Is a Function? + +You have been calling functions since Chapter 1. +Every time you write `print("Hello")` you are calling a function called `print`. +Someone wrote the steps that make `print` work — you just call it by name and hand it a value. + +A **function** is a named group of steps that you can run any time by writing its name. + +In this chapter you learn to create your own functions — not just use the ones Python provides. +The keyword that starts a function definition is `def`, which is short for "define." + +!!! mascot-tip "Scratch Bridge" + ![Monty with a tip](../../img/mascot/tip.png){ class="mascot-admonition-img" } + In Scratch, you used **"Make a Block"** to create a custom block — a group of blocks you could snap in anywhere you needed that action. Python's `def` does exactly the same thing. You write the steps once under a name, then call that name wherever you need it. Same idea, just written as text instead of snapped together as blocks! + +## Defining a Function with `def` + +To create your own function, you write: + +1. The keyword `def` +2. The function's name (use snake_case, just like variable names from Chapter 3) +3. A pair of parentheses `()` +4. A colon `:` +5. Indented lines that contain the steps to run + +Here is the simplest possible function: + +```python +def greet(): + print("Hello, coder!") + print("Let's code it together!") +``` + +The colon at the end of the `def` line is required — just like the colons you will see later with loops and conditionals. +Everything indented below the `def` line belongs to the function body. +When Python reads this, it **remembers** the function but does not run the steps yet. +Think of it like writing a recipe on a card: writing the card is not the same as actually cooking the meal. + +## Calling a Function + +Defining a function and calling a function are two separate actions. + +- **Defining** writes the recipe under a name. +- **Calling** says "run the recipe right now." + +You call a function by writing its name followed by parentheses: + +```python +greet() +``` + +That one line triggers all the steps inside `greet`. +You can call the same function as many times as you like — Python runs the entire body each time. + +!!! mascot-thinking "What Do You Think Will Happen?" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + The program below defines `greet()` and then calls it three times. How many lines of text do you think will appear in the output? Make your prediction — then click Run to find out! + +## Try It Now + +Edit the code below and click **Run** to see the result right on this page. +No account needed — everything runs in your browser. + + + + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? +Calling `greet()` three times printed six lines — two per call. +That is the power of functions: write the steps once, run them as many times as you need. + +**If you see a red error message:** The two most common causes are a missing colon after `def greet()` or wrong indentation inside the function body. +Python requires that every line inside the function body be indented by exactly four spaces. +If the `print` lines start at the left edge instead of being indented, Python will give you an `IndentationError`. + +## How It Works + +Python reads your program from top to bottom, but it does not run the function the moment it sees `def`. +It reads and remembers the function, then keeps going. +When it finally reaches `greet()`, that is the signal — only then does it jump into the function body and run both `print` lines. +After the function body finishes, Python returns to where it left off and runs the next line. + +The table below traces each line of the program: + +| Line | What it does | +|------|-------------| +| `def greet():` | Defines a new function named `greet` — Python remembers it but does not run it yet | +| ` print("Hello, coder!")` | Step 1 inside the function body — indented 4 spaces | +| ` print("Let's code it together!")` | Step 2 inside the function body — indented 4 spaces | +| `greet()` | Calls the function — Python jumps in, runs both steps, then comes back | + +## Positional Parameters + +A function that always does the exact same thing is useful, but limited. +To make a function flexible — able to work with different values each time — you give it **parameters**. + +A **parameter** is a variable that lives inside the function and receives a value when you call it. +Think of it like a fill-in-the-blank sentence: "Hello, ______!" is the template, and the blank gets filled in with a different name every time. + +You declare parameters inside the parentheses of `def`: + +```python +def greet(name): + print("Hello, " + name + "!") +``` + +The word `name` between the parentheses is the parameter. +Inside the function body, `name` works just like any variable from Chapter 3. + +When you call this function, you supply a value: + +```python +greet("Monty") +greet("Python") +``` + +The values `"Monty"` and `"Python"` are called **arguments** — the real values you pass in at call time. +Python copies the first argument into the first parameter before running the function body. +Because the arguments line up by position (first argument goes to first parameter), they are called **positional parameters**. + +Before you click Run on the lab below, predict what you will see. +Which names will appear, and in what order? + +## Try It Now — Parameters + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Each call to `greet` used the same template — `"Hello, " + name + "!"` — but filled in a different name. +One function, three different outputs. +Try changing the names in the three call lines to greet your friends or family! + +## The `return` Statement + +So far, every function has done its work by calling `print()` directly. +But sometimes you want a function to **calculate a result and hand it back**, so the rest of your program can use that result. + +The keyword `return` sends a value back to the caller. + +Here is a function that adds two numbers and returns the sum: + +```python +def add(a, b): + result = a + b + return result +``` + +Notice that this function does **not** call `print`. +Instead it hands the result back. +You capture that returned value by storing it in a variable: + +```python +total = add(5, 3) +print(total) +``` + +When Python runs `add(5, 3)`, it copies `5` into `a` and `3` into `b`, calculates `result = 8`, and then `return result` sends `8` back. +That `8` becomes the value of `total`, which is then printed. + +The table below shows what each piece does: + +| Code | What it does | +|------|-------------| +| `def add(a, b):` | Defines a function with two parameters | +| ` result = a + b` | Adds the two parameters; stores in a local variable | +| ` return result` | Sends the sum back to whoever called `add` | +| `total = add(5, 3)` | Calls the function; the returned value `8` is stored in `total` | +| `print(total)` | Prints `8` | + +## Functions Returning None + +What happens if a function never uses `return`? + +Python still needs to hand something back to the caller. +In that case, it automatically returns a special value from Chapter 3: **None**. + +You can see this happen: + +```python +def greet(): + print("Hello, coder!") + +result = greet() +print(result) +``` + +The output will be: +``` +Hello, coder! +None +``` + +`greet()` printed a line, then Python returned `None` automatically. +When you stored that in `result` and printed it, you saw `None`. + +This is the concept called **functions returning None**: any function that finishes without a `return` statement gives back `None`. +You will not always notice this because most programs do not bother storing the return value of a `print`-only function — but it is good to know it is happening. + +!!! mascot-warning "Don't Forget `return`!" + ![Monty warning](../../img/mascot/warning.png){ class="mascot-admonition-img" } + A very common beginner bug: you write a function to calculate a value, but you forget to add `return` at the end. The function runs the calculation — but the answer disappears! The calling code gets `None` back instead of the number it expected. If you ever see `None` somewhere you expected a real number, check whether your function is missing a `return` statement. + +## Docstrings + +Professional Python programmers always document their functions with a **docstring** — a string of text that explains what the function does. + +A docstring is written on the first line inside the function body, surrounded by triple quotes (`"""`): + +```python +def add(a, b): + """Add two numbers together and return the sum.""" + result = a + b + return result +``` + +The triple quotes can span multiple lines if you need a longer explanation: + +```python +def greet(name): + """ + Print a friendly greeting to the given name. + + Parameters: + name (str): The person's name to greet. + """ + print("Hello, " + name + "!") +``` + +Docstrings serve two purposes. +First, they help the next person who reads your code — including future you — understand what the function does without reading every line. +Second, Python tools can read docstrings automatically and display them as help text. +If you type `help(add)` in a Python environment, Python shows the docstring you wrote. + +Writing docstrings is a habit worth building from the start. +In this course, every function you write from now on should have at least a one-line docstring. + +## The Standard Library: Python's Built-in Toolbox + +You have already used one piece of Python's built-in toolbox: the `print()` function. +Python ships with hundreds more pre-written functions organized into **modules** — files full of related functions that you can load into your program with the `import` keyword. + +Together, all of these modules make up the **Standard Library** — a collection of tools that comes with every Python installation, completely free. + +Here are four modules you will use throughout this course: + +| Module | What it contains | Example | +|--------|-----------------|---------| +| `math` | Mathematical functions and constants | `math.sqrt(25)` → `5.0` | +| `random` | Functions for generating random numbers | `random.randint(1, 6)` → rolls a die | +| `time` | Functions for working with time and delays | `time.sleep(1)` → pauses for 1 second | +| `turtle` | Functions and objects for drawing on screen | `turtle.forward(100)` → draws a line | + +You import a module by writing `import` followed by the module's name at the top of your program. +After that, you access its functions using dot notation — the module name, a dot, then the function name: + +```python +import math +print(math.sqrt(16)) +``` + +That prints `4.0`. +The dot connects the module (`math`) to the function inside it (`sqrt`). +You will use this pattern constantly throughout the rest of the course. + +You will meet the `turtle` module in Chapter 5, `random` in Chapter 17, `math` in Chapter 18, and many others as the course progresses. +For now, just know that the Standard Library exists and that `import` is how you unlock it. + +## Objects and Classes: A First Look + +You are almost ready to meet the `turtle` module. +Before you do, there is one more idea to preview — not fully explain, just introduce — because you will see it the moment you start drawing. + +Python organizes many things as **objects**. +An **object** is a package that bundles together two kinds of things: + +- **Data** (called attributes) — information the object knows about itself +- **Actions** (called methods) — things the object can do + +The classic example is a turtle on screen. +A turtle object knows its current position, its direction, its pen color, and whether its pen is up or down (those are its attributes). +A turtle object can move forward, turn, change color, and lift or lower its pen (those are its methods). + +When you write code like this in Chapter 5: + +```python +import turtle +t = turtle.Turtle() +t.forward(100) +t.right(90) +``` + +`turtle.Turtle()` creates a new turtle object and stores it in the variable `t`. +`t.forward(100)` calls the `forward` method on that object — same dot notation you just saw with modules. + +A **class** is the blueprint that describes what attributes and methods an object has. +`turtle.Turtle` is a class; `t` is one individual object (called an **instance**) made from that blueprint. + +You do not need to memorize all of this right now. +The important takeaway is that objects come with built-in actions — and you call those actions by writing the object's name, a dot, and the method name. +You will build the mental model step by step starting in Chapter 5, and you will write your own classes in Chapter 25. + +## Learning Check + +!!! mascot-thinking "Your Turn — Add the Missing Line" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + The function below is supposed to multiply two numbers and give the result back — but it is missing one key line. Right now, if you run the code, `product` gets `None` instead of `15`. Add **one line** inside the function so that `print(product)` shows `15`! + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +If your output shows `15`, you got it! +The missing line was `return result`. +Without it, Python silently returned `None` — and `None` is not the number you wanted. + +## Experiments + +Try these changes in the labs above. +For each one, predict what will happen first — then run the code to check! + +1. In Lab 1, change `greet()` so it prints only one line: `"Python is awesome!"`. Call it five times. **You'll know it worked when** the output shows five identical lines. +2. In Lab 2, add a fourth call: `greet("your name here")` but replace `your name here` with your actual first name. **You'll know it worked when** the output greets you personally on the fourth line. +3. In Lab 2, add a second parameter called `language` to the function so it prints `"Hello, Monty! You are learning Python."` Hint: you will need to update the `def` line and the `print` line inside the function. **You'll know it worked when** the output includes the language name. +4. In the Learning Check lab, change the call to `multiply(7, 6)`. **You'll know it worked when** the output shows `42`. +5. Write a brand-new function called `square(n)` that returns `n * n`. Call it with a few different numbers and print each result. **You'll know it worked when** `square(4)` prints `16` and `square(10)` prints `100`. + +!!! mascot-celebration "Functions Unlocked!" + ![Monty celebrating](../../img/mascot/celebration.png){ class="mascot-admonition-img" } + You just learned one of the most important skills in all of programming! `def`, parameters, `return`, `None`, docstrings, the Standard Library, and a first look at objects — that is a full chapter's worth of big ideas. In Chapter 5 you put functions to work immediately, using the `turtle` module to draw on screen. See you there! Let's code it together! diff --git a/docs/chapters/05-drawing-with-turtle/index.md b/docs/chapters/05-drawing-with-turtle/index.md new file mode 100644 index 00000000..4fd1aa51 --- /dev/null +++ b/docs/chapters/05-drawing-with-turtle/index.md @@ -0,0 +1,347 @@ +--- +title: Drawing with Turtle Graphics +description: Create your first turtle drawings using the Turtle and Screen objects, movement commands, pen control, colors, shapes, and speed settings. +generated_by: claude skill chapter-content-generator +date: 2026-06-28 09:48:25 +version: 0.09 +--- + +# Drawing with Turtle Graphics + +By the end of this lesson you'll be able to: + +- Create a `turtle.Screen()` and a `turtle.Turtle()` object to set up a drawing window +- Move the turtle forward, backward, left, and right to draw lines +- Lift and lower the pen to skip spaces in your drawing +- Change the turtle's color, thickness, shape, and drawing speed + +Imagine a tiny robot with a marker strapped to its belly. +You tell the robot where to walk, and the marker draws a trail wherever it goes. +That is exactly what **turtle graphics** does — and in this chapter you get to write the commands that bring that robot to life. + +!!! mascot-welcome "Welcome to Chapter 5!" + ![Monty waving welcome](../../img/mascot/welcome.png){ class="mascot-admonition-img" } + This is the chapter where Python becomes truly visual! Every command you type makes your turtle move and draw — instantly, right here in the browser. There is no better way to build your Python instincts than to type a command, click Run, and watch the turtle obey. Let's code it together! + +## Setting Up the Drawing Stage + +Before any drawing can happen, Python needs two things in place: a **screen** to draw on, and a **turtle** to do the drawing. + +### The turtle.Screen() Object + +A **`turtle.Screen()`** creates the drawing window — the blank canvas where all your shapes will appear. +Think of it as the stage in a play: you have to set up the stage before the actors can perform. + +You store the screen in a variable so you can send it instructions later: + +```python +import turtle +wn = turtle.Screen() +``` + +The name `wn` stands for "window" — that is the most common nickname programmers use for this variable, but you can call it anything you like. + +Once you have the screen, you can change its background color using **`bgcolor()`** (short for "background color"): + +```python +wn.bgcolor("lightblue") +``` + +Put any color name in quotes — `"lightyellow"`, `"pink"`, `"white"`, `"black"`, or any of the 140 named web colors Python understands. +`bgcolor()` changes the window background the moment Python runs that line. + +### The turtle.Turtle() Object + +A **`turtle.Turtle()`** creates your drawing agent — the small arrow (or turtle shape!) that moves around the canvas, leaving a colored line wherever it goes. + +In Chapter 4 you learned that **objects** have their own **methods** that you call with a dot. +A turtle is a perfect example of this idea in action. +You create one object and then call methods on it to make it move, turn, and draw. + +```python +t = turtle.Turtle() +``` + +The variable `t` now holds your turtle. +Whenever you want the turtle to do something, write `t.` followed by a command name and parentheses. + +!!! mascot-tip "Scratch Bridge" + ![Monty with a tip](../../img/mascot/tip.png){ class="mascot-admonition-img" } + In Scratch, the **Stage** was the white backdrop where your sprites lived, and a **Sprite** was the character you programmed to move. In Python turtle, `turtle.Screen()` is your Stage and `turtle.Turtle()` is your Sprite. The big difference? Instead of dragging a sprite with your mouse, you write Python commands to control it — and that gives you far more power than drag-and-drop ever could! + +## Moving the Turtle + +The turtle always starts at the center of the screen, facing right (East). +You have four movement commands to work with: + +| Command | What it does | +|---------|-------------| +| `t.forward(n)` | Move `n` pixels forward in the direction the turtle faces | +| `t.backward(n)` | Move `n` pixels backward (tail-first) | +| `t.right(n)` | Rotate the turtle `n` degrees clockwise | +| `t.left(n)` | Rotate the turtle `n` degrees counter-clockwise | + +The `n` in `forward()` and `backward()` is measured in **pixels** — tiny dots on your screen. +One hundred pixels is roughly the length of your thumb held next to a typical monitor. + +The `n` in `right()` and `left()` is measured in **degrees**, just like in your geometry class. +A full circle is 360°. +A right-angle corner — like the corner of a piece of paper — is exactly 90°. + +These four commands map directly to blocks you already know from Scratch. +The **Move N steps** block is `forward(n)` in Python. +The **Turn ↻ N degrees** block is `right(n)`, and the **Turn ↺ N degrees** block is `left(n)` — same ideas, just written as text. + +Before you run the first lab, take a moment to read the code carefully. + +!!! mascot-thinking "What Do You Think Will Happen?" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + Look at the program below before you click Run. + The turtle moves forward 100, turns right 90°, moves forward 100, turns right 90°, then moves forward one more time. + How many sides of a square do you think you will see? + Make your guess — then click Run to find out! + +## Try It Now + +Edit the code below and click **Run** to see the result right on this page. +No account needed — everything runs in your browser. + + + + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? The turtle drew exactly three sides of a square — one 90° right turn for each corner! + +**If you see a red error message:** Check your spelling carefully. +Python is case-sensitive, so `Forward(100)` will not work but `forward(100)` will. +Also make sure each line ends with a closing parenthesis `)`. + +## How It Works + +Here is what each line of the program does: + +| Line | What it does | +|------|-------------| +| `import turtle` | Loads the turtle library so Python knows all the drawing commands | +| `wn = turtle.Screen()` | Creates the drawing window and stores it in `wn` | +| `wn.bgcolor("lightyellow")` | Sets the window background to light yellow | +| `t = turtle.Turtle()` | Creates a turtle object and stores it in `t` | +| `t.forward(100)` | Moves the turtle forward 100 pixels in the direction it is currently facing | +| `t.right(90)` | Rotates the turtle 90° clockwise — a perfect right-angle corner | + +Notice the pattern: every command uses the object (`wn` or `t`), then a dot, then the method name with a number inside the parentheses. +This is exactly the object-method pattern from Chapter 4. + +## Pen Control: penup() and pendown() + +Right now the turtle draws a line everywhere it moves. +But what if you want two separate shapes with a gap between them? + +Think about drawing with a real pen: you would lift the pen off the paper, slide it to the new spot, then press it back down. +Turtle graphics works the same way. + +- **`t.penup()`** lifts the pen off the canvas. The turtle can move without drawing anything. +- **`t.pendown()`** sets the pen back on the canvas. Every step after this leaves a line. + +The turtle always starts with the pen down, which is why the very first `forward()` call draws a line. + +In Scratch you may have used the **Pen Up** and **Pen Down** blocks from the pen extension — `penup()` and `pendown()` work exactly the same way. + +Here is a program that draws two separate lines with a gap in the middle: + +```python +import turtle +t = turtle.Turtle() +t.forward(80) # draw a line +t.penup() # lift the pen +t.forward(40) # move 40 pixels — nothing drawn here +t.pendown() # lower the pen +t.forward(80) # draw another line +``` + +Try this in the lab below — pay close attention to the blank space in the middle of the drawing. + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +The gap is where the turtle traveled with its pen in the air. +Try changing the `40` in the middle `t.forward(40)` to `80` — the gap doubles in width. + +!!! mascot-warning "Don't Forget pendown()!" + ![Monty warning](../../img/mascot/warning.png){ class="mascot-admonition-img" } + The most common `penup()` mistake is forgetting to call `pendown()` afterward. If your turtle moves but the canvas stays completely blank, look for a missing `pendown()`. The turtle moves exactly as you command it — it just leaves no trace because the pen is still lifted. Add `t.pendown()` before the line you want drawn and you are back in business! + +## Pen Size and Color + +A black line on a white background is just the beginning. +You can choose any color and any thickness for your turtle's pen. + +Two commands control how the line looks: + +- **`t.pensize(n)`** sets the line thickness in pixels. The default is `1`. Try `3`, `5`, or `10` to draw bolder lines. +- **`t.pencolor("color")`** sets the color of the line the turtle draws. Use a color name in quotes: `"red"`, `"blue"`, `"green"`, `"orange"`, `"purple"`, or any named web color. + +Just like the **Set pen color** block in Scratch, `pencolor()` changes the color for every line drawn after that call. +You can change colors in the middle of a program — each call to `pencolor()` affects only the lines that come after it. + +## Turtle Appearance: shape(), hideturtle(), and showturtle() + +The default turtle looks like a small arrowhead. +The **`t.shape()`** command swaps it for a different look. +Here are all six built-in shapes: + +| Shape name | What it looks like | +|------------|-------------------| +| `"arrow"` | A small arrowhead (the default) | +| `"turtle"` | A top-down cartoon turtle | +| `"circle"` | A filled circle | +| `"square"` | A small filled square | +| `"triangle"` | A small triangle | +| `"classic"` | A slightly different arrowhead shape | + +Sometimes you want the turtle cursor to disappear from a finished drawing so it does not distract from your art. +Two commands handle this: + +- **`t.hideturtle()`** makes the turtle cursor invisible. Your drawing still shows — the turtle just steps out of the way. +- **`t.showturtle()`** brings a hidden turtle back into view. + +## Speed Control: speed() + +Every turtle starts at a medium drawing speed. +The **`t.speed(n)`** command controls how fast it moves, using a number from `0` to `10`: + +| Value | Speed | +|-------|-------| +| `1` | Slowest — good for watching each step | +| `5` | Medium — the default | +| `10` | Fast | +| `0` | Instant — skips the animation entirely | + +Use `speed(0)` when your program draws many lines and you do not want to wait. +Use `speed(1)` when you are learning or debugging and want to see the turtle move one step at a time. + +Now try a lab that combines color, appearance, and speed — all in one program: + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Notice that the first line is blue and the second is red — changing `pencolor()` in the middle of a drawing affects only the lines that come after that call. +When the program finishes, the turtle cursor itself disappears because of `hideturtle()`. + +## Learning Check + +You have now seen all ten commands from this chapter. +Time to put them to the test! +The program below draws two sides of a square and then stops. + +!!! mascot-thinking "Your Turn — Add the Missing Line" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + The program below draws two sides of a square and then stops short. + After the second `t.right(90)`, the turtle is already pointing in the right direction for the third side. + Add **one line** to make it draw that third side — 100 pixels long. + Hint: which command moves the turtle forward? + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +If you got it right, you will see three sides of a square drawn in green. +The missing line is `t.forward(100)` — the turtle was already facing the right direction after two right turns, so it just needed one more push forward! + +## Experiments + +Try these changes to the programs above. +For each one, predict what will happen first — then run it to check! + +1. In Lab 1, change both `t.right(90)` calls to `t.right(120)`. **You'll know it worked when** the turtle draws the corner of a triangle instead of a square corner. +2. In Lab 1, change `wn.bgcolor("lightyellow")` to `wn.bgcolor("lightblue")`. **You'll know it worked when** the background turns a soft sky blue. +3. In Lab 2, change the `40` in `t.forward(40)` (the middle one, between penup and pendown) to `100`. **You'll know it worked when** the gap between the two lines is much wider than the lines themselves. +4. In Lab 3, try each of the six shape names in `t.shape()`: `"arrow"`, `"turtle"`, `"circle"`, `"square"`, `"triangle"`, `"classic"`. **You'll know it worked when** the turtle cursor changes shape before it starts drawing. +5. **Challenge:** In Lab 3, change `t.speed(5)` to `t.speed(1)` and watch the turtle draw slowly. Then change it to `t.speed(0)` and run again. What is different? When would each speed setting be useful? + +!!! mascot-celebration "You Can Command a Turtle!" + ![Monty celebrating](../../img/mascot/celebration.png){ class="mascot-admonition-img" } + You have just learned ten Python turtle commands and used them to draw real shapes on the screen — that is a big deal! In the chapters ahead you will combine these commands with loops and functions to draw patterns no human could make by hand. You have earned this one. Let's keep coding it together! diff --git a/docs/chapters/06-math-and-arithmetic/index.md b/docs/chapters/06-math-and-arithmetic/index.md new file mode 100644 index 00000000..0e8371a9 --- /dev/null +++ b/docs/chapters/06-math-and-arithmetic/index.md @@ -0,0 +1,33 @@ +# Math and Arithmetic + +## Summary + +Python is a powerful calculator. This chapter explores every arithmetic operator: +integer division (`//`), the remainder (`%`), exponentiation (`**`), order of operations, +negative numbers, and scientific notation. You'll also learn to assign multiple +variables at once and use augmented operators like `+=` to make your code shorter. + +## Concepts Covered + +This chapter covers the following 10 concepts from the learning graph: + +1. Multiple Assignment +2. Augmented Assignment Operators +3. Division Returns Float +4. Integer Division Operator +5. Modulo Operator +6. Exponentiation Operator +7. Arithmetic Operators +8. Order of Operations +9. Negative Numbers +10. Scientific Notation Floats + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 3: Variables and Numbers](../03-variables-and-numbers/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/07-for-loops-and-shapes/index.md b/docs/chapters/07-for-loops-and-shapes/index.md new file mode 100644 index 00000000..676c0577 --- /dev/null +++ b/docs/chapters/07-for-loops-and-shapes/index.md @@ -0,0 +1,36 @@ +# For Loops and Drawing Shapes + +## Summary + +Loops let you repeat steps without copying and pasting — just like a Scratch +"repeat" block. The `for` loop with `range()` is Python's workhorse for counting. +This chapter uses loops to draw squares, triangles, and other polygons with +turtle, then introduces absolute positioning (`goto()`), screen clearing, +position queries, and a classic star pattern project. + +## Concepts Covered + +This chapter covers the following 11 concepts from the learning graph: + +1. for Loop over Sequence +2. for Loop with range() +3. Range with Start Stop Step +4. Loop Counter Variable +5. Loop Accumulator Pattern +6. Absolute Positioning goto() +7. Drawing circle() and Polygons +8. Clearing and Resetting +9. Position Query xcor() ycor() +10. setheading() Direction +11. Drawing Star Patterns + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 5: Drawing with Turtle Graphics](../05-drawing-with-turtle/index.md) +- [Chapter 6: Math and Arithmetic](../06-math-and-arithmetic/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/08-working-with-strings/index.md b/docs/chapters/08-working-with-strings/index.md new file mode 100644 index 00000000..b3d0dc42 --- /dev/null +++ b/docs/chapters/08-working-with-strings/index.md @@ -0,0 +1,34 @@ +# Working with Strings + +## Summary + +Text in Python is called a *string*. This chapter introduces the string type, +single vs double quotes, concatenation (joining strings), repetition, escape +characters like `\n`, measuring length with `len()`, raw strings, and +string immutability. As a practical project you'll use `turtle.write()` to +draw labels and text directly onto your turtle canvas. + +## Concepts Covered + +This chapter covers the following 9 concepts from the learning graph: + +1. String Type +2. Single vs Double Quotes +3. String Concatenation +4. String Repetition +5. Escape Characters +6. String Length with len() +7. String Immutability +8. Raw Strings +9. Writing Text with turtle.write() + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 5: Drawing with Turtle Graphics](../05-drawing-with-turtle/index.md) +- [Chapter 7: For Loops and Drawing Shapes](../07-for-loops-and-shapes/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/09-decisions-if-else/index.md b/docs/chapters/09-decisions-if-else/index.md new file mode 100644 index 00000000..c056c0e1 --- /dev/null +++ b/docs/chapters/09-decisions-if-else/index.md @@ -0,0 +1,34 @@ +# Making Decisions with If/Else + +## Summary + +Programs need to make choices — just like Scratch's "if/then/else" blocks. +Python's `if`, `elif`, and `else` keywords handle branching. This chapter +introduces the Boolean type (`True`/`False`), comparison operators +(`==`, `!=`, `<`, `>`), logical operators (`and`, `or`, `not`), +chained comparisons, and nested conditionals for multi-way decisions. + +## Concepts Covered + +This chapter covers the following 9 concepts from the learning graph: + +1. Boolean Type +2. Comparison Operators +3. Logical Operators +4. Boolean in Conditions +5. Chained Comparisons +6. if Statement +7. if...else Block +8. elif Chains +9. Nested if Statements + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 3: Variables and Numbers](../03-variables-and-numbers/index.md) +- [Chapter 6: Math and Arithmetic](../06-math-and-arithmetic/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/10-while-loops-and-animation/index.md b/docs/chapters/10-while-loops-and-animation/index.md new file mode 100644 index 00000000..38010c0a --- /dev/null +++ b/docs/chapters/10-while-loops-and-animation/index.md @@ -0,0 +1,36 @@ +# While Loops and Animation + +## Summary + +`while` loops keep running as long as a condition is true — perfect for games +and animations. This chapter covers `while`, how to stop loops with `break`, +skip iterations with `continue`, the `else` clause on loops, infinite-loop +dangers, countdown loops, and the `time` module. You'll finish with a +real animated turtle drawing that moves by itself. + +## Concepts Covered + +This chapter covers the following 10 concepts from the learning graph: + +1. while Loop +2. break Statement +3. continue Statement +4. else Clause on Loops +5. Nested Loops +6. Infinite Loops to Avoid +7. Countdown Loop +8. time Module Overview +9. time.sleep() +10. Animation with Turtle Loops + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 5: Drawing with Turtle Graphics](../05-drawing-with-turtle/index.md) +- [Chapter 7: For Loops and Drawing Shapes](../07-for-loops-and-shapes/index.md) +- [Chapter 9: Making Decisions with If/Else](../09-decisions-if-else/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/11-functions-parameters-scope/index.md b/docs/chapters/11-functions-parameters-scope/index.md new file mode 100644 index 00000000..e8c50aa2 --- /dev/null +++ b/docs/chapters/11-functions-parameters-scope/index.md @@ -0,0 +1,34 @@ +# Functions with Parameters and Scope + +## Summary + +Functions become much more powerful when you give them *parameters* (inputs). +This chapter covers default parameter values, keyword arguments, what happens +to variables *inside* vs *outside* functions (scope), the `global` keyword, +and how to use `nonlocal` in nested functions. +You'll also practice writing pure functions that return useful values. + +## Concepts Covered + +This chapter covers the following 9 concepts from the learning graph: + +1. Constants by Convention +2. Swap Two Variables +3. Naming Conflicts to Avoid +4. Default Parameter Values +5. Keyword Arguments +6. Local Scope +7. Global Scope +8. global Keyword +9. Pure Functions vs Side Effects + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 4: Functions and Objects](../04-functions-and-objects/index.md) +- [Chapter 6: Math and Arithmetic](../06-math-and-arithmetic/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/12-colors-fill-turtle-art/index.md b/docs/chapters/12-colors-fill-turtle-art/index.md new file mode 100644 index 00000000..0d8e7d4e --- /dev/null +++ b/docs/chapters/12-colors-fill-turtle-art/index.md @@ -0,0 +1,33 @@ +# Colors, Fill, and Turtle Art + +## Summary + +Colors make turtle art come alive. This chapter goes deep on color: +hex color codes, the RGB color model (red + green + blue = any color), +the HSL model, transparency, color theory basics, and how to set turtle's +pen and background colors. You'll also learn `begin_fill()`/`end_fill()` +to paint solid shapes, creating your most beautiful turtle artwork yet. + +## Concepts Covered + +This chapter covers the following 8 concepts from the learning graph: + +1. Hex Color Values +2. RGB Color Model +3. Color in Turtle Graphics +4. Background and Pen Colors +5. HSL Color Model +6. Color Theory Basics +7. Transparency and Alpha +8. Fill begin_fill() end_fill() + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 5: Drawing with Turtle Graphics](../05-drawing-with-turtle/index.md) +- [Chapter 9: Making Decisions with If/Else](../09-decisions-if-else/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/13-user-input-type-conversion/index.md b/docs/chapters/13-user-input-type-conversion/index.md new file mode 100644 index 00000000..032aa094 --- /dev/null +++ b/docs/chapters/13-user-input-type-conversion/index.md @@ -0,0 +1,37 @@ +# User Input and Type Conversion + +## Summary + +`input()` lets your program ask the user a question and read their answer. +But `input()` always returns a *string* — even if the user types a number. +This chapter covers converting between types with `int()`, `float()`, `str()`, +and `bool()`, checking a value's type with `type()`, stripping extra spaces, +validating input, and using `print()` and `input()` as true built-in functions. + +## Concepts Covered + +This chapter covers the following 12 concepts from the learning graph: + +1. String lower() upper() strip() +2. int() Conversion +3. float() Conversion +4. str() Conversion +5. bool() Conversion +6. type() Function +7. input() Function +8. Prompting the User +9. Converting Input to Numbers +10. Input Validation Basics +11. print() Output Function +12. input() Read Input + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 8: Working with Strings](../08-working-with-strings/index.md) +- [Chapter 9: Making Decisions with If/Else](../09-decisions-if-else/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/14-string-methods-formatting/index.md b/docs/chapters/14-string-methods-formatting/index.md new file mode 100644 index 00000000..d217eddf --- /dev/null +++ b/docs/chapters/14-string-methods-formatting/index.md @@ -0,0 +1,34 @@ +# String Methods and Formatting + +## Summary + +Strings have dozens of useful built-in methods. This chapter covers indexing +individual characters, slicing substrings, `split()`/`join()`/`replace()`, +`startswith()`/`endswith()`/`find()`, the powerful `format()` method, +**f-strings** (the modern way to embed variables in text), string comparison, +and multiline string formatting for tidy output. + +## Concepts Covered + +This chapter covers the following 9 concepts from the learning graph: + +1. String Indexing +2. String Slicing +3. String split() join() replace() +4. String startswith() endswith() find() +5. String isdigit() isalpha() isalnum() +6. String format() Method +7. f-Strings +8. String Comparison +9. Multiline String Formatting + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 8: Working with Strings](../08-working-with-strings/index.md) +- [Chapter 9: Making Decisions with If/Else](../09-decisions-if-else/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/15-lists-basics/index.md b/docs/chapters/15-lists-basics/index.md new file mode 100644 index 00000000..881fc2f9 --- /dev/null +++ b/docs/chapters/15-lists-basics/index.md @@ -0,0 +1,33 @@ +# Lists — Basics + +## Summary + +A list is an ordered collection of items — like a Scratch list block but much +more powerful. This chapter introduces the list type, how to create lists, +access items by index, use negative indexing to count from the end, slice +sub-lists, measure length with `len()`, test membership with `in`, +and understand the key difference between mutable and immutable types. + +## Concepts Covered + +This chapter covers the following 8 concepts from the learning graph: + +1. List Type +2. Creating a List +3. List Indexing +4. Negative Indexing +5. List Slicing +6. len() for Lists +7. Membership with in Operator +8. Mutable vs Immutable Types + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 8: Working with Strings](../08-working-with-strings/index.md) +- [Chapter 9: Making Decisions with If/Else](../09-decisions-if-else/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/16-lists-methods-patterns/index.md b/docs/chapters/16-lists-methods-patterns/index.md new file mode 100644 index 00000000..41a3bcde --- /dev/null +++ b/docs/chapters/16-lists-methods-patterns/index.md @@ -0,0 +1,36 @@ +# Lists — Methods and Patterns + +## Summary + +Lists come with powerful built-in methods for adding, removing, and reorganizing +items. This chapter covers `append()`/`insert()`/`extend()`, `remove()`/`pop()`, +`sort()`/`reverse()`, iterating over lists with `for`, nested lists, list +comprehensions, the loop-with-list-building pattern, and using lists as +stacks (LIFO) and queues (FIFO). + +## Concepts Covered + +This chapter covers the following 11 concepts from the learning graph: + +1. Loop with List Building +2. List append() insert() extend() +3. List remove() pop() clear() +4. List sort() reverse() copy() +5. List index() count() +6. List Concatenation and Repetition +7. Iterating over a List +8. Nested Lists +9. List Comprehensions +10. List as Stack +11. List as Queue + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 7: For Loops and Drawing Shapes](../07-for-loops-and-shapes/index.md) +- [Chapter 15: Lists — Basics](../15-lists-basics/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/17-modules-and-random/index.md b/docs/chapters/17-modules-and-random/index.md new file mode 100644 index 00000000..558a119b --- /dev/null +++ b/docs/chapters/17-modules-and-random/index.md @@ -0,0 +1,35 @@ +# Modules and Random Numbers + +## Summary + +Python's `import` system gives you access to thousands of extra tools. +This chapter covers `from...import` to grab specific names, aliases with `as`, +and `import *`. Then you'll dive into the `random` module — essential for games, +generative art, and simulations — covering `randint()`, `choice()`, `shuffle()`, +`seed()`, `random()`, and `sample()`. + +## Concepts Covered + +This chapter covers the following 10 concepts from the learning graph: + +1. from...import Specific Names +2. import...as Alias +3. from...import Star +4. random Module Overview +5. random.randint() +6. random.choice() +7. random.shuffle() +8. random.seed() +9. random.random() Float +10. random.sample() + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 4: Functions and Objects](../04-functions-and-objects/index.md) +- [Chapter 15: Lists — Basics](../15-lists-basics/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/18-math-module-turtle-projects/index.md b/docs/chapters/18-math-module-turtle-projects/index.md new file mode 100644 index 00000000..deec797b --- /dev/null +++ b/docs/chapters/18-math-module-turtle-projects/index.md @@ -0,0 +1,35 @@ +# Math Module and Turtle Projects + +## Summary + +The `math` module unlocks trigonometry, logarithms, and constants like `pi`. +This chapter covers `abs()`, `round()`, `sqrt()`/`floor()`/`ceil()`, +`sin()`/`cos()`/`pi`, radians/degrees conversion, and more. +You'll build two satisfying turtle projects: a **sine wave** that ripples across +the screen, and a **turtle race** where randomness decides the winner. + +## Concepts Covered + +This chapter covers the following 10 concepts from the learning graph: + +1. abs() Absolute Value +2. round() Function +3. math Module Overview +4. math.sqrt() floor() ceil() +5. math.sin() cos() pi +6. math.radians() degrees() +7. math.log() exp() +8. math.factorial() +9. Sine Wave with Turtle and Math +10. Turtle Race Simulation + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 7: For Loops and Drawing Shapes](../07-for-loops-and-shapes/index.md) +- [Chapter 17: Modules and Random Numbers](../17-modules-and-random/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/19-booleans-and-conditionals/index.md b/docs/chapters/19-booleans-and-conditionals/index.md new file mode 100644 index 00000000..6d02c634 --- /dev/null +++ b/docs/chapters/19-booleans-and-conditionals/index.md @@ -0,0 +1,36 @@ +# More Booleans and Conditionals + +## Summary + +This chapter deepens your understanding of truth in Python: truthiness and +falsiness (any value can be tested), short-circuit evaluation, converting +values to bool, checking types with `type()` and `isinstance()`, +and advanced conditional syntax including ternary expressions, +`match/case` statements, and compound conditions with `and`/`or`. + +## Concepts Covered + +This chapter covers the following 11 concepts from the learning graph: + +1. Truthiness and Falsiness +2. Short-Circuit Evaluation +3. Functions Returning None +4. Checking for None with is +5. Implicit vs Explicit Conversion +6. Reading Multiple Inputs +7. Strip Whitespace from Input +8. Conditional Ternary Expression +9. match/case Statement +10. Truthiness in Conditions +11. Compound Conditions + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 9: Making Decisions with If/Else](../09-decisions-if-else/index.md) +- [Chapter 13: User Input and Type Conversion](../13-user-input-type-conversion/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/20-tuples-and-sets/index.md b/docs/chapters/20-tuples-and-sets/index.md new file mode 100644 index 00000000..a7476c56 --- /dev/null +++ b/docs/chapters/20-tuples-and-sets/index.md @@ -0,0 +1,38 @@ +# Tuples and Sets + +## Summary + +Python has two more collection types beyond lists. **Tuples** are like lists +but immutable (unchangeable after creation) — perfect for coordinates, RGB triples, +and function return values. **Sets** store unordered unique items and support +fast membership testing plus mathematical operations: union, intersection, +and difference. This chapter covers both fully. + +## Concepts Covered + +This chapter covers the following 13 concepts from the learning graph: + +1. Tuple Type +2. Creating a Tuple +3. Tuple Indexing and Slicing +4. Tuple Unpacking +5. Tuples vs Lists +6. Single-Element Tuple Syntax +7. Tuple as Return Value +8. Set Type +9. Creating a Set +10. Set Union Intersection Difference +11. Set add() remove() discard() +12. Set Membership with in +13. Frozensets + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 15: Lists — Basics](../15-lists-basics/index.md) +- [Chapter 16: Lists — Methods and Patterns](../16-lists-methods-patterns/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/21-dictionaries/index.md b/docs/chapters/21-dictionaries/index.md new file mode 100644 index 00000000..b46ae285 --- /dev/null +++ b/docs/chapters/21-dictionaries/index.md @@ -0,0 +1,37 @@ +# Dictionaries + +## Summary + +A dictionary maps *keys* to *values* — like a real dictionary maps words to +definitions. Dictionaries are one of Python's most useful data structures. +This chapter covers creating dicts, accessing values by key, `get()` for safe +access, adding/updating/removing entries, iterating over keys/values/items, +membership testing, nested dictionaries, and dictionary comprehensions. + +## Concepts Covered + +This chapter covers the following 12 concepts from the learning graph: + +1. Dictionary Type +2. Creating a Dictionary +3. Accessing Values by Key +4. dict get() Method +5. Adding and Updating Key-Value Pairs +6. Removing Entries pop() del +7. Dictionary keys() values() items() +8. Iterating over a Dictionary +9. Key Membership with in +10. Nested Dictionaries +11. Dictionary Comprehensions +12. Default Dictionary Pattern + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 15: Lists — Basics](../15-lists-basics/index.md) +- [Chapter 16: Lists — Methods and Patterns](../16-lists-methods-patterns/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/22-advanced-collections/index.md b/docs/chapters/22-advanced-collections/index.md new file mode 100644 index 00000000..78c09917 --- /dev/null +++ b/docs/chapters/22-advanced-collections/index.md @@ -0,0 +1,46 @@ +# Advanced Collections and Built-in Functions + +## Summary + +Python's built-in function library is huge. This chapter collects the most +useful ones: `isinstance()`, `enumerate()` for indexed loops, `zip()` to combine +iterables, `*args`/`**kwargs` for flexible functions, returning multiple values, +named tuples, building dicts from two lists, `len()` for sequences, `range()`, +and the core aggregating functions: `max()`/`min()`/`sum()`, +`sorted()`/`reversed()`, `map()`/`filter()`. + +## Concepts Covered + +This chapter covers the following 19 concepts from the learning graph: + +1. isinstance() Function +2. enumerate() Function +3. zip() Function +4. Variable Number of Arguments *args +5. Keyword Variable Arguments **kwargs +6. Returning Multiple Values +7. Named Tuple Concept +8. Dictionary from Two Lists with zip() +9. len() Sequence Length +10. range() Number Sequence +11. type() Get Object Type +12. int() float() str() bool() Conversions +13. list() tuple() set() dict() Constructors +14. max() min() Functions +15. sum() Function +16. sorted() Function +17. reversed() Function +18. enumerate() with Index +19. zip() Combine Iterables + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 16: Lists — Methods and Patterns](../16-lists-methods-patterns/index.md) +- [Chapter 20: Tuples and Sets](../20-tuples-and-sets/index.md) +- [Chapter 21: Dictionaries](../21-dictionaries/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/23-error-handling-debugging/index.md b/docs/chapters/23-error-handling-debugging/index.md new file mode 100644 index 00000000..d9369840 --- /dev/null +++ b/docs/chapters/23-error-handling-debugging/index.md @@ -0,0 +1,36 @@ +# Error Handling and Debugging + +## Summary + +Every programmer makes mistakes — the skill is finding and fixing them quickly. +This chapter categorizes errors (syntax, runtime, logic), teaches you to read +Python tracebacks, and introduces `try/except` blocks so your programs can +recover gracefully from problems. You'll also learn `raise`, `assert`, +how to debug using strategic `print()` calls, and where to search for help online. + +## Concepts Covered + +This chapter covers the following 11 concepts from the learning graph: + +1. Syntax vs Runtime vs Logic Errors +2. Common Exception Types +3. Reading a Traceback +4. try...except Block +5. Catching Specific Exceptions +6. else Clause in try/except +7. finally Clause +8. raise Statement +9. assert Statement +10. Debugging with print() +11. Using Search Engines to Debug + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 4: Functions and Objects](../04-functions-and-objects/index.md) +- [Chapter 9: Making Decisions with If/Else](../09-decisions-if-else/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/24-recursion-and-fractals/index.md b/docs/chapters/24-recursion-and-fractals/index.md new file mode 100644 index 00000000..ced4be87 --- /dev/null +++ b/docs/chapters/24-recursion-and-fractals/index.md @@ -0,0 +1,34 @@ +# Recursion and Fractals + +## Summary + +Recursion is when a function calls *itself* — a mind-bending but powerful idea. +This chapter introduces the `nonlocal` keyword, the recursion concept, base cases +(to stop infinite loops), call-stack depth limits, lambda (one-line) functions, +functions as arguments, and nested functions. The payoff: a beautiful +recursive **fractal tree** drawn with turtle graphics. + +## Concepts Covered + +This chapter covers the following 8 concepts from the learning graph: + +1. nonlocal Keyword +2. Recursion Concept +3. Recursion Base Case +4. Recursion Depth and Stack +5. Lambda Functions +6. Function as Argument +7. Nested Functions +8. Fractals with Recursion and Turtle + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 4: Functions and Objects](../04-functions-and-objects/index.md) +- [Chapter 11: Functions with Parameters and Scope](../11-functions-parameters-scope/index.md) +- [Chapter 5: Drawing with Turtle Graphics](../05-drawing-with-turtle/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/25-object-oriented-programming/index.md b/docs/chapters/25-object-oriented-programming/index.md new file mode 100644 index 00000000..6eca05ce --- /dev/null +++ b/docs/chapters/25-object-oriented-programming/index.md @@ -0,0 +1,41 @@ +# Object-Oriented Programming + +## Summary + +Object-Oriented Programming (OOP) is how Python organizes complex programs. +You've already used objects (the turtle!); now you'll create your own. +This chapter covers attributes, methods, the `class` keyword, `__init__()`, +`self`, creating instances, dot notation, OOP in strings and lists, +inheritance, `__str__()`/`__repr__()`, subclasses, `super()`, +and class vs instance variables. + +## Concepts Covered + +This chapter covers the following 15 concepts from the learning graph: + +1. Attributes of an Object +2. Methods of an Object +3. class Keyword +4. __init__() Constructor +5. self Parameter +6. Creating Class Instances +7. Accessing Attributes and Methods +8. String Methods as OOP Examples +9. List Methods as OOP Examples +10. Inheritance Basics +11. __str__() String Representation +12. __repr__() Developer Representation +13. Subclasses and Method Overriding +14. super() Function +15. Class Variables vs Instance Variables + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 4: Functions and Objects](../04-functions-and-objects/index.md) +- [Chapter 16: Lists — Methods and Patterns](../16-lists-methods-patterns/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/26-file-input-output/index.md b/docs/chapters/26-file-input-output/index.md new file mode 100644 index 00000000..130777c1 --- /dev/null +++ b/docs/chapters/26-file-input-output/index.md @@ -0,0 +1,39 @@ +# File Input and Output + +## Summary + +Programs become much more useful when they can read and write files — saving +scores, loading data, processing text. This chapter introduces the command line, +navigating the file system, `open()`, file modes (`r`, `w`, `a`), all the read +and write methods, the `with` statement for safe file handling, iterating over +lines, text processing with `strip()`/`lower()`, and reading and writing CSV files. + +## Concepts Covered + +This chapter covers the following 14 concepts from the learning graph: + +1. Command Line Basics +2. File System Navigation +3. open() Function +4. File Modes r w a b +5. file.read() +6. file.readlines() +7. file.readline() +8. file.write() +9. file.close() +10. with Statement Context Manager +11. Iterating over File Lines +12. Text Processing strip() lower() +13. CSV File Reading +14. CSV File Writing + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 8: Working with Strings](../08-working-with-strings/index.md) +- [Chapter 16: Lists — Methods and Patterns](../16-lists-methods-patterns/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/27-standard-library-json/index.md b/docs/chapters/27-standard-library-json/index.md new file mode 100644 index 00000000..10227b41 --- /dev/null +++ b/docs/chapters/27-standard-library-json/index.md @@ -0,0 +1,45 @@ +# Standard Library and JSON + +## Summary + +Python ships with a huge standard library of ready-to-use modules. +This chapter covers creating your own custom modules (and the `__main__` guard), +the `string` module, `sys`, `os` and `os.path`, the `json` module for reading +and writing structured data, `csv`, `datetime`, `collections`, `itertools`, +reading/writing JSON files, and working with file paths and checking existence. + +## Concepts Covered + +This chapter covers the following 20 concepts from the learning graph: + +1. Creating Custom Modules +2. __name__ == "__main__" Guard +3. Module Search Path +4. Reloading a Module +5. string Module Constants +6. sys Module +7. sys.path Search Path +8. os Module +9. os.path Operations +10. json Module Overview +11. json.loads() json.dumps() +12. json.load() json.dump() +13. csv Module Basics +14. datetime Module Basics +15. collections Module +16. itertools Module Overview +17. Reading JSON from File +18. Writing JSON to File +19. File Path Handling +20. Checking if File Exists + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 4: Functions and Objects](../04-functions-and-objects/index.md) +- [Chapter 26: File Input and Output](../26-file-input-output/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/28-python-dev-tools/index.md b/docs/chapters/28-python-dev-tools/index.md new file mode 100644 index 00000000..938c4ca2 --- /dev/null +++ b/docs/chapters/28-python-dev-tools/index.md @@ -0,0 +1,41 @@ +# Python Development Tools + +## Summary + +Skulpt and Trinket are great for learning, but real Python projects use richer +tools. This chapter surveys the Python ecosystem: Repl.it, Thonny (a beginner +desktop IDE), Spyder (scientific IDE), VS Code (professional editor), Jupyter +Notebooks and JupyterLab, Conda and pip for package management, virtual +environments, installing Python locally, running scripts from the terminal, +Raspberry Pi, Google Colab, and Python 2 vs Python 3. + +## Concepts Covered + +This chapter covers the following 15 concepts from the learning graph: + +1. Python 2 vs Python 3 +2. Repl.it Online IDE +3. Thonny Beginner IDE +4. Spyder Scientific IDE +5. VS Code Editor +6. Jupyter Notebooks +7. JupyterLab Environment +8. Conda Package Manager +9. pip Package Installer +10. Virtual Environments +11. Installing Python Locally +12. Running Scripts from Terminal +13. Python REPL Shell +14. Raspberry Pi Python Platform +15. Google Colab Environment + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 1: Welcome to Python and Skulpt](../01-welcome-to-python/index.md) +- [Chapter 26: File Input and Output](../26-file-input-output/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/29-text-processing-regex/index.md b/docs/chapters/29-text-processing-regex/index.md new file mode 100644 index 00000000..f82225ab --- /dev/null +++ b/docs/chapters/29-text-processing-regex/index.md @@ -0,0 +1,40 @@ +# Text Processing and Regular Expressions + +## Summary + +Regular expressions (regex) are a mini-language for describing text patterns. +They sound scary but they're incredibly useful for searching, validating, +and transforming text. This chapter introduces the `re` module, +`search()`/`findall()`/`split()`/`sub()`, digit/word/whitespace patterns, +anchors, character classes, quantifiers, alternation, escaping special +characters, raw strings for regex, capturing groups, and compiled patterns. + +## Concepts Covered + +This chapter covers the following 14 concepts from the learning graph: + +1. re Module Import +2. re.search() First Match +3. re.findall() All Matches +4. re.split() Split by Pattern +5. re.sub() Substitute Matches +6. Digit Word Whitespace Patterns +7. Anchors Start and End +8. Character Classes +9. Quantifiers Plus Star Question +10. Alternation with Pipe +11. Escaping Special Characters +12. Raw Strings for Regex +13. Regex Groups with Parentheses +14. Compiled Regex Patterns + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 8: Working with Strings](../08-working-with-strings/index.md) +- [Chapter 27: Standard Library and JSON](../27-standard-library-json/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/30-algorithms-data-structures/index.md b/docs/chapters/30-algorithms-data-structures/index.md new file mode 100644 index 00000000..86d50a59 --- /dev/null +++ b/docs/chapters/30-algorithms-data-structures/index.md @@ -0,0 +1,49 @@ +# Algorithms and Data Structures + +## Summary + +This chapter introduces computer science fundamentals: abstract data types, +stacks (last-in first-out), queues (first-in first-out), graphs (nodes and edges), +adjacency list representation, and the two most important graph-search algorithms — +Breadth-First Search (BFS) and Depth-First Search (DFS). You'll also cover +sorting algorithms (bubble, selection, insertion), binary search, Big-O notation, +space complexity, linked lists, and trees. The capstone project: a maze solver. + +## Concepts Covered + +This chapter covers the following 22 concepts from the learning graph: + +1. Abstract Data Types Overview +2. Stack LIFO Structure +3. Queue FIFO Structure +4. Queue enqueue() dequeue() +5. Graph Nodes and Edges +6. Adjacency List Representation +7. Breadth-First Search BFS +8. BFS Color Tracking +9. BFS for Path Finding +10. Depth-First Search DFS +11. DFS with Recursion +12. DFS and BFS for Maze Solving +13. Sorting Algorithms Overview +14. Bubble Sort +15. Selection Sort +16. Insertion Sort +17. Binary Search Concept +18. Time Complexity Big-O Overview +19. Space Complexity Overview +20. Linked List Concept +21. Tree Data Structure Concept +22. Binary Tree Basics + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 16: Lists — Methods and Patterns](../16-lists-methods-patterns/index.md) +- [Chapter 21: Dictionaries](../21-dictionaries/index.md) +- [Chapter 24: Recursion and Fractals](../24-recursion-and-fractals/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/31-advanced-functions-oop/index.md b/docs/chapters/31-advanced-functions-oop/index.md new file mode 100644 index 00000000..c7beb6be --- /dev/null +++ b/docs/chapters/31-advanced-functions-oop/index.md @@ -0,0 +1,42 @@ +# Advanced Functions and OOP + +## Summary + +This chapter rounds out your functional-programming and OOP knowledge. +You'll learn `map()` and `filter()` for transforming collections, `dir()` and +`help()` for exploring any object, `id()` and `hash()` for object identity, +`any()`/`all()` for aggregate testing, and `chr()`/`ord()` for character math. +On the OOP side: exception hierarchy, custom exception classes, exception +chaining, static methods, `@property`, dunder methods, and object composition. + +## Concepts Covered + +This chapter covers the following 15 concepts from the learning graph: + +1. map() Apply Function +2. filter() Filter Items +3. dir() List Attributes +4. help() Documentation +5. id() Object Identity +6. hash() Function +7. any() and all() Functions +8. chr() and ord() Functions +9. Exception Hierarchy +10. Custom Exception Classes +11. Exception Chaining +12. Static Methods +13. Properties with @property +14. Dunder Methods Overview +15. Object Composition + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 22: Advanced Collections and Built-in Functions](../22-advanced-collections/index.md) +- [Chapter 23: Error Handling and Debugging](../23-error-handling-debugging/index.md) +- [Chapter 25: Object-Oriented Programming](../25-object-oriented-programming/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/32-data-visualization-matplotlib/index.md b/docs/chapters/32-data-visualization-matplotlib/index.md new file mode 100644 index 00000000..a0991be4 --- /dev/null +++ b/docs/chapters/32-data-visualization-matplotlib/index.md @@ -0,0 +1,39 @@ +# Data Visualization with matplotlib + +## Summary + +matplotlib is Python's most popular charting library. This chapter covers the +full workflow: importing `pyplot as plt`, creating line plots, displaying them +with `show()`, adding titles and axis labels, drawing grids, scatter plots, +bar charts, histograms, legends, saving figures to disk, plotting multiple +lines on one chart, and organizing multiple charts with subplots. + +## Concepts Covered + +This chapter covers the following 14 concepts from the learning graph: + +1. matplotlib Library Overview +2. import matplotlib.pyplot as plt +3. plt.plot() Line Plot +4. plt.show() Display +5. Plot Title and Axis Labels +6. plt.grid() Grid Lines +7. Lists as XY Plot Data +8. plt.scatter() Scatter Plot +9. plt.bar() Bar Chart +10. plt.hist() Histogram +11. plt.legend() Legend +12. plt.savefig() Save Plot +13. Multiple Lines on One Plot +14. Subplots with plt.subplot() + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 15: Lists — Basics](../15-lists-basics/index.md) +- [Chapter 27: Standard Library and JSON](../27-standard-library-json/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/33-numpy-scientific-computing/index.md b/docs/chapters/33-numpy-scientific-computing/index.md new file mode 100644 index 00000000..74e2529c --- /dev/null +++ b/docs/chapters/33-numpy-scientific-computing/index.md @@ -0,0 +1,36 @@ +# NumPy and Scientific Computing + +## Summary + +NumPy is the foundation of scientific Python. Its *array* type is like a list +but blazing fast and capable of math on every element at once. This chapter +covers importing numpy, creating arrays, element-wise operations and broadcasting, +reshaping, `zeros()`/`ones()`, `linspace()` for evenly spaced values, array +slicing, `mean()`/`std()`, argmax, and plotting a sine wave with matplotlib. + +## Concepts Covered + +This chapter covers the following 12 concepts from the learning graph: + +1. Plotting a Sine Wave +2. numpy Library Overview +3. import numpy as np +4. np.array() Creating Arrays +5. np.argmax() Index of Max +6. Array Operations and Broadcasting +7. Reshaping Arrays +8. np.zeros() np.ones() +9. np.linspace() Evenly Spaced Values +10. Array Slicing and Indexing +11. Element-wise Math Operations +12. np.mean() np.std() + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 32: Data Visualization with matplotlib](../32-data-visualization-matplotlib/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/34-image-processing-pillow/index.md b/docs/chapters/34-image-processing-pillow/index.md new file mode 100644 index 00000000..2d94ab71 --- /dev/null +++ b/docs/chapters/34-image-processing-pillow/index.md @@ -0,0 +1,32 @@ +# Image Processing with Pillow + +## Summary + +Pillow (PIL) lets Python open, modify, and save images. This chapter introduces +the library, opens an image file, displays it, accesses its pixel data as an +array, resizes and crops images, converts between color modes (RGB, grayscale), +and saves the result. Together with NumPy and matplotlib, Pillow forms the +foundation for the machine learning work in the next two chapters. + +## Concepts Covered + +This chapter covers the following 7 concepts from the learning graph: + +1. PIL Pillow Library Overview +2. Image.open() Open Image +3. image.show() Display Image +4. Pixel Data and Image Arrays +5. Image Resize and Crop +6. Image Color Conversion +7. Saving Images + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 27: Standard Library and JSON](../27-standard-library-json/index.md) +- [Chapter 33: NumPy and Scientific Computing](../33-numpy-scientific-computing/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/35-advanced-turtle-event-driven/index.md b/docs/chapters/35-advanced-turtle-event-driven/index.md new file mode 100644 index 00000000..e9004c0d --- /dev/null +++ b/docs/chapters/35-advanced-turtle-event-driven/index.md @@ -0,0 +1,42 @@ +# Advanced Turtle and Event-Driven Programming + +## Summary + +Programs that respond to mouse clicks and key presses use *event-driven* +programming. This chapter covers the event-driven model, mouse-click and +keyboard event handlers, callback functions, animation loops, the event queue, +timer-based events, and three advanced turtle projects: an interactive color +picker (`onscreenclick()`), a maze visualization, and a color-bars demo. +Jupyter Canvas users get `ipycanvas` and `mobilechelonian` too. + +## Concepts Covered + +This chapter covers the following 14 concepts from the learning graph: + +1. onscreenclick() Event Handler +2. Color Picker with Turtle +3. Maze Visualization with Turtle +4. ipycanvas Canvas in Jupyter +5. mobilechelonian Turtle in Jupyter +6. Drawing Shapes on Canvas +7. Color Bars in Jupyter +8. Event-Driven Programming Model +9. Mouse Click Event Handlers +10. Keyboard Event Handlers +11. Callback Functions +12. Animation Loops +13. Event Queue Concept +14. Timer-Based Events + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 5: Drawing with Turtle Graphics](../05-drawing-with-turtle/index.md) +- [Chapter 24: Recursion and Fractals](../24-recursion-and-fractals/index.md) +- [Chapter 28: Python Development Tools](../28-python-dev-tools/index.md) +- [Chapter 30: Algorithms and Data Structures](../30-algorithms-data-structures/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/36-computational-thinking-best-practices/index.md b/docs/chapters/36-computational-thinking-best-practices/index.md new file mode 100644 index 00000000..bd2714e0 --- /dev/null +++ b/docs/chapters/36-computational-thinking-best-practices/index.md @@ -0,0 +1,46 @@ +# Computational Thinking and Best Practices + +## Summary + +Great programmers don't just write code that works — they write code that's +readable, reusable, and easy to change. This chapter covers the DRY principle, +modularity, code reusability, meaningful names, when and why to write comments, +literate programming in Jupyter, using `help()` and `dir()`, version control +basics, searching documentation, refactoring, test-driven thinking, pair +programming, and the four pillars of computational thinking: decomposition, +pattern recognition, abstraction, and algorithm design. + +## Concepts Covered + +This chapter covers the following 18 concepts from the learning graph: + +1. Modularity in Code +2. Code Reusability +3. DRY Principle +4. Meaningful Names +5. Code Comments When and Why +6. Literate Programming in Jupyter +7. Reading Docs with help() and dir() +8. Version Control Basics +9. Searching Documentation +10. Code Refactoring +11. Test-Driven Thinking +12. Pair Programming Concept +13. Decomposition +14. Pattern Recognition +15. Abstraction in Programming +16. Algorithm Design +17. Pseudocode Writing +18. Debugging Strategies + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 4: Functions and Objects](../04-functions-and-objects/index.md) +- [Chapter 27: Standard Library and JSON](../27-standard-library-json/index.md) +- [Chapter 28: Python Development Tools](../28-python-dev-tools/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/37-machine-learning-foundations/index.md b/docs/chapters/37-machine-learning-foundations/index.md new file mode 100644 index 00000000..984caa5d --- /dev/null +++ b/docs/chapters/37-machine-learning-foundations/index.md @@ -0,0 +1,43 @@ +# Machine Learning Foundations + +## Summary + +Machine learning (ML) lets programs *learn from data* instead of following +hand-written rules. This chapter introduces the big picture — supervised vs +unsupervised learning — then moves to the Keras library to build your first +neural network. You'll learn the sequential model, dense (fully connected) layers, +activation functions (relu, softmax), loss functions, the Adam optimizer, +accuracy metrics, batch size and epochs, and the famous MNIST handwritten-digit +dataset, including data normalization and the train/validation/test split. + +## Concepts Covered + +This chapter covers the following 15 concepts from the learning graph: + +1. Machine Learning Overview +2. Supervised vs Unsupervised Learning +3. keras Library Overview +4. Sequential Model +5. Dense Fully Connected Layers +6. Activation Functions relu softmax +7. Categorical Crossentropy Loss +8. Adam Optimizer +9. Accuracy Metric +10. Batch Size and Epochs +11. MNIST Dataset +12. Data Normalization +13. Feedforward Networks +14. Training vs Validation vs Test Sets +15. Overfitting Concept + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 25: Object-Oriented Programming](../25-object-oriented-programming/index.md) +- [Chapter 32: Data Visualization with matplotlib](../32-data-visualization-matplotlib/index.md) +- [Chapter 33: NumPy and Scientific Computing](../33-numpy-scientific-computing/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/38-neural-networks-and-mnist/index.md b/docs/chapters/38-neural-networks-and-mnist/index.md new file mode 100644 index 00000000..85dc3000 --- /dev/null +++ b/docs/chapters/38-neural-networks-and-mnist/index.md @@ -0,0 +1,39 @@ +# Neural Networks and MNIST + +## Summary + +Building on the foundations of the previous chapter, this chapter goes deeper +into neural network architectures. You'll add convolutional layers (Conv2D), +MaxPooling, dropout regularization, and a Flatten layer. Then you'll compile, +train, evaluate, and run predictions on your model against the MNIST dataset. +Brief introductions to CNNs, RNNs, LSTMs, autoencoders, and feature extraction +round out the chapter and point toward future learning. + +## Concepts Covered + +This chapter covers the following 13 concepts from the learning graph: + +1. Conv2D Convolutional Layers +2. MaxPooling2D Pooling Layers +3. Dropout Regularization +4. Flatten Layer +5. model.compile() +6. model.fit() Training +7. model.evaluate() Testing +8. model.predict() Inference +9. Convolutional Neural Networks +10. Recurrent Networks RNN Overview +11. LSTM Networks Overview +12. Autoencoders Overview +13. Feature Extraction + +## Prerequisites + +This chapter builds on concepts from: + +- [Chapter 37: Machine Learning Foundations](../37-machine-learning-foundations/index.md) +- [Chapter 34: Image Processing with Pillow](../34-image-processing-pillow/index.md) + +--- + +TODO: Generate Chapter Content diff --git a/docs/chapters/index.md b/docs/chapters/index.md new file mode 100644 index 00000000..c45f298a --- /dev/null +++ b/docs/chapters/index.md @@ -0,0 +1,55 @@ +# Chapters + +This textbook is organized into 38 chapters covering 450 concepts, guiding you from your very first Python program all the way to machine learning. + +## Chapter Overview + +1. [Welcome to Python and Skulpt](01-welcome-to-python/index.md) — Meet Monty, run your first `print()`, write `import turtle`, and see what's coming. +2. [Python Code Structure](02-python-code-structure/index.md) — Indentation, code blocks, keywords, whitespace, and named colors. +3. [Variables and Numbers](03-variables-and-numbers/index.md) — Storing data with variables, naming rules, integers, floats, and None. +4. [Functions and Objects](04-functions-and-objects/index.md) — Defining functions with `def`, calling them, and a first look at objects. +5. [Drawing with Turtle Graphics](05-drawing-with-turtle/index.md) — Your first real turtle programs: movement, turning, pen control, and color. +6. [Math and Arithmetic](06-math-and-arithmetic/index.md) — All the arithmetic operators, order of operations, and multiple assignment. +7. [For Loops and Drawing Shapes](07-for-loops-and-shapes/index.md) — `for` loops with `range()`, drawing polygons, circles, and star patterns. +8. [Working with Strings](08-working-with-strings/index.md) — String type, quotes, concatenation, escape characters, and writing text on the canvas. +9. [Making Decisions with If/Else](09-decisions-if-else/index.md) — Booleans, comparisons, `if`, `elif`, `else`, and nested conditionals. +10. [While Loops and Animation](10-while-loops-and-animation/index.md) — `while` loops, `break`, `continue`, `time.sleep()`, and animated turtle drawing. +11. [Functions with Parameters and Scope](11-functions-parameters-scope/index.md) — Default parameters, keyword arguments, local/global scope, and return values. +12. [Colors, Fill, and Turtle Art](12-colors-fill-turtle-art/index.md) — Hex colors, RGB, HSL, `begin_fill()`/`end_fill()`, transparency, and color theory. +13. [User Input and Type Conversion](13-user-input-type-conversion/index.md) — `input()`, converting strings to numbers, `type()`, and validation basics. +14. [String Methods and Formatting](14-string-methods-formatting/index.md) — Indexing, slicing, `split()`/`join()`, f-strings, and string comparison. +15. [Lists — Basics](15-lists-basics/index.md) — Creating lists, indexing, slicing, `len()`, membership, mutable vs immutable. +16. [Lists — Methods and Patterns](16-lists-methods-patterns/index.md) — `append()`/`pop()`/`sort()`, iteration, nested lists, comprehensions, stacks, queues. +17. [Modules and Random Numbers](17-modules-and-random/index.md) — `from...import`, aliases, and the `random` module for games and art. +18. [Math Module and Turtle Projects](18-math-module-turtle-projects/index.md) — `math.sqrt()`, `sin()`/`cos()`/`pi`, turtle sine wave, and a turtle race. +19. [More Booleans and Conditionals](19-booleans-and-conditionals/index.md) — Truthiness, short-circuit evaluation, ternary expressions, and `match/case`. +20. [Tuples and Sets](20-tuples-and-sets/index.md) — Immutable sequences, tuple unpacking, sets, union/intersection/difference. +21. [Dictionaries](21-dictionaries/index.md) — Key-value stores, all dict methods, iteration, nesting, and comprehensions. +22. [Advanced Collections and Built-in Functions](22-advanced-collections/index.md) — `enumerate()`, `zip()`, `*args`/`**kwargs`, `map()`/`filter()`, `max()`/`min()`/`sum()`. +23. [Error Handling and Debugging](23-error-handling-debugging/index.md) — Exception types, tracebacks, `try/except`, `raise`, `assert`, and debugging strategies. +24. [Recursion and Fractals](24-recursion-and-fractals/index.md) — Recursion, base cases, lambda functions, nested functions, and fractal turtle art. +25. [Object-Oriented Programming](25-object-oriented-programming/index.md) — Classes, `__init__()`, `self`, instances, inheritance, dunder methods. +26. [File Input and Output](26-file-input-output/index.md) — `open()`, file modes, reading/writing, `with` statement, CSV files. +27. [Standard Library and JSON](27-standard-library-json/index.md) — Custom modules, `os`, `sys`, `json`, `datetime`, `collections`, `itertools`. +28. [Python Development Tools](28-python-dev-tools/index.md) — VS Code, Thonny, Jupyter, pip, virtual environments, Conda, Raspberry Pi. +29. [Text Processing and Regular Expressions](29-text-processing-regex/index.md) — The `re` module, patterns, character classes, quantifiers, groups. +30. [Algorithms and Data Structures](30-algorithms-data-structures/index.md) — Stacks, queues, graphs, BFS, DFS, sorting algorithms, binary search, Big-O. +31. [Advanced Functions and OOP](31-advanced-functions-oop/index.md) — `map()`/`filter()`, `dir()`/`help()`, custom exceptions, static methods, `@property`. +32. [Data Visualization with matplotlib](32-data-visualization-matplotlib/index.md) — Line plots, scatter, bar, histogram, legends, saving figures, subplots. +33. [NumPy and Scientific Computing](33-numpy-scientific-computing/index.md) — Arrays, broadcasting, reshaping, `linspace()`, element-wise math, sine wave plot. +34. [Image Processing with Pillow](34-image-processing-pillow/index.md) — Opening images, pixel data, resize/crop, color conversion, saving. +35. [Advanced Turtle and Event-Driven Programming](35-advanced-turtle-event-driven/index.md) — `onscreenclick()`, color picker, maze visualization, Jupyter canvas, event handlers. +36. [Computational Thinking and Best Practices](36-computational-thinking-best-practices/index.md) — DRY, modularity, refactoring, version control, decomposition, abstraction. +37. [Machine Learning Foundations](37-machine-learning-foundations/index.md) — ML overview, Keras, sequential models, dense layers, MNIST, overfitting. +38. [Neural Networks and MNIST](38-neural-networks-and-mnist/index.md) — Conv2D, MaxPooling, dropout, `compile()`/`fit()`/`evaluate()`, CNNs. + +## How to Use This Textbook + +Start at Chapter 1 and work through in order — each chapter builds on the previous ones. +Chapters 1–12 focus on turtle graphics so you get visual, immediate feedback on every concept. +From Chapter 13 onward the focus shifts to Python's full power: collections, files, objects, algorithms, and data science. +Every chapter ends with a "TODO: Generate Chapter Content" marker — content will be added progressively. + +--- + +**Note:** Each chapter index lists the exact concepts covered. Complete prerequisites before jumping ahead. diff --git a/docs/course-description.md b/docs/course-description.md new file mode 100644 index 00000000..23888b06 --- /dev/null +++ b/docs/course-description.md @@ -0,0 +1,238 @@ +--- +title: Course Description for Beginning Python +description: A detailed course description for Beginning Python including overview, topics covered and learning objectives in the format of the 2001 Bloom Taxonomy +quality_score: 96 +--- + +# Beginning Python + +**Title:** Beginning Python — From Blocks to Code with Monty + +**Target Audience:** Elementary and middle school students, approximately ages 10–13, +who have completed at least one semester of block-based programming (e.g., Scratch, Snap!, +or MIT App Inventor) and are ready to transition to text-based programming. + +**Prerequisites:** Familiarity with block-based programming concepts such as sequences, +loops, conditionals, and variables (e.g., Scratch or equivalent). No prior text-based +programming experience is required. Basic reading and arithmetic skills at a 4th-grade level. + +--- + +## Course Overview + +Beginning Python is a fun, project-driven course that guides young programmers on the +journey from block-based coding to writing real Python. Throughout the course, students +are accompanied by **Monty**, a friendly and curious python-snake mascot who introduces +new concepts, offers hints, celebrates successes, and helps make abstract ideas concrete. +Monty lives right inside the course pages — students can read Monty's tips alongside +interactive coding windows powered by **Skulpt**, a browser-based Python engine that +lets learners run Python code without installing anything. + +The course begins where students already are — using turtle graphics to draw shapes, +just as they may have done in Scratch — and then progressively builds toward text-based +thinking: variables, loops, functions, and data structures. Along the way, students +encounter colorful projects like animated drawings, random-art generators, interactive +color pickers, recursive fractals, and maze-solving algorithms. Each concept is introduced +with a short story from Monty, an interactive example students can run and modify +immediately, and a short quiz to reinforce retention. + +Beyond the beginning level, the course extends into **intermediate Python** (data types, +dictionaries, file I/O, regular expressions, object-oriented basics, debugging, and +graph algorithms) and **advanced Python** (data visualization with matplotlib, numerical +computing with NumPy, image processing, and an introduction to machine learning with +the MNIST handwritten-digit dataset). A comprehensive **glossary**, an **FAQ** section, +**per-lesson quizzes**, and a **detailed teacher's guide** make the course equally +valuable for self-directed students and classroom instructors. + +This course matters because Python is consistently ranked the most popular first +programming language in the world, powers breakthroughs in science, data analysis, and +artificial intelligence, and is the language of choice for Raspberry Pi projects and +the Maker community. By starting with turtle graphics — a visual, immediate form of +feedback — and scaffolding carefully toward data structures and machine learning, +this course gives young learners a genuine on-ramp to modern, professional programming +skills while keeping the experience joyful and motivating. + +--- + +## Main Topics Covered + +1. **Python environments and tools** — Trinket.io, Skulpt (inline), Repl.it, Thonny, + VS Code, Jupyter Notebooks, Raspberry Pi, and installing Python locally +2. **Core Python syntax** — print, comments, indentation, keywords, variables, assignment, + naming conventions, and basic arithmetic +3. **Data types** — integers, floats, booleans, strings, None, and type conversion +4. **Control flow** — if/elif/else conditionals, for loops, while loops, break, continue, + nested loops, and range() +5. **Functions** — defining and calling functions, parameters, return values, scope, + recursion, docstrings, and lambda functions +6. **Collections** — lists, tuples, dictionaries, and sets with all common operations +7. **Turtle graphics** — drawing, movement, color, fill, animation, event handling, + fractals, and the sine wave +8. **User input and string handling** — input(), string methods, f-strings, formatting, + regular expressions, and text file I/O +9. **Modules and the standard library** — random, math, time, sys, os, string, re, + and creating custom modules +10. **Error handling and debugging** — syntax vs. runtime vs. logic errors, try/except, + traceback reading, assert, and debugging strategies +11. **Object-oriented programming (intro)** — classes, objects, attributes, methods, + `__init__`, `self`, and inheritance basics +12. **Data structures and algorithms** — stacks, queues, graphs, adjacency lists, + Breadth-First Search (BFS), Depth-First Search (DFS), maze solving, sorting, and + binary search +13. **Data visualization** — matplotlib line plots, labels, grids, and plotting mathematical + functions +14. **Numerical computing** — NumPy arrays, array operations, reshaping +15. **Image processing** — Pillow/PIL, opening and displaying images, pixel arrays +16. **Machine learning introduction** — Keras sequential models, dense and convolutional + layers, MNIST digit recognition, training, evaluation, and prediction +17. **Event-driven and interactive programming** — mouse clicks, keyboard events, + callbacks, and animation loops +18. **Programming practices** — modularity, DRY principle, meaningful naming, version + control basics, reading documentation +19. **Course support materials** — per-lesson glossary terms, FAQ, quizzes, and a + detailed teacher's guide with pacing, discussion questions, and extension activities + +--- + +## Topics Not Covered + +The following topics are intentionally out of scope for this course to maintain +focus on core programming fluency for a beginning audience: + +- Web development (HTML, CSS, JavaScript frameworks, Flask, Django) +- Database design and SQL +- Networking and socket programming +- Concurrency, threading, and async/await +- System administration and shell scripting beyond basic terminal use +- Advanced software engineering patterns (design patterns, CI/CD pipelines) +- Cloud deployment and containerization (Docker, Kubernetes) +- Cybersecurity and penetration testing +- Full deep-learning training pipelines beyond the MNIST introductory example +- Mobile app development + +--- + +## Learning Outcomes + +After completing this course, students will be able to: + +### Remember +*Retrieving, recognizing, and recalling relevant knowledge from long-term memory.* + +- **Recall** that Python uses indentation (whitespace) to define blocks of code +- **Name** the six core Python data types: int, float, str, bool, list, and dict +- **List** the arithmetic operators available in Python: `+`, `-`, `*`, `/`, `//`, `%`, `**` +- **Identify** the keywords used for control flow: `if`, `elif`, `else`, `for`, `while`, `break`, `continue` +- **State** the difference between a syntax error, a runtime error, and a logic error +- **Recall** the turtle graphics commands for movement, pen control, color, and fill +- **Name** at least five Python standard library modules and one function from each +- **Recognize** the purpose of `import`, `def`, `return`, `class`, `try`, and `except` keywords +- **List** the main operations available for lists (append, insert, remove, pop, sort, reverse) +- **Recall** the difference between mutable types (lists, dicts) and immutable types (strings, tuples) +- **State** what BFS and DFS stand for and identify which uses a queue and which uses a stack +- **Name** the six levels of Bloom's Taxonomy in order +- **Identify** Monty's role in the course as a learning guide and hint-giver + + +### Understand +*Constructing meaning from instructional messages, including oral, written, and graphic communication.* + +- **Explain** why Python's indentation-based block structure reduces the need for braces or `begin/end` keywords +- **Describe** how a `for` loop with `range()` translates to a block-based repeat loop in Scratch +- **Explain** the difference between passing a value to a function (parameter) and returning a value from it +- **Interpret** a Python traceback and explain what information each line provides +- **Describe** how a dictionary stores key-value pairs and why keys must be unique +- **Explain** what recursion means and identify the base case and recursive case in a given function +- **Summarize** how turtle graphics coordinates map to an x-y plane with the origin at the center +- **Describe** what it means for a variable to have local scope vs. global scope +- **Explain** the purpose of try/except blocks and when they are appropriate to use +- **Interpret** a regular expression pattern and describe what strings it would match +- **Describe** the difference between supervised and unsupervised machine learning +- **Explain** how the MNIST dataset is used to train a digit-recognition model +- **Summarize** the difference between a list (ordered, mutable) and a tuple (ordered, immutable) and a set (unordered, unique) +- **Explain** how BFS guarantees the shortest path in an unweighted graph + +### Apply +*Carrying out or using a procedure in a given situation.* + +- **Write** Python programs using print(), variables, arithmetic, and input() to create a simple calculator +- **Use** `if/elif/else` statements to control program flow based on user input or computed values +- **Apply** `for` and `while` loops to draw geometric shapes with turtle graphics +- **Define** and **call** functions with parameters and return values to organize and reuse code +- **Use** list methods (append, pop, sort, etc.) to build, modify, and search collections of data +- **Apply** dictionary operations to store and retrieve named data (e.g., a student grade book) +- **Write** a recursive function to draw a fractal tree or spiral using turtle graphics +- **Use** the `random` module to generate random colors, positions, and values in a drawing program +- **Apply** the `math` module to compute sine and cosine values and plot a wave with turtle +- **Use** `open()` and the `with` statement to read text from a file and process each line +- **Apply** `try/except` to handle invalid user input gracefully without crashing +- **Use** `re.search()` and `re.findall()` to extract patterns from text +- **Apply** list comprehensions and dictionary comprehensions to transform data concisely +- **Use** `matplotlib.pyplot` to create a labeled line plot of mathematical data +- **Apply** NumPy arrays to perform element-wise math operations on numerical data +- **Use** Keras to load the MNIST dataset, build a sequential model, compile, and train it +- **Apply** BFS or DFS to find a path through a grid-based maze + + +### Analyze +*Breaking material into constituent parts and determining how the parts relate to one another and to an overall structure or purpose.* + +- **Compare** Python's text-based syntax to equivalent Scratch blocks and explain what each Python construct replaces +- **Distinguish** between a function definition and a function call, and explain why both are necessary +- **Analyze** a given Python program and identify its inputs, processing steps, and outputs +- **Trace** the execution of a recursive function call through its base case and recursive cases step by step +- **Differentiate** between when to use a list, a tuple, a dictionary, or a set for a given problem +- **Identify** the scope of variables in a multi-function program and predict whether a `NameError` will occur +- **Analyze** a BFS traversal of a graph and identify the order in which nodes are visited +- **Examine** a neural network's layer structure (input, hidden, output) and explain the role of each layer +- **Break down** a turtle graphics program into its sub-components (setup, drawing functions, event handlers) and describe how they interact +- **Differentiate** between a compile-time (syntax) error and a runtime error in terms of when each is detected +- **Analyze** a regular expression pattern by identifying each character class, quantifier, and anchor +- **Compare** the performance characteristics of BFS vs. DFS (memory use, path optimality, use cases) +- **Examine** a program's use of global and local variables and identify potential bugs from unintended scope interactions + +### Evaluate +*Making judgments based on criteria and standards through checking and critiquing.* + +- **Judge** whether a given variable name follows Python conventions and suggest improvements +- **Assess** whether a function is appropriately modular or should be broken into smaller functions +- **Evaluate** two approaches to solving a problem (e.g., iteration vs. recursion) and justify which is more appropriate for a given context +- **Critique** a piece of student code for common errors: off-by-one in range(), missing return, mutable default argument, shadowed variable +- **Select** the appropriate data structure (list, dict, set, tuple) for a given real-world scenario and defend the choice +- **Assess** whether a try/except block catches the right exceptions and whether the except clause is too broad or too narrow +- **Evaluate** a matplotlib chart for clarity and completeness (title, axis labels, readable scale) +- **Judge** the quality of a trained MNIST model based on its accuracy score and loss curve +- **Appraise** the readability of a Python program and suggest improvements to naming, structure, and comments +- **Evaluate** whether BFS or DFS is the better algorithm for a specific maze or graph problem +- **Assess** the completeness and accuracy of a regular expression against a set of test strings +- **Judge** whether a recursive function has a correct and reachable base case + +### Create +*Putting elements together to form a coherent or functional whole; reorganizing elements into a new pattern or structure.* + +- **Design** and **build** an original turtle graphics artwork program that uses functions, loops, color, and random elements +- **Construct** a Python program that reads a text file, processes the data using string methods and regular expressions, and writes a summary report +- **Develop** a custom Python module with at least three reusable functions and import it into a separate program +- **Create** a fully functional interactive color-picker application using turtle event handling +- **Build** a recursive fractal drawing (tree, snowflake, or spiral) and tune the depth and branching parameters +- **Design** a dictionary-based data application (e.g., a simple inventory system, word frequency counter, or grade tracker) using loops, conditionals, and file I/O +- **Implement** a BFS or DFS maze solver that reads a maze from a data structure, finds the shortest path, and visualizes the solution with turtle graphics +- **Construct** a data visualization dashboard using matplotlib that plots at least two datasets with labeled axes and a legend +- **Create** a simple class with `__init__`, attributes, and methods, and use it to model a real-world entity (e.g., a turtle race competitor, a quiz question, a playing card) +- **Build** and **train** a Keras neural network to classify handwritten digits from the MNIST dataset and report its test accuracy +- **Design** an original end-to-end Python project that integrates concepts from at least three course sections (e.g., turtle graphics + file I/O + randomness, or data visualization + NumPy + matplotlib) +- **Produce** a complete teacher's-guide-quality lesson plan for one course topic, including learning objectives, sample code, discussion questions, and a quiz + +## Course Materials Included + +- **Glossary:** A comprehensive glossary of 200+ Python and computer science terms, + with plain-language definitions written at a 5th-grade reading level, with examples +- **FAQ:** A frequently-asked-questions section addressing the most common points of + confusion for students transitioning from block-based to text-based programming +- **Quizzes:** Short, auto-graded quizzes (5–10 questions) at the end of each lesson + covering recall, understanding, and application of the lesson's key concepts +- **Teacher's Guide:** A detailed guide for instructors including pacing recommendations, + prerequisite concept maps, discussion prompts, common misconceptions, extension + activities, assessment rubrics, and alignment to CS education standards (CSTA K-12) +- **Monty the Mascot:** Inline mascot tips, hints, and encouragement throughout every + lesson, rendered as styled callout boxes alongside the Skulpt interactive coding windows diff --git a/docs/css/mascot.css b/docs/css/mascot.css new file mode 100644 index 00000000..b3df4d7e --- /dev/null +++ b/docs/css/mascot.css @@ -0,0 +1,137 @@ +/* ============================================ + Learning Mascot: Monty the Python + Pedagogical agent for Beginning Python + Colors: primary #642580 purple, accent #41BAC1 teal + ============================================ */ + +:root { + --mascot-primary: #642580; /* primary purple */ + --mascot-secondary: #41BAC1; /* accent teal */ + --mascot-bg: #f3eaf8; /* light purple tint */ + --mascot-border: #7a2f9e; /* medium purple */ + --mascot-size: 90px; +} + +/* ---- Shared base: match body font size, not MkDocs' smaller admonition default ---- */ +.md-typeset .admonition.mascot-welcome, +.md-typeset .admonition.mascot-thinking, +.md-typeset .admonition.mascot-tip, +.md-typeset .admonition.mascot-warning, +.md-typeset .admonition.mascot-celebration, +.md-typeset .admonition.mascot-encourage, +.md-typeset .admonition.mascot-neutral, +.md-typeset details.mascot-welcome, +.md-typeset details.mascot-thinking, +.md-typeset details.mascot-tip, +.md-typeset details.mascot-warning, +.md-typeset details.mascot-celebration, +.md-typeset details.mascot-encourage, +.md-typeset details.mascot-neutral { + font-size: inherit; +} + +/* ---- Welcome (chapter openings) — primary purple ---- */ +.md-typeset .admonition.mascot-welcome, +.md-typeset details.mascot-welcome { + border-color: var(--mascot-primary); + background-color: var(--mascot-bg); +} +.md-typeset .mascot-welcome > .admonition-title, +.md-typeset .mascot-welcome > summary { + background-color: var(--mascot-primary); + color: white; +} + +/* ---- Thinking (key concepts) — accent teal ---- */ +.md-typeset .admonition.mascot-thinking, +.md-typeset details.mascot-thinking { + border-color: var(--mascot-secondary); + background-color: #e0f7fa; +} +.md-typeset .mascot-thinking > .admonition-title, +.md-typeset .mascot-thinking > summary { + background-color: var(--mascot-secondary); + color: white; +} + +/* ---- Tip (hints) — emerald green (nod to Monty's green scales) ---- */ +.md-typeset .admonition.mascot-tip, +.md-typeset details.mascot-tip { + border-color: #2e7d32; + background-color: #e8f5e9; +} +.md-typeset .mascot-tip > .admonition-title, +.md-typeset .mascot-tip > summary { + background-color: #2e7d32; + color: white; +} + +/* ---- Warning (common mistakes) — red ---- */ +.md-typeset .admonition.mascot-warning, +.md-typeset details.mascot-warning { + border-color: #c62828; + background-color: #ffebee; +} +.md-typeset .mascot-warning > .admonition-title, +.md-typeset .mascot-warning > summary { + background-color: #c62828; + color: white; +} + +/* ---- Celebration (achievements) — deep purple with light text ---- */ +.md-typeset .admonition.mascot-celebration, +.md-typeset details.mascot-celebration { + border-color: #4a148c; + background-color: #311b4f; + color: #f3e5f5; +} +.md-typeset .mascot-celebration > .admonition-title, +.md-typeset .mascot-celebration > summary { + background-color: #4a148c; + color: white; +} + +/* ---- Encourage (difficult content) — blue ---- */ +.md-typeset .admonition.mascot-encourage, +.md-typeset details.mascot-encourage { + border-color: #0277bd; + background-color: #e1f5fe; +} +.md-typeset .mascot-encourage > .admonition-title, +.md-typeset .mascot-encourage > summary { + background-color: #0277bd; + color: white; +} + +/* ---- Neutral (general purpose) — slate gray ---- */ +.md-typeset .admonition.mascot-neutral, +.md-typeset details.mascot-neutral { + border-color: #546e7a; + background-color: #eceff1; +} +.md-typeset .mascot-neutral > .admonition-title, +.md-typeset .mascot-neutral > summary { + background-color: #546e7a; + color: white; +} + +/* ---- Title bar: left-align text, hide default MkDocs icon ---- */ +.md-typeset [class*="mascot-"] > .admonition-title, +.md-typeset [class*="mascot-"] > summary { + text-align: left; + padding-left: 0.8rem; +} +.md-typeset [class*="mascot-"] > .admonition-title::before, +.md-typeset [class*="mascot-"] > summary::before { + display: none; +} + +/* ---- Mascot image floated left inside admonition body ---- */ +.mascot-admonition-img { + float: left; + width: var(--mascot-size); + height: var(--mascot-size); + margin: 0 0.6em 0.2em 0; + object-fit: contain; + pointer-events: none; +} diff --git a/docs/css/skulpt.css b/docs/css/skulpt.css new file mode 100644 index 00000000..4d3ee84e --- /dev/null +++ b/docs/css/skulpt.css @@ -0,0 +1,119 @@ +/* Skulpt embedded Python editor — shared styles for all Skulpt labs. + * + * Single-lab pages use plain IDs: #skulpt-lab, #code, etc. + * Additional labs on the same page use suffixed IDs: #skulpt-lab-2, #code-2, etc. + * Attribute-prefix selectors ([id^="..."]) style both cases from one rule. + */ + +[id="skulpt-lab"], +[id^="skulpt-lab-"] { + display: flex; + gap: 16px; + flex-wrap: wrap; + margin: 1.5em 0; + font-family: monospace; +} + +[id="editor-container"], +[id^="editor-container-"] { + display: flex; + flex-direction: column; + flex: 1; + min-width: 280px; +} + +[id="code"], +[id^="code-"] { + width: 100%; + /* Height is set by skulpt.js on page load to fit the code exactly. + min-height is a fallback in case JS is slow or unavailable. */ + min-height: 120px; + padding: 10px; + font-size: 14px; + font-family: 'Courier New', monospace; + border: 2px solid #642580; + border-radius: 6px 6px 0 0; + background: #1e1e2e; + color: #cdd6f4; + resize: vertical; + box-sizing: border-box; + tab-size: 4; +} + +[id="code"]:focus, +[id^="code-"]:focus { + outline: none; + border-color: #41BAC1; +} + +[id="button-row"], +[id^="button-row-"] { + display: flex; + gap: 8px; + margin-top: 8px; +} + +[id="run-btn"], +[id^="run-btn-"], +[id="reset-btn"], +[id^="reset-btn-"] { + padding: 8px 20px; + font-size: 15px; + border: none; + border-radius: 4px; + cursor: pointer; + font-weight: bold; +} + +[id="run-btn"], +[id^="run-btn-"] { background: #642580; color: white; } +[id="run-btn"]:hover, +[id^="run-btn-"]:hover { background: #7a2f9e; } +[id="reset-btn"], +[id^="reset-btn-"] { background: #41BAC1; color: white; } +[id="reset-btn"]:hover, +[id^="reset-btn-"]:hover { background: #2fa8b0; } + +[id="output"], +[id^="output-"] { + margin-top: 8px; + padding: 8px; + min-height: 36px; + background: #f5f5f5; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 13px; + color: #222; + white-space: pre-wrap; +} + +.skulpt-error { + color: #c0392b; +} + +[id="canvas-container"], +[id^="canvas-container-"] { + flex: 0 0 auto; +} + +[id="turtle-target"], +[id^="turtle-target-"] { + width: 400px; + height: 400px; + border: 2px solid #642580; + border-radius: 6px; + background: white; + overflow: hidden; +} + +/* Text-only labs: canvas panel hidden, editor stretches to full width */ +.skulpt-text-only [id="canvas-container"], +.skulpt-text-only [id^="canvas-container-"] { + display: none; +} + +.skulpt-text-only [id="editor-container"], +.skulpt-text-only [id^="editor-container-"] { + flex: 1 1 100%; + min-width: 0; +} diff --git a/docs/img/dan-headshot-small.png b/docs/img/dan-headshot-small.png new file mode 100644 index 00000000..19c7c30f Binary files /dev/null and b/docs/img/dan-headshot-small.png differ diff --git a/docs/img/mascot/celebration.png b/docs/img/mascot/celebration.png new file mode 100644 index 00000000..1597dfc8 Binary files /dev/null and b/docs/img/mascot/celebration.png differ diff --git a/docs/img/mascot/encouraging.png b/docs/img/mascot/encouraging.png new file mode 100644 index 00000000..da219d98 Binary files /dev/null and b/docs/img/mascot/encouraging.png differ diff --git a/docs/img/mascot/neutral.png b/docs/img/mascot/neutral.png new file mode 100644 index 00000000..0f81e68a Binary files /dev/null and b/docs/img/mascot/neutral.png differ diff --git a/docs/img/mascot/thinking.png b/docs/img/mascot/thinking.png new file mode 100644 index 00000000..a0c46323 Binary files /dev/null and b/docs/img/mascot/thinking.png differ diff --git a/docs/img/mascot/tip.png b/docs/img/mascot/tip.png new file mode 100644 index 00000000..ba4a8ef0 Binary files /dev/null and b/docs/img/mascot/tip.png differ diff --git a/docs/img/mascot/warning.png b/docs/img/mascot/warning.png new file mode 100644 index 00000000..f03951da Binary files /dev/null and b/docs/img/mascot/warning.png differ diff --git a/docs/img/mascot/welcome.png b/docs/img/mascot/welcome.png new file mode 100644 index 00000000..0c540168 Binary files /dev/null and b/docs/img/mascot/welcome.png differ diff --git a/docs/img/stop-sign.png b/docs/img/stop-sign.png new file mode 100644 index 00000000..504458ea Binary files /dev/null and b/docs/img/stop-sign.png differ diff --git a/docs/index.md b/docs/index.md index 78afbb62..9aed921e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,30 +1,30 @@ -# CoderDojo Twin Cities Python Resources -This GitHub repository is for sharing teaching resources to teach Python. This includes hints on getting your Python environments setup up and extensive lesson plans for serveral enviornments. +# Beginning Python Resources +This GitHub repository is for sharing teaching resources to teach Python. This includes hints on getting your Python environments setup up and extensive lesson plans for several environments. -Our mentors have used several different envornments for teaching Python. They each have pros and cons. What our mentors like is getting new students started using a graphical programming environment such as turtle graphics libraries. Here are some of our favorite tools: +Our mentors have used several different environments for teaching Python. They each have pros and cons. What our mentors like is getting new students started using a graphical programming environment such as turtle graphics libraries. Here are some of our favorite tools: - [**Trinket.io**](http://trinket.io) is an easy-to use, kid friendly web-based turtle graphics for beginners. - [**Jupyter Notebooks**](https://jupyter.org/) also have some support for turtle graphics. Jupyter Notebooks can be tricky to setup for the first time, but they are the perfect on-ramp for teaching data literacy. - [**Raspberry Pi**](https://www.raspberrypi.org/documentation/usage/python/) - The Raspberry Pi foundation has selected Python as its primary tool for teaching programming. If you have a Raspberry Pi there are many resources for you. Trinket and Jupyter Notebooks will also run on many Raspberry Pi devices. - **Robots** Our students love robots. Python is also the preferred language in many robotics courses. Today we teach beginning robotics with Scratch and Arduino, but we continue to investigate systems like Raspberry Pi robots that can be programmed with Python. Let us know if you have any low-cost kid friendly ideas. We have tested the JetBot and other robots and we continue to look for solutions. -Now lets briefly go into the pros and cons of these systems. +Now let's briefly go into the pros and cons of these systems. ## Learning Python with Trinket -We use the [trinket.io](http://trinket.io) web site to teach our introduction to python. Trinket has a nice turtle graphics library which is ideal for fast visual feedback. Because it is a free and a pure web web based environment it meets the criteria for our courses. There is no complex setup and each student can continue to do development when they are at home. The downside of Trinket is it has limited functionality, only supports Python 2.X in the free version and you must have an internet connection to use Trinket. If you need Python 3.X web +We use the [trinket.io](http://trinket.io) web site to teach our introduction to python. Trinket has a nice turtle graphics library which is ideal for fast visual feedback. Because it is a free and a pure web-based environment it meets the criteria for our courses. There is no complex setup and each student can continue to do development when they are at home. The downside of Trinket is it has limited functionality, only supports Python 2.X in the free version and you must have an internet connection to use Trinket. If you need Python 3.X web version you can use the free [repl.id](https://repl.it/) web site. ## Learning Python with Jupyter Notebooks -You can also use Jupyter Notebooks to draw turtle graphics. The notebook will open a new window to draw your turtle graphis. Getting Jupyter Notebooks is a bit tricky to setup on many PCs. However, once it is setup it offers tens of thousands of sample programs to learn python coding. Jupyter Notebooks are also the preferred tool by many data science professionals. +You can also use Jupyter Notebooks to draw turtle graphics. The notebook will open a new window to draw your turtle graphics. Getting Jupyter Notebooks is a bit tricky to setup on many PCs. However, once it is setup it offers tens of thousands of sample programs to learn python coding. Jupyter Notebooks are also the preferred tool by many data science professionals. An example of a Jupyter Notebook that uses turtle graphs is [here](jupyter/draw-figure.ipynb) ## Learning Python with Raspberry Pi -If you have a Rasperry Pi there are many great ways to learn Python. One of first things is to try out one of the Python development environments for the Raspberry Pi. +If you have a Raspberry Pi there are many great ways to learn Python. One of first things is to try out one of the Python development environments for the Raspberry Pi. ## Learning Python with Robots -Right now we are continuing to try to find the right combination of easy-of-use and low-cost robots to teach python. If you hear of any good tools, please let us know. +Right now, we are continuing to try to find the right combination of easy-of-use and low-cost robots to teach python. If you hear of any good tools, please let us know. ## Target Audience Learning Python is ideal for students that have good keyboarding skills. If students have difficulty with doing functions like copy and pasting text we suggest they start with a block-programming language like Scratch. @@ -32,7 +32,7 @@ Learning Python is ideal for students that have good keyboarding skills. If stu ## List of Concepts Here are some of the concepts we will be learning in this course. If you are already familiar with these concepts you can skip over some of the labs. -- **importing libraries** We need to tell Pyhton what functions we want to use. We will use the import function to tell Python which functions we need to use in our programs. +- **importing libraries** We need to tell Python what functions we want to use. We will use the import function to tell Python which functions we need to use in our programs. - **drawing** Turtle graphs has a set of drawing functions. We will learn to use these to draw patterns on the screen. - **square walk** - teach your turtle to walk in a square and draw figures. - **variables** Variables make our programs easier to read and easier to understand. @@ -41,7 +41,7 @@ Here are some of the concepts we will be learning in this course. If you are al - **functions** Functions allow us to break large programs into chunks that we can give names and can call over and over. - **function parameters** Functions can also take parameters to change the behavior of a function. - **random numbers** Random number functions allow our programs to have the computer select new random number between a range of numbers. -- **lists** Lists alow us to create collections of names. +- **lists** Lists allow us to create collections of names. - **inputs** Inputs allow us to prompt the user for values. - **recursion** Recursion allows us to have programs call themselves to create repeating patterns. - **modules** Once you have a group of related functions you can put them all together into a module. This makes it easier for others to reuse your programs. diff --git a/docs/intermediate/01-intro.md b/docs/intermediate/01-intro.md index 98ba68be..b5263a04 100644 --- a/docs/intermediate/01-intro.md +++ b/docs/intermediate/01-intro.md @@ -1,6 +1,6 @@ # Introduction to Intermediate Python -This course assumes you are familiar with beginning concepts in Python such as variables, loops, conditionals, random numbers, functions, function parameters, lists and basic recursion. We strongly suggest that you have completed the [CoderDoj Twin Cities Beginning Python Class](../trinket/00-introduction.md) BEFORE you do the intermediate labs. +This course assumes you are familiar with beginning concepts in Python such as variables, loops, conditionals, random numbers, functions, function parameters, lists and basic recursion. We strongly suggest that you have completed the [Beginning Python Class](../trinket/00-introduction.md) BEFORE you do the intermediate labs. Note that you can do the first four lessons using web-based Python programming tools like Trinket.io or repl.it. Starting with lesson #5 on Files you will need to have Python installed on your local computer. Please visit the [Python.org](http://python.org) web site for the installation instructions on your operating systems. You can use the command-line version of Python from a Terminal or shell or you can install one of the Python Integrated Development Environments (IDEs). @@ -11,7 +11,7 @@ The concepts in this course include: 3. [**Checking Data Types of Function Parameters**](./03-data-type-validation.md) - in the beginning course we learned how to pass parameters to functions. Now we learn how to make sure our functions get the data that they expect! 4. [**Maps**](./04-maps.md) - Maps or dictionaries are sets of key-value pairs that are crazy flexible. Unlike a list, where the index can only be fixed sequence of integers starting with 0, the keys in a map can be any integer or string in any order. 5. [**Files**](./05-files.md) - In this lesson we will learn how to open a file and read the data into our program with just a few lines. Not only can we read in data, but we can also write out data! So much power in a few lines of code! -6. [**Images**](./06-images.md) - In our CoderDojo AI Racing League we will be learning how to make a car drive autonomously. But first we need to be able to read in images and display them. In this lab we will show you how easy this is! +6. [**Images**](./06-images.md) - In our AI Racing League we will be learning how to make a car drive autonomously. But first we need to be able to read in images and display them. In this lab we will show you how easy this is! 7. [**Defining Your Own Modules**](./07-modules.md) - In the Beginning Python class we learned how to create functions. Now we learn how to package them up so they are easy for others to use. 8. [**dir() function**](./08-dir.md) - If you ever want to know what functions you can throw at something we got this secret tool called "dir". It really takes the mystery out of what functions you can use and avoids trying to guess what function names are used. Not that guessing games aren't fun! 9. [**Regular expressions**](./09-regex.md) - You sometimes want a list of all the files in a folder that have a .jpg extension for images. This lesson will show you how we can use a shorthand notation to make it easy to specify what files to include and which ones to skip. diff --git a/docs/intermediate/06-images.md b/docs/intermediate/06-images.md index 0b20b711..72fb7b41 100644 --- a/docs/intermediate/06-images.md +++ b/docs/intermediate/06-images.md @@ -8,4 +8,4 @@ my_image = Image.open("/path/to/image.jpg") my_image.show() ``` -The CoderDojo AI Racing League will explore more around working with image data. \ No newline at end of file +The AI Racing League will explore more around working with image data. \ No newline at end of file diff --git a/docs/intermediate/bfsMaze.md b/docs/intermediate/bfsMaze.md index 7da8b18c..d6ca5b67 100644 --- a/docs/intermediate/bfsMaze.md +++ b/docs/intermediate/bfsMaze.md @@ -6,7 +6,7 @@ In this lab, we are going to solve a maze with an **algorithm** called **breadth * A **queue** is another commonly used data structure. Think of it as a line that we always take from the front of and always add to the back (no budging). -First, download the code template found in the ```src/intermediate``` folder of the repository, found [here](https://github.com/CoderDojoTC/python). Then, lets try and implement a solution to solve it! +First, download the code template found in the ```src/intermediate``` folder of the repository, found [here](https://github.com/dmccreary/python). Then, lets try and implement a solution to solve it! One solution is breadth-first search, or BFS. BFS works by cycling through all possible nodes one hop away from your current position, adding them to a **queue** and then cycling through all of those nodes in the queue to see if they are the solution. Lets see how it is implemented below: diff --git a/docs/js/skulpt.js b/docs/js/skulpt.js new file mode 100644 index 00000000..884eeedf --- /dev/null +++ b/docs/js/skulpt.js @@ -0,0 +1,96 @@ +/* Skulpt embedded Python editor — shared functions for all Skulpt labs. + * + * Single-lab pages use the default IDs (no suffix): + * id="code" id="output" id="turtle-target" etc. + * Buttons: onclick="runSkulpt()" onclick="resetSkulpt()" + * + * Pages with multiple labs give each additional lab a suffix, e.g. "-2": + * id="code-2" id="output-2" id="turtle-target-2" etc. + * Buttons: onclick="runSkulpt('-2')" onclick="resetSkulpt('-2')" + */ + +function builtinRead(x) { + if (Sk.builtinFiles === undefined || Sk.builtinFiles['files'][x] === undefined) + throw "File not found: '" + x + "'"; + return Sk.builtinFiles['files'][x]; +} + +/* Escape HTML special characters so print() output is safe to inject via innerHTML. */ +function _skulptEscape(text) { + return text.replace(/&/g, '&').replace(//g, '>'); +} + +function runSkulpt(suffix) { + suffix = suffix || ''; + var target = document.getElementById('turtle-target' + suffix); + var output = document.getElementById('output' + suffix); + var code = document.getElementById('code' + suffix); + if (!target || !output || !code) return; + + target.innerHTML = ''; + output.innerHTML = ''; + + Sk.configure({ + output: function (text) { output.innerHTML += _skulptEscape(text); }, + read: builtinRead, + __future__: Sk.python3, + killableWhile: true, + killableFor: true, + }); + + (Sk.TurtleGraphics || (Sk.TurtleGraphics = {})).target = 'turtle-target' + suffix; + Sk.TurtleGraphics.width = 400; + Sk.TurtleGraphics.height = 400; + + Sk.misceval.asyncToPromise(function () { + return Sk.importMainWithBody('', false, code.value, true); + }).catch(function (err) { + output.innerHTML += '' + _skulptEscape(err.toString()) + ''; + }); +} + +function resetSkulpt(suffix) { + suffix = suffix || ''; + var code = document.getElementById('code' + suffix); + var target = document.getElementById('turtle-target' + suffix); + var output = document.getElementById('output' + suffix); + var key = '_skulptOriginalCode' + suffix; + if (code && window[key] !== undefined) code.value = window[key]; + if (target) target.innerHTML = ''; + if (output) output.innerHTML = ''; +} + +function _initSkulptEditor() { + /* Initialise every textarea whose id is "code" or starts with "code-". */ + document.querySelectorAll('textarea[id="code"], textarea[id^="code-"]').forEach(function (code) { + var suffix = (code.id === 'code') ? '' : code.id.slice(4); /* "code-2" → "-2" */ + window['_skulptOriginalCode' + suffix] = code.value; + + /* Auto-size the textarea to show all initial code without scrolling. + Trim trailing newlines so the blank line before in the + markdown source doesn't add an empty row, then let the browser measure + the exact pixel height via scrollHeight rather than estimating per-line. + scrollHeight excludes borders; +4 compensates for the 2 px top+bottom + border under box-sizing: border-box. */ + var saved = code.value; + code.value = code.value.replace(/\n+$/, ''); + code.style.height = '0px'; + code.style.height = Math.max(120, code.scrollHeight + 4) + 'px'; + code.value = saved; + + code.addEventListener('keydown', function (e) { + if (e.key === 'Tab') { + e.preventDefault(); + var s = code.selectionStart; + code.value = code.value.substring(0, s) + ' ' + code.value.substring(code.selectionEnd); + code.selectionStart = code.selectionEnd = s + 4; + } + }); + }); +} + +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', _initSkulptEditor); +} else { + _initSkulptEditor(); +} diff --git a/docs/learning-graph/add-taxonomy.py b/docs/learning-graph/add-taxonomy.py new file mode 100644 index 00000000..d7a5d36b --- /dev/null +++ b/docs/learning-graph/add-taxonomy.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +""" +Add Taxonomy IDs to Concept Dependency CSV + +Reads the concept dependency CSV and assigns appropriate taxonomy IDs +based on concept labels and position in the concept hierarchy. +""" + +import csv +import re +from typing import Dict, List + + +def assign_taxonomy(concept_id: int, concept_label: str, taxonomy_config: dict = None) -> str: + """ + Assign taxonomy ID based on concept ID and label. + + Args: + concept_id: The concept identifier + concept_label: The concept name/label + taxonomy_config: Optional dictionary mapping taxonomy IDs to their configurations. + Each config contains 'range' (tuple) and 'keywords' (list). + If not provided, returns 'MISC' for all concepts. + + Returns: + Taxonomy ID string + + Example taxonomy_config: + { + 'MATH': { + 'range': (1, 20), + 'keywords': ['number', 'algebra', 'calculus', 'derivative'] + }, + 'CORE': { + 'range': (21, 50), + 'keywords': ['fundamental', 'basic', 'foundation'] + } + } + """ + if taxonomy_config is None: + return 'MISC' + + label_lower = concept_label.lower() + + # Check each taxonomy in order + for tax_id, config in taxonomy_config.items(): + range_start, range_end = config.get('range', (0, 0)) + keywords = config.get('keywords', []) + exclude_keywords = config.get('exclude', []) + + # Check if in range or matches keywords + in_range = range_start <= concept_id <= range_end + matches_keywords = any(kw in label_lower for kw in keywords) + has_exclusions = any(kw in label_lower for kw in exclude_keywords) + + if (in_range or matches_keywords) and not has_exclusions: + return tax_id + + # Default to MISC + return 'MISC' + + +def add_taxonomy_to_csv(input_csv: str, output_csv: str, taxonomy_config: dict = None): + """ + Read CSV, add taxonomy column, and write updated CSV. + + Args: + input_csv: Path to input CSV file + output_csv: Path to output CSV file + taxonomy_config: Optional taxonomy configuration dictionary + + Returns: + Dictionary of taxonomy counts + """ + rows = [] + with open(input_csv, 'r', encoding='utf-8') as f: + reader = csv.DictReader(f) + for row in reader: + concept_id = int(row['ConceptID']) + concept_label = row['ConceptLabel'] + taxonomy_id = assign_taxonomy(concept_id, concept_label, taxonomy_config) + + rows.append({ + 'ConceptID': concept_id, + 'ConceptLabel': concept_label, + 'Dependencies': row['Dependencies'], + 'TaxonomyID': taxonomy_id + }) + + # Write updated CSV + with open(output_csv, 'w', encoding='utf-8', newline='') as f: + fieldnames = ['ConceptID', 'ConceptLabel', 'Dependencies', 'TaxonomyID'] + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + writer.writerows(rows) + + # Count concepts per taxonomy + taxonomy_counts = {} + for row in rows: + tax = row['TaxonomyID'] + taxonomy_counts[tax] = taxonomy_counts.get(tax, 0) + 1 + + print(f"✅ Taxonomy added to CSV: {output_csv}") + print(f"\n📊 Taxonomy Distribution:") + for tax in sorted(taxonomy_counts.keys()): + count = taxonomy_counts[tax] + percentage = (count / len(rows)) * 100 + print(f" {tax:6s}: {count:3d} concepts ({percentage:5.1f}%)") + + return taxonomy_counts + + +if __name__ == "__main__": + import sys + import json + + # Parse command line arguments + if len(sys.argv) < 3: + print("Usage: python add-taxonomy.py [taxonomy_config.json]") + print("\nExample taxonomy_config.json format:") + print(json.dumps({ + 'FOUNDATION': { + 'range': [1, 20], + 'keywords': ['basic', 'fundamental', 'introduction'], + 'exclude': [] + }, + 'ADVANCED': { + 'range': [21, 50], + 'keywords': ['advanced', 'complex', 'detailed'], + 'exclude': [] + } + }, indent=2)) + sys.exit(1) + + input_csv = sys.argv[1] + output_csv = sys.argv[2] + + # Load taxonomy config if provided + taxonomy_config = None + if len(sys.argv) > 3: + config_file = sys.argv[3] + with open(config_file, 'r', encoding='utf-8') as f: + taxonomy_config = json.load(f) + print(f"📋 Loaded taxonomy config from: {config_file}") + else: + print("⚠️ No taxonomy config provided. All concepts will be marked as 'MISC'.") + print(" Provide a taxonomy config JSON file as the third argument.") + + taxonomy_counts = add_taxonomy_to_csv(input_csv, output_csv, taxonomy_config) diff --git a/docs/learning-graph/analyze-graph.py b/docs/learning-graph/analyze-graph.py new file mode 100644 index 00000000..d1476d3b --- /dev/null +++ b/docs/learning-graph/analyze-graph.py @@ -0,0 +1,379 @@ +#!/usr/bin/env python3 +""" +Learning Graph Quality Analysis Script + +Analyzes the concept dependency graph and generates quality metrics including: +- DAG verification +- Indegree/outdegree analysis +- Dependency chain analysis +- Terminal node detection (indegree=0, outdegree>0: nothing depends on them) +- Orphaned node detection (indegree=0, outdegree=0: completely disconnected) +- Connected component analysis +""" + +import csv +from collections import defaultdict, deque +from typing import Dict, List, Set, Tuple + + +def load_graph(csv_path: str) -> Tuple[Dict[int, str], Dict[int, List[int]]]: + """Load the dependency graph from CSV file.""" + concepts = {} # id -> label + dependencies = defaultdict(list) # id -> list of prerequisite ids + + with open(csv_path, 'r', encoding='utf-8') as f: + reader = csv.DictReader(f) + for row in reader: + concept_id = int(row['ConceptID']) + concepts[concept_id] = row['ConceptLabel'] + + if row['Dependencies']: + deps = [int(d) for d in row['Dependencies'].split('|')] + dependencies[concept_id] = deps + + return concepts, dependencies + + +def calculate_indegree(concepts: Dict[int, str], + dependencies: Dict[int, List[int]]) -> Dict[int, int]: + """Calculate indegree (number of concepts that depend on each concept).""" + indegree = {cid: 0 for cid in concepts} + + for concept_id, prereqs in dependencies.items(): + for prereq in prereqs: + indegree[prereq] += 1 + + return indegree + + +def calculate_outdegree(concepts: Dict[int, str], + dependencies: Dict[int, List[int]]) -> Dict[int, int]: + """Calculate outdegree (number of prerequisites for each concept).""" + outdegree = {cid: len(dependencies.get(cid, [])) for cid in concepts} + return outdegree + + +def find_terminal_nodes(concepts: Dict[int, str], + indegree: Dict[int, int], + dependencies: Dict[int, List[int]]) -> List[Tuple[int, str]]: + """Find terminal nodes: concepts that nothing depends on but have prerequisites. + These are natural endpoints of learning paths (indegree=0, outdegree>0).""" + terminal = [(cid, label) for cid, label in concepts.items() + if indegree[cid] == 0 and len(dependencies.get(cid, [])) > 0] + return terminal + + +def find_orphaned_nodes(concepts: Dict[int, str], + indegree: Dict[int, int], + dependencies: Dict[int, List[int]]) -> List[Tuple[int, str]]: + """Find orphaned nodes: completely disconnected concepts with no edges at all. + These have no inbound AND no outbound edges (indegree=0, outdegree=0).""" + orphaned = [(cid, label) for cid, label in concepts.items() + if indegree[cid] == 0 and len(dependencies.get(cid, [])) == 0] + return orphaned + + +def verify_dag(concepts: Dict[int, str], + dependencies: Dict[int, List[int]]) -> Tuple[bool, List[List[int]]]: + """Verify the graph is a DAG using topological sort (Kahn's algorithm). + + Uses the reverse graph (prerequisite → dependent) so that: + - in-degree = number of prerequisites each concept has + - Start from foundational concepts (no prerequisites) + - When a concept's prerequisites are all processed, it can be processed too + """ + # In-degree in reverse graph = number of prerequisites each concept has + prereq_count = {cid: len(dependencies.get(cid, [])) for cid in concepts} + + # Start with foundational concepts (no prerequisites) + queue = deque([cid for cid in concepts if prereq_count[cid] == 0]) + processed = [] + + while queue: + node = queue.popleft() + processed.append(node) + + # Find all concepts that depend on this node (this node is their prerequisite) + for concept_id, prereqs in dependencies.items(): + if node in prereqs: + prereq_count[concept_id] -= 1 + if prereq_count[concept_id] == 0: + queue.append(concept_id) + + is_dag = len(processed) == len(concepts) + cycles = [] if is_dag else find_cycles(concepts, dependencies) + + return is_dag, cycles + + +def find_cycles(concepts: Dict[int, str], + dependencies: Dict[int, List[int]]) -> List[List[int]]: + """Find cycles in the graph using DFS.""" + visited = set() + rec_stack = set() + cycles = [] + + def dfs(node, path): + visited.add(node) + rec_stack.add(node) + path.append(node) + + # Check all nodes that this node depends on (reverse edges in dependency graph) + for next_node, prereqs in dependencies.items(): + if node in prereqs: + if next_node not in visited: + if dfs(next_node, path[:]): + return True + elif next_node in rec_stack: + cycle_start = path.index(next_node) + cycles.append(path[cycle_start:] + [next_node]) + return True + + rec_stack.remove(node) + return False + + for node in concepts: + if node not in visited: + dfs(node, []) + + return cycles + + +def find_longest_chain(concepts: Dict[int, str], + dependencies: Dict[int, List[int]]) -> Tuple[int, List[int]]: + """Find the longest dependency chain using DFS.""" + memo = {} + + def dfs(node): + if node in memo: + return memo[node] + + if node not in dependencies or not dependencies[node]: + memo[node] = (1, [node]) + return memo[node] + + max_length = 0 + max_path = [] + + for prereq in dependencies[node]: + length, path = dfs(prereq) + if length > max_length: + max_length = length + max_path = path + + memo[node] = (max_length + 1, max_path + [node]) + return memo[node] + + max_chain_length = 0 + max_chain_path = [] + + for concept_id in concepts: + length, path = dfs(concept_id) + if length > max_chain_length: + max_chain_length = length + max_chain_path = path + + return max_chain_length, max_chain_path + + +def find_connected_components(concepts: Dict[int, str], + dependencies: Dict[int, List[int]]) -> List[Set[int]]: + """Find connected components (treating graph as undirected).""" + visited = set() + components = [] + + def bfs(start): + component = set() + queue = deque([start]) + component.add(start) + visited.add(start) + + while queue: + node = queue.popleft() + + # Add all neighbors (both directions) + if node in dependencies: + for prereq in dependencies[node]: + if prereq not in visited: + visited.add(prereq) + component.add(prereq) + queue.append(prereq) + + for concept_id, prereqs in dependencies.items(): + if node in prereqs and concept_id not in visited: + visited.add(concept_id) + component.add(concept_id) + queue.append(concept_id) + + return component + + for concept_id in concepts: + if concept_id not in visited: + component = bfs(concept_id) + components.append(component) + + return components + + +def generate_report(csv_path: str, output_path: str): + """Generate comprehensive quality metrics report.""" + concepts, dependencies = load_graph(csv_path) + + # Calculate metrics + indegree = calculate_indegree(concepts, dependencies) + outdegree = calculate_outdegree(concepts, dependencies) + terminal = find_terminal_nodes(concepts, indegree, dependencies) + orphaned = find_orphaned_nodes(concepts, indegree, dependencies) + is_dag, cycles = verify_dag(concepts, dependencies) + max_chain_length, max_chain_path = find_longest_chain(concepts, dependencies) + components = find_connected_components(concepts, dependencies) + + # Foundational concepts (no prerequisites but other concepts depend on them) + foundational = [(cid, label) for cid, label in concepts.items() + if outdegree[cid] == 0 and indegree[cid] > 0] + + # Top concepts by indegree + top_indegree = sorted([(cid, label, indegree[cid]) + for cid, label in concepts.items()], + key=lambda x: x[2], reverse=True)[:10] + + # Calculate average dependencies + total_deps = sum(len(deps) for deps in dependencies.values()) + avg_deps = total_deps / len(dependencies) if dependencies else 0 + + # Generate markdown report + with open(output_path, 'w', encoding='utf-8') as f: + f.write("# Learning Graph Quality Metrics Report\n\n") + f.write("## Overview\n\n") + f.write(f"- **Total Concepts**: {len(concepts)}\n") + f.write(f"- **Foundational Concepts** (no prerequisites, other concepts depend on them): {len(foundational)}\n") + f.write(f"- **Terminal Nodes** (nothing depends on them, but have prerequisites): {len(terminal)}\n") + f.write(f"- **Orphaned Nodes** (completely disconnected, no edges): {len(orphaned)}\n") + f.write(f"- **Concepts with Dependencies**: {len(dependencies)}\n") + f.write(f"- **Average Dependencies per Concept**: {avg_deps:.2f}\n\n") + + f.write("## Graph Structure Validation\n\n") + f.write(f"- **Valid DAG Structure**: {'✅ Yes' if is_dag else '❌ No'}\n") + f.write(f"- **Self-Dependencies**: None detected ✅\n") + f.write(f"- **Cycles Detected**: {len(cycles)}\n\n") + + if cycles: + f.write("### Detected Cycles:\n\n") + for i, cycle in enumerate(cycles, 1): + cycle_labels = [concepts[cid] for cid in cycle] + f.write(f"{i}. {' → '.join(cycle_labels)}\n") + f.write("\n") + + f.write("## Foundational Concepts\n\n") + f.write("These concepts have no prerequisites:\n\n") + for cid, label in foundational: + f.write(f"- **{cid}**: {label}\n") + f.write("\n") + + f.write("## Dependency Chain Analysis\n\n") + f.write(f"- **Maximum Dependency Chain Length**: {max_chain_length}\n\n") + f.write("### Longest Learning Path:\n\n") + for i, cid in enumerate(max_chain_path, 1): + f.write(f"{i}. **{concepts[cid]}** (ID: {cid})\n") + f.write("\n") + + terminal_pct = len(terminal) / len(concepts) * 100 if concepts else 0 + f.write("## Terminal Nodes Analysis\n\n") + f.write("Terminal nodes are concepts that nothing else depends on but have prerequisites. ") + f.write("They represent natural endpoints of learning paths — culminating or specialized concepts.\n\n") + f.write(f"- **Total Terminal Nodes**: {len(terminal)} ({terminal_pct:.1f}% of all concepts)\n") + f.write(f"- **Healthy Range**: 5-40% of total concepts\n\n") + if terminal: + f.write("Concepts at the end of learning paths:\n\n") + for cid, label in terminal[:20]: # Show first 20 + f.write(f"- **{cid}**: {label}\n") + if len(terminal) > 20: + f.write(f"\n*...and {len(terminal) - 20} more*\n") + else: + f.write("No terminal nodes detected.\n") + f.write("\n") + + f.write("## Orphaned Nodes Analysis\n\n") + f.write("Orphaned nodes are completely disconnected concepts with no inbound AND no outbound edges. ") + f.write("These indicate a quality problem — every concept should connect to the graph.\n\n") + f.write(f"- **Total Orphaned Nodes**: {len(orphaned)}\n\n") + if orphaned: + f.write("⚠️ Completely disconnected concepts:\n\n") + for cid, label in orphaned: + f.write(f"- **{cid}**: {label}\n") + else: + f.write("✅ No orphaned nodes detected. All concepts are connected to the graph.\n") + f.write("\n") + + f.write("## Connected Components\n\n") + f.write(f"- **Number of Connected Components**: {len(components)}\n\n") + if len(components) == 1: + f.write("✅ All concepts are connected in a single graph.\n\n") + else: + f.write("⚠️ Multiple disconnected subgraphs detected:\n\n") + for i, component in enumerate(components, 1): + f.write(f"### Component {i} ({len(component)} concepts)\n\n") + for cid in sorted(list(component)[:10]): + f.write(f"- {concepts[cid]}\n") + if len(component) > 10: + f.write(f"- *...and {len(component) - 10} more*\n") + f.write("\n") + + f.write("## Indegree Analysis\n\n") + f.write("Top 10 concepts that are prerequisites for the most other concepts:\n\n") + f.write("| Rank | Concept ID | Concept Label | Indegree |\n") + f.write("|------|-----------|---------------|----------|\n") + for i, (cid, label, ind) in enumerate(top_indegree, 1): + f.write(f"| {i} | {cid} | {label} | {ind} |\n") + f.write("\n") + + f.write("## Outdegree Distribution\n\n") + outdeg_dist = defaultdict(int) + for deg in outdegree.values(): + outdeg_dist[deg] += 1 + + f.write("| Dependencies | Number of Concepts |\n") + f.write("|--------------|--------------------|\n") + for deg in sorted(outdeg_dist.keys()): + f.write(f"| {deg} | {outdeg_dist[deg]} |\n") + f.write("\n") + + f.write("## Recommendations\n\n") + if len(components) > 1: + f.write("- ⚠️ **Connect disconnected components**: Add dependencies to link separate subgraphs\n") + if orphaned: + f.write(f"- ⚠️ **Orphaned nodes detected** ({len(orphaned)}): These concepts are completely disconnected and must be linked to the graph\n") + if terminal_pct > 40: + f.write(f"- ℹ️ **High terminal node percentage** ({terminal_pct:.1f}%): Consider if some terminal concepts should be prerequisites for advanced concepts\n") + elif terminal_pct < 5: + f.write(f"- ℹ️ **Low terminal node percentage** ({terminal_pct:.1f}%): Graph may lack endpoint specialization\n") + else: + f.write(f"- ✅ **Terminal node percentage** ({terminal_pct:.1f}%): Within healthy range (5-40%)\n") + if is_dag: + f.write("- ✅ **DAG structure verified**: Graph supports valid learning progressions\n") + if max_chain_length > 15: + f.write(f"- ℹ️ **Long dependency chains** ({max_chain_length}): Ensure students can follow extended learning paths\n") + if avg_deps < 1.5: + f.write("- ℹ️ **Consider adding cross-dependencies**: More connections could create richer learning pathways\n") + + f.write("\n---\n\n") + f.write("*Report generated by learning-graph-reports/analyze_graph.py*\n") + + print(f"✅ Quality metrics report generated: {output_path}") + return is_dag, len(foundational), len(terminal), len(orphaned), max_chain_length + + +if __name__ == "__main__": + import sys + + # Parse command line arguments + if len(sys.argv) < 3: + print("Usage: python analyze-graph.py ") + print("\nExample:") + print(" python analyze-graph.py learning-graph.csv quality-metrics.md") + sys.exit(1) + + csv_path = sys.argv[1] + output_path = sys.argv[2] + + generate_report(csv_path, output_path) diff --git a/docs/learning-graph/color-config.json b/docs/learning-graph/color-config.json new file mode 100644 index 00000000..6a9b7085 --- /dev/null +++ b/docs/learning-graph/color-config.json @@ -0,0 +1,16 @@ +{ + "ENV": "SteelBlue", + "SYN": "DarkSlateBlue", + "DAT": "DarkGreen", + "CTL": "LimeGreen", + "FUN": "Gold", + "COL": "DarkGoldenrod", + "MOD": "Teal", + "TXT": "DodgerBlue", + "FIO": "LightSkyBlue", + "ERR": "Crimson", + "OOP": "MediumPurple", + "VIZ": "DarkOrchid", + "ALG": "OliveDrab", + "ADV": "Orange" +} diff --git a/docs/learning-graph/concept-list-v1.md b/docs/learning-graph/concept-list-v1.md new file mode 100644 index 00000000..9815b28d --- /dev/null +++ b/docs/learning-graph/concept-list-v1.md @@ -0,0 +1,521 @@ +# Beginning Python — Concept List v1 + +This concept list was derived from the existing manually created course content in the `docs/` directory +and supplemented with additional concepts appropriate for a beginning Python course. +The original textbook was created by hand by humans starting around May of 2020 when Trinket was +the best practice for teaching introduction to Python with Turtle graphics. This +course was used in the CoderDojo Twin Cities coding clubs and the Code Savvy clubs for many years. +It serves as the foundation for the learning graph used to regenerate the course in June of 2026 +using Claude Code Opus 2.6 in High effort mode. + +--- + +## 1. Development Environments & Setup + +1. Python interpreter overview +2. Python 2 vs Python 3 differences +3. Trinket.io — web-based Python environment +4. repl.it — online Python IDE +5. Thonny — beginner-friendly Python IDE +6. Spyder IDE — scientific Python IDE +7. VS Code — general-purpose code editor +8. Jupyter Notebooks — interactive computational environment +9. JupyterLab — enhanced Jupyter environment +10. Conda — environment and package manager +11. pip — Python package installer +12. Virtual environments +13. Installing Python locally +14. Running Python scripts from the terminal +15. The Python REPL (interactive shell) +16. Raspberry Pi as a Python platform + +--- + +## 2. Basic Syntax & Output + +17. print() function +18. Comments (single-line with `#`) +19. Multi-line strings (triple quotes) +20. Indentation as syntax (whitespace rules) +21. Case sensitivity in Python +22. Python keywords (reserved words) +23. Blank lines and code readability + +--- + +## 3. Variables & Assignment + +24. Variable definition and assignment (`=`) +25. Variable naming rules (letters, digits, underscores) +26. Snake_case naming convention +27. Meaningful variable names +28. Multiple assignment (`a, b = 1, 2`) +29. Augmented assignment operators (`+=`, `-=`, `*=`, `/=`) +30. Constants (by convention, ALL_CAPS) + +--- + +## 4. Data Types + +### Numeric +31. Integers (`int`) — whole numbers, positive and negative +32. Floats (`float`) — decimal numbers +33. Division always returns float in Python 3 +34. Integer division (`//`) +35. Modulo operator (`%`) — remainder after division +36. Exponentiation (`**`) +37. Arithmetic operators: `+`, `-`, `*`, `/` + +### Boolean +38. Boolean type (`bool`) — `True` and `False` +39. Comparison operators: `>`, `<`, `>=`, `<=`, `==`, `!=` +40. Logical operators: `and`, `or`, `not` +41. Truthiness and falsiness of values + +### Strings +42. String type (`str`) — text enclosed in quotes +43. Single vs double quotes +44. String concatenation with `+` +45. String repetition with `*` +46. String indexing (0-based) +47. String slicing (`s[start:end:step]`) +48. Escape characters (`\n`, `\t`, `\\`, `\"`) +49. String length with `len()` +50. String methods: `.lower()`, `.upper()`, `.strip()`, `.lstrip()`, `.rstrip()` +51. String methods: `.split()`, `.join()`, `.replace()` +52. String methods: `.startswith()`, `.endswith()`, `.find()`, `.count()` +53. String methods: `.isdigit()`, `.isalpha()`, `.isalnum()` +54. String formatting with `.format()` +55. f-strings (formatted string literals) +56. String immutability + +### None +57. `None` — null/empty value, `NoneType` +58. Functions without `return` return `None` +59. Checking for `None` with `is None` + +--- + +## 5. Type Conversion (Casting) + +60. `int()` — convert to integer +61. `float()` — convert to float +62. `str()` — convert to string +63. `bool()` — convert to boolean +64. `type()` — inspect a variable's type +65. `isinstance()` — check if object is an instance of a type + +--- + +## 6. User Input + +66. `input()` function — read text from user +67. Prompting the user (passing a string to `input()`) +68. Converting input strings to numbers with `int()` / `float()` +69. Input validation basics + +--- + +## 7. Control Flow — Conditionals + +70. `if` statement +71. `if...else` block +72. `elif` (else-if) chains +73. Nested `if` statements +74. Conditional expressions (ternary): `x if condition else y` +75. `match`/`case` statement (Python 3.10+, structural pattern matching) + +--- + +## 8. Control Flow — Loops + +76. `for` loop — iterating over a sequence +77. `for` loop with `range()` +78. `range(start, stop, step)` +79. `while` loop — condition-based repetition +80. `break` — exit a loop early +81. `continue` — skip to next iteration +82. `else` clause on loops +83. Nested loops +84. Loop counter variable (`i`, `j`) +85. Infinite loops and how to avoid them +86. `enumerate()` — iterate with index and value +87. `zip()` — iterate over multiple sequences simultaneously + +--- + +## 9. Functions + +88. Defining a function with `def` +89. Calling a function +90. Function parameters (positional) +91. Default parameter values +92. Keyword arguments +93. `return` statement +94. Functions that return `None` implicitly +95. Local scope — variables inside functions +96. Global scope — variables at module level +97. `global` keyword — access global variable inside function +98. `nonlocal` keyword — access enclosing scope variable +99. Docstrings — documenting functions +100. Pure functions vs functions with side effects +101. Recursion — a function calling itself +102. Recursion base case and recursive case +103. Recursion depth and stack overflow +104. Lambda functions (anonymous functions) + +--- + +## 10. Collections — Lists + +105. List type (`list`) — ordered, mutable collection +106. Creating a list with `[]` +107. List indexing (0-based, negative indexing) +108. List slicing +109. `len()` — number of items in a list +110. List methods: `.append()`, `.insert()`, `.extend()` +111. List methods: `.remove()`, `.pop()`, `.clear()` +112. List methods: `.sort()`, `.reverse()`, `.copy()` +113. List methods: `.index()`, `.count()` +114. Checking membership with `in` +115. List concatenation and repetition +116. Iterating over a list with `for` +117. Nested lists (lists of lists) +118. List comprehensions + +--- + +## 11. Collections — Tuples + +119. Tuple type (`tuple`) — ordered, immutable collection +120. Creating a tuple with `()` +121. Tuple indexing and slicing +122. Tuple unpacking +123. When to use tuples vs lists +124. Single-element tuple syntax (`(x,)`) + +--- + +## 12. Collections — Dictionaries + +125. Dictionary type (`dict`) — key-value pairs +126. Creating a dictionary with `{}` +127. Accessing values by key (`d[key]`) +128. `.get()` method — safe key access with default +129. Adding and updating key-value pairs +130. Removing entries: `.pop()`, `del` +131. Dictionary methods: `.keys()`, `.values()`, `.items()` +132. Iterating over a dictionary +133. Checking key membership with `in` +134. Nested dictionaries +135. Dictionary comprehensions + +--- + +## 13. Collections — Sets + +136. Set type (`set`) — unordered collection of unique items +137. Creating a set with `{}` or `set()` +138. Set operations: union (`|`), intersection (`&`), difference (`-`) +139. `.add()`, `.remove()`, `.discard()` methods +140. Checking membership with `in` +141. Frozensets (immutable sets) + +--- + +## 14. Built-in Functions + +142. `print()` — output to console +143. `input()` — read user input +144. `len()` — length of a sequence +145. `range()` — generate a sequence of numbers +146. `type()` — get type of an object +147. `int()`, `float()`, `str()`, `bool()` — type conversions +148. `list()`, `tuple()`, `set()`, `dict()` — collection constructors +149. `max()`, `min()` — find maximum/minimum +150. `sum()` — sum values in an iterable +151. `abs()` — absolute value +152. `round()` — round a number +153. `sorted()` — return sorted list +154. `reversed()` — return reverse iterator +155. `enumerate()` — iterate with index +156. `zip()` — combine iterables +157. `map()` — apply function to each item +158. `filter()` — filter items by condition +159. `dir()` — list attributes/methods of an object +160. `help()` — display documentation + +--- + +## 15. Modules & Imports + +161. `import` statement +162. `from ... import ...` — import specific names +163. `import ... as ...` — alias a module +164. `from ... import *` — import all (use sparingly) +165. Creating custom modules (`.py` files) +166. `__name__ == "__main__"` guard +167. The Python standard library overview + +### Standard Library Modules +168. `random` — random number generation +169. `random.randint(min, max)` +170. `random.choice(sequence)` +171. `random.shuffle(list)` +172. `random.seed()` — reproducibility +173. `math` — mathematical functions +174. `math.sqrt()`, `math.floor()`, `math.ceil()` +175. `math.sin()`, `math.cos()`, `math.pi` +176. `math.radians()` — degrees to radians +177. `string` — string constants (punctuation, digits, etc.) +178. `time` — time operations +179. `time.sleep()` — pause execution +180. `sys` — system-level operations +181. `sys.path` — Python module search path +182. `os` — operating system interface +183. `os.path` — file path operations +184. `re` — regular expressions + +--- + +## 16. Regular Expressions + +185. Importing `re` module +186. `re.search(pattern, string)` — find first match +187. `re.findall(pattern, string)` — find all matches +188. `re.split(pattern, string)` — split by pattern +189. `re.sub(pattern, replacement, string)` — substitute matches +190. Common patterns: `\d` (digit), `\w` (word char), `\s` (whitespace) +191. Anchors: `^` (start), `$` (end) +192. Character classes: `[a-z]`, `[A-Z]`, `[0-9]` +193. Quantifiers: `+` (one or more), `*` (zero or more), `?` (optional) +194. Alternation with `|` +195. Escaping special characters with `\` +196. Raw strings for regex patterns (`r"..."`) + +--- + +## 17. File Input/Output + +197. `open()` function +198. File modes: `'r'` (read), `'w'` (write), `'a'` (append), `'b'` (binary) +199. `file.read()` — read entire file as string +200. `file.readlines()` — read all lines into a list +201. `file.readline()` — read one line at a time +202. `file.write()` — write string to file +203. `file.close()` — close file handle +204. `with` statement (context manager) for safe file handling +205. Iterating over file lines with `for` +206. String methods for text processing: `.strip()`, `.lower()`, `.replace()` +207. CSV file reading basics + +--- + +## 18. Error Handling + +208. Types of errors: syntax errors vs runtime errors vs logic errors +209. Common exceptions: `ValueError`, `TypeError`, `IndexError`, `KeyError`, `NameError`, `ZeroDivisionError` +210. Reading a traceback (stack trace) +211. `try...except` block +212. `except ExceptionType as e` — catching specific exceptions +213. `else` clause in try/except +214. `finally` clause — always executes +215. `raise` — raising exceptions manually +216. `assert` statement with error messages +217. Debugging with `print()` statements +218. Using Google and Stack Overflow to debug errors + +--- + +## 19. Object-Oriented Programming (Intro) + +219. Objects and classes — conceptual overview +220. Attributes — properties of an object +221. Methods — functions belonging to an object +222. `class` keyword — defining a class +223. `__init__()` — constructor method +224. `self` parameter +225. Creating instances of a class +226. Accessing attributes and calling methods (`obj.attr`, `obj.method()`) +227. String methods as examples of OOP +228. List methods as examples of OOP +229. Inheritance — basics +230. `__str__()` — string representation of an object + +--- + +## 20. Turtle Graphics + +231. `import turtle` +232. Creating a `turtle.Turtle()` object +233. Creating a `turtle.Screen()` object +234. Screen setup: `setup(width, height)`, `bgcolor(color)`, `title(text)` +235. Movement: `forward()`, `backward()`, `left()`, `right()` +236. Absolute positioning: `goto(x, y)`, `setx()`, `sety()` +237. Pen control: `penup()`, `pendown()`, `pensize()` +238. Color: `color()`, `pencolor()`, `fillcolor()` +239. Fill: `begin_fill()`, `end_fill()` +240. Drawing shapes: `circle(radius)`, drawing squares/polygons with loops +241. Turtle appearance: `shape()` (turtle, arrow, circle, square, triangle, classic) +242. Hiding/showing turtle: `hideturtle()`, `showturtle()` +243. Writing text: `write(text, font=...)` +244. Clearing: `clear()`, `reset()` +245. Position query: `xcor()`, `ycor()`, `heading()` +246. Speed control: `speed(value)` +247. Direction: `setheading(angle)` +248. Event handling: `onscreenclick(function)` +249. Animation with turtle (frame-based loops) +250. Building a color picker with turtle +251. Drawing fractals with recursion and turtle +252. Drawing a sine wave with turtle and math + +--- + +## 21. Data Visualization + +253. `matplotlib` library overview +254. `import matplotlib.pyplot as plt` +255. `plt.plot(x, y)` — line plot +256. `plt.show()` — display plot +257. `plt.title()`, `plt.xlabel()`, `plt.ylabel()` — labels +258. `plt.grid()` — show grid lines +259. Plotting a sine wave +260. Working with lists as x/y data + +--- + +## 22. Numerical Computing (NumPy Intro) + +261. `numpy` library overview +262. `import numpy as np` +263. `np.array()` — creating arrays +264. `np.argmax()` — index of maximum value +265. Array operations and broadcasting basics +266. Reshaping arrays (`array.reshape()`) + +--- + +## 23. Image Processing (Intro) + +267. PIL (Python Imaging Library) / Pillow overview +268. `Image.open(path)` — open an image +269. `image.show()` — display an image +270. Pixel data and image arrays + +--- + +## 24. Data Structures & Algorithms + +271. Abstract data types overview +272. Stack — LIFO (Last In, First Out) +273. Queue — FIFO (First In, First Out) +274. Queue operations: enqueue (`append()`), dequeue (`pop(0)`) +275. Graph — nodes and edges +276. Adjacency list representation +277. Breadth-First Search (BFS) algorithm +278. BFS color tracking (white, gray, black) +279. BFS for path finding +280. Depth-First Search (DFS) algorithm +281. DFS with recursion and backtracking +282. DFS and BFS for maze solving +283. Sorting algorithms overview (bubble, selection, insertion) +284. Binary search concept + +--- + +## 25. Machine Learning & Neural Networks (Advanced) + +285. Machine learning overview — supervised vs unsupervised +286. `keras` library overview +287. Sequential model +288. Dense layers — fully connected layers +289. Activation functions: `relu`, `softmax` +290. Conv2D — convolutional layers +291. MaxPooling2D — pooling layers +292. Dropout — regularization to prevent overfitting +293. Flatten layer — reshape for dense layers +294. `model.compile()` — loss function, optimizer, metrics +295. `model.fit()` — training the model +296. `model.evaluate()` — testing accuracy +297. `model.predict()` — making predictions +298. Loss functions: `categorical_crossentropy` +299. Optimizer: Adam +300. Metrics: accuracy +301. Batch size and epochs +302. MNIST dataset — handwritten digit recognition +303. Data normalization/preprocessing +304. Convolutional Neural Networks (CNN) +305. Feedforward networks +306. Recurrent networks (RNN) — overview +307. LSTM networks — overview +308. Autoencoders — overview + +--- + +## 26. Graphics in Jupyter + +309. `ipycanvas` — canvas drawing in Jupyter +310. `mobilechelonian` — turtle graphics in Jupyter +311. Drawing shapes on a canvas +312. Color bars and data visualization in Jupyter + +--- + +## 27. Event-Driven & Interactive Programming + +313. Event-driven programming model +314. Mouse click event handlers (`onscreenclick`) +315. Keyboard event handlers (turtle `onkey`) +316. Callback functions +317. Animation loops + +--- + +## 28. Programming Practices & Patterns + +318. Modularity — breaking code into functions +319. Code reusability +320. DRY principle (Don't Repeat Yourself) +321. Meaningful variable and function names +322. Code comments — when and why +323. Literate programming with Jupyter +324. Reading documentation with `help()` and `dir()` +325. Version control basics (git overview) +326. Searching Stack Overflow and documentation + +--- + +## 29. Color & Graphics Concepts + +327. Named colors (red, green, blue, orange, etc.) +328. Hex color values (`#FA057F`) +329. RGB color model +330. Color in turtle graphics +331. Background and pen colors + +--- + +## Concepts Added Beyond Existing Content + +The following concepts are recommended additions to make the course more complete +for a modern beginning Python curriculum: + +332. f-strings (formatted string literals) — more readable than `.format()` +333. List comprehensions — concise way to build lists +334. Dictionary comprehensions +335. `with` statement / context managers — safe resource handling +336. `match`/`case` statement (Python 3.10+) — modern pattern matching +337. Lambda functions — anonymous single-expression functions +338. `map()` and `filter()` — functional programming basics +339. Sorting with a key function (`sorted(list, key=...)`) +340. String f-string formatting with format specifiers (e.g., `{x:.2f}`) +341. `os` and `os.path` — file path and directory operations +342. CSV files — reading/writing structured data +343. Exception hierarchy — understanding `Exception` base class +344. `raise` — throwing custom errors +345. Class `__str__()` and `__repr__()` methods +346. Inheritance — subclasses and method overriding +347. DRY principle and code reuse patterns +348. `__name__ == "__main__"` guard for runnable modules +349. Virtual environments — keeping projects isolated +350. Reading and writing JSON files (`json` module) diff --git a/docs/learning-graph/concept-list.md b/docs/learning-graph/concept-list.md new file mode 100644 index 00000000..9dddde3e --- /dev/null +++ b/docs/learning-graph/concept-list.md @@ -0,0 +1,634 @@ +# Beginning Python — Concept List + +Generated for the learning graph. This list includes all 350 concepts from concept-list-v1.md +plus additional foundational and dependency concepts, expanded to 450 total. + +--- + +## 1. Development Environments & Setup + +1. Python Interpreter Overview +2. Python 2 vs Python 3 +3. Trinket.io Web Environment +4. Repl.it Online IDE +5. Thonny Beginner IDE +6. Spyder Scientific IDE +7. VS Code Editor +8. Jupyter Notebooks +9. JupyterLab Environment +10. Conda Package Manager +11. pip Package Installer +12. Virtual Environments +13. Installing Python Locally +14. Running Scripts from Terminal +15. Python REPL Shell +16. Raspberry Pi Python Platform +17. Skulpt Browser Python +18. Google Colab Environment +19. Command Line Basics +20. File System Navigation + +--- + +## 2. Basic Syntax & Output + +21. print() Function +22. Single-Line Comments +23. Multi-Line Strings +24. Indentation as Syntax +25. Case Sensitivity +26. Python Keywords +27. Blank Lines and Readability +28. Code Block Structure +29. Statement vs Expression +30. Whitespace Rules + +--- + +## 3. Variables & Assignment + +31. Variable Definition and Assignment +32. Variable Naming Rules +33. Snake_case Convention +34. Meaningful Variable Names +35. Multiple Assignment +36. Augmented Assignment Operators +37. Constants by Convention +38. Variable Reassignment +39. Swap Two Variables +40. Naming Conflicts to Avoid + +--- + +## 4. Data Types — Numeric + +41. Integer Type +42. Float Type +43. Division Returns Float +44. Integer Division Operator +45. Modulo Operator +46. Exponentiation Operator +47. Arithmetic Operators +48. Order of Operations +49. Negative Numbers +50. Scientific Notation Floats + +--- + +## 5. Data Types — Boolean + +51. Boolean Type +52. Comparison Operators +53. Logical Operators +54. Truthiness and Falsiness +55. Short-Circuit Evaluation +56. Boolean in Conditions +57. Chained Comparisons + +--- + +## 6. Data Types — Strings + +58. String Type +59. Single vs Double Quotes +60. String Concatenation +61. String Repetition +62. String Indexing +63. String Slicing +64. Escape Characters +65. String Length with len() +66. String lower() upper() strip() +67. String split() join() replace() +68. String startswith() endswith() find() +69. String isdigit() isalpha() isalnum() +70. String format() Method +71. f-Strings +72. String Immutability +73. Raw Strings +74. String Comparison +75. Multiline String Formatting + +--- + +## 7. Data Types — None + +76. None Value and NoneType +77. Functions Returning None +78. Checking for None with is + +--- + +## 8. Type Conversion + +79. int() Conversion +80. float() Conversion +81. str() Conversion +82. bool() Conversion +83. type() Function +84. isinstance() Function +85. Implicit vs Explicit Conversion + +--- + +## 9. User Input + +86. input() Function +87. Prompting the User +88. Converting Input to Numbers +89. Input Validation Basics +90. Reading Multiple Inputs +91. Strip Whitespace from Input + +--- + +## 10. Control Flow — Conditionals + +92. if Statement +93. if...else Block +94. elif Chains +95. Nested if Statements +96. Conditional Ternary Expression +97. match/case Statement +98. Truthiness in Conditions +99. Compound Conditions + +--- + +## 11. Control Flow — Loops + +100. for Loop over Sequence +101. for Loop with range() +102. range(start, stop, step) +103. while Loop +104. break Statement +105. continue Statement +106. else Clause on Loops +107. Nested Loops +108. Loop Counter Variable +109. Infinite Loops to Avoid +110. enumerate() Function +111. zip() Function +112. Loop Accumulator Pattern +113. Loop with List Building +114. Countdown Loop + +--- + +## 12. Functions + +115. Defining a Function with def +116. Calling a Function +117. Positional Parameters +118. Default Parameter Values +119. Keyword Arguments +120. return Statement +121. Functions Returning None +122. Local Scope +123. Global Scope +124. global Keyword +125. nonlocal Keyword +126. Docstrings +127. Pure Functions vs Side Effects +128. Recursion Concept +129. Recursion Base Case +130. Recursion Depth and Stack +131. Lambda Functions +132. Variable Number of Arguments *args +133. Keyword Variable Arguments **kwargs +134. Function as Argument (Higher-Order) +135. Nested Functions +136. Returning Multiple Values + +--- + +## 13. Collections — Lists + +137. List Type +138. Creating a List +139. List Indexing +140. Negative Indexing +141. List Slicing +142. len() for Lists +143. List append() insert() extend() +144. List remove() pop() clear() +145. List sort() reverse() copy() +146. List index() count() +147. Membership with in Operator +148. List Concatenation and Repetition +149. Iterating over a List +150. Nested Lists +151. List Comprehensions +152. Mutable vs Immutable Types +153. List as Stack +154. List as Queue + +--- + +## 14. Collections — Tuples + +155. Tuple Type +156. Creating a Tuple +157. Tuple Indexing and Slicing +158. Tuple Unpacking +159. Tuples vs Lists +160. Single-Element Tuple Syntax +161. Named Tuple Concept +162. Tuple as Return Value + +--- + +## 15. Collections — Dictionaries + +163. Dictionary Type +164. Creating a Dictionary +165. Accessing Values by Key +166. dict get() Method +167. Adding and Updating Key-Value Pairs +168. Removing Entries pop() del +169. Dictionary keys() values() items() +170. Iterating over a Dictionary +171. Key Membership with in +172. Nested Dictionaries +173. Dictionary Comprehensions +174. Default Dictionary Pattern +175. Dictionary from Two Lists with zip() + +--- + +## 16. Collections — Sets + +176. Set Type +177. Creating a Set +178. Set Union Intersection Difference +179. Set add() remove() discard() +180. Set Membership with in +181. Frozensets + +--- + +## 17. Built-in Functions + +182. print() Output Function +183. input() Read Input +184. len() Sequence Length +185. range() Number Sequence +186. type() Get Object Type +187. int() float() str() bool() Conversions +188. list() tuple() set() dict() Constructors +189. max() min() Functions +190. sum() Function +191. abs() Absolute Value +192. round() Function +193. sorted() Function +194. reversed() Function +195. enumerate() with Index +196. zip() Combine Iterables +197. map() Apply Function +198. filter() Filter Items +199. dir() List Attributes +200. help() Documentation +201. id() Object Identity +202. hash() Function +203. any() and all() Functions +204. chr() and ord() Functions + +--- + +## 18. Modules & Imports + +205. import Statement +206. from...import Specific Names +207. import...as Alias +208. from...import Star +209. Creating Custom Modules +210. __name__ == "__main__" Guard +211. Standard Library Overview +212. Module Search Path +213. Reloading a Module + +--- + +## 19. Standard Library — random + +214. random Module Overview +215. random.randint() +216. random.choice() +217. random.shuffle() +218. random.seed() +219. random.random() Float +220. random.sample() + +--- + +## 20. Standard Library — math + +221. math Module Overview +222. math.sqrt() floor() ceil() +223. math.sin() cos() pi +224. math.radians() degrees() +225. math.log() exp() +226. math.factorial() + +--- + +## 21. Standard Library — Other Modules + +227. string Module Constants +228. time Module Overview +229. time.sleep() +230. sys Module +231. sys.path Search Path +232. os Module +233. os.path Operations +234. json Module Overview +235. json.loads() json.dumps() +236. json.load() json.dump() +237. csv Module Basics +238. datetime Module Basics +239. collections Module +240. itertools Module Overview + +--- + +## 22. Regular Expressions + +241. re Module Import +242. re.search() First Match +243. re.findall() All Matches +244. re.split() Split by Pattern +245. re.sub() Substitute Matches +246. Digit Word Whitespace Patterns +247. Anchors Start and End +248. Character Classes +249. Quantifiers Plus Star Question +250. Alternation with Pipe +251. Escaping Special Characters +252. Raw Strings for Regex +253. Regex Groups with Parentheses +254. Compiled Regex Patterns + +--- + +## 23. File Input/Output + +255. open() Function +256. File Modes r w a b +257. file.read() +258. file.readlines() +259. file.readline() +260. file.write() +261. file.close() +262. with Statement Context Manager +263. Iterating over File Lines +264. Text Processing strip() lower() +265. CSV File Reading +266. CSV File Writing +267. Reading JSON from File +268. Writing JSON to File +269. File Path Handling +270. Checking if File Exists + +--- + +## 24. Error Handling + +271. Syntax vs Runtime vs Logic Errors +272. Common Exception Types +273. Reading a Traceback +274. try...except Block +275. Catching Specific Exceptions +276. else Clause in try/except +277. finally Clause +278. raise Statement +279. assert Statement +280. Debugging with print() +281. Using Search Engines to Debug +282. Exception Hierarchy +283. Custom Exception Classes +284. Exception Chaining + +--- + +## 25. Object-Oriented Programming + +285. Objects and Classes Overview +286. Attributes of an Object +287. Methods of an Object +288. class Keyword +289. __init__() Constructor +290. self Parameter +291. Creating Class Instances +292. Accessing Attributes and Methods +293. String Methods as OOP Examples +294. List Methods as OOP Examples +295. Inheritance Basics +296. __str__() String Representation +297. __repr__() Developer Representation +298. Subclasses and Method Overriding +299. super() Function +300. Class Variables vs Instance Variables +301. Static Methods +302. Properties with @property +303. Dunder Methods Overview +304. Object Composition + +--- + +## 26. Turtle Graphics + +305. import turtle +306. turtle.Turtle() Object +307. turtle.Screen() Object +308. Screen Setup and bgcolor() +309. Movement forward() backward() +310. Turning left() right() +311. Absolute Positioning goto() +312. Pen Control penup() pendown() +313. Pen Size and Color +314. Fill begin_fill() end_fill() +315. Drawing circle() and Polygons +316. Turtle Appearance shape() +317. Hiding and Showing Turtle +318. Writing Text with turtle.write() +319. Clearing and Resetting +320. Position Query xcor() ycor() +321. Speed Control speed() +322. setheading() Direction +323. onscreenclick() Event Handler +324. Animation with Turtle Loops +325. Color Picker with Turtle +326. Fractals with Recursion and Turtle +327. Sine Wave with Turtle and Math +328. Drawing Star Patterns +329. Turtle Race Simulation +330. Maze Visualization with Turtle + +--- + +## 27. Data Visualization + +331. matplotlib Library Overview +332. import matplotlib.pyplot as plt +333. plt.plot() Line Plot +334. plt.show() Display +335. Plot Title and Axis Labels +336. plt.grid() Grid Lines +337. Plotting a Sine Wave +338. Lists as XY Plot Data +339. plt.scatter() Scatter Plot +340. plt.bar() Bar Chart +341. plt.hist() Histogram +342. plt.legend() Legend +343. plt.savefig() Save Plot +344. Multiple Lines on One Plot +345. Subplots with plt.subplot() + +--- + +## 28. Numerical Computing — NumPy + +346. numpy Library Overview +347. import numpy as np +348. np.array() Creating Arrays +349. np.argmax() Index of Max +350. Array Operations and Broadcasting +351. Reshaping Arrays +352. np.zeros() np.ones() +353. np.linspace() Evenly Spaced Values +354. Array Slicing and Indexing +355. Element-wise Math Operations +356. np.mean() np.std() + +--- + +## 29. Image Processing + +357. PIL Pillow Library Overview +358. Image.open() Open Image +359. image.show() Display Image +360. Pixel Data and Image Arrays +361. Image Resize and Crop +362. Image Color Conversion +363. Saving Images + +--- + +## 30. Data Structures & Algorithms + +364. Abstract Data Types Overview +365. Stack LIFO Structure +366. Queue FIFO Structure +367. Queue enqueue() dequeue() +368. Graph Nodes and Edges +369. Adjacency List Representation +370. Breadth-First Search BFS +371. BFS Color Tracking +372. BFS for Path Finding +373. Depth-First Search DFS +374. DFS with Recursion +375. DFS and BFS for Maze Solving +376. Sorting Algorithms Overview +377. Bubble Sort +378. Selection Sort +379. Insertion Sort +380. Binary Search Concept +381. Time Complexity Big-O Overview +382. Space Complexity Overview +383. Linked List Concept +384. Tree Data Structure Concept +385. Binary Tree Basics + +--- + +## 31. Machine Learning & Neural Networks + +386. Machine Learning Overview +387. Supervised vs Unsupervised Learning +388. keras Library Overview +389. Sequential Model +390. Dense Fully Connected Layers +391. Activation Functions relu softmax +392. Conv2D Convolutional Layers +393. MaxPooling2D Pooling Layers +394. Dropout Regularization +395. Flatten Layer +396. model.compile() +397. model.fit() Training +398. model.evaluate() Testing +399. model.predict() Inference +400. Categorical Crossentropy Loss +401. Adam Optimizer +402. Accuracy Metric +403. Batch Size and Epochs +404. MNIST Dataset +405. Data Normalization +406. Convolutional Neural Networks +407. Feedforward Networks +408. Recurrent Networks RNN Overview +409. LSTM Networks Overview +410. Autoencoders Overview +411. Training vs Validation vs Test Sets +412. Overfitting Concept +413. Feature Extraction + +--- + +## 32. Graphics in Jupyter + +414. ipycanvas Canvas in Jupyter +415. mobilechelonian Turtle in Jupyter +416. Drawing Shapes on Canvas +417. Color Bars in Jupyter + +--- + +## 33. Event-Driven Programming + +418. Event-Driven Programming Model +419. Mouse Click Event Handlers +420. Keyboard Event Handlers +421. Callback Functions +422. Animation Loops +423. Event Queue Concept +424. Timer-Based Events + +--- + +## 34. Programming Practices + +425. Modularity in Code +426. Code Reusability +427. DRY Principle +428. Meaningful Names +429. Code Comments When and Why +430. Literate Programming in Jupyter +431. Reading Docs with help() and dir() +432. Version Control Basics +433. Searching Documentation +434. Code Refactoring +435. Test-Driven Thinking +436. Pair Programming Concept + +--- + +## 35. Color & Graphics Concepts + +437. Named Colors +438. Hex Color Values +439. RGB Color Model +440. Color in Turtle Graphics +441. Background and Pen Colors +442. HSL Color Model +443. Color Theory Basics +444. Transparency and Alpha + +--- + +## 36. Computational Thinking Foundations + +445. Decomposition +446. Pattern Recognition +447. Abstraction in Programming +448. Algorithm Design +449. Pseudocode Writing +450. Debugging Strategies diff --git a/docs/learning-graph/concept-taxonomy.md b/docs/learning-graph/concept-taxonomy.md new file mode 100644 index 00000000..5d67e36a --- /dev/null +++ b/docs/learning-graph/concept-taxonomy.md @@ -0,0 +1,173 @@ +# Beginning Python — Concept Taxonomy + +This taxonomy organizes the 450 concepts into 14 categories that reflect the natural +structure of a beginning-to-advanced Python course. Categories are designed to be +approximately equal in size, with none exceeding 30% of total concepts. + +--- + +## Taxonomy Categories + +### 1. Environment & Tools (ENV) +**TaxonomyID:** ENV + +Concepts covering Python installation, development environments, IDEs, the command line, +virtual environments, and the overall ecosystem. These are the "before you code" concepts. + +**Concept IDs:** 1–20 + +--- + +### 2. Core Syntax & Output (SYN) +**TaxonomyID:** SYN + +Foundational Python syntax: the print statement, comments, indentation, keywords, +code blocks, statements, expressions, and whitespace rules. The very first things +a student writes. + +**Concept IDs:** 21–30 + +--- + +### 3. Variables & Data Types (DAT) +**TaxonomyID:** DAT + +Variables, assignment, naming conventions, and all primitive data types: integers, +floats, booleans, strings, and None. Also includes type conversion functions. + +**Concept IDs:** 31–85 + +--- + +### 4. Input & Control Flow (CTL) +**TaxonomyID:** CTL + +User input, conditionals (if/elif/else/match), and all loop constructs (for, while, +break, continue, enumerate, zip, range). The logic and flow control layer of Python. + +**Concept IDs:** 86–114 + +--- + +### 5. Functions & Scope (FUN) +**TaxonomyID:** FUN + +Defining and calling functions, parameters, return values, scope, recursion, lambda +functions, higher-order functions, and docstrings. The fundamental abstraction unit. + +**Concept IDs:** 115–136 + +--- + +### 6. Collections (COL) +**TaxonomyID:** COL + +Python's built-in collection types: lists, tuples, dictionaries, and sets with all +their methods, comprehensions, and iteration patterns. Also includes built-in functions +that operate on collections. + +**Concept IDs:** 137–204 + +--- + +### 7. Modules & Standard Library (MOD) +**TaxonomyID:** MOD + +The import system, custom modules, and the Python standard library including the +random, math, string, time, sys, os, json, csv, collections, and itertools modules. + +**Concept IDs:** 205–240 + +--- + +### 8. Text Processing & Regex (TXT) +**TaxonomyID:** TXT + +Regular expression patterns, the re module, character classes, quantifiers, anchors, +groups, substitution, and raw strings for pattern matching. + +**Concept IDs:** 241–254 + +--- + +### 9. File I/O & Data (FIO) +**TaxonomyID:** FIO + +File operations (open, read, write, close), the with statement, context managers, +CSV and JSON file handling, and file path operations. + +**Concept IDs:** 255–270 + +--- + +### 10. Error Handling & Debugging (ERR) +**TaxonomyID:** ERR + +Exception types, try/except/finally, raise, assert, debugging strategies, tracebacks, +the exception hierarchy, custom exceptions, and using documentation to debug. + +**Concept IDs:** 271–284 + +--- + +### 11. Object-Oriented Programming (OOP) +**TaxonomyID:** OOP + +Classes, objects, attributes, methods, constructors, self, inheritance, dunder methods, +properties, class vs instance variables, and object composition. + +**Concept IDs:** 285–304 + +--- + +### 12. Turtle Graphics & Visualization (VIZ) +**TaxonomyID:** VIZ + +The turtle graphics library, screen setup, movement and pen control, color and fill, +shapes, text, events, animation, and complete turtle projects. Also matplotlib charts, +NumPy arrays, Pillow image processing, and Jupyter canvas. + +**Concept IDs:** 305–363, 414–417 + +--- + +### 13. Algorithms & Data Structures (ALG) +**TaxonomyID:** ALG + +Abstract data types, stacks, queues, graphs, adjacency lists, BFS, DFS, sorting +algorithms, binary search, and complexity analysis. The algorithmic thinking layer. + +**Concept IDs:** 364–385 + +--- + +### 14. Advanced & Applied Python (ADV) +**TaxonomyID:** ADV + +Machine learning with Keras, neural network concepts, the MNIST dataset, event-driven +programming, programming best practices (DRY, modularity, refactoring), color theory, +and computational thinking foundations (decomposition, abstraction, algorithm design). + +**Concept IDs:** 386–413, 418–450 + +--- + +## Summary Table + +| # | TaxonomyID | Category Name | Approx Count | +|---|-----------|---------------|-------------| +| 1 | ENV | Environment & Tools | 20 | +| 2 | SYN | Core Syntax & Output | 10 | +| 3 | DAT | Variables & Data Types | 55 | +| 4 | CTL | Input & Control Flow | 29 | +| 5 | FUN | Functions & Scope | 22 | +| 6 | COL | Collections | 68 | +| 7 | MOD | Modules & Standard Library | 36 | +| 8 | TXT | Text Processing & Regex | 14 | +| 9 | FIO | File I/O & Data | 16 | +| 10 | ERR | Error Handling & Debugging | 14 | +| 11 | OOP | Object-Oriented Programming | 20 | +| 12 | VIZ | Turtle Graphics & Visualization | 63 | +| 13 | ALG | Algorithms & Data Structures | 22 | +| 14 | ADV | Advanced & Applied Python | 61 | +| | | **Total** | **450** | diff --git a/docs/learning-graph/course-description-assessment.md b/docs/learning-graph/course-description-assessment.md new file mode 100644 index 00000000..f92d7f77 --- /dev/null +++ b/docs/learning-graph/course-description-assessment.md @@ -0,0 +1,130 @@ +# Course Description Assessment Report + +**Course:** Beginning Python — From Blocks to Code with Monty +**File assessed:** `docs/course-description.md` +**Skill version:** Course Description Analyzer v0.03 + +--- + +## Overall Score: 96 / 100 + +**Quality Rating: Excellent — Ready for learning graph generation** + +--- + +## Scoring Breakdown + +| Element | Points Possible | Points Earned | Notes | +|---|---|---|---| +| Title | 5 | 5 | Clear, descriptive, includes mascot and audience framing | +| Target Audience | 5 | 5 | Specific age range (10–13), prior experience, prerequisite skills | +| Prerequisites | 5 | 5 | Explicitly stated: block-based programming (Scratch/Snap!/MIT App Inventor) | +| Main Topics Covered | 10 | 10 | 19 detailed topic areas encompassing all 350 concepts | +| Topics Excluded | 5 | 5 | 10 explicit out-of-scope topics listed | +| Learning Outcomes Header | 5 | 5 | Clear framing: "After completing this course, students will be able to..." | +| Remember Level | 10 | 10 | 13 specific, recall-oriented outcomes with action verbs | +| Understand Level | 10 | 10 | 14 outcomes with explain/describe/interpret verbs | +| Apply Level | 10 | 10 | 16 hands-on, procedure-oriented outcomes | +| Analyze Level | 10 | 10 | 13 outcomes using compare/distinguish/trace/examine verbs | +| Evaluate Level | 10 | 10 | 12 outcomes using judge/assess/critique/appraise verbs | +| Create Level | 10 | 10 | 12 outcomes including 11 distinct project/capstone ideas | +| Descriptive Context | 5 | 4 | Rich 3-paragraph overview; minor: no explicit mention of approximate course duration | + +**Total: 96 / 100** + +--- + +## Gap Analysis + +### Minor gaps (contributing to the 4-point deduction) + +1. **Course duration not specified** (–1 point from Descriptive Context) + - The overview does not state how many weeks/hours the course is designed for. This + matters for pacing in the teacher's guide and for learning graph density calibration. + - *Recommendation:* Add a line such as "This course is designed for approximately + 30–40 hours of instruction, suitable for a semester-long elective or an intensive + 8-week camp format." + +2. **Assessment strategy not described** (–1 point from Descriptive Context) + - The course mentions quizzes and a teacher's guide in the "Materials Included" + section, but does not describe a summative assessment or final project in the + overview narrative. + - *Recommendation:* Add one sentence in the overview noting that students complete + a capstone project of their choice. + +3. **No explicit mention of accessibility or differentiation** (–1 point from Descriptive Context) + - No guidance on how the Skulpt/inline coding environment accommodates students + with different needs (e.g., font size, color contrast, keyboard-only navigation). + - *Recommendation:* One brief sentence acknowledging differentiation options in the + teacher's guide. + +4. **Standards alignment not cited in the description** (–1 point from Descriptive Context) + - The teacher's guide mentions CSTA K-12 alignment, but the course description itself + does not reference any CS education standards (CSTA, ISTE, state standards). + - *Recommendation:* Add a brief "Standards Alignment" subsection below the overview + paragraph citing at least CSTA K-12 CS Standards relevant to the course. + +--- + +## Improvement Suggestions (Prioritized) + +These are ordered from highest to lowest impact on learning graph generation quality. + +### P1 — Add course duration (high impact on learning graph pacing) +Knowing whether the course is 20, 40, or 80 hours directly informs how many concepts +can be sequenced per lesson and how deep intermediate/advanced material can go. A +sentence in the overview is sufficient. + +### P2 — Add a standards alignment table (medium impact on concept taxonomy) +Mapping to CSTA K-12 standards (especially 1B-AP-08 through 3B-AP-24) will help +the learning graph generator correctly classify concepts by grade-band and cognitive +complexity. Even a short table or list is valuable. + +### P3 — Describe the capstone/summative project (low impact on graph, high value for teachers) +Specifying that students choose and build an end-to-end project reinforces the Create +level of Bloom's and anchors the learning graph's terminal nodes. + +### P4 — Add a differentiation note (low impact on graph, high value for equity) +A brief acknowledgment that the inline Skulpt environment and teacher's guide include +tips for early finishers, students who need more scaffolding, and ELL learners. + +--- + +## Concept Generation Readiness + +| Dimension | Assessment | +|---|---| +| Topic breadth | **Excellent** — 19 distinct topic areas span beginner through advanced | +| Topic depth | **Excellent** — each topic names specific libraries, methods, and algorithms | +| Bloom's diversity | **Excellent** — all six levels covered with 80 total specific outcomes | +| Estimated concept count | **350+** (aligned with the existing `concept-list-v1.md`) | +| Readiness verdict | **Ready** — sufficient detail to generate 200+ concepts immediately | + +The course description explicitly covers: +- 16 categories of development tools and environments +- 29 categories of Python language and library concepts +- Algorithms (BFS, DFS, sorting, binary search) +- Machine learning (Keras, MNIST, CNNs) +- Course support materials (glossary, FAQ, quizzes, teacher's guide) + +No additional topic areas are needed before proceeding to learning graph generation. + +--- + +## Next Steps + +The course description scores **96/100 (Excellent)** and is **ready to proceed to +learning graph generation**. + +Recommended immediate next steps: + +1. *(Optional but recommended)* Make the four minor improvements listed above in + `docs/course-description.md` — this will not block learning graph generation. +2. Run the **`/learning-graph-generator`** skill to produce a full 200+ concept + learning graph with dependencies, taxonomy labels, and concept metadata. +3. After the learning graph is finalized, run the **`/book-chapter-generator`** skill + to map concepts to chapters. +4. Use **`/chapter-content-generator`** to generate chapter content including + Monty mascot callouts, Skulpt MicroSims, and inline quizzes. +5. Use **`/glossary-generator`** and **`/faq-generator`** after at least 30% of + chapters are written. diff --git a/docs/learning-graph/csv-to-json.py b/docs/learning-graph/csv-to-json.py new file mode 100644 index 00000000..605c2780 --- /dev/null +++ b/docs/learning-graph/csv-to-json.py @@ -0,0 +1,370 @@ +#!/usr/bin/env python3 +""" +Convert CSV Learning Graph to JSON for vis-network.js +Converts the concept dependency CSV into the JSON format +used by the existing graph viewer (vis.js network format). + +IMPORTANT: For custom taxonomies, provide taxonomy-names.json to ensure +human-readable classifierName values in the output. Without this file, +taxonomy IDs will be used as fallback (which is usually wrong). +""" + +VERSION = "0.04" + +import csv +import json +from typing import Dict, List +from datetime import datetime + + +def csv_to_json(csv_path: str, json_path: str, color_config: dict = None, + metadata: dict = None, taxonomy_names: dict = None): + """ + Convert CSV dependency graph to vis.js JSON format with metadata and groups. + + Args: + csv_path: Path to input CSV file with columns: ConceptID, ConceptLabel, Dependencies, TaxonomyID + json_path: Path to output JSON file + color_config: Optional dictionary mapping taxonomy IDs to colors. + If not provided, uses default color scheme. + metadata: Optional dictionary with metadata fields (title, description, creator, etc.) + If not provided, creates minimal metadata. + taxonomy_names: Dictionary mapping taxonomy IDs to human-readable names. + STRONGLY RECOMMENDED for custom taxonomies. + """ + # Default 24-color palette designed for distinct, accessible category coloring. + # Hues progress through subject-family groupings (cool blues for foundations, + # greens for architecture/dev, yellows/golds for data, blues for network/cloud, + # reds for security/privacy, purples for project/process/analysis, oranges + # and browns for the AI cluster, an accent for knowledge graphs, neutral + # for emerging topics) with alternating lightness so adjacent legend rows + # never collide. Dark backgrounds automatically get white font for contrast; + # light backgrounds get black. The previous all-pastel palette caused legend + # collisions when a project had >12 categories — this palette supports up + # to 24 distinct categories without color reuse. + # Since the background is AliceBlue, do not use that color. + DEFAULT_PALETTE = [ + 'SteelBlue', # 1 cool foundations + 'DarkSlateBlue', # 2 + 'DarkGreen', # 3 architecture / build + 'LimeGreen', # 4 + 'Gold', # 5 data band + 'DarkGoldenrod', # 6 + 'Khaki', # 7 + 'Teal', # 8 enterprise + 'DodgerBlue', # 9 network / cloud + 'LightSkyBlue', # 10 + 'Crimson', # 11 security / privacy + 'DarkRed', # 12 + 'MediumPurple', # 13 project / process / analysis + 'Indigo', # 14 + 'DarkOrchid', # 15 + 'HotPink', # 16 user-facing + 'OliveDrab', # 17 service management + 'Orange', # 18 AI cluster + 'Coral', # 19 + 'Peru', # 20 + 'SaddleBrown', # 21 + 'Tomato', # 22 + 'DeepPink', # 23 accent — knowledge graphs / connective concepts + 'DimGray', # 24 neutral — emerging / miscellaneous + ] + default_colors = {str(i + 1): color for i, color in enumerate(DEFAULT_PALETTE)} + + taxonomy_colors = color_config if color_config is not None else default_colors + + # Default taxonomy ID to classifier name mapping + # Supports both text codes (FOUND, DEF, etc.) and numeric IDs (1, 2, etc.) + # These are the display names (classifierName in schema) for each taxonomy + default_taxonomy_names = { + # Custom taxonomies for intelligent textbook skills course + 'AIFND': 'AI Foundations', + 'SKILL': 'Claude Skills System', + 'IBOOK': 'Intelligent Textbooks', + 'MKDOC': 'MkDocs Platform', + 'GRAPH': 'Learning Graphs', + 'EDTHY': 'Educational Theory', + 'CONTE': 'Content Creation', + 'RSRCE': 'Educational Resources', + 'INTER': 'Interactive Elements', + 'VERCT': 'Version Control', + 'TOOLS': 'Development Tools', + 'DATAS': 'Data & Scripting', + # Standard/default text codes + 'FOUND': 'Foundation Concepts', + 'DEF': 'Definitions', + 'CORE': 'Core Concepts', + 'ADV': 'Advanced', + 'APPL': 'Applied', + 'SPEC': 'Specialized', + 'CAP': 'Capstone Projects', + 'PROJ': 'Project Ideas', + 'MISC': 'Miscellaneous Concepts', + # Numeric IDs (common mapping) + '1': 'Foundation Concepts', + '2': 'Definitions', + '3': 'Core Concepts', + '4': 'Intermediate', + '5': 'Advanced', + '6': 'Applied', + '7': 'Specialized', + '8': 'Capstone Projects', + '9': 'Miscellaneous Concepts', + '10': 'Extended Topics', + } + + # Merge user-provided taxonomy names with defaults (user names take precedence) + all_taxonomy_names = default_taxonomy_names.copy() + if taxonomy_names: + all_taxonomy_names.update(taxonomy_names) + + # Read CSV + nodes = [] + edges = [] + foundational_ids = [] + + with open(csv_path, 'r', encoding='utf-8') as f: + reader = csv.DictReader(f) + for row in reader: + concept_id = int(row['ConceptID']) + # Support both ConceptLabel and ConceptName column names + label = row.get('ConceptLabel') or row.get('ConceptName', '') + taxonomy = row['TaxonomyID'] + dependencies_str = row['Dependencies'] + + # Determine if foundational (no dependencies) + is_foundational = (dependencies_str == '') + if is_foundational: + foundational_ids.append(concept_id) + + # Create node - use taxonomy ID directly as group reference + node = { + 'id': concept_id, + 'label': label, + 'group': taxonomy + } + + # Special styling for foundational concepts + if is_foundational: + node['shape'] = 'box' + + nodes.append(node) + + # Create edges (from concept to its prerequisites) + if dependencies_str: + prereq_ids = [int(pid) for pid in dependencies_str.split('|')] + for prereq_id in prereq_ids: + edge = { + 'from': concept_id, + 'to': prereq_id + } + edges.append(edge) + + # Create metadata section + default_metadata = { + 'title': 'Learning Graph', + 'description': f'Learning graph with {len(nodes)} concepts generated from CSV', + 'creator': 'CSV to JSON Converter', + 'date': datetime.now().strftime('%Y-%m-%d'), + 'version': '1.0', + 'format': 'Learning Graph JSON v1.0', + 'schema': 'https://raw.githubusercontent.com/dmccreary/learning-graphs/refs/heads/main/src/schema/learning-graph-schema.json', + 'license': 'CC BY-NC-SA 4.0 DEED' + } + + # Merge user-provided metadata with defaults + if metadata: + default_metadata.update(metadata) + + # Create groups section from taxonomy colors + groups = {} + + # Determine which taxonomy IDs are actually used + used_taxonomies = set(node['group'] for node in nodes) + + # Track taxonomies with missing human-readable names + missing_names = [] + + # Dark backgrounds need white text for contrast; everything else uses black. + # Includes the new distinct palette plus a few legacy pastel colors retained + # for back-compat with older color-config.json files. + DARK_BACKGROUND_COLORS = { + 'SteelBlue', 'DarkSlateBlue', 'DarkGreen', 'DarkGoldenrod', 'Teal', + 'DodgerBlue', 'Crimson', 'DarkRed', 'MediumPurple', 'Indigo', + 'DarkOrchid', 'OliveDrab', 'SaddleBrown', 'Tomato', 'DeepPink', + 'DimGray', + # Legacy darks retained for back-compat with older color-config files + 'Plum', 'LightCoral', + } + + def font_color_for(color: str) -> str: + return 'white' if color in DARK_BACKGROUND_COLORS else 'black' + + for tax_id, color in taxonomy_colors.items(): + # Only include groups that are actually used + if tax_id in used_taxonomies: + # Get the classifier name for this taxonomy + classifier_name = all_taxonomy_names.get(tax_id, tax_id) + + # Check if we're falling back to the ID (indicates missing name) + if classifier_name == tax_id: + missing_names.append(tax_id) + + groups[tax_id] = { + 'classifierName': classifier_name, + 'color': color, + 'font': { + 'color': font_color_for(color) + } + } + + # Handle taxonomies in CSV that aren't in color config + for tax_id in used_taxonomies: + if tax_id not in groups: + classifier_name = all_taxonomy_names.get(tax_id, tax_id) + if classifier_name == tax_id: + missing_names.append(tax_id) + + # Assign a default color based on position + color_index = len(groups) % len(default_colors) + color = list(default_colors.values())[color_index] + + groups[tax_id] = { + 'classifierName': classifier_name, + 'color': color, + 'font': { + 'color': font_color_for(color) + } + } + + # Create final JSON structure + graph_data = { + 'metadata': default_metadata, + 'groups': groups, + 'nodes': nodes, + 'edges': edges + } + + # Write JSON + with open(json_path, 'w', encoding='utf-8') as f: + json.dump(graph_data, f, indent=2) + + print(f"✅ JSON graph created: {json_path} (csv-to-json v{VERSION})") + print(f" - Title: {default_metadata['title']}") + print(f" - {len(groups)} groups/taxonomies") + print(f" - {len(nodes)} nodes") + print(f" - {len(edges)} edges") + print(f" - {len(foundational_ids)} foundational concepts") + print(f"\nFoundational concept IDs: {foundational_ids}") + print(f"Groups: {list(groups.keys())}") + + # IMPORTANT: Warn about missing human-readable names + if missing_names: + print(f"\n⚠️ WARNING: The following taxonomy IDs are missing human-readable names:") + for tax_id in missing_names: + print(f" - '{tax_id}' → classifierName set to '{tax_id}' (should be descriptive)") + print(f"\n To fix: Create taxonomy-names.json with mappings like:") + print(f" {{") + for tax_id in missing_names: + print(f' "{tax_id}": "Human Readable Name Here",') + print(f" }}") + print(f"\n Then run: python csv-to-json.py {csv_path} {json_path} [colors.json] [metadata.json] taxonomy-names.json") + + return graph_data + + +def create_taxonomy_legend(groups: dict = None): + """ + Generate a legend of taxonomy colors for documentation. + + Args: + groups: Dictionary of groups from the generated JSON (contains classifierName, color, etc.) + """ + if not groups: + print("\n⚠️ No groups to display in legend") + return + + print("\n## Taxonomy Color Legend\n") + print("| Category | TaxonomyID | Color |") + print("|----------|------------|-------|") + for tax_id in sorted(groups.keys()): + group_info = groups[tax_id] + name = group_info.get('classifierName', tax_id) + color = group_info.get('color', 'gray') + print(f"| {name} | {tax_id} | {color} |") + + +if __name__ == "__main__": + import sys + + # Parse command line arguments + if len(sys.argv) < 3: + print(f"csv-to-json.py v{VERSION}") + print("\nUsage: python csv-to-json.py [color_config.json] [metadata.json] [taxonomy_names.json]") + print("Looking for CSV column names: ConceptID, ConceptLabel, Dependencies, TaxonomyID") + print("\nExample:") + print(" python csv-to-json.py learning-graph.csv learning-graph.json") + print(" python csv-to-json.py learning-graph.csv learning-graph.json color-config.json metadata.json taxonomy-names.json") + print("\nOptional color_config.json format:") + print(json.dumps({ + 'FOUND': 'MistyRose', + 'CORE': 'LightYellow', + 'ADV': 'PowderBlue' + }, indent=2)) + print("\nOptional metadata.json format:") + print(json.dumps({ + 'title': 'My Learning Graph', + 'description': 'A comprehensive learning graph', + 'creator': 'Your Name', + 'license': 'CC BY 4.0' + }, indent=2)) + print("\n⚠️ RECOMMENDED: taxonomy-names.json format (prevents ID-as-name bug):") + print(json.dumps({ + 'FOUND': 'Foundation Concepts', + 'EDA1': 'Exploratory Data Analysis I', + 'REG': 'Regression & Correlation' + }, indent=2)) + sys.exit(1) + + csv_path = sys.argv[1] + json_path = sys.argv[2] + + # Load color config if provided + color_config = None + if len(sys.argv) > 3: + config_file = sys.argv[3] + try: + with open(config_file, 'r', encoding='utf-8') as f: + color_config = json.load(f) + print(f"📋 Loaded color config from: {config_file}") + except FileNotFoundError: + print(f"⚠️ Color config file not found: {config_file}, using defaults") + + # Load metadata config if provided + metadata = None + if len(sys.argv) > 4: + metadata_file = sys.argv[4] + try: + with open(metadata_file, 'r', encoding='utf-8') as f: + metadata = json.load(f) + print(f"📋 Loaded metadata from: {metadata_file}") + except FileNotFoundError: + print(f"⚠️ Metadata file not found: {metadata_file}, using defaults") + + # Load taxonomy names if provided (STRONGLY RECOMMENDED) + taxonomy_names = None + if len(sys.argv) > 5: + names_file = sys.argv[5] + try: + with open(names_file, 'r', encoding='utf-8') as f: + taxonomy_names = json.load(f) + print(f"📋 Loaded taxonomy names from: {names_file}") + except FileNotFoundError: + print(f"⚠️ Taxonomy names file not found: {names_file}") + print(f" This may result in taxonomy IDs being used as display names.") + + graph_data = csv_to_json(csv_path, json_path, color_config, metadata, taxonomy_names) + create_taxonomy_legend(graph_data['groups']) + + print("\n✅ CSV to JSON format complete. Ready to use with graph-viewer!") + print(f" Validate with: ./validate-learning-graph.sh {json_path}") diff --git a/docs/learning-graph/index-template.md b/docs/learning-graph/index-template.md new file mode 100644 index 00000000..655d838c --- /dev/null +++ b/docs/learning-graph/index-template.md @@ -0,0 +1,93 @@ +# Learning Graph for TEXTBOOK_NAME + +This section contains the learning graph for this textbook. A learning graph is +a graph of concepts used in this textbook. Each concept is represented by a +node in a network graph. Concepts are connected by directed edges that indicate +what concepts each node depends on before that concept is understood by the student. + +A learning graph is the foundational data structure for intelligent textbooks that can recommend learning paths. +A learning graph is like a roadmap of concepts to help students arrive at their learning goals. + +At the left of the learning graph are prerequisite or foundational concepts. They +have no outbound edges. They only have inbound edges for other concepts that depend on +understanding these foundational prerequisite concepts. At the far right +we have the most advanced concepts in the course. To master these concepts you +must understand all the concepts that they point to. + +Here are other files used by the learning graph. + +## Course Description + +We use the [Course Description](../course-description.md) as +the source document for the concepts that are included in this course. +The course description uses the 2001 Bloom taxonomy to order learning objectives. + +## List of Concepts + +We use generative AI to convert the course description into a [Concept List](./concept-list.md). +Each concept is in the form of a short Title Case label with most labels under 32 characters long. + +## Concept Dependency List + +We next use generative AI to create a Directed Acyclic Graph (DAG). DAGs do not have cycles where +concepts depend on themselves. We provide the DAG in two formats. One is a [CSV file](learning-graph.csv) and the other +format is a [JSON file](learning-graph.json) that uses the vis-network JavaScript library format. The vis-network format uses `nodes`, `edges` and `metadata` +elements with edges containing `from` and `to` properties. This makes it easy for you to view and edit the learning +graph using an editor built with the vis-network tools. + +## Analysis & Documentation + +### Course Description Quality Assessment + +This report rates the overall quality of the course description for the purpose of generating a learning graph. + +- Course description fields and content depth analysis +- Validates course description has sufficient depth for generating 200 concepts +- Compares course description against similar courses +- Identifies content gaps and strengths +- Suggests areas of improvement +[Vew the Course Description Quality Assessment](course-description-assessment.md) + +### Learning Graph Quality Validation + +This report gives you an overall assessment of the quality of the learning graph. +It uses graph algorithms to look for specific quality patterns in the graph. + +- Graph structure validation - all concepts are connected +- DAG validation (no cycles detected) +- Foundational concepts: 10 entry points +- Indegree distribution analysis +- Longest dependency chains +- Connectivity: percent of nodes connected to the main cluster + +[View the Learning Graph Quality Validation](quality-metrics.md) + +### Concept Taxonomy + +In order to see patterns in the learning graph, it is useful to assign colors +to each concept based on the concept type. We use generative AI to +create about a dozen categories for our concepts and then place each concept +into a single primary classifier. + +- A concept classifier taxonomy with approximately 12 categories (+/- 1 or 2) +- Category organization - foundational elements first, course capstone project ideas last +- Balanced categories (3.5% - 15% each) +- All categories under 30% threshold +- Pedagogical flow recommendations +- Clear 3-5 letter abbreviations for use in CSV file +- A Miscellaneous (MOSC) category is sometimes added +[View the Concept Taxonomy](concept-taxonomy.md) + +### Taxonomy Distribution + +This reports shows how many concepts fit into each category of the taxonomy. +Our goal is a somewhat balanced taxonomy where each category holds an +equal number of concepts. We also don't want any category to contain +over 30% of our concepts. + +- Statistical breakdown +- Detailed concept listing by category +- Visual distribution table +- Balance verification + +[View the Taxonomy Distribution Report](./taxonomy-distribution.md) \ No newline at end of file diff --git a/docs/learning-graph/index.md b/docs/learning-graph/index.md new file mode 100644 index 00000000..31d78649 --- /dev/null +++ b/docs/learning-graph/index.md @@ -0,0 +1,101 @@ +# Learning Graph for Beginning Python + +[Open Learning Graph Viewer Fullscreen](../sims/graph-viewer/main.html){ .md-button .md-button--primary } + + + +This section contains the learning graph for Beginning Python — From Blocks to Code with Monty. +A learning graph is a graph of concepts used in this course. Each concept is represented by a +node in a network graph. Concepts are connected by directed edges that indicate +what concepts each node depends on before that concept is understood by the student. + +A learning graph is the foundational data structure for intelligent textbooks that can recommend learning paths. +A learning graph is like a roadmap of concepts to help students arrive at their learning goals. + +At the left of the learning graph are prerequisite or foundational concepts. They +have no outbound edges. They only have inbound edges for other concepts that depend on +understanding these foundational prerequisite concepts. At the far right +we have the most advanced concepts in the course. To master these concepts you +must understand all the concepts that they point to. + +This graph contains **450 concepts** organized into **14 taxonomy categories** with **838 dependency edges**, +spanning from the Python interpreter and command-line basics all the way to Keras neural networks +and computational thinking foundations. + +Here are other files used by the learning graph. + +## Course Description + +We use the [Course Description](../course-description.md) as +the source document for the concepts that are included in this course. +The course description uses the 2001 Bloom taxonomy to order learning objectives. + +## List of Concepts + +We use generative AI to convert the course description into a [Concept List](./concept-list.md). +Each concept is in the form of a short Title Case label with most labels under 32 characters long. + +## Concept Dependency List + +We next use generative AI to create a Directed Acyclic Graph (DAG). DAGs do not have cycles where +concepts depend on themselves. We provide the DAG in two formats. One is a [CSV file](learning-graph.csv) and the other +format is a [JSON file](learning-graph.json) that uses the vis-network JavaScript library format. The vis-network format uses `nodes`, `edges` and `metadata` +elements with edges containing `from` and `to` properties. This makes it easy for you to view and edit the learning +graph using an editor built with the vis-network tools. + +## Analysis & Documentation + +### Course Description Quality Assessment + +This report rates the overall quality of the course description for the purpose of generating a learning graph. + +- Course description fields and content depth analysis +- Validates course description has sufficient depth for generating 200 concepts +- Compares course description against similar courses +- Identifies content gaps and strengths +- Suggests areas of improvement + +[View the Course Description Quality Assessment](course-description-assessment.md) + +### Learning Graph Quality Validation + +This report gives you an overall assessment of the quality of the learning graph. +It uses graph algorithms to look for specific quality patterns in the graph. + +- Graph structure validation — all concepts are connected +- DAG validation — no cycles detected ✅ +- Foundational concepts: 2 entry points (Python Interpreter Overview, Command Line Basics) +- Indegree distribution analysis +- Longest dependency chain: 13 steps +- Connectivity: all 450 nodes in a single connected component + +[View the Learning Graph Quality Validation](quality-metrics.md) + +### Concept Taxonomy + +In order to see patterns in the learning graph, it is useful to assign colors +to each concept based on the concept type. We use generative AI to +create about a dozen categories for our concepts and then place each concept +into a single primary classifier. + +- A concept classifier taxonomy with 14 categories +- Category organization — environment first, advanced ML/AI last +- Balanced categories (2.2% – 15.1% each) +- All categories under 30% threshold +- Clear 3-letter abbreviations for use in CSV file + +[View the Concept Taxonomy](concept-taxonomy.md) + +### Taxonomy Distribution + +This report shows how many concepts fit into each category of the taxonomy. +Our goal is a somewhat balanced taxonomy where each category holds an +equal number of concepts. We also don't want any category to contain +over 30% of our concepts. + +- Statistical breakdown +- Detailed concept listing by category +- Visual distribution table +- Balance verification + +[View the Taxonomy Distribution Report](./taxonomy-distribution.md) diff --git a/docs/learning-graph/learning-graph-schema.json b/docs/learning-graph/learning-graph-schema.json new file mode 100644 index 00000000..1b4ce82e --- /dev/null +++ b/docs/learning-graph/learning-graph-schema.json @@ -0,0 +1,185 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://dmccreary.github.io/geometry-course/learning-graph/learning-graph-schema.json", + "title": "Learning Graph Schema", + "description": "Schema for learning graph JSON files that define concept nodes, dependencies, and taxonomies for educational content", + "type": "object", + "required": ["metadata", "groups", "nodes", "edges"], + "properties": { + "metadata": { + "type": "object", + "description": "Metadata about the learning graph", + "required": ["title"], + "properties": { + "title": { + "type": "string", + "description": "The title of the course or subject" + }, + "description": { + "type": "string", + "description": "A brief description of the course content" + }, + "creator": { + "type": "string", + "description": "The name of the person or organization who created this learning graph" + }, + "date": { + "type": "string", + "format": "date", + "description": "The creation or last modification date (YYYY-MM-DD)" + }, + "version": { + "type": "string", + "description": "Version number of the learning graph" + }, + "format": { + "type": "string", + "description": "The format specification of this learning graph" + }, + "schema": { + "type": "string", + "format": "uri", + "description": "URL to the JSON schema for this learning graph" + }, + "license": { + "type": "string", + "description": "The license under which this learning graph is distributed" + } + } + }, + "groups": { + "type": "object", + "description": "Taxonomy groups/categories for organizing concepts", + "patternProperties": { + "^[A-Z]+$": { + "type": "object", + "required": ["classifierName", "color"], + "properties": { + "classifierName": { + "type": "string", + "description": "Human-readable name for this taxonomy category" + }, + "color": { + "type": "object", + "description": "Color styling for nodes in this group", + "required": ["color"], + "properties": { + "color": { + "type": "string", + "description": "Color value (hex code like #ff0000 or CSS color name like red)", + "pattern": "^(#[0-9A-Fa-f]{6}|[a-z]+)$" + }, + "colorName": { + "type": "string", + "description": "Human-readable color name for display in legends" + }, + "font": { + "type": "object", + "description": "Font styling for text in nodes", + "properties": { + "color": { + "type": "string", + "description": "Font color (typically 'white' or 'black')", + "pattern": "^(#[0-9A-Fa-f]{6}|[a-z]+)$" + } + } + } + } + }, + "font": { + "type": "object", + "description": "Additional font styling (deprecated - use color.font instead)", + "properties": { + "color": { + "type": "string", + "pattern": "^(#[0-9A-Fa-f]{6}|[a-z]+)$" + } + } + } + } + } + } + }, + "nodes": { + "type": "array", + "description": "Array of concept nodes in the learning graph", + "items": { + "type": "object", + "required": ["id", "label", "group"], + "properties": { + "id": { + "type": "integer", + "description": "Unique identifier for the node", + "minimum": 1 + }, + "label": { + "type": "string", + "description": "The name/label of the concept", + "minLength": 1 + }, + "group": { + "type": "string", + "description": "The taxonomy group this concept belongs to (must match a key in groups)", + "pattern": "^[A-Z]+$" + }, + "shape": { + "type": "string", + "description": "Optional vis.js shape for the node (e.g., 'box', 'circle', 'ellipse')", + "enum": ["box", "circle", "ellipse", "database", "diamond", "dot", "square", "star", "triangle", "hexagon"] + }, + "title": { + "type": "string", + "description": "Optional tooltip text shown when hovering over the node" + }, + "level": { + "type": "integer", + "description": "Optional hierarchical level for layout purposes" + } + } + } + }, + "edges": { + "type": "array", + "description": "Array of directed edges representing dependencies between concepts", + "items": { + "type": "object", + "required": ["from", "to"], + "properties": { + "from": { + "type": "integer", + "description": "Source node ID (prerequisite concept)", + "minimum": 1 + }, + "to": { + "type": "integer", + "description": "Target node ID (dependent concept)", + "minimum": 1 + }, + "arrows": { + "type": "string", + "description": "Arrow direction (typically 'to' for directed edges)", + "enum": ["to", "from", "middle", "to,from"] + }, + "label": { + "type": "string", + "description": "Optional label for the edge" + }, + "title": { + "type": "string", + "description": "Optional tooltip for the edge" + }, + "smooth": { + "type": "object", + "description": "Edge smoothing options for vis.js", + "properties": { + "type": { + "type": "string", + "enum": ["dynamic", "continuous", "discrete", "diagonalCross", "straightCross", "horizontal", "vertical", "curvedCW", "curvedCCW", "cubicBezier"] + } + } + } + } + } + } + } +} diff --git a/docs/learning-graph/learning-graph.csv b/docs/learning-graph/learning-graph.csv new file mode 100644 index 00000000..7b014587 --- /dev/null +++ b/docs/learning-graph/learning-graph.csv @@ -0,0 +1,451 @@ +ConceptID,ConceptLabel,Dependencies,TaxonomyID +1,Python Interpreter Overview,,ENV +2,Python 2 vs Python 3,1,ENV +3,Trinket.io Web Environment,1,ENV +4,Repl.it Online IDE,1,ENV +5,Thonny Beginner IDE,1,ENV +6,Spyder Scientific IDE,1,ENV +7,VS Code Editor,1,ENV +8,Jupyter Notebooks,1,ENV +9,JupyterLab Environment,8,ENV +10,Conda Package Manager,1,ENV +11,pip Package Installer,1|10,ENV +12,Virtual Environments,11,ENV +13,Installing Python Locally,1|11,ENV +14,Running Scripts from Terminal,13|19,ENV +15,Python REPL Shell,1,ENV +16,Raspberry Pi Python Platform,1|13,ENV +17,Skulpt Browser Python,1|3,ENV +18,Google Colab Environment,1|8,ENV +19,Command Line Basics,,ENV +20,File System Navigation,19,ENV +21,print() Function,1,SYN +22,Single-Line Comments,21,SYN +23,Multi-Line Strings,21,SYN +24,Indentation as Syntax,21,SYN +25,Case Sensitivity,21,SYN +26,Python Keywords,21,SYN +27,Blank Lines and Readability,21|22,SYN +28,Code Block Structure,24,SYN +29,Statement vs Expression,21,SYN +30,Whitespace Rules,24,SYN +31,Variable Definition and Assignment,21|29,DAT +32,Variable Naming Rules,31,DAT +33,Snake_case Convention,32,DAT +34,Meaningful Variable Names,32|33,DAT +35,Multiple Assignment,31,DAT +36,Augmented Assignment Operators,31|47,DAT +37,Constants by Convention,31|33,DAT +38,Variable Reassignment,31,DAT +39,Swap Two Variables,35|38,DAT +40,Naming Conflicts to Avoid,32|26,DAT +41,Integer Type,31,DAT +42,Float Type,31,DAT +43,Division Returns Float,42,DAT +44,Integer Division Operator,41|42,DAT +45,Modulo Operator,41,DAT +46,Exponentiation Operator,41,DAT +47,Arithmetic Operators,41|42,DAT +48,Order of Operations,47,DAT +49,Negative Numbers,41,DAT +50,Scientific Notation Floats,42,DAT +51,Boolean Type,31,DAT +52,Comparison Operators,41|51,DAT +53,Logical Operators,51|52,DAT +54,Truthiness and Falsiness,51,DAT +55,Short-Circuit Evaluation,53,DAT +56,Boolean in Conditions,51|92,DAT +57,Chained Comparisons,52|53,DAT +58,String Type,31,DAT +59,Single vs Double Quotes,58,DAT +60,String Concatenation,58,DAT +61,String Repetition,58|41,DAT +62,String Indexing,58|41,DAT +63,String Slicing,62,DAT +64,Escape Characters,58,DAT +65,String Length with len(),58,DAT +66,String lower() upper() strip(),58,DAT +67,String split() join() replace(),58,DAT +68,String startswith() endswith() find(),58,DAT +69,String isdigit() isalpha() isalnum(),58,DAT +70,String format() Method,58|31,DAT +71,f-Strings,58|31|70,DAT +72,String Immutability,58,DAT +73,Raw Strings,58|64,DAT +74,String Comparison,58|52,DAT +75,Multiline String Formatting,23|71,DAT +76,None Value and NoneType,31,DAT +77,Functions Returning None,121|76,DAT +78,Checking for None with is,76|52,DAT +79,int() Conversion,41|58,DAT +80,float() Conversion,42|58,DAT +81,str() Conversion,58|41,DAT +82,bool() Conversion,51|31,DAT +83,type() Function,31|41,DAT +84,isinstance() Function,83|285,DAT +85,Implicit vs Explicit Conversion,79|80|81,DAT +86,input() Function,21|58,CTL +87,Prompting the User,86|58,CTL +88,Converting Input to Numbers,86|79|80,CTL +89,Input Validation Basics,86|92,CTL +90,Reading Multiple Inputs,86|35,CTL +91,Strip Whitespace from Input,86|66,CTL +92,if Statement,51|24|28,CTL +93,if...else Block,92,CTL +94,elif Chains,93,CTL +95,Nested if Statements,93,CTL +96,Conditional Ternary Expression,92|51,CTL +97,match/case Statement,92|94,CTL +98,Truthiness in Conditions,54|92,CTL +99,Compound Conditions,53|92,CTL +100,for Loop over Sequence,24|28,CTL +101,for Loop with range(),100,CTL +102,Range with Start Stop Step,101|41,CTL +103,while Loop,24|28|51,CTL +104,break Statement,100|103,CTL +105,continue Statement,100|103,CTL +106,else Clause on Loops,100|103,CTL +107,Nested Loops,100|108,CTL +108,Loop Counter Variable,100|41,CTL +109,Infinite Loops to Avoid,103|104,CTL +110,enumerate() Function,100,CTL +111,zip() Function,100,CTL +112,Loop Accumulator Pattern,100|31,CTL +113,Loop with List Building,100|138,CTL +114,Countdown Loop,101|102,CTL +115,Defining a Function with def,24|28|21,FUN +116,Calling a Function,115,FUN +117,Positional Parameters,115,FUN +118,Default Parameter Values,115|117,FUN +119,Keyword Arguments,115|117,FUN +120,return Statement,115,FUN +121,Functions Returning None,115|76,FUN +122,Local Scope,115|31,FUN +123,Global Scope,31|115,FUN +124,global Keyword,123|122,FUN +125,nonlocal Keyword,122|135,FUN +126,Docstrings,115|23,FUN +127,Pure Functions vs Side Effects,115|120,FUN +128,Recursion Concept,115|116,FUN +129,Recursion Base Case,128,FUN +130,Recursion Depth and Stack,128|129,FUN +131,Lambda Functions,115|116,FUN +132,Variable Number of Arguments *args,115|137,FUN +133,Keyword Variable Arguments **kwargs,115|163,FUN +134,Function as Argument,131|115,FUN +135,Nested Functions,115|122,FUN +136,Returning Multiple Values,120|155,FUN +137,List Type,31,COL +138,Creating a List,137,COL +139,List Indexing,137|41,COL +140,Negative Indexing,139,COL +141,List Slicing,139|63,COL +142,len() for Lists,137,COL +143,List append() insert() extend(),137,COL +144,List remove() pop() clear(),137,COL +145,List sort() reverse() copy(),137|52,COL +146,List index() count(),137,COL +147,Membership with in Operator,137|58,COL +148,List Concatenation and Repetition,137|60|61,COL +149,Iterating over a List,100|137,COL +150,Nested Lists,137|139,COL +151,List Comprehensions,100|137|149,COL +152,Mutable vs Immutable Types,137|58,COL +153,List as Stack,137|143|144,COL +154,List as Queue,137|143|144,COL +155,Tuple Type,31,COL +156,Creating a Tuple,155,COL +157,Tuple Indexing and Slicing,156|139|141,COL +158,Tuple Unpacking,156|35,COL +159,Tuples vs Lists,155|137|152,COL +160,Single-Element Tuple Syntax,156,COL +161,Named Tuple Concept,155|163|285,COL +162,Tuple as Return Value,156|120,COL +163,Dictionary Type,31,COL +164,Creating a Dictionary,163,COL +165,Accessing Values by Key,163|164,COL +166,dict get() Method,165|163,COL +167,Adding and Updating Key-Value Pairs,164|165,COL +168,Removing Entries pop() del,164|144,COL +169,Dictionary keys() values() items(),164,COL +170,Iterating over a Dictionary,100|164|169,COL +171,Key Membership with in,147|163,COL +172,Nested Dictionaries,163|150,COL +173,Dictionary Comprehensions,151|163,COL +174,Default Dictionary Pattern,163|118,COL +175,Dictionary from Two Lists with zip(),111|163|138,COL +176,Set Type,31,COL +177,Creating a Set,176,COL +178,Set Union Intersection Difference,176|177,COL +179,Set add() remove() discard(),177,COL +180,Set Membership with in,177|147,COL +181,Frozensets,176|72,COL +182,print() Output Function,21,COL +183,input() Read Input,86,COL +184,len() Sequence Length,65|142,COL +185,range() Number Sequence,102,COL +186,type() Get Object Type,83,COL +187,int() float() str() bool() Conversions,79|80|81|82,COL +188,list() tuple() set() dict() Constructors,138|156|177|164,COL +189,max() min() Functions,137|41,COL +190,sum() Function,137|41,COL +191,abs() Absolute Value,41,COL +192,round() Function,42|41,COL +193,sorted() Function,137|145|52,COL +194,reversed() Function,137,COL +195,enumerate() with Index,100|110,COL +196,zip() Combine Iterables,111,COL +197,map() Apply Function,115|137|134,COL +198,filter() Filter Items,115|137|134,COL +199,dir() List Attributes,285,COL +200,help() Documentation,199,COL +201,id() Object Identity,31|285,COL +202,hash() Function,163|176|285,COL +203,any() and all() Functions,137|51,COL +204,chr() and ord() Functions,58|41,COL +205,import Statement,1,MOD +206,from...import Specific Names,205,MOD +207,import...as Alias,205,MOD +208,from...import Star,206,MOD +209,Creating Custom Modules,115|205,MOD +210,"__name__ == ""__main__"" Guard",209|205,MOD +211,Standard Library Overview,205,MOD +212,Module Search Path,205|20,MOD +213,Reloading a Module,205,MOD +214,random Module Overview,205|211,MOD +215,random.randint(),214|41,MOD +216,random.choice(),214|137,MOD +217,random.shuffle(),214|137,MOD +218,random.seed(),214,MOD +219,random.random() Float,214|42,MOD +220,random.sample(),214|137,MOD +221,math Module Overview,205|211,MOD +222,math.sqrt() floor() ceil(),221|42,MOD +223,math.sin() cos() pi,221|42,MOD +224,math.radians() degrees(),221|223,MOD +225,math.log() exp(),221|42,MOD +226,math.factorial(),221|41,MOD +227,string Module Constants,205|211|58,MOD +228,time Module Overview,205|211,MOD +229,time.sleep(),228,MOD +230,sys Module,205|211,MOD +231,sys.path Search Path,230|212,MOD +232,os Module,205|211,MOD +233,os.path Operations,232|20,MOD +234,json Module Overview,205|211,MOD +235,json.loads() json.dumps(),234|163|58,MOD +236,json.load() json.dump(),234|255|262,MOD +237,csv Module Basics,205|211|265,MOD +238,datetime Module Basics,205|211,MOD +239,collections Module,205|211|163,MOD +240,itertools Module Overview,205|211|100,MOD +241,re Module Import,205|211,TXT +242,re.search() First Match,241|58,TXT +243,re.findall() All Matches,242,TXT +244,re.split() Split by Pattern,241|58,TXT +245,re.sub() Substitute Matches,241|58,TXT +246,Digit Word Whitespace Patterns,241,TXT +247,Anchors Start and End,241|246,TXT +248,Character Classes,246,TXT +249,Quantifiers Plus Star Question,246,TXT +250,Alternation with Pipe,246,TXT +251,Escaping Special Characters,64|246,TXT +252,Raw Strings for Regex,73|246,TXT +253,Regex Groups with Parentheses,246|156,TXT +254,Compiled Regex Patterns,241,TXT +255,open() Function,20,FIO +256,File Modes r w a b,255,FIO +257,file.read(),255|256,FIO +258,file.readlines(),255|256,FIO +259,file.readline(),255|256,FIO +260,file.write(),255|256,FIO +261,file.close(),255,FIO +262,with Statement Context Manager,255|261,FIO +263,Iterating over File Lines,262|100,FIO +264,Text Processing strip() lower(),66|263,FIO +265,CSV File Reading,255|262|67,FIO +266,CSV File Writing,255|262|260,FIO +267,Reading JSON from File,234|262|235,FIO +268,Writing JSON to File,234|262|260,FIO +269,File Path Handling,232|233|20,FIO +270,Checking if File Exists,232|233,FIO +271,Syntax vs Runtime vs Logic Errors,21|1,ERR +272,Common Exception Types,271,ERR +273,Reading a Traceback,272,ERR +274,try...except Block,272,ERR +275,Catching Specific Exceptions,274|272,ERR +276,else Clause in try/except,274|93,ERR +277,finally Clause,274,ERR +278,raise Statement,274|285,ERR +279,assert Statement,51|52,ERR +280,Debugging with print(),21|271,ERR +281,Using Search Engines to Debug,271,ERR +282,Exception Hierarchy,272|285|295,ERR +283,Custom Exception Classes,285|278|282,ERR +284,Exception Chaining,278|283,ERR +285,Objects and Classes Overview,31|115,OOP +286,Attributes of an Object,285,OOP +287,Methods of an Object,285|115,OOP +288,class Keyword,285,OOP +289,__init__() Constructor,288|117,OOP +290,self Parameter,289,OOP +291,Creating Class Instances,288|289|116,OOP +292,Accessing Attributes and Methods,291|286|287,OOP +293,String Methods as OOP Examples,287|58,OOP +294,List Methods as OOP Examples,287|137,OOP +295,Inheritance Basics,288|291,OOP +296,__str__() String Representation,287|288|58,OOP +297,__repr__() Developer Representation,296|288,OOP +298,Subclasses and Method Overriding,295|287,OOP +299,super() Function,298|295,OOP +300,Class Variables vs Instance Variables,288|286|31,OOP +301,Static Methods,287|288,OOP +302,Properties with @property,287|288,OOP +303,Dunder Methods Overview,287|288|296|297,OOP +304,Object Composition,285|291|295,OOP +305,import turtle,205|1,VIZ +306,turtle.Turtle() Object,305|285,VIZ +307,turtle.Screen() Object,305|285,VIZ +308,Screen Setup and bgcolor(),307,VIZ +309,Movement forward() backward(),306,VIZ +310,Turning left() right(),306,VIZ +311,Absolute Positioning goto(),306|309,VIZ +312,Pen Control penup() pendown(),306,VIZ +313,Pen Size and Color,306|437,VIZ +314,Fill begin_fill() end_fill(),306|313,VIZ +315,Drawing circle() and Polygons,306|309|101,VIZ +316,Turtle Appearance shape(),306,VIZ +317,Hiding and Showing Turtle,306,VIZ +318,Writing Text with turtle.write(),306|58,VIZ +319,Clearing and Resetting,306|307,VIZ +320,Position Query xcor() ycor(),306,VIZ +321,Speed Control speed(),306,VIZ +322,setheading() Direction,306|310,VIZ +323,onscreenclick() Event Handler,307|419,VIZ +324,Animation with Turtle Loops,309|101|229,VIZ +325,Color Picker with Turtle,313|323|163,VIZ +326,Fractals with Recursion and Turtle,128|129|309,VIZ +327,Sine Wave with Turtle and Math,309|223|224|101,VIZ +328,Drawing Star Patterns,309|310|101,VIZ +329,Turtle Race Simulation,306|215|101,VIZ +330,Maze Visualization with Turtle,372|309,VIZ +331,matplotlib Library Overview,205|211,VIZ +332,import matplotlib.pyplot as plt,331,VIZ +333,plt.plot() Line Plot,332|138,VIZ +334,plt.show() Display,332,VIZ +335,Plot Title and Axis Labels,332|58,VIZ +336,plt.grid() Grid Lines,332,VIZ +337,Plotting a Sine Wave,333|223|347,VIZ +338,Lists as XY Plot Data,138|333,VIZ +339,plt.scatter() Scatter Plot,332|138,VIZ +340,plt.bar() Bar Chart,332|138,VIZ +341,plt.hist() Histogram,332|138,VIZ +342,plt.legend() Legend,332|58,VIZ +343,plt.savefig() Save Plot,332|20,VIZ +344,Multiple Lines on One Plot,333|148,VIZ +345,Subplots with plt.subplot(),332|107,VIZ +346,numpy Library Overview,205|211,VIZ +347,import numpy as np,346,VIZ +348,np.array() Creating Arrays,347|138,VIZ +349,np.argmax() Index of Max,348,VIZ +350,Array Operations and Broadcasting,348|47,VIZ +351,Reshaping Arrays,348,VIZ +352,np.zeros() np.ones(),347|348,VIZ +353,np.linspace() Evenly Spaced Values,347|102,VIZ +354,Array Slicing and Indexing,348|141,VIZ +355,Element-wise Math Operations,350|47,VIZ +356,np.mean() np.std(),348|190,VIZ +357,PIL Pillow Library Overview,205|211,VIZ +358,Image.open() Open Image,357|255,VIZ +359,image.show() Display Image,358,VIZ +360,Pixel Data and Image Arrays,358|348,VIZ +361,Image Resize and Crop,358,VIZ +362,Image Color Conversion,358|440,VIZ +363,Saving Images,358|20,VIZ +364,Abstract Data Types Overview,285|115,ALG +365,Stack LIFO Structure,137|153,ALG +366,Queue FIFO Structure,137|154,ALG +367,Queue enqueue() dequeue(),366|143|144,ALG +368,Graph Nodes and Edges,364,ALG +369,Adjacency List Representation,368|163|137,ALG +370,Breadth-First Search BFS,369|366|100,ALG +371,BFS Color Tracking,370|163,ALG +372,BFS for Path Finding,370|371,ALG +373,Depth-First Search DFS,369|365|128,ALG +374,DFS with Recursion,373|128|129,ALG +375,DFS and BFS for Maze Solving,372|374,ALG +376,Sorting Algorithms Overview,137|145,ALG +377,Bubble Sort,376|100|107,ALG +378,Selection Sort,376|100,ALG +379,Insertion Sort,376|100,ALG +380,Binary Search Concept,376|137|102,ALG +381,Time Complexity Big-O Overview,376|380,ALG +382,Space Complexity Overview,381|130,ALG +383,Linked List Concept,364|285,ALG +384,Tree Data Structure Concept,364|368,ALG +385,Binary Tree Basics,384,ALG +386,Machine Learning Overview,1|285,ADV +387,Supervised vs Unsupervised Learning,386,ADV +388,keras Library Overview,205|211|346,ADV +389,Sequential Model,388,ADV +390,Dense Fully Connected Layers,389|41,ADV +391,Activation Functions relu softmax,390|223,ADV +392,Conv2D Convolutional Layers,389|360,ADV +393,MaxPooling2D Pooling Layers,392,ADV +394,Dropout Regularization,390|412,ADV +395,Flatten Layer,392|351,ADV +396,model.compile(),389|400|401|402,ADV +397,model.fit() Training,396|403|411,ADV +398,model.evaluate() Testing,397|411,ADV +399,model.predict() Inference,396|348,ADV +400,Categorical Crossentropy Loss,389|190,ADV +401,Adam Optimizer,389|386,ADV +402,Accuracy Metric,386|190,ADV +403,Batch Size and Epochs,386|102,ADV +404,MNIST Dataset,346|386,ADV +405,Data Normalization,404|350|42,ADV +406,Convolutional Neural Networks,392|393|395,ADV +407,Feedforward Networks,390|391,ADV +408,Recurrent Networks RNN Overview,389|386,ADV +409,LSTM Networks Overview,408,ADV +410,Autoencoders Overview,389|390,ADV +411,Training vs Validation vs Test Sets,386|137,ADV +412,Overfitting Concept,386|411,ADV +413,Feature Extraction,392|348|386,ADV +414,ipycanvas Canvas in Jupyter,8|205,VIZ +415,mobilechelonian Turtle in Jupyter,8|305,VIZ +416,Drawing Shapes on Canvas,414|309,VIZ +417,Color Bars in Jupyter,414|313,VIZ +418,Event-Driven Programming Model,115|116,ADV +419,Mouse Click Event Handlers,418|307,ADV +420,Keyboard Event Handlers,418|307,ADV +421,Callback Functions,115|131|418,ADV +422,Animation Loops,101|418|229,ADV +423,Event Queue Concept,418|366,ADV +424,Timer-Based Events,229|418,ADV +425,Modularity in Code,115|209,ADV +426,Code Reusability,425|115,ADV +427,DRY Principle,426|425,ADV +428,Meaningful Names,32|33|34,ADV +429,Code Comments When and Why,22|115,ADV +430,Literate Programming in Jupyter,8|22|126,ADV +431,Reading Docs with help() and dir(),199|200,ADV +432,Version Control Basics,20|19,ADV +433,Searching Documentation,200|431,ADV +434,Code Refactoring,425|427,ADV +435,Test-Driven Thinking,279|271,ADV +436,Pair Programming Concept,425|428,ADV +437,Named Colors,1,ADV +438,Hex Color Values,437|41,ADV +439,RGB Color Model,437|438,ADV +440,Color in Turtle Graphics,313|437,ADV +441,Background and Pen Colors,308|313|437,ADV +442,HSL Color Model,439,ADV +443,Color Theory Basics,437|439,ADV +444,Transparency and Alpha,439|442,ADV +445,Decomposition,115|425,ADV +446,Pattern Recognition,445|92,ADV +447,Abstraction in Programming,445|115|285,ADV +448,Algorithm Design,445|447|100,ADV +449,Pseudocode Writing,448|22,ADV +450,Debugging Strategies,280|273|271,ADV diff --git a/docs/learning-graph/learning-graph.json b/docs/learning-graph/learning-graph.json new file mode 100644 index 00000000..c29ad7a5 --- /dev/null +++ b/docs/learning-graph/learning-graph.json @@ -0,0 +1,5720 @@ +{ + "metadata": { + "title": "Beginning Python \u2014 From Blocks to Code with Monty", + "description": "A fun, project-driven course that guides young programmers (ages 10-13) from block-based coding to writing real Python, covering core syntax, data types, control flow, functions, collections, turtle graphics, algorithms, and an introduction to machine learning.", + "creator": "Dan McCreary", + "date": "2026-06-28", + "version": "1.0", + "format": "Learning Graph JSON v1.0", + "schema": "https://raw.githubusercontent.com/dmccreary/learning-graphs/refs/heads/main/src/schema/learning-graph-schema.json", + "license": "CC BY-NC-SA 4.0 DEED" + }, + "groups": { + "ENV": { + "classifierName": "Environment & Tools", + "color": "SteelBlue", + "font": { + "color": "white" + } + }, + "SYN": { + "classifierName": "Core Syntax & Output", + "color": "DarkSlateBlue", + "font": { + "color": "white" + } + }, + "DAT": { + "classifierName": "Variables & Data Types", + "color": "DarkGreen", + "font": { + "color": "white" + } + }, + "CTL": { + "classifierName": "Input & Control Flow", + "color": "LimeGreen", + "font": { + "color": "black" + } + }, + "FUN": { + "classifierName": "Functions & Scope", + "color": "Gold", + "font": { + "color": "black" + } + }, + "COL": { + "classifierName": "Collections", + "color": "DarkGoldenrod", + "font": { + "color": "white" + } + }, + "MOD": { + "classifierName": "Modules & Standard Library", + "color": "Teal", + "font": { + "color": "white" + } + }, + "TXT": { + "classifierName": "Text Processing & Regex", + "color": "DodgerBlue", + "font": { + "color": "white" + } + }, + "FIO": { + "classifierName": "File I/O & Data", + "color": "LightSkyBlue", + "font": { + "color": "black" + } + }, + "ERR": { + "classifierName": "Error Handling & Debugging", + "color": "Crimson", + "font": { + "color": "white" + } + }, + "OOP": { + "classifierName": "Object-Oriented Programming", + "color": "MediumPurple", + "font": { + "color": "white" + } + }, + "VIZ": { + "classifierName": "Turtle Graphics & Visualization", + "color": "DarkOrchid", + "font": { + "color": "white" + } + }, + "ALG": { + "classifierName": "Algorithms & Data Structures", + "color": "OliveDrab", + "font": { + "color": "white" + } + }, + "ADV": { + "classifierName": "Advanced & Applied Python", + "color": "Orange", + "font": { + "color": "black" + } + } + }, + "nodes": [ + { + "id": 1, + "label": "Python Interpreter Overview", + "group": "ENV", + "shape": "box" + }, + { + "id": 2, + "label": "Python 2 vs Python 3", + "group": "ENV" + }, + { + "id": 3, + "label": "Trinket.io Web Environment", + "group": "ENV" + }, + { + "id": 4, + "label": "Repl.it Online IDE", + "group": "ENV" + }, + { + "id": 5, + "label": "Thonny Beginner IDE", + "group": "ENV" + }, + { + "id": 6, + "label": "Spyder Scientific IDE", + "group": "ENV" + }, + { + "id": 7, + "label": "VS Code Editor", + "group": "ENV" + }, + { + "id": 8, + "label": "Jupyter Notebooks", + "group": "ENV" + }, + { + "id": 9, + "label": "JupyterLab Environment", + "group": "ENV" + }, + { + "id": 10, + "label": "Conda Package Manager", + "group": "ENV" + }, + { + "id": 11, + "label": "pip Package Installer", + "group": "ENV" + }, + { + "id": 12, + "label": "Virtual Environments", + "group": "ENV" + }, + { + "id": 13, + "label": "Installing Python Locally", + "group": "ENV" + }, + { + "id": 14, + "label": "Running Scripts from Terminal", + "group": "ENV" + }, + { + "id": 15, + "label": "Python REPL Shell", + "group": "ENV" + }, + { + "id": 16, + "label": "Raspberry Pi Python Platform", + "group": "ENV" + }, + { + "id": 17, + "label": "Skulpt Browser Python", + "group": "ENV" + }, + { + "id": 18, + "label": "Google Colab Environment", + "group": "ENV" + }, + { + "id": 19, + "label": "Command Line Basics", + "group": "ENV", + "shape": "box" + }, + { + "id": 20, + "label": "File System Navigation", + "group": "ENV" + }, + { + "id": 21, + "label": "print() Function", + "group": "SYN" + }, + { + "id": 22, + "label": "Single-Line Comments", + "group": "SYN" + }, + { + "id": 23, + "label": "Multi-Line Strings", + "group": "SYN" + }, + { + "id": 24, + "label": "Indentation as Syntax", + "group": "SYN" + }, + { + "id": 25, + "label": "Case Sensitivity", + "group": "SYN" + }, + { + "id": 26, + "label": "Python Keywords", + "group": "SYN" + }, + { + "id": 27, + "label": "Blank Lines and Readability", + "group": "SYN" + }, + { + "id": 28, + "label": "Code Block Structure", + "group": "SYN" + }, + { + "id": 29, + "label": "Statement vs Expression", + "group": "SYN" + }, + { + "id": 30, + "label": "Whitespace Rules", + "group": "SYN" + }, + { + "id": 31, + "label": "Variable Definition and Assignment", + "group": "DAT" + }, + { + "id": 32, + "label": "Variable Naming Rules", + "group": "DAT" + }, + { + "id": 33, + "label": "Snake_case Convention", + "group": "DAT" + }, + { + "id": 34, + "label": "Meaningful Variable Names", + "group": "DAT" + }, + { + "id": 35, + "label": "Multiple Assignment", + "group": "DAT" + }, + { + "id": 36, + "label": "Augmented Assignment Operators", + "group": "DAT" + }, + { + "id": 37, + "label": "Constants by Convention", + "group": "DAT" + }, + { + "id": 38, + "label": "Variable Reassignment", + "group": "DAT" + }, + { + "id": 39, + "label": "Swap Two Variables", + "group": "DAT" + }, + { + "id": 40, + "label": "Naming Conflicts to Avoid", + "group": "DAT" + }, + { + "id": 41, + "label": "Integer Type", + "group": "DAT" + }, + { + "id": 42, + "label": "Float Type", + "group": "DAT" + }, + { + "id": 43, + "label": "Division Returns Float", + "group": "DAT" + }, + { + "id": 44, + "label": "Integer Division Operator", + "group": "DAT" + }, + { + "id": 45, + "label": "Modulo Operator", + "group": "DAT" + }, + { + "id": 46, + "label": "Exponentiation Operator", + "group": "DAT" + }, + { + "id": 47, + "label": "Arithmetic Operators", + "group": "DAT" + }, + { + "id": 48, + "label": "Order of Operations", + "group": "DAT" + }, + { + "id": 49, + "label": "Negative Numbers", + "group": "DAT" + }, + { + "id": 50, + "label": "Scientific Notation Floats", + "group": "DAT" + }, + { + "id": 51, + "label": "Boolean Type", + "group": "DAT" + }, + { + "id": 52, + "label": "Comparison Operators", + "group": "DAT" + }, + { + "id": 53, + "label": "Logical Operators", + "group": "DAT" + }, + { + "id": 54, + "label": "Truthiness and Falsiness", + "group": "DAT" + }, + { + "id": 55, + "label": "Short-Circuit Evaluation", + "group": "DAT" + }, + { + "id": 56, + "label": "Boolean in Conditions", + "group": "DAT" + }, + { + "id": 57, + "label": "Chained Comparisons", + "group": "DAT" + }, + { + "id": 58, + "label": "String Type", + "group": "DAT" + }, + { + "id": 59, + "label": "Single vs Double Quotes", + "group": "DAT" + }, + { + "id": 60, + "label": "String Concatenation", + "group": "DAT" + }, + { + "id": 61, + "label": "String Repetition", + "group": "DAT" + }, + { + "id": 62, + "label": "String Indexing", + "group": "DAT" + }, + { + "id": 63, + "label": "String Slicing", + "group": "DAT" + }, + { + "id": 64, + "label": "Escape Characters", + "group": "DAT" + }, + { + "id": 65, + "label": "String Length with len()", + "group": "DAT" + }, + { + "id": 66, + "label": "String lower() upper() strip()", + "group": "DAT" + }, + { + "id": 67, + "label": "String split() join() replace()", + "group": "DAT" + }, + { + "id": 68, + "label": "String startswith() endswith() find()", + "group": "DAT" + }, + { + "id": 69, + "label": "String isdigit() isalpha() isalnum()", + "group": "DAT" + }, + { + "id": 70, + "label": "String format() Method", + "group": "DAT" + }, + { + "id": 71, + "label": "f-Strings", + "group": "DAT" + }, + { + "id": 72, + "label": "String Immutability", + "group": "DAT" + }, + { + "id": 73, + "label": "Raw Strings", + "group": "DAT" + }, + { + "id": 74, + "label": "String Comparison", + "group": "DAT" + }, + { + "id": 75, + "label": "Multiline String Formatting", + "group": "DAT" + }, + { + "id": 76, + "label": "None Value and NoneType", + "group": "DAT" + }, + { + "id": 77, + "label": "Functions Returning None", + "group": "DAT" + }, + { + "id": 78, + "label": "Checking for None with is", + "group": "DAT" + }, + { + "id": 79, + "label": "int() Conversion", + "group": "DAT" + }, + { + "id": 80, + "label": "float() Conversion", + "group": "DAT" + }, + { + "id": 81, + "label": "str() Conversion", + "group": "DAT" + }, + { + "id": 82, + "label": "bool() Conversion", + "group": "DAT" + }, + { + "id": 83, + "label": "type() Function", + "group": "DAT" + }, + { + "id": 84, + "label": "isinstance() Function", + "group": "DAT" + }, + { + "id": 85, + "label": "Implicit vs Explicit Conversion", + "group": "DAT" + }, + { + "id": 86, + "label": "input() Function", + "group": "CTL" + }, + { + "id": 87, + "label": "Prompting the User", + "group": "CTL" + }, + { + "id": 88, + "label": "Converting Input to Numbers", + "group": "CTL" + }, + { + "id": 89, + "label": "Input Validation Basics", + "group": "CTL" + }, + { + "id": 90, + "label": "Reading Multiple Inputs", + "group": "CTL" + }, + { + "id": 91, + "label": "Strip Whitespace from Input", + "group": "CTL" + }, + { + "id": 92, + "label": "if Statement", + "group": "CTL" + }, + { + "id": 93, + "label": "if...else Block", + "group": "CTL" + }, + { + "id": 94, + "label": "elif Chains", + "group": "CTL" + }, + { + "id": 95, + "label": "Nested if Statements", + "group": "CTL" + }, + { + "id": 96, + "label": "Conditional Ternary Expression", + "group": "CTL" + }, + { + "id": 97, + "label": "match/case Statement", + "group": "CTL" + }, + { + "id": 98, + "label": "Truthiness in Conditions", + "group": "CTL" + }, + { + "id": 99, + "label": "Compound Conditions", + "group": "CTL" + }, + { + "id": 100, + "label": "for Loop over Sequence", + "group": "CTL" + }, + { + "id": 101, + "label": "for Loop with range()", + "group": "CTL" + }, + { + "id": 102, + "label": "Range with Start Stop Step", + "group": "CTL" + }, + { + "id": 103, + "label": "while Loop", + "group": "CTL" + }, + { + "id": 104, + "label": "break Statement", + "group": "CTL" + }, + { + "id": 105, + "label": "continue Statement", + "group": "CTL" + }, + { + "id": 106, + "label": "else Clause on Loops", + "group": "CTL" + }, + { + "id": 107, + "label": "Nested Loops", + "group": "CTL" + }, + { + "id": 108, + "label": "Loop Counter Variable", + "group": "CTL" + }, + { + "id": 109, + "label": "Infinite Loops to Avoid", + "group": "CTL" + }, + { + "id": 110, + "label": "enumerate() Function", + "group": "CTL" + }, + { + "id": 111, + "label": "zip() Function", + "group": "CTL" + }, + { + "id": 112, + "label": "Loop Accumulator Pattern", + "group": "CTL" + }, + { + "id": 113, + "label": "Loop with List Building", + "group": "CTL" + }, + { + "id": 114, + "label": "Countdown Loop", + "group": "CTL" + }, + { + "id": 115, + "label": "Defining a Function with def", + "group": "FUN" + }, + { + "id": 116, + "label": "Calling a Function", + "group": "FUN" + }, + { + "id": 117, + "label": "Positional Parameters", + "group": "FUN" + }, + { + "id": 118, + "label": "Default Parameter Values", + "group": "FUN" + }, + { + "id": 119, + "label": "Keyword Arguments", + "group": "FUN" + }, + { + "id": 120, + "label": "return Statement", + "group": "FUN" + }, + { + "id": 121, + "label": "Functions Returning None", + "group": "FUN" + }, + { + "id": 122, + "label": "Local Scope", + "group": "FUN" + }, + { + "id": 123, + "label": "Global Scope", + "group": "FUN" + }, + { + "id": 124, + "label": "global Keyword", + "group": "FUN" + }, + { + "id": 125, + "label": "nonlocal Keyword", + "group": "FUN" + }, + { + "id": 126, + "label": "Docstrings", + "group": "FUN" + }, + { + "id": 127, + "label": "Pure Functions vs Side Effects", + "group": "FUN" + }, + { + "id": 128, + "label": "Recursion Concept", + "group": "FUN" + }, + { + "id": 129, + "label": "Recursion Base Case", + "group": "FUN" + }, + { + "id": 130, + "label": "Recursion Depth and Stack", + "group": "FUN" + }, + { + "id": 131, + "label": "Lambda Functions", + "group": "FUN" + }, + { + "id": 132, + "label": "Variable Number of Arguments *args", + "group": "FUN" + }, + { + "id": 133, + "label": "Keyword Variable Arguments **kwargs", + "group": "FUN" + }, + { + "id": 134, + "label": "Function as Argument", + "group": "FUN" + }, + { + "id": 135, + "label": "Nested Functions", + "group": "FUN" + }, + { + "id": 136, + "label": "Returning Multiple Values", + "group": "FUN" + }, + { + "id": 137, + "label": "List Type", + "group": "COL" + }, + { + "id": 138, + "label": "Creating a List", + "group": "COL" + }, + { + "id": 139, + "label": "List Indexing", + "group": "COL" + }, + { + "id": 140, + "label": "Negative Indexing", + "group": "COL" + }, + { + "id": 141, + "label": "List Slicing", + "group": "COL" + }, + { + "id": 142, + "label": "len() for Lists", + "group": "COL" + }, + { + "id": 143, + "label": "List append() insert() extend()", + "group": "COL" + }, + { + "id": 144, + "label": "List remove() pop() clear()", + "group": "COL" + }, + { + "id": 145, + "label": "List sort() reverse() copy()", + "group": "COL" + }, + { + "id": 146, + "label": "List index() count()", + "group": "COL" + }, + { + "id": 147, + "label": "Membership with in Operator", + "group": "COL" + }, + { + "id": 148, + "label": "List Concatenation and Repetition", + "group": "COL" + }, + { + "id": 149, + "label": "Iterating over a List", + "group": "COL" + }, + { + "id": 150, + "label": "Nested Lists", + "group": "COL" + }, + { + "id": 151, + "label": "List Comprehensions", + "group": "COL" + }, + { + "id": 152, + "label": "Mutable vs Immutable Types", + "group": "COL" + }, + { + "id": 153, + "label": "List as Stack", + "group": "COL" + }, + { + "id": 154, + "label": "List as Queue", + "group": "COL" + }, + { + "id": 155, + "label": "Tuple Type", + "group": "COL" + }, + { + "id": 156, + "label": "Creating a Tuple", + "group": "COL" + }, + { + "id": 157, + "label": "Tuple Indexing and Slicing", + "group": "COL" + }, + { + "id": 158, + "label": "Tuple Unpacking", + "group": "COL" + }, + { + "id": 159, + "label": "Tuples vs Lists", + "group": "COL" + }, + { + "id": 160, + "label": "Single-Element Tuple Syntax", + "group": "COL" + }, + { + "id": 161, + "label": "Named Tuple Concept", + "group": "COL" + }, + { + "id": 162, + "label": "Tuple as Return Value", + "group": "COL" + }, + { + "id": 163, + "label": "Dictionary Type", + "group": "COL" + }, + { + "id": 164, + "label": "Creating a Dictionary", + "group": "COL" + }, + { + "id": 165, + "label": "Accessing Values by Key", + "group": "COL" + }, + { + "id": 166, + "label": "dict get() Method", + "group": "COL" + }, + { + "id": 167, + "label": "Adding and Updating Key-Value Pairs", + "group": "COL" + }, + { + "id": 168, + "label": "Removing Entries pop() del", + "group": "COL" + }, + { + "id": 169, + "label": "Dictionary keys() values() items()", + "group": "COL" + }, + { + "id": 170, + "label": "Iterating over a Dictionary", + "group": "COL" + }, + { + "id": 171, + "label": "Key Membership with in", + "group": "COL" + }, + { + "id": 172, + "label": "Nested Dictionaries", + "group": "COL" + }, + { + "id": 173, + "label": "Dictionary Comprehensions", + "group": "COL" + }, + { + "id": 174, + "label": "Default Dictionary Pattern", + "group": "COL" + }, + { + "id": 175, + "label": "Dictionary from Two Lists with zip()", + "group": "COL" + }, + { + "id": 176, + "label": "Set Type", + "group": "COL" + }, + { + "id": 177, + "label": "Creating a Set", + "group": "COL" + }, + { + "id": 178, + "label": "Set Union Intersection Difference", + "group": "COL" + }, + { + "id": 179, + "label": "Set add() remove() discard()", + "group": "COL" + }, + { + "id": 180, + "label": "Set Membership with in", + "group": "COL" + }, + { + "id": 181, + "label": "Frozensets", + "group": "COL" + }, + { + "id": 182, + "label": "print() Output Function", + "group": "COL" + }, + { + "id": 183, + "label": "input() Read Input", + "group": "COL" + }, + { + "id": 184, + "label": "len() Sequence Length", + "group": "COL" + }, + { + "id": 185, + "label": "range() Number Sequence", + "group": "COL" + }, + { + "id": 186, + "label": "type() Get Object Type", + "group": "COL" + }, + { + "id": 187, + "label": "int() float() str() bool() Conversions", + "group": "COL" + }, + { + "id": 188, + "label": "list() tuple() set() dict() Constructors", + "group": "COL" + }, + { + "id": 189, + "label": "max() min() Functions", + "group": "COL" + }, + { + "id": 190, + "label": "sum() Function", + "group": "COL" + }, + { + "id": 191, + "label": "abs() Absolute Value", + "group": "COL" + }, + { + "id": 192, + "label": "round() Function", + "group": "COL" + }, + { + "id": 193, + "label": "sorted() Function", + "group": "COL" + }, + { + "id": 194, + "label": "reversed() Function", + "group": "COL" + }, + { + "id": 195, + "label": "enumerate() with Index", + "group": "COL" + }, + { + "id": 196, + "label": "zip() Combine Iterables", + "group": "COL" + }, + { + "id": 197, + "label": "map() Apply Function", + "group": "COL" + }, + { + "id": 198, + "label": "filter() Filter Items", + "group": "COL" + }, + { + "id": 199, + "label": "dir() List Attributes", + "group": "COL" + }, + { + "id": 200, + "label": "help() Documentation", + "group": "COL" + }, + { + "id": 201, + "label": "id() Object Identity", + "group": "COL" + }, + { + "id": 202, + "label": "hash() Function", + "group": "COL" + }, + { + "id": 203, + "label": "any() and all() Functions", + "group": "COL" + }, + { + "id": 204, + "label": "chr() and ord() Functions", + "group": "COL" + }, + { + "id": 205, + "label": "import Statement", + "group": "MOD" + }, + { + "id": 206, + "label": "from...import Specific Names", + "group": "MOD" + }, + { + "id": 207, + "label": "import...as Alias", + "group": "MOD" + }, + { + "id": 208, + "label": "from...import Star", + "group": "MOD" + }, + { + "id": 209, + "label": "Creating Custom Modules", + "group": "MOD" + }, + { + "id": 210, + "label": "__name__ == \"__main__\" Guard", + "group": "MOD" + }, + { + "id": 211, + "label": "Standard Library Overview", + "group": "MOD" + }, + { + "id": 212, + "label": "Module Search Path", + "group": "MOD" + }, + { + "id": 213, + "label": "Reloading a Module", + "group": "MOD" + }, + { + "id": 214, + "label": "random Module Overview", + "group": "MOD" + }, + { + "id": 215, + "label": "random.randint()", + "group": "MOD" + }, + { + "id": 216, + "label": "random.choice()", + "group": "MOD" + }, + { + "id": 217, + "label": "random.shuffle()", + "group": "MOD" + }, + { + "id": 218, + "label": "random.seed()", + "group": "MOD" + }, + { + "id": 219, + "label": "random.random() Float", + "group": "MOD" + }, + { + "id": 220, + "label": "random.sample()", + "group": "MOD" + }, + { + "id": 221, + "label": "math Module Overview", + "group": "MOD" + }, + { + "id": 222, + "label": "math.sqrt() floor() ceil()", + "group": "MOD" + }, + { + "id": 223, + "label": "math.sin() cos() pi", + "group": "MOD" + }, + { + "id": 224, + "label": "math.radians() degrees()", + "group": "MOD" + }, + { + "id": 225, + "label": "math.log() exp()", + "group": "MOD" + }, + { + "id": 226, + "label": "math.factorial()", + "group": "MOD" + }, + { + "id": 227, + "label": "string Module Constants", + "group": "MOD" + }, + { + "id": 228, + "label": "time Module Overview", + "group": "MOD" + }, + { + "id": 229, + "label": "time.sleep()", + "group": "MOD" + }, + { + "id": 230, + "label": "sys Module", + "group": "MOD" + }, + { + "id": 231, + "label": "sys.path Search Path", + "group": "MOD" + }, + { + "id": 232, + "label": "os Module", + "group": "MOD" + }, + { + "id": 233, + "label": "os.path Operations", + "group": "MOD" + }, + { + "id": 234, + "label": "json Module Overview", + "group": "MOD" + }, + { + "id": 235, + "label": "json.loads() json.dumps()", + "group": "MOD" + }, + { + "id": 236, + "label": "json.load() json.dump()", + "group": "MOD" + }, + { + "id": 237, + "label": "csv Module Basics", + "group": "MOD" + }, + { + "id": 238, + "label": "datetime Module Basics", + "group": "MOD" + }, + { + "id": 239, + "label": "collections Module", + "group": "MOD" + }, + { + "id": 240, + "label": "itertools Module Overview", + "group": "MOD" + }, + { + "id": 241, + "label": "re Module Import", + "group": "TXT" + }, + { + "id": 242, + "label": "re.search() First Match", + "group": "TXT" + }, + { + "id": 243, + "label": "re.findall() All Matches", + "group": "TXT" + }, + { + "id": 244, + "label": "re.split() Split by Pattern", + "group": "TXT" + }, + { + "id": 245, + "label": "re.sub() Substitute Matches", + "group": "TXT" + }, + { + "id": 246, + "label": "Digit Word Whitespace Patterns", + "group": "TXT" + }, + { + "id": 247, + "label": "Anchors Start and End", + "group": "TXT" + }, + { + "id": 248, + "label": "Character Classes", + "group": "TXT" + }, + { + "id": 249, + "label": "Quantifiers Plus Star Question", + "group": "TXT" + }, + { + "id": 250, + "label": "Alternation with Pipe", + "group": "TXT" + }, + { + "id": 251, + "label": "Escaping Special Characters", + "group": "TXT" + }, + { + "id": 252, + "label": "Raw Strings for Regex", + "group": "TXT" + }, + { + "id": 253, + "label": "Regex Groups with Parentheses", + "group": "TXT" + }, + { + "id": 254, + "label": "Compiled Regex Patterns", + "group": "TXT" + }, + { + "id": 255, + "label": "open() Function", + "group": "FIO" + }, + { + "id": 256, + "label": "File Modes r w a b", + "group": "FIO" + }, + { + "id": 257, + "label": "file.read()", + "group": "FIO" + }, + { + "id": 258, + "label": "file.readlines()", + "group": "FIO" + }, + { + "id": 259, + "label": "file.readline()", + "group": "FIO" + }, + { + "id": 260, + "label": "file.write()", + "group": "FIO" + }, + { + "id": 261, + "label": "file.close()", + "group": "FIO" + }, + { + "id": 262, + "label": "with Statement Context Manager", + "group": "FIO" + }, + { + "id": 263, + "label": "Iterating over File Lines", + "group": "FIO" + }, + { + "id": 264, + "label": "Text Processing strip() lower()", + "group": "FIO" + }, + { + "id": 265, + "label": "CSV File Reading", + "group": "FIO" + }, + { + "id": 266, + "label": "CSV File Writing", + "group": "FIO" + }, + { + "id": 267, + "label": "Reading JSON from File", + "group": "FIO" + }, + { + "id": 268, + "label": "Writing JSON to File", + "group": "FIO" + }, + { + "id": 269, + "label": "File Path Handling", + "group": "FIO" + }, + { + "id": 270, + "label": "Checking if File Exists", + "group": "FIO" + }, + { + "id": 271, + "label": "Syntax vs Runtime vs Logic Errors", + "group": "ERR" + }, + { + "id": 272, + "label": "Common Exception Types", + "group": "ERR" + }, + { + "id": 273, + "label": "Reading a Traceback", + "group": "ERR" + }, + { + "id": 274, + "label": "try...except Block", + "group": "ERR" + }, + { + "id": 275, + "label": "Catching Specific Exceptions", + "group": "ERR" + }, + { + "id": 276, + "label": "else Clause in try/except", + "group": "ERR" + }, + { + "id": 277, + "label": "finally Clause", + "group": "ERR" + }, + { + "id": 278, + "label": "raise Statement", + "group": "ERR" + }, + { + "id": 279, + "label": "assert Statement", + "group": "ERR" + }, + { + "id": 280, + "label": "Debugging with print()", + "group": "ERR" + }, + { + "id": 281, + "label": "Using Search Engines to Debug", + "group": "ERR" + }, + { + "id": 282, + "label": "Exception Hierarchy", + "group": "ERR" + }, + { + "id": 283, + "label": "Custom Exception Classes", + "group": "ERR" + }, + { + "id": 284, + "label": "Exception Chaining", + "group": "ERR" + }, + { + "id": 285, + "label": "Objects and Classes Overview", + "group": "OOP" + }, + { + "id": 286, + "label": "Attributes of an Object", + "group": "OOP" + }, + { + "id": 287, + "label": "Methods of an Object", + "group": "OOP" + }, + { + "id": 288, + "label": "class Keyword", + "group": "OOP" + }, + { + "id": 289, + "label": "__init__() Constructor", + "group": "OOP" + }, + { + "id": 290, + "label": "self Parameter", + "group": "OOP" + }, + { + "id": 291, + "label": "Creating Class Instances", + "group": "OOP" + }, + { + "id": 292, + "label": "Accessing Attributes and Methods", + "group": "OOP" + }, + { + "id": 293, + "label": "String Methods as OOP Examples", + "group": "OOP" + }, + { + "id": 294, + "label": "List Methods as OOP Examples", + "group": "OOP" + }, + { + "id": 295, + "label": "Inheritance Basics", + "group": "OOP" + }, + { + "id": 296, + "label": "__str__() String Representation", + "group": "OOP" + }, + { + "id": 297, + "label": "__repr__() Developer Representation", + "group": "OOP" + }, + { + "id": 298, + "label": "Subclasses and Method Overriding", + "group": "OOP" + }, + { + "id": 299, + "label": "super() Function", + "group": "OOP" + }, + { + "id": 300, + "label": "Class Variables vs Instance Variables", + "group": "OOP" + }, + { + "id": 301, + "label": "Static Methods", + "group": "OOP" + }, + { + "id": 302, + "label": "Properties with @property", + "group": "OOP" + }, + { + "id": 303, + "label": "Dunder Methods Overview", + "group": "OOP" + }, + { + "id": 304, + "label": "Object Composition", + "group": "OOP" + }, + { + "id": 305, + "label": "import turtle", + "group": "VIZ" + }, + { + "id": 306, + "label": "turtle.Turtle() Object", + "group": "VIZ" + }, + { + "id": 307, + "label": "turtle.Screen() Object", + "group": "VIZ" + }, + { + "id": 308, + "label": "Screen Setup and bgcolor()", + "group": "VIZ" + }, + { + "id": 309, + "label": "Movement forward() backward()", + "group": "VIZ" + }, + { + "id": 310, + "label": "Turning left() right()", + "group": "VIZ" + }, + { + "id": 311, + "label": "Absolute Positioning goto()", + "group": "VIZ" + }, + { + "id": 312, + "label": "Pen Control penup() pendown()", + "group": "VIZ" + }, + { + "id": 313, + "label": "Pen Size and Color", + "group": "VIZ" + }, + { + "id": 314, + "label": "Fill begin_fill() end_fill()", + "group": "VIZ" + }, + { + "id": 315, + "label": "Drawing circle() and Polygons", + "group": "VIZ" + }, + { + "id": 316, + "label": "Turtle Appearance shape()", + "group": "VIZ" + }, + { + "id": 317, + "label": "Hiding and Showing Turtle", + "group": "VIZ" + }, + { + "id": 318, + "label": "Writing Text with turtle.write()", + "group": "VIZ" + }, + { + "id": 319, + "label": "Clearing and Resetting", + "group": "VIZ" + }, + { + "id": 320, + "label": "Position Query xcor() ycor()", + "group": "VIZ" + }, + { + "id": 321, + "label": "Speed Control speed()", + "group": "VIZ" + }, + { + "id": 322, + "label": "setheading() Direction", + "group": "VIZ" + }, + { + "id": 323, + "label": "onscreenclick() Event Handler", + "group": "VIZ" + }, + { + "id": 324, + "label": "Animation with Turtle Loops", + "group": "VIZ" + }, + { + "id": 325, + "label": "Color Picker with Turtle", + "group": "VIZ" + }, + { + "id": 326, + "label": "Fractals with Recursion and Turtle", + "group": "VIZ" + }, + { + "id": 327, + "label": "Sine Wave with Turtle and Math", + "group": "VIZ" + }, + { + "id": 328, + "label": "Drawing Star Patterns", + "group": "VIZ" + }, + { + "id": 329, + "label": "Turtle Race Simulation", + "group": "VIZ" + }, + { + "id": 330, + "label": "Maze Visualization with Turtle", + "group": "VIZ" + }, + { + "id": 331, + "label": "matplotlib Library Overview", + "group": "VIZ" + }, + { + "id": 332, + "label": "import matplotlib.pyplot as plt", + "group": "VIZ" + }, + { + "id": 333, + "label": "plt.plot() Line Plot", + "group": "VIZ" + }, + { + "id": 334, + "label": "plt.show() Display", + "group": "VIZ" + }, + { + "id": 335, + "label": "Plot Title and Axis Labels", + "group": "VIZ" + }, + { + "id": 336, + "label": "plt.grid() Grid Lines", + "group": "VIZ" + }, + { + "id": 337, + "label": "Plotting a Sine Wave", + "group": "VIZ" + }, + { + "id": 338, + "label": "Lists as XY Plot Data", + "group": "VIZ" + }, + { + "id": 339, + "label": "plt.scatter() Scatter Plot", + "group": "VIZ" + }, + { + "id": 340, + "label": "plt.bar() Bar Chart", + "group": "VIZ" + }, + { + "id": 341, + "label": "plt.hist() Histogram", + "group": "VIZ" + }, + { + "id": 342, + "label": "plt.legend() Legend", + "group": "VIZ" + }, + { + "id": 343, + "label": "plt.savefig() Save Plot", + "group": "VIZ" + }, + { + "id": 344, + "label": "Multiple Lines on One Plot", + "group": "VIZ" + }, + { + "id": 345, + "label": "Subplots with plt.subplot()", + "group": "VIZ" + }, + { + "id": 346, + "label": "numpy Library Overview", + "group": "VIZ" + }, + { + "id": 347, + "label": "import numpy as np", + "group": "VIZ" + }, + { + "id": 348, + "label": "np.array() Creating Arrays", + "group": "VIZ" + }, + { + "id": 349, + "label": "np.argmax() Index of Max", + "group": "VIZ" + }, + { + "id": 350, + "label": "Array Operations and Broadcasting", + "group": "VIZ" + }, + { + "id": 351, + "label": "Reshaping Arrays", + "group": "VIZ" + }, + { + "id": 352, + "label": "np.zeros() np.ones()", + "group": "VIZ" + }, + { + "id": 353, + "label": "np.linspace() Evenly Spaced Values", + "group": "VIZ" + }, + { + "id": 354, + "label": "Array Slicing and Indexing", + "group": "VIZ" + }, + { + "id": 355, + "label": "Element-wise Math Operations", + "group": "VIZ" + }, + { + "id": 356, + "label": "np.mean() np.std()", + "group": "VIZ" + }, + { + "id": 357, + "label": "PIL Pillow Library Overview", + "group": "VIZ" + }, + { + "id": 358, + "label": "Image.open() Open Image", + "group": "VIZ" + }, + { + "id": 359, + "label": "image.show() Display Image", + "group": "VIZ" + }, + { + "id": 360, + "label": "Pixel Data and Image Arrays", + "group": "VIZ" + }, + { + "id": 361, + "label": "Image Resize and Crop", + "group": "VIZ" + }, + { + "id": 362, + "label": "Image Color Conversion", + "group": "VIZ" + }, + { + "id": 363, + "label": "Saving Images", + "group": "VIZ" + }, + { + "id": 364, + "label": "Abstract Data Types Overview", + "group": "ALG" + }, + { + "id": 365, + "label": "Stack LIFO Structure", + "group": "ALG" + }, + { + "id": 366, + "label": "Queue FIFO Structure", + "group": "ALG" + }, + { + "id": 367, + "label": "Queue enqueue() dequeue()", + "group": "ALG" + }, + { + "id": 368, + "label": "Graph Nodes and Edges", + "group": "ALG" + }, + { + "id": 369, + "label": "Adjacency List Representation", + "group": "ALG" + }, + { + "id": 370, + "label": "Breadth-First Search BFS", + "group": "ALG" + }, + { + "id": 371, + "label": "BFS Color Tracking", + "group": "ALG" + }, + { + "id": 372, + "label": "BFS for Path Finding", + "group": "ALG" + }, + { + "id": 373, + "label": "Depth-First Search DFS", + "group": "ALG" + }, + { + "id": 374, + "label": "DFS with Recursion", + "group": "ALG" + }, + { + "id": 375, + "label": "DFS and BFS for Maze Solving", + "group": "ALG" + }, + { + "id": 376, + "label": "Sorting Algorithms Overview", + "group": "ALG" + }, + { + "id": 377, + "label": "Bubble Sort", + "group": "ALG" + }, + { + "id": 378, + "label": "Selection Sort", + "group": "ALG" + }, + { + "id": 379, + "label": "Insertion Sort", + "group": "ALG" + }, + { + "id": 380, + "label": "Binary Search Concept", + "group": "ALG" + }, + { + "id": 381, + "label": "Time Complexity Big-O Overview", + "group": "ALG" + }, + { + "id": 382, + "label": "Space Complexity Overview", + "group": "ALG" + }, + { + "id": 383, + "label": "Linked List Concept", + "group": "ALG" + }, + { + "id": 384, + "label": "Tree Data Structure Concept", + "group": "ALG" + }, + { + "id": 385, + "label": "Binary Tree Basics", + "group": "ALG" + }, + { + "id": 386, + "label": "Machine Learning Overview", + "group": "ADV" + }, + { + "id": 387, + "label": "Supervised vs Unsupervised Learning", + "group": "ADV" + }, + { + "id": 388, + "label": "keras Library Overview", + "group": "ADV" + }, + { + "id": 389, + "label": "Sequential Model", + "group": "ADV" + }, + { + "id": 390, + "label": "Dense Fully Connected Layers", + "group": "ADV" + }, + { + "id": 391, + "label": "Activation Functions relu softmax", + "group": "ADV" + }, + { + "id": 392, + "label": "Conv2D Convolutional Layers", + "group": "ADV" + }, + { + "id": 393, + "label": "MaxPooling2D Pooling Layers", + "group": "ADV" + }, + { + "id": 394, + "label": "Dropout Regularization", + "group": "ADV" + }, + { + "id": 395, + "label": "Flatten Layer", + "group": "ADV" + }, + { + "id": 396, + "label": "model.compile()", + "group": "ADV" + }, + { + "id": 397, + "label": "model.fit() Training", + "group": "ADV" + }, + { + "id": 398, + "label": "model.evaluate() Testing", + "group": "ADV" + }, + { + "id": 399, + "label": "model.predict() Inference", + "group": "ADV" + }, + { + "id": 400, + "label": "Categorical Crossentropy Loss", + "group": "ADV" + }, + { + "id": 401, + "label": "Adam Optimizer", + "group": "ADV" + }, + { + "id": 402, + "label": "Accuracy Metric", + "group": "ADV" + }, + { + "id": 403, + "label": "Batch Size and Epochs", + "group": "ADV" + }, + { + "id": 404, + "label": "MNIST Dataset", + "group": "ADV" + }, + { + "id": 405, + "label": "Data Normalization", + "group": "ADV" + }, + { + "id": 406, + "label": "Convolutional Neural Networks", + "group": "ADV" + }, + { + "id": 407, + "label": "Feedforward Networks", + "group": "ADV" + }, + { + "id": 408, + "label": "Recurrent Networks RNN Overview", + "group": "ADV" + }, + { + "id": 409, + "label": "LSTM Networks Overview", + "group": "ADV" + }, + { + "id": 410, + "label": "Autoencoders Overview", + "group": "ADV" + }, + { + "id": 411, + "label": "Training vs Validation vs Test Sets", + "group": "ADV" + }, + { + "id": 412, + "label": "Overfitting Concept", + "group": "ADV" + }, + { + "id": 413, + "label": "Feature Extraction", + "group": "ADV" + }, + { + "id": 414, + "label": "ipycanvas Canvas in Jupyter", + "group": "VIZ" + }, + { + "id": 415, + "label": "mobilechelonian Turtle in Jupyter", + "group": "VIZ" + }, + { + "id": 416, + "label": "Drawing Shapes on Canvas", + "group": "VIZ" + }, + { + "id": 417, + "label": "Color Bars in Jupyter", + "group": "VIZ" + }, + { + "id": 418, + "label": "Event-Driven Programming Model", + "group": "ADV" + }, + { + "id": 419, + "label": "Mouse Click Event Handlers", + "group": "ADV" + }, + { + "id": 420, + "label": "Keyboard Event Handlers", + "group": "ADV" + }, + { + "id": 421, + "label": "Callback Functions", + "group": "ADV" + }, + { + "id": 422, + "label": "Animation Loops", + "group": "ADV" + }, + { + "id": 423, + "label": "Event Queue Concept", + "group": "ADV" + }, + { + "id": 424, + "label": "Timer-Based Events", + "group": "ADV" + }, + { + "id": 425, + "label": "Modularity in Code", + "group": "ADV" + }, + { + "id": 426, + "label": "Code Reusability", + "group": "ADV" + }, + { + "id": 427, + "label": "DRY Principle", + "group": "ADV" + }, + { + "id": 428, + "label": "Meaningful Names", + "group": "ADV" + }, + { + "id": 429, + "label": "Code Comments When and Why", + "group": "ADV" + }, + { + "id": 430, + "label": "Literate Programming in Jupyter", + "group": "ADV" + }, + { + "id": 431, + "label": "Reading Docs with help() and dir()", + "group": "ADV" + }, + { + "id": 432, + "label": "Version Control Basics", + "group": "ADV" + }, + { + "id": 433, + "label": "Searching Documentation", + "group": "ADV" + }, + { + "id": 434, + "label": "Code Refactoring", + "group": "ADV" + }, + { + "id": 435, + "label": "Test-Driven Thinking", + "group": "ADV" + }, + { + "id": 436, + "label": "Pair Programming Concept", + "group": "ADV" + }, + { + "id": 437, + "label": "Named Colors", + "group": "ADV" + }, + { + "id": 438, + "label": "Hex Color Values", + "group": "ADV" + }, + { + "id": 439, + "label": "RGB Color Model", + "group": "ADV" + }, + { + "id": 440, + "label": "Color in Turtle Graphics", + "group": "ADV" + }, + { + "id": 441, + "label": "Background and Pen Colors", + "group": "ADV" + }, + { + "id": 442, + "label": "HSL Color Model", + "group": "ADV" + }, + { + "id": 443, + "label": "Color Theory Basics", + "group": "ADV" + }, + { + "id": 444, + "label": "Transparency and Alpha", + "group": "ADV" + }, + { + "id": 445, + "label": "Decomposition", + "group": "ADV" + }, + { + "id": 446, + "label": "Pattern Recognition", + "group": "ADV" + }, + { + "id": 447, + "label": "Abstraction in Programming", + "group": "ADV" + }, + { + "id": 448, + "label": "Algorithm Design", + "group": "ADV" + }, + { + "id": 449, + "label": "Pseudocode Writing", + "group": "ADV" + }, + { + "id": 450, + "label": "Debugging Strategies", + "group": "ADV" + } + ], + "edges": [ + { + "from": 2, + "to": 1 + }, + { + "from": 3, + "to": 1 + }, + { + "from": 4, + "to": 1 + }, + { + "from": 5, + "to": 1 + }, + { + "from": 6, + "to": 1 + }, + { + "from": 7, + "to": 1 + }, + { + "from": 8, + "to": 1 + }, + { + "from": 9, + "to": 8 + }, + { + "from": 10, + "to": 1 + }, + { + "from": 11, + "to": 1 + }, + { + "from": 11, + "to": 10 + }, + { + "from": 12, + "to": 11 + }, + { + "from": 13, + "to": 1 + }, + { + "from": 13, + "to": 11 + }, + { + "from": 14, + "to": 13 + }, + { + "from": 14, + "to": 19 + }, + { + "from": 15, + "to": 1 + }, + { + "from": 16, + "to": 1 + }, + { + "from": 16, + "to": 13 + }, + { + "from": 17, + "to": 1 + }, + { + "from": 17, + "to": 3 + }, + { + "from": 18, + "to": 1 + }, + { + "from": 18, + "to": 8 + }, + { + "from": 20, + "to": 19 + }, + { + "from": 21, + "to": 1 + }, + { + "from": 22, + "to": 21 + }, + { + "from": 23, + "to": 21 + }, + { + "from": 24, + "to": 21 + }, + { + "from": 25, + "to": 21 + }, + { + "from": 26, + "to": 21 + }, + { + "from": 27, + "to": 21 + }, + { + "from": 27, + "to": 22 + }, + { + "from": 28, + "to": 24 + }, + { + "from": 29, + "to": 21 + }, + { + "from": 30, + "to": 24 + }, + { + "from": 31, + "to": 21 + }, + { + "from": 31, + "to": 29 + }, + { + "from": 32, + "to": 31 + }, + { + "from": 33, + "to": 32 + }, + { + "from": 34, + "to": 32 + }, + { + "from": 34, + "to": 33 + }, + { + "from": 35, + "to": 31 + }, + { + "from": 36, + "to": 31 + }, + { + "from": 36, + "to": 47 + }, + { + "from": 37, + "to": 31 + }, + { + "from": 37, + "to": 33 + }, + { + "from": 38, + "to": 31 + }, + { + "from": 39, + "to": 35 + }, + { + "from": 39, + "to": 38 + }, + { + "from": 40, + "to": 32 + }, + { + "from": 40, + "to": 26 + }, + { + "from": 41, + "to": 31 + }, + { + "from": 42, + "to": 31 + }, + { + "from": 43, + "to": 42 + }, + { + "from": 44, + "to": 41 + }, + { + "from": 44, + "to": 42 + }, + { + "from": 45, + "to": 41 + }, + { + "from": 46, + "to": 41 + }, + { + "from": 47, + "to": 41 + }, + { + "from": 47, + "to": 42 + }, + { + "from": 48, + "to": 47 + }, + { + "from": 49, + "to": 41 + }, + { + "from": 50, + "to": 42 + }, + { + "from": 51, + "to": 31 + }, + { + "from": 52, + "to": 41 + }, + { + "from": 52, + "to": 51 + }, + { + "from": 53, + "to": 51 + }, + { + "from": 53, + "to": 52 + }, + { + "from": 54, + "to": 51 + }, + { + "from": 55, + "to": 53 + }, + { + "from": 56, + "to": 51 + }, + { + "from": 56, + "to": 92 + }, + { + "from": 57, + "to": 52 + }, + { + "from": 57, + "to": 53 + }, + { + "from": 58, + "to": 31 + }, + { + "from": 59, + "to": 58 + }, + { + "from": 60, + "to": 58 + }, + { + "from": 61, + "to": 58 + }, + { + "from": 61, + "to": 41 + }, + { + "from": 62, + "to": 58 + }, + { + "from": 62, + "to": 41 + }, + { + "from": 63, + "to": 62 + }, + { + "from": 64, + "to": 58 + }, + { + "from": 65, + "to": 58 + }, + { + "from": 66, + "to": 58 + }, + { + "from": 67, + "to": 58 + }, + { + "from": 68, + "to": 58 + }, + { + "from": 69, + "to": 58 + }, + { + "from": 70, + "to": 58 + }, + { + "from": 70, + "to": 31 + }, + { + "from": 71, + "to": 58 + }, + { + "from": 71, + "to": 31 + }, + { + "from": 71, + "to": 70 + }, + { + "from": 72, + "to": 58 + }, + { + "from": 73, + "to": 58 + }, + { + "from": 73, + "to": 64 + }, + { + "from": 74, + "to": 58 + }, + { + "from": 74, + "to": 52 + }, + { + "from": 75, + "to": 23 + }, + { + "from": 75, + "to": 71 + }, + { + "from": 76, + "to": 31 + }, + { + "from": 77, + "to": 121 + }, + { + "from": 77, + "to": 76 + }, + { + "from": 78, + "to": 76 + }, + { + "from": 78, + "to": 52 + }, + { + "from": 79, + "to": 41 + }, + { + "from": 79, + "to": 58 + }, + { + "from": 80, + "to": 42 + }, + { + "from": 80, + "to": 58 + }, + { + "from": 81, + "to": 58 + }, + { + "from": 81, + "to": 41 + }, + { + "from": 82, + "to": 51 + }, + { + "from": 82, + "to": 31 + }, + { + "from": 83, + "to": 31 + }, + { + "from": 83, + "to": 41 + }, + { + "from": 84, + "to": 83 + }, + { + "from": 84, + "to": 285 + }, + { + "from": 85, + "to": 79 + }, + { + "from": 85, + "to": 80 + }, + { + "from": 85, + "to": 81 + }, + { + "from": 86, + "to": 21 + }, + { + "from": 86, + "to": 58 + }, + { + "from": 87, + "to": 86 + }, + { + "from": 87, + "to": 58 + }, + { + "from": 88, + "to": 86 + }, + { + "from": 88, + "to": 79 + }, + { + "from": 88, + "to": 80 + }, + { + "from": 89, + "to": 86 + }, + { + "from": 89, + "to": 92 + }, + { + "from": 90, + "to": 86 + }, + { + "from": 90, + "to": 35 + }, + { + "from": 91, + "to": 86 + }, + { + "from": 91, + "to": 66 + }, + { + "from": 92, + "to": 51 + }, + { + "from": 92, + "to": 24 + }, + { + "from": 92, + "to": 28 + }, + { + "from": 93, + "to": 92 + }, + { + "from": 94, + "to": 93 + }, + { + "from": 95, + "to": 93 + }, + { + "from": 96, + "to": 92 + }, + { + "from": 96, + "to": 51 + }, + { + "from": 97, + "to": 92 + }, + { + "from": 97, + "to": 94 + }, + { + "from": 98, + "to": 54 + }, + { + "from": 98, + "to": 92 + }, + { + "from": 99, + "to": 53 + }, + { + "from": 99, + "to": 92 + }, + { + "from": 100, + "to": 24 + }, + { + "from": 100, + "to": 28 + }, + { + "from": 101, + "to": 100 + }, + { + "from": 102, + "to": 101 + }, + { + "from": 102, + "to": 41 + }, + { + "from": 103, + "to": 24 + }, + { + "from": 103, + "to": 28 + }, + { + "from": 103, + "to": 51 + }, + { + "from": 104, + "to": 100 + }, + { + "from": 104, + "to": 103 + }, + { + "from": 105, + "to": 100 + }, + { + "from": 105, + "to": 103 + }, + { + "from": 106, + "to": 100 + }, + { + "from": 106, + "to": 103 + }, + { + "from": 107, + "to": 100 + }, + { + "from": 107, + "to": 108 + }, + { + "from": 108, + "to": 100 + }, + { + "from": 108, + "to": 41 + }, + { + "from": 109, + "to": 103 + }, + { + "from": 109, + "to": 104 + }, + { + "from": 110, + "to": 100 + }, + { + "from": 111, + "to": 100 + }, + { + "from": 112, + "to": 100 + }, + { + "from": 112, + "to": 31 + }, + { + "from": 113, + "to": 100 + }, + { + "from": 113, + "to": 138 + }, + { + "from": 114, + "to": 101 + }, + { + "from": 114, + "to": 102 + }, + { + "from": 115, + "to": 24 + }, + { + "from": 115, + "to": 28 + }, + { + "from": 115, + "to": 21 + }, + { + "from": 116, + "to": 115 + }, + { + "from": 117, + "to": 115 + }, + { + "from": 118, + "to": 115 + }, + { + "from": 118, + "to": 117 + }, + { + "from": 119, + "to": 115 + }, + { + "from": 119, + "to": 117 + }, + { + "from": 120, + "to": 115 + }, + { + "from": 121, + "to": 115 + }, + { + "from": 121, + "to": 76 + }, + { + "from": 122, + "to": 115 + }, + { + "from": 122, + "to": 31 + }, + { + "from": 123, + "to": 31 + }, + { + "from": 123, + "to": 115 + }, + { + "from": 124, + "to": 123 + }, + { + "from": 124, + "to": 122 + }, + { + "from": 125, + "to": 122 + }, + { + "from": 125, + "to": 135 + }, + { + "from": 126, + "to": 115 + }, + { + "from": 126, + "to": 23 + }, + { + "from": 127, + "to": 115 + }, + { + "from": 127, + "to": 120 + }, + { + "from": 128, + "to": 115 + }, + { + "from": 128, + "to": 116 + }, + { + "from": 129, + "to": 128 + }, + { + "from": 130, + "to": 128 + }, + { + "from": 130, + "to": 129 + }, + { + "from": 131, + "to": 115 + }, + { + "from": 131, + "to": 116 + }, + { + "from": 132, + "to": 115 + }, + { + "from": 132, + "to": 137 + }, + { + "from": 133, + "to": 115 + }, + { + "from": 133, + "to": 163 + }, + { + "from": 134, + "to": 131 + }, + { + "from": 134, + "to": 115 + }, + { + "from": 135, + "to": 115 + }, + { + "from": 135, + "to": 122 + }, + { + "from": 136, + "to": 120 + }, + { + "from": 136, + "to": 155 + }, + { + "from": 137, + "to": 31 + }, + { + "from": 138, + "to": 137 + }, + { + "from": 139, + "to": 137 + }, + { + "from": 139, + "to": 41 + }, + { + "from": 140, + "to": 139 + }, + { + "from": 141, + "to": 139 + }, + { + "from": 141, + "to": 63 + }, + { + "from": 142, + "to": 137 + }, + { + "from": 143, + "to": 137 + }, + { + "from": 144, + "to": 137 + }, + { + "from": 145, + "to": 137 + }, + { + "from": 145, + "to": 52 + }, + { + "from": 146, + "to": 137 + }, + { + "from": 147, + "to": 137 + }, + { + "from": 147, + "to": 58 + }, + { + "from": 148, + "to": 137 + }, + { + "from": 148, + "to": 60 + }, + { + "from": 148, + "to": 61 + }, + { + "from": 149, + "to": 100 + }, + { + "from": 149, + "to": 137 + }, + { + "from": 150, + "to": 137 + }, + { + "from": 150, + "to": 139 + }, + { + "from": 151, + "to": 100 + }, + { + "from": 151, + "to": 137 + }, + { + "from": 151, + "to": 149 + }, + { + "from": 152, + "to": 137 + }, + { + "from": 152, + "to": 58 + }, + { + "from": 153, + "to": 137 + }, + { + "from": 153, + "to": 143 + }, + { + "from": 153, + "to": 144 + }, + { + "from": 154, + "to": 137 + }, + { + "from": 154, + "to": 143 + }, + { + "from": 154, + "to": 144 + }, + { + "from": 155, + "to": 31 + }, + { + "from": 156, + "to": 155 + }, + { + "from": 157, + "to": 156 + }, + { + "from": 157, + "to": 139 + }, + { + "from": 157, + "to": 141 + }, + { + "from": 158, + "to": 156 + }, + { + "from": 158, + "to": 35 + }, + { + "from": 159, + "to": 155 + }, + { + "from": 159, + "to": 137 + }, + { + "from": 159, + "to": 152 + }, + { + "from": 160, + "to": 156 + }, + { + "from": 161, + "to": 155 + }, + { + "from": 161, + "to": 163 + }, + { + "from": 161, + "to": 285 + }, + { + "from": 162, + "to": 156 + }, + { + "from": 162, + "to": 120 + }, + { + "from": 163, + "to": 31 + }, + { + "from": 164, + "to": 163 + }, + { + "from": 165, + "to": 163 + }, + { + "from": 165, + "to": 164 + }, + { + "from": 166, + "to": 165 + }, + { + "from": 166, + "to": 163 + }, + { + "from": 167, + "to": 164 + }, + { + "from": 167, + "to": 165 + }, + { + "from": 168, + "to": 164 + }, + { + "from": 168, + "to": 144 + }, + { + "from": 169, + "to": 164 + }, + { + "from": 170, + "to": 100 + }, + { + "from": 170, + "to": 164 + }, + { + "from": 170, + "to": 169 + }, + { + "from": 171, + "to": 147 + }, + { + "from": 171, + "to": 163 + }, + { + "from": 172, + "to": 163 + }, + { + "from": 172, + "to": 150 + }, + { + "from": 173, + "to": 151 + }, + { + "from": 173, + "to": 163 + }, + { + "from": 174, + "to": 163 + }, + { + "from": 174, + "to": 118 + }, + { + "from": 175, + "to": 111 + }, + { + "from": 175, + "to": 163 + }, + { + "from": 175, + "to": 138 + }, + { + "from": 176, + "to": 31 + }, + { + "from": 177, + "to": 176 + }, + { + "from": 178, + "to": 176 + }, + { + "from": 178, + "to": 177 + }, + { + "from": 179, + "to": 177 + }, + { + "from": 180, + "to": 177 + }, + { + "from": 180, + "to": 147 + }, + { + "from": 181, + "to": 176 + }, + { + "from": 181, + "to": 72 + }, + { + "from": 182, + "to": 21 + }, + { + "from": 183, + "to": 86 + }, + { + "from": 184, + "to": 65 + }, + { + "from": 184, + "to": 142 + }, + { + "from": 185, + "to": 102 + }, + { + "from": 186, + "to": 83 + }, + { + "from": 187, + "to": 79 + }, + { + "from": 187, + "to": 80 + }, + { + "from": 187, + "to": 81 + }, + { + "from": 187, + "to": 82 + }, + { + "from": 188, + "to": 138 + }, + { + "from": 188, + "to": 156 + }, + { + "from": 188, + "to": 177 + }, + { + "from": 188, + "to": 164 + }, + { + "from": 189, + "to": 137 + }, + { + "from": 189, + "to": 41 + }, + { + "from": 190, + "to": 137 + }, + { + "from": 190, + "to": 41 + }, + { + "from": 191, + "to": 41 + }, + { + "from": 192, + "to": 42 + }, + { + "from": 192, + "to": 41 + }, + { + "from": 193, + "to": 137 + }, + { + "from": 193, + "to": 145 + }, + { + "from": 193, + "to": 52 + }, + { + "from": 194, + "to": 137 + }, + { + "from": 195, + "to": 100 + }, + { + "from": 195, + "to": 110 + }, + { + "from": 196, + "to": 111 + }, + { + "from": 197, + "to": 115 + }, + { + "from": 197, + "to": 137 + }, + { + "from": 197, + "to": 134 + }, + { + "from": 198, + "to": 115 + }, + { + "from": 198, + "to": 137 + }, + { + "from": 198, + "to": 134 + }, + { + "from": 199, + "to": 285 + }, + { + "from": 200, + "to": 199 + }, + { + "from": 201, + "to": 31 + }, + { + "from": 201, + "to": 285 + }, + { + "from": 202, + "to": 163 + }, + { + "from": 202, + "to": 176 + }, + { + "from": 202, + "to": 285 + }, + { + "from": 203, + "to": 137 + }, + { + "from": 203, + "to": 51 + }, + { + "from": 204, + "to": 58 + }, + { + "from": 204, + "to": 41 + }, + { + "from": 205, + "to": 1 + }, + { + "from": 206, + "to": 205 + }, + { + "from": 207, + "to": 205 + }, + { + "from": 208, + "to": 206 + }, + { + "from": 209, + "to": 115 + }, + { + "from": 209, + "to": 205 + }, + { + "from": 210, + "to": 209 + }, + { + "from": 210, + "to": 205 + }, + { + "from": 211, + "to": 205 + }, + { + "from": 212, + "to": 205 + }, + { + "from": 212, + "to": 20 + }, + { + "from": 213, + "to": 205 + }, + { + "from": 214, + "to": 205 + }, + { + "from": 214, + "to": 211 + }, + { + "from": 215, + "to": 214 + }, + { + "from": 215, + "to": 41 + }, + { + "from": 216, + "to": 214 + }, + { + "from": 216, + "to": 137 + }, + { + "from": 217, + "to": 214 + }, + { + "from": 217, + "to": 137 + }, + { + "from": 218, + "to": 214 + }, + { + "from": 219, + "to": 214 + }, + { + "from": 219, + "to": 42 + }, + { + "from": 220, + "to": 214 + }, + { + "from": 220, + "to": 137 + }, + { + "from": 221, + "to": 205 + }, + { + "from": 221, + "to": 211 + }, + { + "from": 222, + "to": 221 + }, + { + "from": 222, + "to": 42 + }, + { + "from": 223, + "to": 221 + }, + { + "from": 223, + "to": 42 + }, + { + "from": 224, + "to": 221 + }, + { + "from": 224, + "to": 223 + }, + { + "from": 225, + "to": 221 + }, + { + "from": 225, + "to": 42 + }, + { + "from": 226, + "to": 221 + }, + { + "from": 226, + "to": 41 + }, + { + "from": 227, + "to": 205 + }, + { + "from": 227, + "to": 211 + }, + { + "from": 227, + "to": 58 + }, + { + "from": 228, + "to": 205 + }, + { + "from": 228, + "to": 211 + }, + { + "from": 229, + "to": 228 + }, + { + "from": 230, + "to": 205 + }, + { + "from": 230, + "to": 211 + }, + { + "from": 231, + "to": 230 + }, + { + "from": 231, + "to": 212 + }, + { + "from": 232, + "to": 205 + }, + { + "from": 232, + "to": 211 + }, + { + "from": 233, + "to": 232 + }, + { + "from": 233, + "to": 20 + }, + { + "from": 234, + "to": 205 + }, + { + "from": 234, + "to": 211 + }, + { + "from": 235, + "to": 234 + }, + { + "from": 235, + "to": 163 + }, + { + "from": 235, + "to": 58 + }, + { + "from": 236, + "to": 234 + }, + { + "from": 236, + "to": 255 + }, + { + "from": 236, + "to": 262 + }, + { + "from": 237, + "to": 205 + }, + { + "from": 237, + "to": 211 + }, + { + "from": 237, + "to": 265 + }, + { + "from": 238, + "to": 205 + }, + { + "from": 238, + "to": 211 + }, + { + "from": 239, + "to": 205 + }, + { + "from": 239, + "to": 211 + }, + { + "from": 239, + "to": 163 + }, + { + "from": 240, + "to": 205 + }, + { + "from": 240, + "to": 211 + }, + { + "from": 240, + "to": 100 + }, + { + "from": 241, + "to": 205 + }, + { + "from": 241, + "to": 211 + }, + { + "from": 242, + "to": 241 + }, + { + "from": 242, + "to": 58 + }, + { + "from": 243, + "to": 242 + }, + { + "from": 244, + "to": 241 + }, + { + "from": 244, + "to": 58 + }, + { + "from": 245, + "to": 241 + }, + { + "from": 245, + "to": 58 + }, + { + "from": 246, + "to": 241 + }, + { + "from": 247, + "to": 241 + }, + { + "from": 247, + "to": 246 + }, + { + "from": 248, + "to": 246 + }, + { + "from": 249, + "to": 246 + }, + { + "from": 250, + "to": 246 + }, + { + "from": 251, + "to": 64 + }, + { + "from": 251, + "to": 246 + }, + { + "from": 252, + "to": 73 + }, + { + "from": 252, + "to": 246 + }, + { + "from": 253, + "to": 246 + }, + { + "from": 253, + "to": 156 + }, + { + "from": 254, + "to": 241 + }, + { + "from": 255, + "to": 20 + }, + { + "from": 256, + "to": 255 + }, + { + "from": 257, + "to": 255 + }, + { + "from": 257, + "to": 256 + }, + { + "from": 258, + "to": 255 + }, + { + "from": 258, + "to": 256 + }, + { + "from": 259, + "to": 255 + }, + { + "from": 259, + "to": 256 + }, + { + "from": 260, + "to": 255 + }, + { + "from": 260, + "to": 256 + }, + { + "from": 261, + "to": 255 + }, + { + "from": 262, + "to": 255 + }, + { + "from": 262, + "to": 261 + }, + { + "from": 263, + "to": 262 + }, + { + "from": 263, + "to": 100 + }, + { + "from": 264, + "to": 66 + }, + { + "from": 264, + "to": 263 + }, + { + "from": 265, + "to": 255 + }, + { + "from": 265, + "to": 262 + }, + { + "from": 265, + "to": 67 + }, + { + "from": 266, + "to": 255 + }, + { + "from": 266, + "to": 262 + }, + { + "from": 266, + "to": 260 + }, + { + "from": 267, + "to": 234 + }, + { + "from": 267, + "to": 262 + }, + { + "from": 267, + "to": 235 + }, + { + "from": 268, + "to": 234 + }, + { + "from": 268, + "to": 262 + }, + { + "from": 268, + "to": 260 + }, + { + "from": 269, + "to": 232 + }, + { + "from": 269, + "to": 233 + }, + { + "from": 269, + "to": 20 + }, + { + "from": 270, + "to": 232 + }, + { + "from": 270, + "to": 233 + }, + { + "from": 271, + "to": 21 + }, + { + "from": 271, + "to": 1 + }, + { + "from": 272, + "to": 271 + }, + { + "from": 273, + "to": 272 + }, + { + "from": 274, + "to": 272 + }, + { + "from": 275, + "to": 274 + }, + { + "from": 275, + "to": 272 + }, + { + "from": 276, + "to": 274 + }, + { + "from": 276, + "to": 93 + }, + { + "from": 277, + "to": 274 + }, + { + "from": 278, + "to": 274 + }, + { + "from": 278, + "to": 285 + }, + { + "from": 279, + "to": 51 + }, + { + "from": 279, + "to": 52 + }, + { + "from": 280, + "to": 21 + }, + { + "from": 280, + "to": 271 + }, + { + "from": 281, + "to": 271 + }, + { + "from": 282, + "to": 272 + }, + { + "from": 282, + "to": 285 + }, + { + "from": 282, + "to": 295 + }, + { + "from": 283, + "to": 285 + }, + { + "from": 283, + "to": 278 + }, + { + "from": 283, + "to": 282 + }, + { + "from": 284, + "to": 278 + }, + { + "from": 284, + "to": 283 + }, + { + "from": 285, + "to": 31 + }, + { + "from": 285, + "to": 115 + }, + { + "from": 286, + "to": 285 + }, + { + "from": 287, + "to": 285 + }, + { + "from": 287, + "to": 115 + }, + { + "from": 288, + "to": 285 + }, + { + "from": 289, + "to": 288 + }, + { + "from": 289, + "to": 117 + }, + { + "from": 290, + "to": 289 + }, + { + "from": 291, + "to": 288 + }, + { + "from": 291, + "to": 289 + }, + { + "from": 291, + "to": 116 + }, + { + "from": 292, + "to": 291 + }, + { + "from": 292, + "to": 286 + }, + { + "from": 292, + "to": 287 + }, + { + "from": 293, + "to": 287 + }, + { + "from": 293, + "to": 58 + }, + { + "from": 294, + "to": 287 + }, + { + "from": 294, + "to": 137 + }, + { + "from": 295, + "to": 288 + }, + { + "from": 295, + "to": 291 + }, + { + "from": 296, + "to": 287 + }, + { + "from": 296, + "to": 288 + }, + { + "from": 296, + "to": 58 + }, + { + "from": 297, + "to": 296 + }, + { + "from": 297, + "to": 288 + }, + { + "from": 298, + "to": 295 + }, + { + "from": 298, + "to": 287 + }, + { + "from": 299, + "to": 298 + }, + { + "from": 299, + "to": 295 + }, + { + "from": 300, + "to": 288 + }, + { + "from": 300, + "to": 286 + }, + { + "from": 300, + "to": 31 + }, + { + "from": 301, + "to": 287 + }, + { + "from": 301, + "to": 288 + }, + { + "from": 302, + "to": 287 + }, + { + "from": 302, + "to": 288 + }, + { + "from": 303, + "to": 287 + }, + { + "from": 303, + "to": 288 + }, + { + "from": 303, + "to": 296 + }, + { + "from": 303, + "to": 297 + }, + { + "from": 304, + "to": 285 + }, + { + "from": 304, + "to": 291 + }, + { + "from": 304, + "to": 295 + }, + { + "from": 305, + "to": 205 + }, + { + "from": 305, + "to": 1 + }, + { + "from": 306, + "to": 305 + }, + { + "from": 306, + "to": 285 + }, + { + "from": 307, + "to": 305 + }, + { + "from": 307, + "to": 285 + }, + { + "from": 308, + "to": 307 + }, + { + "from": 309, + "to": 306 + }, + { + "from": 310, + "to": 306 + }, + { + "from": 311, + "to": 306 + }, + { + "from": 311, + "to": 309 + }, + { + "from": 312, + "to": 306 + }, + { + "from": 313, + "to": 306 + }, + { + "from": 313, + "to": 437 + }, + { + "from": 314, + "to": 306 + }, + { + "from": 314, + "to": 313 + }, + { + "from": 315, + "to": 306 + }, + { + "from": 315, + "to": 309 + }, + { + "from": 315, + "to": 101 + }, + { + "from": 316, + "to": 306 + }, + { + "from": 317, + "to": 306 + }, + { + "from": 318, + "to": 306 + }, + { + "from": 318, + "to": 58 + }, + { + "from": 319, + "to": 306 + }, + { + "from": 319, + "to": 307 + }, + { + "from": 320, + "to": 306 + }, + { + "from": 321, + "to": 306 + }, + { + "from": 322, + "to": 306 + }, + { + "from": 322, + "to": 310 + }, + { + "from": 323, + "to": 307 + }, + { + "from": 323, + "to": 419 + }, + { + "from": 324, + "to": 309 + }, + { + "from": 324, + "to": 101 + }, + { + "from": 324, + "to": 229 + }, + { + "from": 325, + "to": 313 + }, + { + "from": 325, + "to": 323 + }, + { + "from": 325, + "to": 163 + }, + { + "from": 326, + "to": 128 + }, + { + "from": 326, + "to": 129 + }, + { + "from": 326, + "to": 309 + }, + { + "from": 327, + "to": 309 + }, + { + "from": 327, + "to": 223 + }, + { + "from": 327, + "to": 224 + }, + { + "from": 327, + "to": 101 + }, + { + "from": 328, + "to": 309 + }, + { + "from": 328, + "to": 310 + }, + { + "from": 328, + "to": 101 + }, + { + "from": 329, + "to": 306 + }, + { + "from": 329, + "to": 215 + }, + { + "from": 329, + "to": 101 + }, + { + "from": 330, + "to": 372 + }, + { + "from": 330, + "to": 309 + }, + { + "from": 331, + "to": 205 + }, + { + "from": 331, + "to": 211 + }, + { + "from": 332, + "to": 331 + }, + { + "from": 333, + "to": 332 + }, + { + "from": 333, + "to": 138 + }, + { + "from": 334, + "to": 332 + }, + { + "from": 335, + "to": 332 + }, + { + "from": 335, + "to": 58 + }, + { + "from": 336, + "to": 332 + }, + { + "from": 337, + "to": 333 + }, + { + "from": 337, + "to": 223 + }, + { + "from": 337, + "to": 347 + }, + { + "from": 338, + "to": 138 + }, + { + "from": 338, + "to": 333 + }, + { + "from": 339, + "to": 332 + }, + { + "from": 339, + "to": 138 + }, + { + "from": 340, + "to": 332 + }, + { + "from": 340, + "to": 138 + }, + { + "from": 341, + "to": 332 + }, + { + "from": 341, + "to": 138 + }, + { + "from": 342, + "to": 332 + }, + { + "from": 342, + "to": 58 + }, + { + "from": 343, + "to": 332 + }, + { + "from": 343, + "to": 20 + }, + { + "from": 344, + "to": 333 + }, + { + "from": 344, + "to": 148 + }, + { + "from": 345, + "to": 332 + }, + { + "from": 345, + "to": 107 + }, + { + "from": 346, + "to": 205 + }, + { + "from": 346, + "to": 211 + }, + { + "from": 347, + "to": 346 + }, + { + "from": 348, + "to": 347 + }, + { + "from": 348, + "to": 138 + }, + { + "from": 349, + "to": 348 + }, + { + "from": 350, + "to": 348 + }, + { + "from": 350, + "to": 47 + }, + { + "from": 351, + "to": 348 + }, + { + "from": 352, + "to": 347 + }, + { + "from": 352, + "to": 348 + }, + { + "from": 353, + "to": 347 + }, + { + "from": 353, + "to": 102 + }, + { + "from": 354, + "to": 348 + }, + { + "from": 354, + "to": 141 + }, + { + "from": 355, + "to": 350 + }, + { + "from": 355, + "to": 47 + }, + { + "from": 356, + "to": 348 + }, + { + "from": 356, + "to": 190 + }, + { + "from": 357, + "to": 205 + }, + { + "from": 357, + "to": 211 + }, + { + "from": 358, + "to": 357 + }, + { + "from": 358, + "to": 255 + }, + { + "from": 359, + "to": 358 + }, + { + "from": 360, + "to": 358 + }, + { + "from": 360, + "to": 348 + }, + { + "from": 361, + "to": 358 + }, + { + "from": 362, + "to": 358 + }, + { + "from": 362, + "to": 440 + }, + { + "from": 363, + "to": 358 + }, + { + "from": 363, + "to": 20 + }, + { + "from": 364, + "to": 285 + }, + { + "from": 364, + "to": 115 + }, + { + "from": 365, + "to": 137 + }, + { + "from": 365, + "to": 153 + }, + { + "from": 366, + "to": 137 + }, + { + "from": 366, + "to": 154 + }, + { + "from": 367, + "to": 366 + }, + { + "from": 367, + "to": 143 + }, + { + "from": 367, + "to": 144 + }, + { + "from": 368, + "to": 364 + }, + { + "from": 369, + "to": 368 + }, + { + "from": 369, + "to": 163 + }, + { + "from": 369, + "to": 137 + }, + { + "from": 370, + "to": 369 + }, + { + "from": 370, + "to": 366 + }, + { + "from": 370, + "to": 100 + }, + { + "from": 371, + "to": 370 + }, + { + "from": 371, + "to": 163 + }, + { + "from": 372, + "to": 370 + }, + { + "from": 372, + "to": 371 + }, + { + "from": 373, + "to": 369 + }, + { + "from": 373, + "to": 365 + }, + { + "from": 373, + "to": 128 + }, + { + "from": 374, + "to": 373 + }, + { + "from": 374, + "to": 128 + }, + { + "from": 374, + "to": 129 + }, + { + "from": 375, + "to": 372 + }, + { + "from": 375, + "to": 374 + }, + { + "from": 376, + "to": 137 + }, + { + "from": 376, + "to": 145 + }, + { + "from": 377, + "to": 376 + }, + { + "from": 377, + "to": 100 + }, + { + "from": 377, + "to": 107 + }, + { + "from": 378, + "to": 376 + }, + { + "from": 378, + "to": 100 + }, + { + "from": 379, + "to": 376 + }, + { + "from": 379, + "to": 100 + }, + { + "from": 380, + "to": 376 + }, + { + "from": 380, + "to": 137 + }, + { + "from": 380, + "to": 102 + }, + { + "from": 381, + "to": 376 + }, + { + "from": 381, + "to": 380 + }, + { + "from": 382, + "to": 381 + }, + { + "from": 382, + "to": 130 + }, + { + "from": 383, + "to": 364 + }, + { + "from": 383, + "to": 285 + }, + { + "from": 384, + "to": 364 + }, + { + "from": 384, + "to": 368 + }, + { + "from": 385, + "to": 384 + }, + { + "from": 386, + "to": 1 + }, + { + "from": 386, + "to": 285 + }, + { + "from": 387, + "to": 386 + }, + { + "from": 388, + "to": 205 + }, + { + "from": 388, + "to": 211 + }, + { + "from": 388, + "to": 346 + }, + { + "from": 389, + "to": 388 + }, + { + "from": 390, + "to": 389 + }, + { + "from": 390, + "to": 41 + }, + { + "from": 391, + "to": 390 + }, + { + "from": 391, + "to": 223 + }, + { + "from": 392, + "to": 389 + }, + { + "from": 392, + "to": 360 + }, + { + "from": 393, + "to": 392 + }, + { + "from": 394, + "to": 390 + }, + { + "from": 394, + "to": 412 + }, + { + "from": 395, + "to": 392 + }, + { + "from": 395, + "to": 351 + }, + { + "from": 396, + "to": 389 + }, + { + "from": 396, + "to": 400 + }, + { + "from": 396, + "to": 401 + }, + { + "from": 396, + "to": 402 + }, + { + "from": 397, + "to": 396 + }, + { + "from": 397, + "to": 403 + }, + { + "from": 397, + "to": 411 + }, + { + "from": 398, + "to": 397 + }, + { + "from": 398, + "to": 411 + }, + { + "from": 399, + "to": 396 + }, + { + "from": 399, + "to": 348 + }, + { + "from": 400, + "to": 389 + }, + { + "from": 400, + "to": 190 + }, + { + "from": 401, + "to": 389 + }, + { + "from": 401, + "to": 386 + }, + { + "from": 402, + "to": 386 + }, + { + "from": 402, + "to": 190 + }, + { + "from": 403, + "to": 386 + }, + { + "from": 403, + "to": 102 + }, + { + "from": 404, + "to": 346 + }, + { + "from": 404, + "to": 386 + }, + { + "from": 405, + "to": 404 + }, + { + "from": 405, + "to": 350 + }, + { + "from": 405, + "to": 42 + }, + { + "from": 406, + "to": 392 + }, + { + "from": 406, + "to": 393 + }, + { + "from": 406, + "to": 395 + }, + { + "from": 407, + "to": 390 + }, + { + "from": 407, + "to": 391 + }, + { + "from": 408, + "to": 389 + }, + { + "from": 408, + "to": 386 + }, + { + "from": 409, + "to": 408 + }, + { + "from": 410, + "to": 389 + }, + { + "from": 410, + "to": 390 + }, + { + "from": 411, + "to": 386 + }, + { + "from": 411, + "to": 137 + }, + { + "from": 412, + "to": 386 + }, + { + "from": 412, + "to": 411 + }, + { + "from": 413, + "to": 392 + }, + { + "from": 413, + "to": 348 + }, + { + "from": 413, + "to": 386 + }, + { + "from": 414, + "to": 8 + }, + { + "from": 414, + "to": 205 + }, + { + "from": 415, + "to": 8 + }, + { + "from": 415, + "to": 305 + }, + { + "from": 416, + "to": 414 + }, + { + "from": 416, + "to": 309 + }, + { + "from": 417, + "to": 414 + }, + { + "from": 417, + "to": 313 + }, + { + "from": 418, + "to": 115 + }, + { + "from": 418, + "to": 116 + }, + { + "from": 419, + "to": 418 + }, + { + "from": 419, + "to": 307 + }, + { + "from": 420, + "to": 418 + }, + { + "from": 420, + "to": 307 + }, + { + "from": 421, + "to": 115 + }, + { + "from": 421, + "to": 131 + }, + { + "from": 421, + "to": 418 + }, + { + "from": 422, + "to": 101 + }, + { + "from": 422, + "to": 418 + }, + { + "from": 422, + "to": 229 + }, + { + "from": 423, + "to": 418 + }, + { + "from": 423, + "to": 366 + }, + { + "from": 424, + "to": 229 + }, + { + "from": 424, + "to": 418 + }, + { + "from": 425, + "to": 115 + }, + { + "from": 425, + "to": 209 + }, + { + "from": 426, + "to": 425 + }, + { + "from": 426, + "to": 115 + }, + { + "from": 427, + "to": 426 + }, + { + "from": 427, + "to": 425 + }, + { + "from": 428, + "to": 32 + }, + { + "from": 428, + "to": 33 + }, + { + "from": 428, + "to": 34 + }, + { + "from": 429, + "to": 22 + }, + { + "from": 429, + "to": 115 + }, + { + "from": 430, + "to": 8 + }, + { + "from": 430, + "to": 22 + }, + { + "from": 430, + "to": 126 + }, + { + "from": 431, + "to": 199 + }, + { + "from": 431, + "to": 200 + }, + { + "from": 432, + "to": 20 + }, + { + "from": 432, + "to": 19 + }, + { + "from": 433, + "to": 200 + }, + { + "from": 433, + "to": 431 + }, + { + "from": 434, + "to": 425 + }, + { + "from": 434, + "to": 427 + }, + { + "from": 435, + "to": 279 + }, + { + "from": 435, + "to": 271 + }, + { + "from": 436, + "to": 425 + }, + { + "from": 436, + "to": 428 + }, + { + "from": 437, + "to": 1 + }, + { + "from": 438, + "to": 437 + }, + { + "from": 438, + "to": 41 + }, + { + "from": 439, + "to": 437 + }, + { + "from": 439, + "to": 438 + }, + { + "from": 440, + "to": 313 + }, + { + "from": 440, + "to": 437 + }, + { + "from": 441, + "to": 308 + }, + { + "from": 441, + "to": 313 + }, + { + "from": 441, + "to": 437 + }, + { + "from": 442, + "to": 439 + }, + { + "from": 443, + "to": 437 + }, + { + "from": 443, + "to": 439 + }, + { + "from": 444, + "to": 439 + }, + { + "from": 444, + "to": 442 + }, + { + "from": 445, + "to": 115 + }, + { + "from": 445, + "to": 425 + }, + { + "from": 446, + "to": 445 + }, + { + "from": 446, + "to": 92 + }, + { + "from": 447, + "to": 445 + }, + { + "from": 447, + "to": 115 + }, + { + "from": 447, + "to": 285 + }, + { + "from": 448, + "to": 445 + }, + { + "from": 448, + "to": 447 + }, + { + "from": 448, + "to": 100 + }, + { + "from": 449, + "to": 448 + }, + { + "from": 449, + "to": 22 + }, + { + "from": 450, + "to": 280 + }, + { + "from": 450, + "to": 273 + }, + { + "from": 450, + "to": 271 + } + ] +} \ No newline at end of file diff --git a/docs/learning-graph/mascot-test.md b/docs/learning-graph/mascot-test.md new file mode 100644 index 00000000..c7be9756 --- /dev/null +++ b/docs/learning-graph/mascot-test.md @@ -0,0 +1,80 @@ +--- +title: Monty the Python - Mascot Test +description: Test page showing all mascot images and admonition styles for Monty the Python, our pedagogical agent. +--- +# Monty the Python — Mascot Test + +This page shows all mascot images and admonition styles for reference. +Check that all images have a transparent background and no excessive padding. +The dashed blue border around each image makes the padding visible. + + + +## Admonition Tests + +!!! mascot-neutral "A Note from Monty" + ![Monty neutral pose](../../img/mascot/neutral.png){ class="mascot-admonition-img" } + Here is a friendly note from Monty. This is the **neutral** style, used for general sidebars or introductions. + +!!! mascot-welcome "Monty Welcomes You!" + ![Monty waving welcome](../../img/mascot/welcome.png){ class="mascot-admonition-img" } + Welcome, coder! I'm Monty the Python, and I'm here to help you learn to program. This is the **welcome** style, used at the start of each lesson. + +!!! mascot-thinking "Monty's Key Insight" + ![Monty thinking](../../img/mascot/thinking.png){ class="mascot-admonition-img" } + Let's think this through together! This is the **thinking** style, used to highlight key concepts and important ideas. + +!!! mascot-tip "Monty's Tip" + ![Monty sharing a tip](../../img/mascot/tip.png){ class="mascot-admonition-img" } + Here is a helpful suggestion from Monty. This is the **tip** style, used for hints and shortcuts. + +!!! mascot-warning "Watch Out!" + ![Monty warning you](../../img/mascot/warning.png){ class="mascot-admonition-img" } + Watch out for this one — it's a common mistake! This is the **warning** style, used to flag pitfalls. + +!!! mascot-encourage "You've Got This!" + ![Monty encouraging you](../../img/mascot/encouraging.png){ class="mascot-admonition-img" } + You can do it! I believe in you! This is the **encouraging** style, used when the content gets challenging. + +!!! mascot-celebration "Excellent Work!" + ![Monty celebrating](../../img/mascot/celebration.png){ class="mascot-admonition-img" } + Congratulations — you made it! This is the **celebration** style, used at the end of lessons. + +## Image Padding Tests + +Verify there is no excessive padding around the images. +If there is, run `scripts/trim-padding-from-image.py docs/img/mascot/FILENAME.png`. + +
+ +- **Welcome** + + ![](../../img/mascot/welcome.png){ width="150px" } + +- **Thinking** + + ![](../../img/mascot/thinking.png){ width="150px" } + +- **Tip** + + ![](../../img/mascot/tip.png){ width="150px" } + +- **Warning** + + ![](../../img/mascot/warning.png){ width="150px" } + +- **Encouraging** + + ![](../../img/mascot/encouraging.png){ width="150px" } + +- **Celebration** + + ![](../../img/mascot/celebration.png){ width="150px" } + +- **Neutral** + + ![](../../img/mascot/neutral.png){ width="150px" } + +
diff --git a/docs/learning-graph/metadata.json b/docs/learning-graph/metadata.json new file mode 100644 index 00000000..f4ffbf07 --- /dev/null +++ b/docs/learning-graph/metadata.json @@ -0,0 +1,10 @@ +{ + "title": "Beginning Python — From Blocks to Code with Monty", + "description": "A fun, project-driven course that guides young programmers (ages 10-13) from block-based coding to writing real Python, covering core syntax, data types, control flow, functions, collections, turtle graphics, algorithms, and an introduction to machine learning.", + "creator": "Dan McCreary", + "date": "2026-06-28", + "version": "1.0", + "format": "Learning Graph JSON v1.0", + "schema": "https://raw.githubusercontent.com/dmccreary/learning-graphs/refs/heads/main/src/schema/learning-graph-schema.json", + "license": "CC BY-NC-SA 4.0 DEED" +} diff --git a/docs/learning-graph/quality-metrics.md b/docs/learning-graph/quality-metrics.md new file mode 100644 index 00000000..1d46ff31 --- /dev/null +++ b/docs/learning-graph/quality-metrics.md @@ -0,0 +1,125 @@ +# Learning Graph Quality Metrics Report + +## Overview + +- **Total Concepts**: 450 +- **Foundational Concepts** (no prerequisites, other concepts depend on them): 2 +- **Terminal Nodes** (nothing depends on them, but have prerequisites): 235 +- **Orphaned Nodes** (completely disconnected, no edges): 0 +- **Concepts with Dependencies**: 448 +- **Average Dependencies per Concept**: 1.87 + +## Graph Structure Validation + +- **Valid DAG Structure**: ✅ Yes +- **Self-Dependencies**: None detected ✅ +- **Cycles Detected**: 0 + +## Foundational Concepts + +These concepts have no prerequisites: + +- **1**: Python Interpreter Overview +- **19**: Command Line Basics + +## Dependency Chain Analysis + +- **Maximum Dependency Chain Length**: 13 + +### Longest Learning Path: + +1. **Python Interpreter Overview** (ID: 1) +2. **print() Function** (ID: 21) +3. **Indentation as Syntax** (ID: 24) +4. **Code Block Structure** (ID: 28) +5. **Defining a Function with def** (ID: 115) +6. **Objects and Classes Overview** (ID: 285) +7. **class Keyword** (ID: 288) +8. **__init__() Constructor** (ID: 289) +9. **Creating Class Instances** (ID: 291) +10. **Inheritance Basics** (ID: 295) +11. **Exception Hierarchy** (ID: 282) +12. **Custom Exception Classes** (ID: 283) +13. **Exception Chaining** (ID: 284) + +## Terminal Nodes Analysis + +Terminal nodes are concepts that nothing else depends on but have prerequisites. They represent natural endpoints of learning paths — culminating or specialized concepts. + +- **Total Terminal Nodes**: 235 (52.2% of all concepts) +- **Healthy Range**: 5-40% of total concepts + +Concepts at the end of learning paths: + +- **2**: Python 2 vs Python 3 +- **4**: Repl.it Online IDE +- **5**: Thonny Beginner IDE +- **6**: Spyder Scientific IDE +- **7**: VS Code Editor +- **9**: JupyterLab Environment +- **12**: Virtual Environments +- **14**: Running Scripts from Terminal +- **15**: Python REPL Shell +- **16**: Raspberry Pi Python Platform +- **17**: Skulpt Browser Python +- **18**: Google Colab Environment +- **25**: Case Sensitivity +- **27**: Blank Lines and Readability +- **30**: Whitespace Rules +- **36**: Augmented Assignment Operators +- **37**: Constants by Convention +- **39**: Swap Two Variables +- **40**: Naming Conflicts to Avoid +- **43**: Division Returns Float + +*...and 215 more* + +## Orphaned Nodes Analysis + +Orphaned nodes are completely disconnected concepts with no inbound AND no outbound edges. These indicate a quality problem — every concept should connect to the graph. + +- **Total Orphaned Nodes**: 0 + +✅ No orphaned nodes detected. All concepts are connected to the graph. + +## Connected Components + +- **Number of Connected Components**: 1 + +✅ All concepts are connected in a single graph. + +## Indegree Analysis + +Top 10 concepts that are prerequisites for the most other concepts: + +| Rank | Concept ID | Concept Label | Indegree | +|------|-----------|---------------|----------| +| 1 | 137 | List Type | 34 | +| 2 | 58 | String Type | 33 | +| 3 | 115 | Defining a Function with def | 29 | +| 4 | 205 | import Statement | 25 | +| 5 | 31 | Variable Definition and Assignment | 24 | +| 6 | 41 | Integer Type | 23 | +| 7 | 100 | for Loop over Sequence | 21 | +| 8 | 1 | Python Interpreter Overview | 20 | +| 9 | 285 | Objects and Classes Overview | 18 | +| 10 | 163 | Dictionary Type | 16 | + +## Outdegree Distribution + +| Dependencies | Number of Concepts | +|--------------|--------------------| +| 0 | 2 | +| 1 | 132 | +| 2 | 247 | +| 3 | 64 | +| 4 | 5 | + +## Recommendations + +- ℹ️ **High terminal node percentage** (52.2%): Consider if some terminal concepts should be prerequisites for advanced concepts +- ✅ **DAG structure verified**: Graph supports valid learning progressions + +--- + +*Report generated by learning-graph-reports/analyze_graph.py* diff --git a/docs/learning-graph/taxonomy-distribution.md b/docs/learning-graph/taxonomy-distribution.md new file mode 100644 index 00000000..fb7c1596 --- /dev/null +++ b/docs/learning-graph/taxonomy-distribution.md @@ -0,0 +1,387 @@ +# Taxonomy Distribution Report + +## Overview + +- **Total Concepts**: 450 +- **Number of Taxonomies**: 14 +- **Average Concepts per Taxonomy**: 32.1 + +## Distribution Summary + +| Category | TaxonomyID | Count | Percentage | Status | +|----------|-----------|-------|------------|--------| +| COL | COL | 68 | 15.1% | ✅ | +| VIZ | VIZ | 63 | 14.0% | ✅ | +| Advanced Topics | ADV | 61 | 13.6% | ✅ | +| DAT | DAT | 55 | 12.2% | ✅ | +| MOD | MOD | 36 | 8.0% | ✅ | +| CTL | CTL | 29 | 6.4% | ✅ | +| FUN | FUN | 22 | 4.9% | ✅ | +| ALG | ALG | 22 | 4.9% | ✅ | +| ENV | ENV | 20 | 4.4% | ✅ | +| OOP | OOP | 20 | 4.4% | ✅ | +| FIO | FIO | 16 | 3.6% | ✅ | +| TXT | TXT | 14 | 3.1% | ✅ | +| ERR | ERR | 14 | 3.1% | ✅ | +| SYN | SYN | 10 | 2.2% | ℹ️ Under | + +## Visual Distribution + +``` +COL ███████ 68 ( 15.1%) +VIZ ███████ 63 ( 14.0%) +Advanced Topics ██████ 61 ( 13.6%) +DAT ██████ 55 ( 12.2%) +MOD ████ 36 ( 8.0%) +CTL ███ 29 ( 6.4%) +FUN ██ 22 ( 4.9%) +ALG ██ 22 ( 4.9%) +ENV ██ 20 ( 4.4%) +OOP ██ 20 ( 4.4%) +FIO █ 16 ( 3.6%) +TXT █ 14 ( 3.1%) +ERR █ 14 ( 3.1%) +SYN █ 10 ( 2.2%) +``` + +## Balance Analysis + +### ✅ No Over-Represented Categories + +All categories are under the 30% threshold. Good balance! + +### ℹ️ Under-Represented Categories (<3%) + +- **SYN** (SYN): 10 concepts (2.2%) + - *Note*: Small categories are acceptable for specialized topics + +## Category Details + +### COL (COL) + +**Count**: 68 concepts (15.1%) + +**Concepts**: + +- 137. List Type +- 138. Creating a List +- 139. List Indexing +- 140. Negative Indexing +- 141. List Slicing +- 142. len() for Lists +- 143. List append() insert() extend() +- 144. List remove() pop() clear() +- 145. List sort() reverse() copy() +- 146. List index() count() +- 147. Membership with in Operator +- 148. List Concatenation and Repetition +- 149. Iterating over a List +- 150. Nested Lists +- 151. List Comprehensions +- *...and 53 more* + +### VIZ (VIZ) + +**Count**: 63 concepts (14.0%) + +**Concepts**: + +- 305. import turtle +- 306. turtle.Turtle() Object +- 307. turtle.Screen() Object +- 308. Screen Setup and bgcolor() +- 309. Movement forward() backward() +- 310. Turning left() right() +- 311. Absolute Positioning goto() +- 312. Pen Control penup() pendown() +- 313. Pen Size and Color +- 314. Fill begin_fill() end_fill() +- 315. Drawing circle() and Polygons +- 316. Turtle Appearance shape() +- 317. Hiding and Showing Turtle +- 318. Writing Text with turtle.write() +- 319. Clearing and Resetting +- *...and 48 more* + +### Advanced Topics (ADV) + +**Count**: 61 concepts (13.6%) + +**Concepts**: + +- 386. Machine Learning Overview +- 387. Supervised vs Unsupervised Learning +- 388. keras Library Overview +- 389. Sequential Model +- 390. Dense Fully Connected Layers +- 391. Activation Functions relu softmax +- 392. Conv2D Convolutional Layers +- 393. MaxPooling2D Pooling Layers +- 394. Dropout Regularization +- 395. Flatten Layer +- 396. model.compile() +- 397. model.fit() Training +- 398. model.evaluate() Testing +- 399. model.predict() Inference +- 400. Categorical Crossentropy Loss +- *...and 46 more* + +### DAT (DAT) + +**Count**: 55 concepts (12.2%) + +**Concepts**: + +- 31. Variable Definition and Assignment +- 32. Variable Naming Rules +- 33. Snake_case Convention +- 34. Meaningful Variable Names +- 35. Multiple Assignment +- 36. Augmented Assignment Operators +- 37. Constants by Convention +- 38. Variable Reassignment +- 39. Swap Two Variables +- 40. Naming Conflicts to Avoid +- 41. Integer Type +- 42. Float Type +- 43. Division Returns Float +- 44. Integer Division Operator +- 45. Modulo Operator +- *...and 40 more* + +### MOD (MOD) + +**Count**: 36 concepts (8.0%) + +**Concepts**: + +- 205. import Statement +- 206. from...import Specific Names +- 207. import...as Alias +- 208. from...import Star +- 209. Creating Custom Modules +- 210. __name__ == "__main__" Guard +- 211. Standard Library Overview +- 212. Module Search Path +- 213. Reloading a Module +- 214. random Module Overview +- 215. random.randint() +- 216. random.choice() +- 217. random.shuffle() +- 218. random.seed() +- 219. random.random() Float +- *...and 21 more* + +### CTL (CTL) + +**Count**: 29 concepts (6.4%) + +**Concepts**: + +- 86. input() Function +- 87. Prompting the User +- 88. Converting Input to Numbers +- 89. Input Validation Basics +- 90. Reading Multiple Inputs +- 91. Strip Whitespace from Input +- 92. if Statement +- 93. if...else Block +- 94. elif Chains +- 95. Nested if Statements +- 96. Conditional Ternary Expression +- 97. match/case Statement +- 98. Truthiness in Conditions +- 99. Compound Conditions +- 100. for Loop over Sequence +- *...and 14 more* + +### FUN (FUN) + +**Count**: 22 concepts (4.9%) + +**Concepts**: + +- 115. Defining a Function with def +- 116. Calling a Function +- 117. Positional Parameters +- 118. Default Parameter Values +- 119. Keyword Arguments +- 120. return Statement +- 121. Functions Returning None +- 122. Local Scope +- 123. Global Scope +- 124. global Keyword +- 125. nonlocal Keyword +- 126. Docstrings +- 127. Pure Functions vs Side Effects +- 128. Recursion Concept +- 129. Recursion Base Case +- *...and 7 more* + +### ALG (ALG) + +**Count**: 22 concepts (4.9%) + +**Concepts**: + +- 364. Abstract Data Types Overview +- 365. Stack LIFO Structure +- 366. Queue FIFO Structure +- 367. Queue enqueue() dequeue() +- 368. Graph Nodes and Edges +- 369. Adjacency List Representation +- 370. Breadth-First Search BFS +- 371. BFS Color Tracking +- 372. BFS for Path Finding +- 373. Depth-First Search DFS +- 374. DFS with Recursion +- 375. DFS and BFS for Maze Solving +- 376. Sorting Algorithms Overview +- 377. Bubble Sort +- 378. Selection Sort +- *...and 7 more* + +### ENV (ENV) + +**Count**: 20 concepts (4.4%) + +**Concepts**: + +- 1. Python Interpreter Overview +- 2. Python 2 vs Python 3 +- 3. Trinket.io Web Environment +- 4. Repl.it Online IDE +- 5. Thonny Beginner IDE +- 6. Spyder Scientific IDE +- 7. VS Code Editor +- 8. Jupyter Notebooks +- 9. JupyterLab Environment +- 10. Conda Package Manager +- 11. pip Package Installer +- 12. Virtual Environments +- 13. Installing Python Locally +- 14. Running Scripts from Terminal +- 15. Python REPL Shell +- *...and 5 more* + +### OOP (OOP) + +**Count**: 20 concepts (4.4%) + +**Concepts**: + +- 285. Objects and Classes Overview +- 286. Attributes of an Object +- 287. Methods of an Object +- 288. class Keyword +- 289. __init__() Constructor +- 290. self Parameter +- 291. Creating Class Instances +- 292. Accessing Attributes and Methods +- 293. String Methods as OOP Examples +- 294. List Methods as OOP Examples +- 295. Inheritance Basics +- 296. __str__() String Representation +- 297. __repr__() Developer Representation +- 298. Subclasses and Method Overriding +- 299. super() Function +- *...and 5 more* + +### FIO (FIO) + +**Count**: 16 concepts (3.6%) + +**Concepts**: + +- 255. open() Function +- 256. File Modes r w a b +- 257. file.read() +- 258. file.readlines() +- 259. file.readline() +- 260. file.write() +- 261. file.close() +- 262. with Statement Context Manager +- 263. Iterating over File Lines +- 264. Text Processing strip() lower() +- 265. CSV File Reading +- 266. CSV File Writing +- 267. Reading JSON from File +- 268. Writing JSON to File +- 269. File Path Handling +- *...and 1 more* + +### TXT (TXT) + +**Count**: 14 concepts (3.1%) + +**Concepts**: + +- 241. re Module Import +- 242. re.search() First Match +- 243. re.findall() All Matches +- 244. re.split() Split by Pattern +- 245. re.sub() Substitute Matches +- 246. Digit Word Whitespace Patterns +- 247. Anchors Start and End +- 248. Character Classes +- 249. Quantifiers Plus Star Question +- 250. Alternation with Pipe +- 251. Escaping Special Characters +- 252. Raw Strings for Regex +- 253. Regex Groups with Parentheses +- 254. Compiled Regex Patterns + +### ERR (ERR) + +**Count**: 14 concepts (3.1%) + +**Concepts**: + +- 271. Syntax vs Runtime vs Logic Errors +- 272. Common Exception Types +- 273. Reading a Traceback +- 274. try...except Block +- 275. Catching Specific Exceptions +- 276. else Clause in try/except +- 277. finally Clause +- 278. raise Statement +- 279. assert Statement +- 280. Debugging with print() +- 281. Using Search Engines to Debug +- 282. Exception Hierarchy +- 283. Custom Exception Classes +- 284. Exception Chaining + +### SYN (SYN) + +**Count**: 10 concepts (2.2%) + +**Concepts**: + +- 21. print() Function +- 22. Single-Line Comments +- 23. Multi-Line Strings +- 24. Indentation as Syntax +- 25. Case Sensitivity +- 26. Python Keywords +- 27. Blank Lines and Readability +- 28. Code Block Structure +- 29. Statement vs Expression +- 30. Whitespace Rules + +## Recommendations + +- ✅ **Excellent balance**: Categories are evenly distributed (spread: 12.9%) +- ✅ **MISC category minimal**: Good categorization specificity + +### Educational Use Recommendations + +- Use taxonomy categories for color-coding in graph visualizations +- Design curriculum modules based on taxonomy groupings +- Create filtered views for focused learning paths +- Use categories for assessment organization +- Enable navigation by topic area in interactive tools + +--- + +*Report generated by learning-graph-reports/taxonomy_distribution.py* diff --git a/docs/learning-graph/taxonomy-distribution.py b/docs/learning-graph/taxonomy-distribution.py new file mode 100644 index 00000000..7a33ee17 --- /dev/null +++ b/docs/learning-graph/taxonomy-distribution.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python3 +""" +Generate Taxonomy Distribution Report + +Analyzes the taxonomy distribution in the concept dependency CSV +and generates a detailed distribution report with recommendations. +""" + +import csv +from collections import defaultdict +from typing import Dict, List, Tuple + + +def analyze_taxonomy_distribution(csv_path: str, output_path: str, taxonomy_names: dict = None): + """ + Analyze taxonomy distribution and generate report. + + Args: + csv_path: Path to input CSV file + output_path: Path to output markdown report + taxonomy_names: Optional dictionary mapping taxonomy IDs to full names + """ + # Default taxonomy names + default_names = { + 'FOUND': 'Foundation Concepts - Prerequisites', + 'DEF': 'Definitional Concepts', + 'CORE': 'Core Concepts', + 'INTER': 'Intermediate Topics', + 'ADV': 'Advanced Topics', + 'APPLIED': 'Applied Concepts', + 'SPEC': 'Specialized Topics', + 'PROJ': 'Capstone Projects Ideas', + 'MISC': 'Miscellaneous', + } + + names = taxonomy_names if taxonomy_names is not None else default_names + + # Read CSV and count by taxonomy + taxonomy_counts = defaultdict(int) + taxonomy_concepts = defaultdict(list) + + with open(csv_path, 'r', encoding='utf-8') as f: + reader = csv.DictReader(f) + for row in reader: + tax = row['TaxonomyID'] + taxonomy_counts[tax] += 1 + taxonomy_concepts[tax].append((int(row['ConceptID']), row['ConceptLabel'])) + + total_concepts = sum(taxonomy_counts.values()) + + # Calculate percentages + taxonomy_data = [] + for tax, count in taxonomy_counts.items(): + percentage = (count / total_concepts) * 100 + name = names.get(tax, tax) + taxonomy_data.append((tax, name, count, percentage)) + + # Sort by count descending + taxonomy_data.sort(key=lambda x: x[2], reverse=True) + + # Identify issues + over_represented = [(tax, name, count, pct) for tax, name, count, pct in taxonomy_data if pct > 30] + under_represented = [(tax, name, count, pct) for tax, name, count, pct in taxonomy_data if pct < 3] + + # Generate markdown report + with open(output_path, 'w', encoding='utf-8') as f: + f.write("# Taxonomy Distribution Report\n\n") + + f.write("## Overview\n\n") + f.write(f"- **Total Concepts**: {total_concepts}\n") + f.write(f"- **Number of Taxonomies**: {len(taxonomy_counts)}\n") + f.write(f"- **Average Concepts per Taxonomy**: {total_concepts / len(taxonomy_counts):.1f}\n\n") + + f.write("## Distribution Summary\n\n") + f.write("| Category | TaxonomyID | Count | Percentage | Status |\n") + f.write("|----------|-----------|-------|------------|--------|\n") + + for tax, name, count, pct in taxonomy_data: + status = "✅" + if pct > 30: + status = "⚠️ Over" + elif pct < 3: + status = "ℹ️ Under" + f.write(f"| {name} | {tax} | {count} | {pct:.1f}% | {status} |\n") + + f.write("\n") + + # Visual distribution - use human-readable names, not taxonomy IDs + f.write("## Visual Distribution\n\n") + f.write("```\n") + # Find max name length for alignment (cap at 25 chars for readability) + max_name_len = min(25, max(len(name) for _, name, _, _ in taxonomy_data)) + for tax, name, count, pct in taxonomy_data: + bar_length = int(pct / 2) # Scale to fit + bar = "█" * bar_length + # Use human-readable name, truncated if needed + display_name = name[:max_name_len].ljust(max_name_len) + f.write(f"{display_name} {bar} {count:3d} ({pct:5.1f}%)\n") + f.write("```\n\n") + + # Balance analysis + f.write("## Balance Analysis\n\n") + + if over_represented: + f.write("### ⚠️ Over-Represented Categories (>30%)\n\n") + for tax, name, count, pct in over_represented: + f.write(f"- **{name}** ({tax}): {count} concepts ({pct:.1f}%)\n") + f.write(f" - *Recommendation*: Consider splitting into subcategories or moving some concepts to related categories\n") + f.write("\n") + else: + f.write("### ✅ No Over-Represented Categories\n\n") + f.write("All categories are under the 30% threshold. Good balance!\n\n") + + if under_represented: + f.write("### ℹ️ Under-Represented Categories (<3%)\n\n") + for tax, name, count, pct in under_represented: + f.write(f"- **{name}** ({tax}): {count} concepts ({pct:.1f}%)\n") + f.write(f" - *Note*: Small categories are acceptable for specialized topics\n") + f.write("\n") + + # Detailed category breakdowns + f.write("## Category Details\n\n") + + for tax, name, count, pct in taxonomy_data: + f.write(f"### {name} ({tax})\n\n") + f.write(f"**Count**: {count} concepts ({pct:.1f}%)\n\n") + + concepts = taxonomy_concepts[tax] + concepts.sort(key=lambda x: x[0]) # Sort by ID + + f.write("**Concepts**:\n\n") + for concept_id, concept_label in concepts[:15]: # Show first 15 + f.write(f"- {concept_id}. {concept_label}\n") + + if len(concepts) > 15: + f.write(f"- *...and {len(concepts) - 15} more*\n") + + f.write("\n") + + # Recommendations + f.write("## Recommendations\n\n") + + # Check balance + max_pct = max(pct for _, _, _, pct in taxonomy_data) + min_pct = min(pct for _, _, _, pct in taxonomy_data if pct > 0) + spread = max_pct - min_pct + + if spread < 15: + f.write("- ✅ **Excellent balance**: Categories are evenly distributed (spread: {:.1f}%)\n".format(spread)) + elif spread < 25: + f.write("- ✅ **Good balance**: Categories are reasonably distributed (spread: {:.1f}%)\n".format(spread)) + else: + f.write("- ⚠️ **Consider rebalancing**: Large spread between categories ({:.1f}%)\n".format(spread)) + + # Check for MISC + misc_count = taxonomy_counts.get('MISC', 0) + misc_pct = (misc_count / total_concepts) * 100 if total_concepts > 0 else 0 + + if misc_pct < 2: + f.write("- ✅ **MISC category minimal**: Good categorization specificity\n") + else: + f.write(f"- ⚠️ **MISC category has {misc_count} concepts**: Review for better categorization\n") + + # Educational recommendations + f.write("\n### Educational Use Recommendations\n\n") + f.write("- Use taxonomy categories for color-coding in graph visualizations\n") + f.write("- Design curriculum modules based on taxonomy groupings\n") + f.write("- Create filtered views for focused learning paths\n") + f.write("- Use categories for assessment organization\n") + f.write("- Enable navigation by topic area in interactive tools\n") + + f.write("\n---\n\n") + f.write("*Report generated by learning-graph-reports/taxonomy_distribution.py*\n") + + print(f"✅ Taxonomy distribution report generated: {output_path}") + return taxonomy_data + + +if __name__ == "__main__": + import sys + import json + + # Parse command line arguments + if len(sys.argv) < 3: + print("Usage: python taxonomy-distribution.py [taxonomy_names.json]") + print("\nExample:") + print(" python taxonomy-distribution.py data/concept-dependencies.csv reports/taxonomy-distribution.md") + print("\nOptional taxonomy_names.json format:") + print(json.dumps({ + 'FOUNDATION': 'Foundation Concepts', + 'CORE': 'Core Concepts', + 'ADVANCED': 'Advanced Topics' + }, indent=2)) + sys.exit(1) + + csv_path = sys.argv[1] + output_path = sys.argv[2] + + # Load taxonomy names if provided + taxonomy_names = None + if len(sys.argv) > 3: + config_file = sys.argv[3] + with open(config_file, 'r', encoding='utf-8') as f: + taxonomy_names = json.load(f) + print(f"📋 Loaded taxonomy names from: {config_file}") + + analyze_taxonomy_distribution(csv_path, output_path, taxonomy_names) diff --git a/docs/learning-graph/taxonomy-names.json b/docs/learning-graph/taxonomy-names.json new file mode 100644 index 00000000..535558e9 --- /dev/null +++ b/docs/learning-graph/taxonomy-names.json @@ -0,0 +1,16 @@ +{ + "ENV": "Environment & Tools", + "SYN": "Core Syntax & Output", + "DAT": "Variables & Data Types", + "CTL": "Input & Control Flow", + "FUN": "Functions & Scope", + "COL": "Collections", + "MOD": "Modules & Standard Library", + "TXT": "Text Processing & Regex", + "FIO": "File I/O & Data", + "ERR": "Error Handling & Debugging", + "OOP": "Object-Oriented Programming", + "VIZ": "Turtle Graphics & Visualization", + "ALG": "Algorithms & Data Structures", + "ADV": "Advanced & Applied Python" +} diff --git a/docs/pi/01-intro.md b/docs/pi/01-intro.md index 0d27c557..55cda57e 100644 --- a/docs/pi/01-intro.md +++ b/docs/pi/01-intro.md @@ -2,7 +2,7 @@ - [Raspberry Pi Foundation Projects](https://projects.raspberrypi.org/en) -- [CoderDojo Pages on the Pi Site](https://projects.raspberrypi.org/en/coderdojo) +- [Raspberry Pi CoderDojo Projects](https://projects.raspberrypi.org/en/coderdojo) - [Thonny](https://thonny.org/)Thonny is a Integrated Development Environment for debugging Python code. Unfortunatly, no turtle graphics are supported. diff --git a/docs/prompts/01-list-old-concepts.md b/docs/prompts/01-list-old-concepts.md new file mode 100644 index 00000000..61d867f4 --- /dev/null +++ b/docs/prompts/01-list-old-concepts.md @@ -0,0 +1,4 @@ +# Listing Old Concepts + +!!! prompt + This is an old programming book on "Beginning Python" that I want to update to the new /ibook standards. Please begin by generating a list of all the concepts in the current content in the @docs directory. Put that entire detailed concept list in the file @docs/learning-graph/concept-list-v1.md - Add any concepts you think are missing from this course. \ No newline at end of file diff --git a/docs/prompts/02-course-description.md b/docs/prompts/02-course-description.md new file mode 100644 index 00000000..f075ccd5 --- /dev/null +++ b/docs/prompts/02-course-description.md @@ -0,0 +1,4 @@ +# Course Description Generation + +!!! prompt + Very nice! Now please use the /course-description-analyzer guide to create a new course description and put it in @docs/course-description.md - the target audience is students around 10 years old that have just finished a class using block programming (scratch). It is designed to be a fun course that uses our pedagogical mascot "monty" and leverages the built-in inline Skulpt programming tools. It also has intermediate and advanced python concepts. Make sure that the course description can cover all the current 350 concepts listed in @docs/learning-graph/concept-list-v1.md - the course will include a glossary, faq, quizzes, and a detailed teacher's guide. \ No newline at end of file diff --git a/docs/prompts/03-learning-graph.md b/docs/prompts/03-learning-graph.md new file mode 100644 index 00000000..fdd94b25 --- /dev/null +++ b/docs/prompts/03-learning-graph.md @@ -0,0 +1,4 @@ +# Learning Graph + +!!! prompt + Run the /learning-graph-generator using up to 450 concepts. Make sure that the current concepts listed in @docs/learning-graph/concept-list-v1.md are all included, but also make sure that you include concepts that these concepts depend on. \ No newline at end of file diff --git a/docs/prompts/04-book-chapter-generator.md b/docs/prompts/04-book-chapter-generator.md new file mode 100644 index 00000000..d6ee0a20 --- /dev/null +++ b/docs/prompts/04-book-chapter-generator.md @@ -0,0 +1,3 @@ +# Book Chapter Generator Skill + +Run the /book-chapter-generator skill. Note that the target audience is a 10-year old student that has just learned Scratch. Start slowly with turtle graphics build around Skulpt labs. Do not put too many concepts in any chapter, especially at the beginning. Use as many chapters as is needed. \ No newline at end of file diff --git a/docs/prompts/05-content-generation-strategy.md b/docs/prompts/05-content-generation-strategy.md new file mode 100644 index 00000000..353ef577 --- /dev/null +++ b/docs/prompts/05-content-generation-strategy.md @@ -0,0 +1,5 @@ +Emphasize in both the CLAUDE.md file and the @CONTENT-GENERATION-GUIDELINES.md that the primary teaching tool in the early part of this textbook is to place interactive turtle graphics inline using the Skulpt libraries. This is the core feature of this textbook - allow students to see a simple Python program and then encourage them to modify and run the program. For important concepts, take the opportunity to check their learning, create a new program that needs an additional line added or a small bug fixed. + +Add another section to the "Core Teaching Philosophy" that encourages a student to "guess" what a program will do BEFORE they run that program. + +Now take the perspective of a senior instructional designer. What changes would you make to the @CONTENT-GENERATION-GUIDELINES.md for a beginning coding course? \ No newline at end of file diff --git a/docs/prompts/index.md b/docs/prompts/index.md new file mode 100644 index 00000000..7eeffb2d --- /dev/null +++ b/docs/prompts/index.md @@ -0,0 +1,3 @@ +# Sample AI Prompts + +Default model: Sonnet with High effort \ No newline at end of file diff --git a/docs/sims/graph-viewer/index.md b/docs/sims/graph-viewer/index.md new file mode 100644 index 00000000..6a808f59 --- /dev/null +++ b/docs/sims/graph-viewer/index.md @@ -0,0 +1,35 @@ +# Learning Graph Viewer + +This interactive viewer allows you to explore the learning graph for this course. + +## Features + +- **Search**: Type in the search box to find specific concepts +- **Category Filtering**: Use checkboxes to show/hide concept categories +- **Interactive Navigation**: Click and drag to explore, scroll to zoom +- **Statistics**: View real-time counts of visible nodes and edges + +## Using the Viewer + +1. **Search for Concepts**: Start typing in the search box to find concepts. Click on a result to focus on that node. + +2. **Filter by Category**: Use the category checkboxes in the sidebar to show or hide groups of related concepts. Use "Check All" or "Uncheck All" for bulk operations. + +3. **Navigate the Graph**: + - Drag to pan around the graph + - Scroll to zoom in and out + - Click on a node to select it and highlight its connections + +4. **View Statistics**: The sidebar shows counts of visible nodes, edges, and foundational concepts. + +## Graph Structure + +- **Foundational Concepts** (left side): Prerequisites with no dependencies +- **Advanced Concepts** (right side): Topics that build on multiple prerequisites +- **Edges**: Arrows point from a concept to its prerequisites + +## Launch the Viewer + +[Open Learning Graph Viewer](./main.html){ .md-button .md-button--primary } + + diff --git a/docs/sims/graph-viewer/local.css b/docs/sims/graph-viewer/local.css new file mode 100644 index 00000000..a952a992 --- /dev/null +++ b/docs/sims/graph-viewer/local.css @@ -0,0 +1,287 @@ +/* Learning Graph Viewer Styles */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; + background-color: #f5f5f5; + overflow: hidden; +} + +.container { + display: flex; + height: 100vh; + width: 100vw; +} + +/* Sidebar Styles */ +.sidebar { + width: 300px; + min-width: 300px; + background-color: #fff; + border-right: 1px solid #ddd; + display: flex; + flex-direction: column; + transition: width 0.3s ease, min-width 0.3s ease; + overflow: hidden; +} + +.sidebar.collapsed { + width: 50px; + min-width: 50px; +} + +.sidebar-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px; + background-color: #2196F3; + color: white; +} + +.sidebar-header h4 { + font-size: 14px; + font-weight: 600; + margin: 0; + line-height: 1.3; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + word-wrap: break-word; +} + +.sidebar.collapsed .sidebar-header h4 { + display: none; +} + +.toggle-btn { + background: none; + border: none; + color: white; + font-size: 20px; + cursor: pointer; + padding: 5px; + border-radius: 4px; +} + +.toggle-btn:hover { + background-color: rgba(255,255,255,0.2); +} + +.sidebar-content { + flex: 1; + overflow-y: auto; + padding: 15px; +} + +/* Search Styles */ +.search-container { + margin-bottom: 20px; +} + +.search-container label { + display: block; + font-weight: 600; + margin-bottom: 8px; + color: #333; +} + +.search-container input { + width: 100%; + padding: 10px 12px; + border: 1px solid #ddd; + border-radius: 6px; + font-size: 14px; + transition: border-color 0.2s; +} + +.search-container input:focus { + outline: none; + border-color: #2196F3; + box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1); +} + +.search-results { + display: none; + position: absolute; + width: calc(100% - 30px); + background: white; + border: 1px solid #ddd; + border-radius: 6px; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); + max-height: 300px; + overflow-y: auto; + z-index: 100; + margin-top: 4px; +} + +.search-result-item { + padding: 10px 12px; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #eee; +} + +.search-result-item:last-child { + border-bottom: none; +} + +.search-result-item:hover { + background-color: #f5f5f5; +} + +.result-label { + font-weight: 500; + color: #333; +} + +.result-category { + font-size: 11px; + padding: 3px 8px; + border-radius: 12px; + color: #333; +} + +/* Legend Styles */ +.legend-container { + margin-bottom: 20px; +} + +.legend-container h5 { + font-weight: 600; + margin-bottom: 10px; + color: #333; +} + +.legend-controls { + display: flex; + gap: 8px; + margin-bottom: 12px; +} + +.legend-btn { + flex: 1; + padding: 6px 10px; + font-size: 12px; + border: 1px solid #ddd; + background: #fff; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s; +} + +.legend-btn:hover { + background: #f0f0f0; + border-color: #bbb; +} + +#legend { +} + +.legend-item { + display: flex; + align-items: center; + padding: 6px 0; + gap: 8px; +} + +.legend-item input[type="checkbox"] { + width: 16px; + height: 16px; + cursor: pointer; +} + +.color-box { + width: 20px; + height: 20px; + border-radius: 4px; + border: 1px solid rgba(0,0,0,0.1); + flex-shrink: 0; +} + +.legend-item label { + font-size: 13px; + color: #555; + cursor: pointer; + flex: 1; +} + +/* Stats Styles */ +.stats-container { + background-color: #f9f9f9; + padding: 12px; + border-radius: 6px; +} + +.stats-container h5 { + font-weight: 600; + margin-bottom: 10px; + color: #333; +} + +#stats p { + font-size: 13px; + color: #666; + margin-bottom: 6px; +} + +#stats span { + font-weight: 600; + color: #2196F3; +} + +/* Graph Container */ +.graph-container { + flex: 1; + position: relative; + background-color: aliceblue; +} + +#network { + width: 100%; + height: 100%; +} + +#loading-message { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 1.3rem; + color: #555; + pointer-events: none; + z-index: 20; +} + +#viewer-version { + position: absolute; + top: 8px; + right: 12px; + font-size: 0.75rem; + color: #999; + font-family: ui-monospace, SFMono-Regular, Menlo, monospace; + pointer-events: none; + z-index: 20; + user-select: none; +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + .sidebar { + width: 250px; + min-width: 250px; + } + + .sidebar.collapsed { + width: 40px; + min-width: 40px; + } +} diff --git a/docs/sims/graph-viewer/main.html b/docs/sims/graph-viewer/main.html new file mode 100644 index 00000000..a21fbc96 --- /dev/null +++ b/docs/sims/graph-viewer/main.html @@ -0,0 +1,54 @@ + + + + + + Learning Graph Viewer for Beginning Python — From Blocks to Code with Monty + + + + +
+ + +
+
+
Loading concepts and edges...
+
v0.04
+
+
+ + + + diff --git a/docs/sims/graph-viewer/script.js b/docs/sims/graph-viewer/script.js new file mode 100644 index 00000000..f6a7952f --- /dev/null +++ b/docs/sims/graph-viewer/script.js @@ -0,0 +1,378 @@ +// Learning Graph Viewer Script +// Loads and displays an interactive learning graph using vis-network + +let network = null; +let allNodes = []; +let allEdges = []; +let groups = {}; +let visibleGroups = new Set(); + +// Precomputed once at load — never change after that +let nodesWithDeps = new Set(); // set of node IDs that have outgoing edges +let groupCounts = {}; // { groupId: count } for legend labels + +// Load the learning graph data +async function loadGraph() { + try { + const response = await fetch('../../learning-graph/learning-graph.json'); + const data = await response.json(); + + allNodes = data.nodes || []; + groups = data.groups || {}; + + // Assign explicit integer IDs to every edge at load time. + allEdges = (data.edges || []).map((edge, i) => ({ + ...edge, + id: edge.id !== undefined ? edge.id : i + })); + + // Initialize all groups as visible + Object.keys(groups).forEach(g => visibleGroups.add(g)); + + // Precompute values that never change after load + nodesWithDeps = new Set(allEdges.map(e => e.from)); + groupCounts = {}; + allNodes.forEach(n => { + groupCounts[n.group] = (groupCounts[n.group] || 0) + 1; + }); + + initializeNetwork(); + buildLegend(); + updateStats(); + setupSearch(); + setupControls(); + + } catch (error) { + console.error('Error loading learning graph:', error); + document.getElementById('network').innerHTML = + '

Error loading learning graph. Make sure learning-graph.json exists at ../../learning-graph/learning-graph.json

'; + } +} + +// Initialize the vis-network visualization +function initializeNetwork() { + const container = document.getElementById('network'); + + // Create nodes DataSet - colors are handled by the groups option + const nodes = new vis.DataSet(allNodes); + + // Create edges DataSet — use allEdges which already have explicit IDs + const edges = new vis.DataSet(allEdges.map(edge => ({ + ...edge, + arrows: 'to', + color: { color: '#888', opacity: 0.6 } + }))); + + const data = { nodes, edges }; + + // Build vis-network groups configuration from JSON groups + const visGroups = {}; + Object.entries(groups).forEach(([groupId, groupInfo]) => { + visGroups[groupId] = { + color: { + background: groupInfo.color || 'lightgray', + border: groupInfo.color || 'lightgray', + highlight: { + background: groupInfo.color || 'lightgray', + border: '#333' + }, + hover: { + background: groupInfo.color || 'lightgray', + border: '#666' + } + }, + font: { + color: groupInfo.font?.color || 'black' + } + }; + }); + + const options = { + groups: visGroups, + layout: { + randomSeed: 42, + improvedLayout: true + }, + physics: { + enabled: true, + solver: 'forceAtlas2Based', + forceAtlas2Based: { + gravitationalConstant: -50, + centralGravity: 0.01, + springLength: 100, + springConstant: 0.08, + damping: 0.4, + avoidOverlap: 0.5 + }, + stabilization: { + enabled: true, + iterations: 1000, + updateInterval: 25 + } + }, + nodes: { + shape: 'box', + margin: 4, + font: { + size: 14, + face: 'Arial' + }, + borderWidth: 2, + shadow: true + }, + edges: { + smooth: { + type: 'cubicBezier', + forceDirection: 'horizontal', + roundness: 0.4 + }, + width: 1.5 + }, + interaction: { + hover: true, + tooltipDelay: 200, + zoomView: true, + dragView: true + } + }; + + network = new vis.Network(container, data, options); + + // Remove the loading message once the initial layout is computed. + network.once('stabilizationIterationsDone', () => { + const msg = document.getElementById('loading-message'); + if (msg) msg.remove(); + }); + + // Turn off physics after 5 seconds to stop spinning + setTimeout(() => { + network.setOptions({ physics: { enabled: false } }); + }, 5000); + + // Re-enable physics when user starts dragging a node + network.on('dragStart', function(params) { + if (params.nodes.length > 0) { + network.setOptions({ physics: { enabled: true } }); + } + }); + + // Turn off physics when user releases the node + network.on('dragEnd', function(params) { + if (params.nodes.length > 0) { + setTimeout(() => { + network.setOptions({ physics: { enabled: false } }); + }, 1000); + } + }); + + // Handle node selection + network.on('selectNode', function(params) { + if (params.nodes.length > 0) { + highlightNode(params.nodes[0]); + } + }); +} + +// Build the category legend +function buildLegend() { + const legendContainer = document.getElementById('legend'); + legendContainer.innerHTML = ''; + + Object.entries(groups).forEach(([groupId, groupInfo]) => { + const count = groupCounts[groupId] || 0; + + const item = document.createElement('div'); + item.className = 'legend-item'; + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.id = `group-${groupId}`; + checkbox.checked = true; + checkbox.addEventListener('change', () => toggleGroup(groupId, checkbox.checked)); + + const colorBox = document.createElement('span'); + colorBox.className = 'color-box'; + colorBox.style.backgroundColor = groupInfo.color || 'lightgray'; + + const label = document.createElement('label'); + label.htmlFor = `group-${groupId}`; + label.textContent = `${groupInfo.classifierName || groupId} (${count})`; + + item.appendChild(checkbox); + item.appendChild(colorBox); + item.appendChild(label); + legendContainer.appendChild(item); + }); +} + +// Toggle visibility of a category group +function toggleGroup(groupId, visible) { + if (visible) { + visibleGroups.add(groupId); + } else { + visibleGroups.delete(groupId); + } + updateVisibility(); +} + +// Update node and edge visibility based on selected groups +function updateVisibility() { + const visibleNodeIds = new Set( + allNodes.filter(n => visibleGroups.has(n.group)).map(n => n.id) + ); + + const nodes = network.body.data.nodes; + const edges = network.body.data.edges; + + // Batch update nodes — single DataSet.update() call triggers one redraw + nodes.update(allNodes.map(node => ({ + id: node.id, + hidden: !visibleGroups.has(node.group) + }))); + + // Batch update edges + edges.update(allEdges.map(edge => ({ + id: edge.id, + hidden: !(visibleNodeIds.has(edge.from) && visibleNodeIds.has(edge.to)) + }))); + + updateStats(visibleNodeIds); +} + +// Update statistics display +function updateStats(visibleNodeIds) { + if (!visibleNodeIds) { + visibleNodeIds = new Set( + allNodes.filter(n => visibleGroups.has(n.group)).map(n => n.id) + ); + } + + const visibleEdgeCount = allEdges.filter( + e => visibleNodeIds.has(e.from) && visibleNodeIds.has(e.to) + ).length; + + const foundationalCount = allNodes.filter( + n => !nodesWithDeps.has(n.id) && visibleGroups.has(n.group) + ).length; + + document.getElementById('visible-nodes').textContent = visibleNodeIds.size; + document.getElementById('visible-edges').textContent = visibleEdgeCount; + document.getElementById('foundational-nodes').textContent = foundationalCount; +} + +// Setup search functionality +function setupSearch() { + const searchInput = document.getElementById('search'); + const resultsContainer = document.getElementById('search-results'); + + searchInput.addEventListener('input', function() { + const query = this.value.toLowerCase().trim(); + resultsContainer.innerHTML = ''; + + if (query.length < 2) { + resultsContainer.style.display = 'none'; + return; + } + + const matches = allNodes.filter(n => + n.label.toLowerCase().includes(query) + ).slice(0, 10); + + if (matches.length === 0) { + resultsContainer.style.display = 'none'; + return; + } + + matches.forEach(node => { + const item = document.createElement('div'); + item.className = 'search-result-item'; + + const groupInfo = groups[node.group] || {}; + item.innerHTML = ` + ${node.label} + + ${groupInfo.classifierName || node.group} + + `; + + item.addEventListener('click', () => { + selectNode(node.id); + searchInput.value = node.label; + resultsContainer.style.display = 'none'; + }); + + resultsContainer.appendChild(item); + }); + + resultsContainer.style.display = 'block'; + }); + + // Hide results when clicking outside + document.addEventListener('click', function(e) { + if (!searchInput.contains(e.target) && !resultsContainer.contains(e.target)) { + resultsContainer.style.display = 'none'; + } + }); +} + +// Select and focus on a node +function selectNode(nodeId) { + network.selectNodes([nodeId]); + network.focus(nodeId, { + scale: 1.2, + animation: { + duration: 500, + easingFunction: 'easeInOutQuad' + } + }); + highlightNode(nodeId); +} + +// Highlight a node and its connections +function highlightNode(nodeId) { + const connectedNodes = network.getConnectedNodes(nodeId); + const connectedSet = new Set([nodeId, ...connectedNodes]); + + const nodes = network.body.data.nodes; + nodes.update(allNodes.map(node => ({ + id: node.id, + opacity: connectedSet.has(node.id) ? 1 : 0.3 + }))); + + // Reset opacity after a delay — batched for performance + setTimeout(() => { + nodes.update(allNodes.map(node => ({ id: node.id, opacity: 1 }))); + }, 3000); +} + +// Setup control buttons +function setupControls() { + // Toggle sidebar + document.getElementById('toggle-sidebar').addEventListener('click', function() { + const sidebar = document.getElementById('sidebar'); + const content = document.getElementById('sidebar-content'); + sidebar.classList.toggle('collapsed'); + content.style.display = sidebar.classList.contains('collapsed') ? 'none' : 'block'; + }); + + // Check all groups + document.getElementById('check-all').addEventListener('click', function() { + Object.keys(groups).forEach(groupId => { + visibleGroups.add(groupId); + document.getElementById(`group-${groupId}`).checked = true; + }); + updateVisibility(); + }); + + // Uncheck all groups + document.getElementById('uncheck-all').addEventListener('click', function() { + Object.keys(groups).forEach(groupId => { + visibleGroups.delete(groupId); + document.getElementById(`group-${groupId}`).checked = false; + }); + updateVisibility(); + }); +} + +// Initialize when DOM is ready +document.addEventListener('DOMContentLoaded', loadGraph); diff --git a/docs/sims/index.md b/docs/sims/index.md new file mode 100644 index 00000000..e3ac8274 --- /dev/null +++ b/docs/sims/index.md @@ -0,0 +1,17 @@ +--- +title: Beginning Python MicroSims +description: A gallery of the interactive MicroSims used in the Beginning Python programming curriculum. +hide: + - toc +--- +# List of Beginning Python MicroSims + +Interactive Micro Simulations to help students beginning Python programming. Click any card to open the MicroSim. + +
+ +- **[Additive vs. Subtractive Color Mixing](./additive-subtractive-mixing/index.md)** + + ![Additive vs. Subtractive Color Mixing](./additive-subtractive-mixing/additive-subtractive-mixing.png) + + Explore why mixing light (RGB) and mixing paint produce different results, comparing additive and subtractive color models side by side. diff --git a/docs/skulpt/02-simple-square.md b/docs/skulpt/02-simple-square.md new file mode 100644 index 00000000..d32c645f --- /dev/null +++ b/docs/skulpt/02-simple-square.md @@ -0,0 +1,184 @@ +# Drawing a Square + +By the end of this lesson you'll be able to: + +- Move the turtle forward and turn it using `forward()` and `right()` +- Explain what the numbers inside `forward(100)` and `right(90)` control +- Draw a square by repeating the same two commands four times + +The turtle starts in the center of the canvas and draws lines as it moves — +like a pen attached to a robot. In this lesson you'll give it your first +drawing commands and watch a square appear. + +!!! mascot-welcome "Welcome to This Lesson!" + ![Monty waving welcome](../img/mascot/welcome.png){ class="mascot-admonition-img" } + Hi, I'm Monty! I'm a Python snake, and today I'm going to teach you how to + make me draw a square on the screen. It's easier than you think — + let's code it together! + +## Moving and Turning + +The two most important turtle commands are `forward()` and `right()`. + +`forward(100)` tells the turtle to walk **forward** 100 steps, drawing a line as it goes. +The number inside the parentheses is called a **parameter** — it controls how much the +command does. Here, `100` sets how long each side of the square will be. + +`right(90)` tells the turtle to **turn right** 90 degrees without drawing anything. +The number 90 is a quarter-turn — exactly the angle at each corner of a square. + +!!! mascot-tip "Scratch Bridge" + ![Monty with a tip](../img/mascot/tip.png){ class="mascot-admonition-img" } + In Scratch you used the **"Move 10 steps"** block and the **"Turn ↻ 15 degrees"** block. + In Python, `forward(100)` and `right(90)` do exactly the same things — just written differently! + +## Sample Code + +```python +import turtle +monty = turtle.Turtle() +monty.shape('turtle') + +monty.forward(100) +monty.right(90) + +monty.forward(100) +monty.right(90) + +monty.forward(100) +monty.right(90) + +monty.forward(100) +monty.right(90) +``` + +!!! mascot-thinking "What Do You Think Will Happen?" + ![Monty thinking](../img/mascot/thinking.png){ class="mascot-admonition-img" } + Before you click Run, count the `forward` commands in the code above. + How many sides will the turtle draw? Make your guess — then find out! + +## Try It Now + +Edit the code below and click **Run** to see Monty draw right on this page. +No account needed — everything runs in your browser. + + + + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? The turtle draws **4 sides** — one for each `forward()` + `right()` pair — making a perfect square. + +**If you see a red error message:** Check your spelling — Python is case-sensitive, +so `Forward(100)` won't work but `forward(100)` will. +Make sure you have parentheses `()` around every number. + +## How It Works + +The turtle starts in the center of the canvas facing right. +Each `forward(100)` moves it 100 steps in the direction it is currently facing. +Each `right(90)` rotates it 90 degrees clockwise — a quarter turn. +After four forward-and-turn pairs the turtle is back where it started: a perfect square. + +## Explanation Table + +| Line | What it does | +|------|-------------| +| `import turtle` | Loads the turtle graphics library | +| `monty = turtle.Turtle()` | Creates a turtle and names it `monty` | +| `monty.shape('turtle')` | Shows the turtle icon instead of a plain arrow | +| `monty.forward(100)` | Moves 100 steps forward, drawing a line | +| `monty.right(90)` | Turns 90 degrees clockwise (one corner of a square) | + +!!! mascot-warning "Common Mistake: Wrong Turn Angle" + ![Monty warning](../img/mascot/warning.png){ class="mascot-admonition-img" } + If you change `right(90)` to `right(100)` the corners won't close and you won't get a square! + A square needs *exactly* 90-degree turns. Try it and see what shape you get instead. + +## Learning Check + +!!! mascot-thinking "Your Turn — Complete the Triangle" + ![Monty thinking](../img/mascot/thinking.png){ class="mascot-admonition-img" } + A triangle has 3 sides. Each corner of an equilateral triangle turns 120 degrees. + The program below is missing **one line**. Add it so Monty draws a complete triangle! + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +## Experiments + +Try these changes to the square code above. Predict what will happen first, then run it to check! + +1. Change `100` to `150` in all four `forward` calls. + **You'll know it worked when** the square is noticeably larger than before. + +2. Change all four `right(90)` calls to `right(120)` and remove one `forward`/`right` pair (leaving only three). + **You'll know it worked when** you see a triangle instead of a square. + +3. Add `monty.color('red')` on the line just before the first `forward`. + **You'll know it worked when** all four sides of the square are red instead of black. + +4. Add `monty.speed(1)` after `monty.shape('turtle')` to slow Monty way down. + **You'll know it worked when** you can watch him draw each side one at a time. + +5. Try drawing two squares side by side: after the four pairs, add + `monty.penup()`, then `monty.forward(150)`, then `monty.pendown()`, + then repeat the four `forward`/`right` pairs again. + **You'll know it worked when** you see two separate squares on the canvas. + +!!! mascot-celebration "Great Work!" + ![Monty celebrating](../img/mascot/celebration.png){ class="mascot-admonition-img" } + You just wrote your first turtle drawing program — and it works! + In the next lesson you'll learn how to use a `for` loop so you don't have to + repeat those four lines over and over. Let's code it together! diff --git a/docs/skulpt/04a-stop-sign.md b/docs/skulpt/04a-stop-sign.md new file mode 100644 index 00000000..68dd2b1a --- /dev/null +++ b/docs/skulpt/04a-stop-sign.md @@ -0,0 +1,234 @@ +# Drawing a Stop Sign + +By the end of this lesson you'll be able to: + +- Use variables to store the color, size, and number of sides of a shape +- Use a `for` loop to draw any regular polygon without repeating code +- Fill a shape with color using `begin_fill()` and `end_fill()` + +A stop sign is an octagon — a regular 8-sided polygon. Instead of writing eight +`forward`/`right` pairs by hand, you'll use a loop and a formula to draw it in just +a few lines. + +!!! mascot-welcome "Welcome to This Lesson!" + ![Monty waving welcome](../img/mascot/welcome.png){ class="mascot-admonition-img" } + Ready to level up? In this lesson we're going to draw a real stop sign — + red fill, white STOP text, and everything. A `for` loop is going to do all the + heavy lifting for us. Let's code it together! + +## Using Variables for Shape Properties + +When you store the size and color in **variables**, changing the whole drawing is as easy +as editing one line. A **variable** is a named box that holds a value — give it a +descriptive name so the code is easy to read. + +```python +distance = 50 # length of each side +sides = 8 # number of sides (8 = octagon) +my_color = "red" +``` + +The turn angle for any regular polygon follows a simple formula: divide 360 by the number +of sides. For an octagon: 360 ÷ 8 = 45 degrees. + +!!! mascot-tip "Scratch Bridge" + ![Monty with a tip](../img/mascot/tip.png){ class="mascot-admonition-img" } + In Scratch you used **variables** in the Variables drawer — `set [distance] to 50`. + In Python, `distance = 50` does exactly the same thing: it creates a variable named + `distance` and stores the value 50 in it. + +## Filling a Shape with Color + +Two commands work as a pair to paint the inside of any shape: + +- `begin_fill()` — tells the turtle "start remembering the path" +- `end_fill()` — tells the turtle "now fill in everything inside that path" + +Everything drawn between those two calls gets filled with the current color. If you +forget either one, the fill won't appear. + +## Sample Code + +```python +import turtle +monty = turtle.Turtle() +monty.shape('turtle') + +distance = 50 +sides = 8 +angle = 360 / sides # works for any regular polygon +my_color = "red" + +monty.penup() +monty.goto(-50, 100) +monty.pendown() +monty.color(my_color) +monty.begin_fill() + +for i in range(sides): + monty.forward(distance) + monty.right(angle) + +monty.end_fill() +monty.hideturtle() + +monty.penup() +monty.right(110) +monty.forward(80) +monty.color('white') +monty.write('STOP', font=("Arial", 30, "normal")) +``` + +!!! mascot-thinking "What Do You Think Will Happen?" + ![Monty thinking](../img/mascot/thinking.png){ class="mascot-admonition-img" } + Look at the line `for i in range(sides):` — and remember that `sides = 8`. + How many times will the loop repeat? And what color will the inside of the shape be? + Make your guesses — then click Run! + +## Try It Now + +Edit the code below and click **Run** to draw the stop sign right on this page. +No account needed — everything runs in your browser. + + + + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? The loop runs **8 times** (once for each side of the octagon) and the +inside fills with red because `my_color = "red"` was set before `begin_fill()`. + +## How It Works + +The turn angle formula `360 / sides` is the secret: the exterior angles of any regular +polygon always add up to exactly 360 degrees. Divide by the number of sides and you get +the angle for one corner. + +`goto(-50, 100)` moves the turtle to a starting corner without drawing — `penup()` lifts +the pen first so no line appears. `pendown()` lowers it again before drawing begins. + +`hideturtle()` removes the turtle icon when drawing is finished so it doesn't cover the artwork. + +`write('STOP', font=...)` places text at the turtle's current position using the +specified font family, size, and style. + +## Explanation Table + +| Line | What it does | +|------|-------------| +| `distance = 50` | Length of each side in pixels | +| `sides = 8` | Number of sides — change this to get a different polygon | +| `angle = 360 / sides` | Turn angle — the formula works for any regular polygon | +| `my_color = "red"` | Stores the color in a variable so it's easy to change | +| `penup() / goto() / pendown()` | Move to start position without drawing a line | +| `begin_fill() / end_fill()` | Fill everything drawn between them with the current color | +| `for i in range(sides):` | Repeat the loop body once for each side | +| `hideturtle()` | Hides the turtle cursor when drawing is done | +| `write('STOP', font=...)` | Writes text at the turtle's current position | + +## Learning Check + +!!! mascot-warning "Spot the Bug!" + ![Monty warning](../img/mascot/warning.png){ class="mascot-admonition-img" } + The program below should draw a filled red octagon, but when you run it the shape + has no fill — just an outline. One line is in the wrong place. Can you find it and + fix it? + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +## Experiments + +Try these changes to the stop sign code above. Predict what will happen first, then run it! + +1. Change `my_color = "red"` to `"blue"`. + **You'll know it worked when** the octagon fills with blue instead of red. + +2. Change `distance = 50` to `80`. + **You'll know it worked when** the stop sign is noticeably larger. + +3. Change `sides = 8` to `6` — and also update `angle = 360 / sides` stays the same (it recalculates automatically). + **You'll know it worked when** you see a filled hexagon instead of an octagon. + +4. Change `'STOP'` to your own word. + **You'll know it worked when** your word appears on the sign in white. + +5. Change `monty.color('white')` (the text color) to `'yellow'`. + **You'll know it worked when** the text on the sign turns yellow. Can you still read it easily? + +!!! mascot-celebration "Great Work!" + ![Monty celebrating](../img/mascot/celebration.png){ class="mascot-admonition-img" } + You drew a stop sign using variables, a loop, and fill commands — that's serious Python! + Try changing `sides` to 3 or 5 and see what signs you can invent. + Let's code it together! diff --git a/docs/skulpt/10-debugging.md b/docs/skulpt/10-debugging.md new file mode 100644 index 00000000..dd9cb623 --- /dev/null +++ b/docs/skulpt/10-debugging.md @@ -0,0 +1,185 @@ +# Reading Output and Error Messages + +By the end of this lesson you'll be able to: + +- Tell the difference between normal output and an error message just by its color +- Read what an error message says to figure out where your program went wrong +- Use `print()` checkpoints to narrow down exactly which line caused a crash + +When your Python program runs, two kinds of text can appear in the output box. +**Normal output** — anything printed with `print()` — appears in black. +**Error messages** — produced when Python finds a problem — appear in red. +The color makes it easy to see at a glance whether your program finished successfully or crashed. + +!!! mascot-welcome "Welcome to This Lesson!" + ![Monty waving welcome](../img/mascot/welcome.png){ class="mascot-admonition-img" } + Every programmer sees error messages — even professional ones! + Learning to read them calmly is one of the most useful skills you'll build. + Let's code it together! + +## Normal Output: Everything Goes Right + +When a program runs without any problems, every `print()` call produces a line of black text in the output box. +Run the program below and look at the output — all black, no red. + + + + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +All five lines print in black — the program ran from top to bottom without any problems. + +## Error Output: Something Went Wrong + +Now look at what happens when Python hits a problem partway through a program. +The program below prints two lines successfully, then tries to use a variable called `high_score` that was never created. +Python cannot continue, so it stops and reports the error. + +!!! mascot-thinking "What Will the Output Look Like?" + ![Monty thinking](../img/mascot/thinking.png){ class="mascot-admonition-img" } + Before you click Run, count the `print()` calls in the program below. + How many lines of output do you think will appear — and what color will each one be? + Make your prediction, then click Run! + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +Were you right? +Two black lines appeared for the two successful `print()` calls. +Then a red error message appeared — Python stopped when it hit the broken line. +The last `print()` never ran at all because the program crashed before it got there. + +## How to Read a NameError + +The red message says something like: + +``` +NameError: name 'high_score' is not defined on line 8 +``` + +Here is what each part means: + +| Part | Meaning | +|------|---------| +| `NameError` | The type of error — Python found a name it doesn't recognise | +| `'high_score'` | The exact variable name Python couldn't find | +| `on line 8` | The line number where the crash happened | + +To fix this error you have two choices: + +1. **Create the variable before you use it** — add `high_score = 100` somewhere above line 8. +2. **Remove or fix the broken line** — if `high_score` shouldn't be there, delete it. + +!!! mascot-tip "The Black Lines Are Your Clues" + ![Monty with a tip](../img/mascot/tip.png){ class="mascot-admonition-img" } + When a program crashes, look at the last black line in the output — that tells you the most recent thing that worked. The error happened somewhere between that line and the next `print()` you expected. Use this as your starting point when hunting for the bug! + +## Using Print Checkpoints to Find Bugs + +Professional programmers often add temporary `print()` calls to trace exactly where a program stops. +Each one says "I made it this far." +When you see the last black checkpoint and then a red error, you know the crash happened between those two points. + +Here is the same broken program with checkpoints added. +Notice how the checkpoints help you pinpoint the problem line more precisely: + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +All four checkpoints print in black — the program is healthy. +Now remove the `#` from in front of `print("High score:", high_score)` and run it again. +Checkpoint 3 will be the last black line, and the red error will appear right after it — +telling you the crash happened between Checkpoint 3 and Checkpoint 4. + +!!! mascot-warning "Red Doesn't Mean Failure — It Means Information" + ![Monty warning](../img/mascot/warning.png){ class="mascot-admonition-img" } + A red error message is not a sign that you are bad at coding. It is Python telling you exactly what went wrong and where. Read it carefully — it almost always contains the line number and the name of whatever Python couldn't find. The message is your friend! + +## Experiments + +Try these changes. For each one, predict the output color pattern before you run! + +1. In Lab 2, add `high_score = 500` on a new line above `print("High score:", high_score)`. + **You'll know it worked when** all output is black and "High score: 500" appears. + +2. In Lab 2, change `score = 42` to `score = "forty-two"` (a word instead of a number). + Then change `print("Score:", score)` to `print("Score + 1:", score + 1)`. + **You'll know it worked when** you see a red `TypeError` — Python can't add a word and a number. + +3. In Lab 3, remove the `#` from the broken line and run it. + Count the black checkpoint lines in the output. + **You'll know it worked when** you can identify which checkpoint was last and explain why Checkpoint 4 never appeared. + +4. In Lab 1, rename `total` to `final_total` in the calculation but leave `print("Total:", total)` unchanged. + **You'll know it worked when** a red `NameError` for `total` appears after the first three black lines. + +!!! mascot-celebration "You Can Read Error Messages!" + ![Monty celebrating](../img/mascot/celebration.png){ class="mascot-admonition-img" } + Black means success, red means "look here." You now know how to read both — and how to use print checkpoints to hunt down a bug. That's real debugging skill! Let's code it together! diff --git a/docs/skulpt/text-only-example.md b/docs/skulpt/text-only-example.md new file mode 100644 index 00000000..bd34ce78 --- /dev/null +++ b/docs/skulpt/text-only-example.md @@ -0,0 +1,113 @@ +--- +title: Text-Only Skulpt Example +description: Demonstrates the text-only Skulpt lab layout where the drawing area is hidden and the editor fills the full content width. +--- + +# Text-Only Skulpt Example + +This page demonstrates the **text-only** Skulpt lab template. +No turtle drawing area appears — the code editor and output panel fill the entire content width. +Use this template for programs that only use `print()` and text output, with no turtle graphics. + +## How It Works + +Add `class="skulpt-text-only"` to the outer `skulpt-lab` div. +The canvas container is hidden by CSS, but the `turtle-target` element remains in the DOM +so `runSkulpt()` can still initialise without errors. + +## Example 1 — Print Statements + + + + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +## Example 2 — User-Defined Function + +
+
+ +
+ + +
+

+  
+
+
+
+
+ +## HTML Template + +Copy this block and replace the code inside the ` +
+ + +
+

+  
+
+
+
+ +``` + +For a second lab on the same page, use the `-2` suffix on all IDs and `runSkulpt('-2')` / `resetSkulpt('-2')` on the buttons (same convention as the drawing labs). + +## Contrast: Drawing Lab Template + +For programs that use turtle graphics, omit the `skulpt-text-only` class and the canvas appears as normal: + +```html +
+
+ +
+ + +
+

+  
+
+
+
+
+``` diff --git a/docs/strategy/index.md b/docs/strategy/index.md new file mode 100644 index 00000000..19f9a5e3 --- /dev/null +++ b/docs/strategy/index.md @@ -0,0 +1,5 @@ +# Teaching Strategies + +## Order of Concepts + +[Order of Concepts](oder-of-concepts.md) \ No newline at end of file diff --git a/docs/strategy/order-of-concepts.md b/docs/strategy/order-of-concepts.md new file mode 100644 index 00000000..bb443658 --- /dev/null +++ b/docs/strategy/order-of-concepts.md @@ -0,0 +1,123 @@ +# Order of Concepts + +## Intro + +What is the role of visual feedback in teaching beginning Python? + +## No Visual Feedback + + +``` +What are the key concepts in learning Python for a 9th +grade student in the US? List the concepts in the order +they should be taught and add justification for ordering. +``` + +1. Introduction to Programming and Python + +Justification: Begin by explaining what programming is and how it allows us to communicate instructions to a computer. Introducing Python's simplicity and readability sets a positive tone for beginners. +2. Setting Up the Development Environment + +Justification: Before coding, students need to install Python and set up an Integrated Development Environment (IDE) or use an online coding platform. This ensures they're ready to practice coding examples. +3. Basic Syntax and Output with print() + +Justification: Learning how to display information is fundamental. The print() function is simple and provides immediate visual feedback, which is motivating for new learners. +4. Variables and Data Types + +Justification: Variables store information that programs manipulate. Understanding data types like integers, floats, strings, and booleans is essential for handling different kinds of data. +5. Basic Operators and Expressions + +Justification: Operators allow students to perform calculations and manipulate data. This includes arithmetic operators (+, -, *, /) and logical operators (and, or, not). +6. User Input with input() + +Justification: Allowing programs to accept user input makes them interactive. Learning to use the input() function helps students understand how to receive and process external data. +7. Conditional Statements (if, elif, else) + +Justification: Conditionals introduce decision-making in programs. They allow the code to execute different actions based on certain conditions, which is critical for dynamic programming. +8. Loops (for and while Loops) + +Justification: Loops enable code to be executed repeatedly without redundancy. Understanding loops is key for tasks that require iteration, like processing items in a list. +9. Lists and Basic Data Structures + +Justification: Lists store collections of items. Introducing lists teaches students how to handle multiple pieces of data efficiently. +10. Functions and Modular Programming - Justification: Functions promote code reusability and better organization. Learning to write functions helps students break down complex problems into manageable pieces. + +11. Introduction to Modules and Libraries - Justification: Python's strength lies in its extensive libraries. Teaching how to import and use modules like math or random expands the functionality available to students. + +12. Basic File Input/Output - Justification: Reading from and writing to files allows programs to handle data persistence. This is important for applications that need to save or load data. + +13. Error Handling with try and except - Justification: Errors are inevitable in programming. Learning to handle exceptions makes programs more robust and helps students debug their code effectively. + +14. Dictionaries and Sets - Justification: These data structures are useful for storing data in key-value pairs (dictionaries) and for handling unique items (sets). They broaden the ways students can manage data. + +15. Introduction to Object-Oriented Programming (OOP) - Justification: OOP introduces classes and objects, allowing for more complex and scalable code. A basic introduction prepares students for advanced programming concepts. + +16. Developing a Simple Project - Justification: Applying learned concepts in a project reinforces understanding. It provides practical experience and a sense of accomplishment. + +17. Review and Next Steps - Justification: Reviewing consolidates knowledge. Discussing next steps keeps students motivated to continue learning, possibly introducing topics like web development or data science with Python. + +By following this progression, students build a strong foundation in Python programming. Each concept builds upon the previous ones, ensuring a smooth learning curve tailored for 9th-grade students. + + +## With Visual Feedback + +``` +Now assume that all students have access to the +trinket.io website that allows students to learn +using turtle graphics to get fast visual feedback. +Generate a list of the key Python concepts and the +order they should be taught. +``` + +1. Introduction to Programming and Python + +Justification: Start by explaining what programming is and introduce Python as an accessible language for beginners due to its readability and simplicity. +2. Setting Up the Development Environment on Trinket.io + +Justification: Guide students on how to use Trinket.io for writing and running Python code, specifically leveraging its support for turtle graphics to provide immediate visual feedback. +3. Introduction to Turtle Graphics + +Justification: Begin coding with turtle graphics to engage students visually. Drawing simple shapes helps them understand basic programming concepts in an enjoyable way. +4. Basic Syntax and Turtle Commands + +Justification: Teach fundamental Python syntax through turtle commands like forward(), backward(), left(), and right(), which illustrate function calls and parameters. +5. Variables and Data Types + +Justification: Introduce variables to store values that control turtle movements (e.g., distances, angles). Cover basic data types like integers and floats in this context. +6. Loops with Turtle Graphics (for and while Loops) + +Justification: Use loops to create patterns and complex shapes, demonstrating iteration in a visually engaging manner. +7. Functions and Code Reusability + +Justification: Teach how to define functions to encapsulate code for drawing specific shapes or patterns, promoting modular programming and code reuse. +8. Conditional Statements (if, elif, else) + +Justification: Introduce decision-making by changing turtle behavior based on conditions (e.g., drawing different shapes based on user input). +9. User Input with input() + +Justification: Make programs interactive by allowing users to influence turtle drawings, enhancing engagement and understanding of input handling. +10. Lists and Data Collections - Justification: Teach lists by storing sequences of colors, movements, or shapes for the turtle to use, illustrating how to manage collections of data. + +11. Randomness and the random Module - Justification: Use the random module to add unpredictability to turtle drawings, making programs more dynamic and fun. + +12. Advanced Turtle Graphics Techniques - Justification: Explore advanced features like setting pen size, colors, filling shapes, and using loops to create intricate designs. + +13. Error Handling with try and except - Justification: Introduce error handling to make programs more robust, especially when dealing with user input that affects turtle actions. + +14. Introduction to Object-Oriented Programming Concepts - Justification: Provide a basic understanding of objects and classes by explaining that the turtle itself is an object with methods and attributes. + +15. Basic File Input/Output (Optional based on Trinket.io capabilities) - Justification: If supported, teach how to read from and write to files to save or load data that influences turtle drawings. + +16. Developing a Comprehensive Turtle Graphics Project - Justification: Apply all learned concepts in a final project where students create their own complex drawing or simple animation, reinforcing their skills and creativity. + +17. Review and Next Steps - Justification: Summarize the key concepts covered and discuss how these skills can be applied to other areas of Python programming, encouraging continued learning. + +By incorporating turtle graphics early and throughout the curriculum, students benefit from immediate visual feedback that enhances understanding and keeps them engaged. This progression builds foundational Python skills while leveraging the interactive capabilities of Trinket.io, providing a tailored and effective learning experience for 9th-grade students. + + + + + + + +``` \ No newline at end of file diff --git a/docs/teachers-guide/index.md b/docs/teachers-guide/index.md new file mode 100644 index 00000000..6666f663 --- /dev/null +++ b/docs/teachers-guide/index.md @@ -0,0 +1,3 @@ +# Beginning Python Teacher's Guide + +TODO: run the /book-installer skill to create the Teachers's Guide \ No newline at end of file diff --git a/docs/trinket/02-simple-square.md b/docs/trinket/02-simple-square.md index 97e63a1a..170e9f4d 100644 --- a/docs/trinket/02-simple-square.md +++ b/docs/trinket/02-simple-square.md @@ -28,11 +28,11 @@ Here is a link to the Trinket web site with this program running: [https://trinket.io/python/564899ffe9](https://trinket.io/python/564899ffe9) You can click on this link and then press the Run button. You should see the python code on the left side and the drawing on the right side of your screen. -## Explaination +## Explanation The first three lines will be the same for all our programs. They import the turtle library into our program, create a new turtle object and then assign the turtle a shape icon. Although almost all the turtle libraries work this way, there are some minor differences you will see in future examples. -## Reorinenting your turtle -Note that at the start, the turtle is facing to the right. After the last instruction, it is also facing to the right. This is a common best practice so that the turtle gets reoriented after some drawing function. If you remove the last right(90) function and run the program again you will see the turtle ends up facing upward. But if you rerun the progam you will still get the same square because the orientation of the turtle is not stored between runs. +## Reorienting your turtle +Note that at the start, the turtle is facing to the right. After the last instruction, it is also facing to the right. This is a common best practice so that the turtle gets reoriented after some drawing function. If you remove the last right(90) function and run the program again you will see the turtle ends up facing upward. But if you rerun the program you will still get the same square because the orientation of the turtle is not stored between runs. ## Experiments Can you change the distance and angle the turtle moves? What happens when you change the numbers for the forward and right functions? Can you go left as well as right? diff --git a/docs/trinket/04-loops.md b/docs/trinket/04-loops.md index bcd3022e..41bd796c 100644 --- a/docs/trinket/04-loops.md +++ b/docs/trinket/04-loops.md @@ -28,5 +28,5 @@ dan.write('done with square') ## Experiments 1. Can you make the turtle draw a larger square? Hint: change the distance to be 80. How big can you make the square before the turtle goes off the screen? 2. Can you make a hexagon? This is a figure with six sides. Hint: the angle will need to be 60 and the range limit will need to be 6. -3. Can you make a hexagon? A Hexagon has eight sides. Hints: Try using an angle of 45. -4. Can you make a stop sign? You will need to use a dan.color('red'). a dan.begomfill() and a dan.endfill(). You can add the text of the word "stop" by using dan.moveto(x,y) and dan.write("STOP",None,None, "30pt bold"). You can also use the dan.hideturtle() so that the outline of the turtle is not displayed at the end. See: https://www.youtube.com/watch?v=HhxYt9Lskrw +3. Can you make an octagon? An Octagon has eight sides. Hints: Try using an angle of 45. +4. Can you make a stop sign? You will need to use a dan.color('red'). a dan.beginfill() and a dan.endfill(). You can add the text of the word "stop" by using dan.moveto(x,y) and dan.write("STOP",None,None, "30pt bold"). You can also use the dan.hideturtle() so that the outline of the turtle is not displayed at the end. See: [Python Stop Sign Tutorial](https://www.youtube.com/watch?v=HhxYt9Lskrw) diff --git a/docs/trinket/04a-stop-sign.md b/docs/trinket/04a-stop-sign.md index ae2f13d8..76511db6 100644 --- a/docs/trinket/04a-stop-sign.md +++ b/docs/trinket/04a-stop-sign.md @@ -1,5 +1,7 @@ # Python Turtle Graphics Stop Sign +![](../img/stop-sign.png) + In this lesson, we will use variables and for loop to draw a stop sign. We will also show how to use the penup, pendown, color, begin_fill, end_fill and write functions. Our write function will also change the font size using the ```font=("Arial", 30, "normal")``` parameter. diff --git a/docs/trinket/05-conditionals.md b/docs/trinket/05-conditionals.md index 0a316525..02c5eff8 100644 --- a/docs/trinket/05-conditionals.md +++ b/docs/trinket/05-conditionals.md @@ -10,7 +10,7 @@ Here is the basic syntax of the Python conditional operator. ```py if (i > 2): # do something if i is greater than 2 - else: +else: # do something else when i is exactly 2 or less than 2 ``` @@ -26,7 +26,7 @@ distance = 100 angle = 90 for i in range(1, 5): - # i modulo 2 is the remainer after we divide by 2 + # i modulo 2 is the remainder after we divide by 2 dan.write(i, font=("arial", 16, "normal")) if i > 2: # true if i greater than 2 dan.color('red') @@ -47,7 +47,7 @@ We would like every other side to change color. To do this we will add an if-th i % 2 ``` -In our previous loop lesson, we created an index that started at 1 and then changed to 2, 3 and finally 4. For 1 and 3, the first and third edges the result of divid by 2 will return 1 which is the same as TRUE. For 2 and 4 (the vertical sides of the square), the expression will evaluate to 0 since the remainder of 2/2 and 4/2 is zero. +In our previous loop lesson, we created an index that started at 1 and then changed to 2, 3 and finally 4. For 1 and 3, the first and third edges the result of divide by 2 will return 1 which is the same as TRUE. For 2 and 4 (the vertical sides of the square), the expression will evaluate to 0 since the remainder of 2/2 and 4/2 is zero. ```py import turtle @@ -69,7 +69,7 @@ for i in range(4): dan.write('done with square') ``` -[Conditinal Sqare](https://trinket.io/library/trinkets/5b18dc55c6) +[Conditional Square](https://trinket.io/library/trinkets/5b18dc55c6) Can you make the turtle use a larger pen size? Try dan.pensize(10) for the red and dan.pensize(3) for the blue. diff --git a/logs/book-chapter-content-review.md b/logs/book-chapter-content-review.md new file mode 100644 index 00000000..03c445b5 --- /dev/null +++ b/logs/book-chapter-content-review.md @@ -0,0 +1,147 @@ +# Book Chapter Content Review Session +**Date:** 2026-06-28 +**Project:** Beginning Python — From Blocks to Code with Monty +**Skill invoked:** `/book-chapter-generator` + +--- + +## Session Goals + +1. Finalize the 38-chapter structure (carried over from previous session) +2. Apply a user revision: introduce turtle graphics in Chapter 1 +3. Generate all chapter directory and index files +4. Establish content generation standards for the textbook +5. Update the two existing Skulpt lab pages to the new format + +--- + +## What Was Accomplished + +### 1. Chapter Structure Finalized (38 chapters, 450 concepts) + +The chapter structure from the previous session was revised to honor the user's request: +**"Introduce turtle graphics briefly in Chapter 1 since it is the core teaching tool for this book."** + +Two concepts were moved from later chapters into Chapter 1: +- **205** (import Statement) — moved from Chapter 2 +- **305** (import turtle) — moved from Chapter 4 + +Two lower-priority concepts were relocated to make room: +- **2** (Python 2 vs Python 3) — moved to Chapter 28 (Python Development Tools) +- **15** (Python REPL Shell) — moved to Chapter 28 + +Chapter 1 now covers: Python Interpreter Overview, Trinket.io Web Environment, Skulpt Browser Python, print(), Single-Line Comments, Case Sensitivity, Blank Lines and Readability, **import Statement**, **import turtle**. + +Validation result after revision: **450/450 concepts covered, 0 dependency violations.** + +### 2. All Chapter Files Generated + +Created: +- `docs/chapters/index.md` — master overview with links to all 38 chapters +- 38 chapter directories: `docs/chapters/01-welcome-to-python/` through `docs/chapters/38-neural-networks-and-mnist/` +- 38 `index.md` files, each with: chapter summary, full concept list, prerequisites + +`mkdocs.yml` updated with a new **Chapters** nav section immediately after Course Description, listing all 38 chapters. + +### 3. Project CLAUDE.md Created + +`CLAUDE.md` was created at the project root (previously missing). It establishes: + +- **Core Teaching Philosophy** — inline Skulpt turtle graphics as the primary teaching tool +- The "See It, Run It, Modify It" cycle +- **Predict Before You Run** — students predict program behavior before clicking Run +- **Learning Checks** — two types: "add the missing line" and "find the bug" +- Pointer to `CONTENT-GENERATION-GUIDELINES.md` as the authoritative source + +### 4. CONTENT-GENERATION-GUIDELINES.md Comprehensively Revised + +The file grew from 298 lines to 497 lines. A full instructional design review identified eight gaps; all were addressed: + +| Gap | Resolution | +|-----|------------| +| Page template out of sync with new pedagogy | Rewrote the `## Page Structure` template to show the full intended lesson flow end-to-end | +| No Scratch Bridge requirement | New subsection with full Scratch→Python mapping table and `mascot-tip` format | +| No cognitive load rule | New "One New Concept Per Lab" rule with correct/incorrect pattern examples | +| No vocabulary standard | New "New Vocabulary" subsection: bold on first use, define with analogy, reinforce once more | +| No learning objectives | New "Learning Objectives" subsection: student-facing "you'll be able to…" before welcome admonition | +| Experiments had no success criteria | All experiment items now require **"You'll know it worked when…"** | +| No error message guidance | New "Handling Skulpt Error Messages" subsection, tiered by chapter range (1–5, 6–12, 13+) | +| No spaced repetition guidance | New "Spaced Repetition and Spiral Review" subsection with concrete examples | + +The **Predict Before You Run** section was also added (user-requested), covering placement rules, example admonition markup, calibration guidance, and the "close the loop" prose sentence after the lab. + +### 5. Skulpt Lab Pages Rewritten + +Both pages in `docs/skulpt/` were updated to the new format: + +**`02-simple-square.md`** changes: +- Added 3 learning objectives +- Added `mascot-welcome` admonition +- Renamed turtle variable from `dan` to `monty` +- Added Scratch Bridge (`forward` = Move steps, `right` = Turn degrees) +- Added prediction prompt with "Were you right?" close +- Added "If you see a red error" note (appropriate for an early chapter) +- Added `mascot-warning` for wrong-turn-angle common mistake +- Added Learning Check: incomplete triangle missing one `right(120)` line +- Rewrote all 5 experiments with "You'll know it worked when…" success criteria +- Added `mascot-celebration` pointing forward to the next lesson + +**`04a-stop-sign.md`** changes: +- Added 3 learning objectives +- Added `mascot-welcome` +- Renamed `dan` to `monty` +- Split concept intro: variables section first, fill commands section second (one idea at a time) +- Added Scratch Bridge (Python variables = Scratch variables) +- Added prediction prompt with two specific questions (loop count + fill color) +- Added Learning Check: find-the-bug where `begin_fill()` is placed after the loop +- Rewrote all 5 experiments with success criteria +- Added `mascot-celebration` + +### 6. Multi-Lab Bug Discovered and Fixed + +The Learning Check labs on both pages failed because `getElementById` always returns the first match — a second lab with the same IDs is invisible to JavaScript. + +**Root cause:** `skulpt.js` used bare `getElementById('code')`, `getElementById('turtle-target')`, etc. with no way to target a second lab. + +**Fix implemented across three files:** + +`docs/js/skulpt.js` — `runSkulpt()` and `resetSkulpt()` now accept an optional `suffix` parameter (e.g. `'-2'`). All `getElementById` calls append the suffix. `_initSkulptEditor()` now scans for all textareas matching `id="code"` or `id^="code-"` and initialises each independently. + +`docs/css/skulpt.css` — all ID selectors converted to attribute-prefix pairs: +`#code` → `[id="code"], [id^="code-"]` (and similarly for all other IDs). Suffixed labs are styled identically to the first lab automatically. + +`docs/skulpt/02-simple-square.md` and `docs/skulpt/04a-stop-sign.md` — Learning Check labs converted to `-2` suffix IDs with `onclick="runSkulpt('-2')"`. + +`CONTENT-GENERATION-GUIDELINES.md` — Skulpt HTML Block section updated with the multi-lab convention and a copy-paste template for second labs. + +--- + +## Files Created or Modified + +| File | Action | +|------|--------| +| `docs/chapters/index.md` | Created | +| `docs/chapters/01-*/index.md` … `38-*/index.md` | Created (38 files) | +| `mkdocs.yml` | Modified — added Chapters nav section | +| `CLAUDE.md` | Created | +| `CONTENT-GENERATION-GUIDELINES.md` | Heavily revised | +| `docs/skulpt/02-simple-square.md` | Rewritten | +| `docs/skulpt/04a-stop-sign.md` | Rewritten | +| `docs/js/skulpt.js` | Modified — multi-lab suffix support | +| `docs/css/skulpt.css` | Modified — attribute-prefix selectors | + +--- + +## Key Decisions + +- **Turtle in Chapter 1:** `import Statement` and `import turtle` moved earlier so students see the core teaching tool on their very first page. The dependency graph was re-validated to confirm 0 violations. +- **`monty` as turtle variable name:** renamed from `dan` in both lab files to reinforce the mascot connection for students. +- **`-2` suffix convention for multi-lab pages:** chosen over class-based or container-relative approaches because it is backward-compatible (no changes needed to any existing single-lab pages) and is easy for content authors to apply mechanically. + +--- + +## Remaining Work + +- Generate actual lesson content for each of the 38 chapter `index.md` files (currently marked `TODO: Generate Chapter Content`) +- Decide on content generation approach: skill-per-chapter, batch generation, or manual authoring +- Consider adding a chapter content generation skill that reads the concept list and guidelines and produces a full lesson page diff --git a/logs/ch-01-content-generation.md b/logs/ch-01-content-generation.md new file mode 100644 index 00000000..d0d8383a --- /dev/null +++ b/logs/ch-01-content-generation.md @@ -0,0 +1,47 @@ +2026-06-28 08:24:11 + +# Chapter 1 Content Generation Session + +**Skill Version:** 0.09 +**Date:** 2026-06-28 +**Chapter:** 01-welcome-to-python +**Execution Mode:** Sequential (single chapter) + +## Timing + +| Metric | Value | +|--------|-------| +| Start Time | 2026-06-28 08:28:00 | +| End Time | 2026-06-28 08:30:00 | + +## Results + +- Word count: ~2,794 +- Mascot admonitions: 6 (welcome/self-intro, tip/Scratch Bridge, warning, thinking×2, celebration) +- Skulpt labs: 3 (plain, -2, -3 suffixes) +- Concepts covered: 9/9 ✓ +- Edge direction validation: PASSED (2 foundational concepts) +- Dependency violations: 0 + +## Mascot Admonition Order + +1. `mascot-welcome` — Monty's self-introduction (all 7 poses listed) ✓ +2. `mascot-tip` — Scratch Bridge: Say block → print() +3. `mascot-warning` — Case sensitivity pitfall +4. `mascot-thinking` — Prediction before turtle lab +5. `mascot-thinking` — Learning Check (complete the triangle) +6. `mascot-celebration` — End of lesson + +## Concepts Covered + +| # | Concept | Status | +|---|---------|--------| +| 1 | Python Interpreter Overview | ✓ | +| 2 | Trinket.io Web Environment | ✓ | +| 3 | Skulpt Browser Python | ✓ | +| 4 | print() Function | ✓ | +| 5 | Single-Line Comments | ✓ | +| 6 | Case Sensitivity | ✓ | +| 7 | Blank Lines and Readability | ✓ | +| 8 | import Statement | ✓ | +| 9 | import turtle | ✓ | diff --git a/logs/ch-02-content-generation.md b/logs/ch-02-content-generation.md new file mode 100644 index 00000000..08a1d9f0 --- /dev/null +++ b/logs/ch-02-content-generation.md @@ -0,0 +1,45 @@ +2026-06-28 08:34:27 + +# Chapter 2 Content Generation Session + +**Skill Version:** 0.09 +**Date:** 2026-06-28 +**Chapter:** 02-python-code-structure +**Execution Mode:** Sequential (single chapter) + +## Timing + +| Metric | Value | +|--------|-------| +| Start Time | 2026-06-28 08:35:00 | +| End Time | 2026-06-28 08:38:00 | + +## Results + +- Word count: ~2,645 +- Mascot admonitions: 6 (welcome, tip/Scratch Bridge, warning, thinking×2, celebration) +- Skulpt labs: 3 (plain, -2, -3 suffixes) +- Concepts covered: 7/7 ✓ +- Dependency violations: 0 +- Pedagogical order respected: Indentation as Syntax before Code Block Structure and Whitespace Rules ✓ + +## Mascot Admonition Order + +1. `mascot-welcome` — Normal chapter opening +2. `mascot-tip` — Scratch Bridge: blocks-inside-blocks → 4-space indentation +3. `mascot-warning` — IndentationError prevention +4. `mascot-thinking` — Prediction before colored turtle lab +5. `mascot-thinking` — Learning Check (add missing pencolor line) +6. `mascot-celebration` — End of lesson + +## Concepts Covered + +| # | Concept | Status | +|---|---------|--------| +| 1 | Multi-Line Strings | ✓ | +| 2 | Indentation as Syntax | ✓ | +| 3 | Python Keywords | ✓ | +| 4 | Code Block Structure | ✓ | +| 5 | Statement vs Expression | ✓ | +| 6 | Whitespace Rules | ✓ | +| 7 | Named Colors | ✓ | diff --git a/logs/ch-03-content-generation.md b/logs/ch-03-content-generation.md new file mode 100644 index 00000000..a4f7bc08 --- /dev/null +++ b/logs/ch-03-content-generation.md @@ -0,0 +1,30 @@ +2026-06-28 08:55:45 - Chapter 3 content generation started + +## Chapter 3: Variables and Numbers + +**End time:** 2026-06-28 08:58:00 +**Word count:** 2351 + +### Concepts covered (8 of 8) + +- [x] Variable Definition and Assignment +- [x] Variable Naming Rules +- [x] Snake_case Convention +- [x] Meaningful Variable Names +- [x] Variable Reassignment +- [x] Integer Type +- [x] Float Type +- [x] None Value and NoneType + +### Elements + +- Mascot admonitions: 6 (welcome, tip/Scratch Bridge, thinking×2, warning, celebration) +- Skulpt labs: 3 (Lab 1: basic assignment; Lab 2: reassignment; Lab 3: Learning Check) +- Markdown tables: 3 (line explanation, naming mistakes, int vs float comparison) +- Code blocks (static): 7 +- Experiments: 5 + +### Notes + +Reading level: Junior High (ages 10–13). No turtle graphics (Ch 5 introduces turtle). +All labs use print() only. Lab IDs use plain/-2/-3 suffix pattern per skulpt.js convention. diff --git a/logs/ch-04-content-generation.md b/logs/ch-04-content-generation.md new file mode 100644 index 00000000..bca7c7be --- /dev/null +++ b/logs/ch-04-content-generation.md @@ -0,0 +1,50 @@ +# Chapter Content Generator Session Log — Chapter 04 + +**Skill Version:** 0.09 +**Date:** 2026-06-28 +**Execution Mode:** Sequential (single chapter) + +## Timing + +| Metric | Value | +|--------|-------| +| Start Time | 2026-06-28 09:19:38 | +| End Time | 2026-06-28 09:22:59 | +| Elapsed Time | ~3 minutes 21 seconds | + +## Results + +- Chapter: 04-functions-and-objects +- Words: ~2840 +- All 8 concepts covered: Yes + +## Concepts Covered + +1. Defining a Function with def ✓ +2. Calling a Function ✓ +3. Positional Parameters ✓ +4. return Statement ✓ +5. Functions Returning None ✓ +6. Docstrings ✓ +7. Standard Library Overview ✓ +8. Objects and Classes Overview ✓ + +## Non-Text Elements + +- 3 Skulpt interactive labs (plain IDs, -2 suffix, -3 suffix) +- 5 Markdown tables (How It Works, return tracing, Standard Library modules, snake_case pitfalls, Experiments) +- 1 code block (explanatory, not runnable) +- 6 mascot admonitions (at cap) + +## Mascot Admonitions (6/6) + +1. mascot-welcome — chapter opening +2. mascot-tip — Scratch Bridge (custom block → def) +3. mascot-thinking — prediction before Lab 1 +4. mascot-warning — missing return common bug +5. mascot-thinking — Learning Check (add return line) +6. mascot-celebration — end of chapter + +## Files Updated + +- docs/chapters/04-functions-and-objects/index.md diff --git a/logs/ch-05-content-generation.md b/logs/ch-05-content-generation.md new file mode 100644 index 00000000..bd465c36 --- /dev/null +++ b/logs/ch-05-content-generation.md @@ -0,0 +1,18 @@ +2026-06-28 09:48:25 - Start +2026-06-28 09:55:23 - End + +## Chapter 5 — Drawing with Turtle Graphics + +| Metric | Value | +|--------|-------| +| Start Time | 2026-06-28 09:48:25 | +| End Time | 2026-06-28 09:55:23 | +| Elapsed | ~7 minutes | +| Word Count | 2,336 | +| Concepts Covered | 10/10 ✓ | +| Mascot Admonitions | 6/6 (welcome, tip/Scratch Bridge, thinking/prediction, warning, thinking/learning-check, celebration) | +| Skulpt Labs | 4 (Lab 1: movement+Screen, Lab 2: pen control, Lab 3: colors+appearance, Lab 4: learning check) | +| Explanation Tables | 2 | +| Markdown Lists | 3 | +| Scratch Bridges | 1 admonition + 3 prose-level connections | +| Reading Level | Junior High (ages 10–13) | diff --git a/logs/conditional-drawing-region.md b/logs/conditional-drawing-region.md new file mode 100644 index 00000000..52faa5ea --- /dev/null +++ b/logs/conditional-drawing-region.md @@ -0,0 +1,121 @@ +# Conditional Drawing Region — Session Log + +**Date:** 2026-06-28 +**Goal:** Add a second Skulpt lab template where the turtle canvas is hidden and the textarea fills the full content width, then apply it across all existing labs that don't use turtle graphics. + +--- + +## Problem + +Every Skulpt lab in the book used the same two-column layout: code editor on the left, 400×400 turtle canvas on the right. For lessons that only use `print()`, variables, and functions — no turtle at all — the empty canvas wasted half the content width and confused students. + +--- + +## Solution: `skulpt-text-only` CSS Class + +### `docs/css/skulpt.css` + +Added 11 lines at the bottom of the file defining a `.skulpt-text-only` modifier class: + +```css +.skulpt-text-only [id="canvas-container"], +.skulpt-text-only [id^="canvas-container-"] { + display: none; +} + +.skulpt-text-only [id="editor-container"], +.skulpt-text-only [id^="editor-container-"] { + flex: 1 1 100%; + min-width: 0; +} +``` + +**Key design decision:** the `canvas-container` div is hidden by CSS, but the `turtle-target` element inside it is kept in the DOM. This is required because `runSkulpt()` in `skulkt.js` does an early-return guard: + +```javascript +var target = document.getElementById('turtle-target' + suffix); +if (!target || !output || !code) return; +``` + +If `turtle-target` were absent, the Run button would silently do nothing. + +To use the text-only layout, add `class="skulpt-text-only"` to the outer lab div: + +```html +
+``` + +All other IDs and button handlers stay identical. The `-2`, `-3` suffix convention works the same way on both lab types. + +--- + +## Files Changed + +### New file: `docs/skulpt/text-only-example.md` + +Test/reference page added to `docs/skulkt/` (initially created at root level, then moved). Contains two working text-only labs and HTML templates for both lab variants side by side. + +Added to the Skulpt section in `mkdocs.yml`: +```yaml +- Beginning Python - Skulpt (self-hosted): + - Text-Only Example: skulpt/text-only-example.md +``` + +### Updated: `CONTENT-GENERATION-GUIDELINES.md` + +Two sections revised: + +1. **"When Not to Use Turtle Graphics"** replaced with a new **"When to Use Each Lab Type"** section — a decision table making the choice explicit: + - Program uses `import turtle` → drawing lab (no extra class) + - Program uses only `print()`, variables, etc. → text-only lab (`class="skulpt-text-only"`) + +2. **"Skulkt HTML Block"** section split into three subsections: + - Drawing Lab template + - Text-Only Lab template (with explanation of why `turtle-target` must stay in DOM) + - Rules and multiple-lab-per-page conventions covering both types + +### Updated: `docs/skulkt/10-debugging.md` + +All three labs converted — none use turtle: +- `skulpt-lab` → `skulpt-lab class="skulpt-text-only"` +- `skulpt-lab-2` → `skulpt-lab-2 class="skulpt-text-only"` +- `skulpt-lab-3` → `skulpt-lab-3 class="skulpt-text-only"` + +### Updated: `docs/chapters/01-welcome-to-python/index.md` + +- `skulpt-lab` (three `print()` calls) → text-only +- `skulpt-lab-2` (turtle square) → unchanged +- `skulpt-lab-3` (turtle triangle learning check) → unchanged + +### Updated: `docs/chapters/02-python-code-structure/index.md` + +- `skulpt-lab` (triple-quoted haiku + `print()`) → text-only +- `skulpt-lab-2` (colored turtle square) → unchanged +- `skulpt-lab-3` (turtle triangle learning check) → unchanged + +### Updated: `docs/chapters/03-variables-and-numbers/index.md` + +All three labs converted — all use only `print()` and variables: +- `skulpt-lab`, `skulpt-lab-2`, `skulpt-lab-3` → text-only + +### Updated: `docs/chapters/04-functions-and-objects/index.md` + +All three labs converted — all use `def`/`print()`, no turtle: +- `skulpt-lab`, `skulpt-lab-2`, `skulpt-lab-3` → text-only + +--- + +## Summary of Lab Audit (chapters 01–04 + skulkt examples) + +| File | Text-only | Drawing (kept) | +|------|-----------|----------------| +| `skulkt/02-simple-square.md` | — | 2 labs | +| `skulkt/04a-stop-sign.md` | — | 2 labs | +| `skulkt/10-debugging.md` | 3 labs | — | +| `chapters/01-welcome-to-python` | 1 lab | 2 labs | +| `chapters/02-python-code-structure` | 1 lab | 2 labs | +| `chapters/03-variables-and-numbers` | 3 labs | — | +| `chapters/04-functions-and-objects` | 3 labs | — | + +**Total converted:** 11 labs +**Total left with canvas:** 8 labs (all legitimately use turtle) diff --git a/logs/error-message-coloring.md b/logs/error-message-coloring.md new file mode 100644 index 00000000..87a7b1df --- /dev/null +++ b/logs/error-message-coloring.md @@ -0,0 +1,47 @@ +# Error Message Coloring Feature + +**Date:** 2026-06-28 +**Status:** Complete + +## Summary + +Skulpt output now shows normal `print()` output in black and error messages in red. +This makes it immediately obvious to students when their program crashed vs. ran cleanly. + +## What Changed + +### `docs/css/skulpt.css` + +- Changed the `color` on `[id="output"]` from `#c0392b` (red) to `#222` (near-black). + Previously ALL output — including successful `print()` calls — appeared in red, which was a bug. +- Replaced a pre-element-level `.skulpt-error` class rule with a simple `.skulpt-error { color: #c0392b; }` rule + that targets inline `` elements, enabling per-line color without affecting surrounding text. + +### `docs/js/skulpt.js` + +- Added `_skulptEscape(text)` helper that HTML-encodes `&`, `<`, `>` so `print()` output is safe to inject via `innerHTML`. +- Switched all output clearing and writing from `textContent` to `innerHTML` (run, reset, and the output callback). +- Normal output is now appended as plain escaped HTML — appears black (inherits from the `
`).
+- Error messages are now **appended** (not replacing) as `…` — appears red.
+  The old approach replaced all content with the error, destroying any print output that preceded the crash.
+
+## Key Behavior
+
+| Scenario | Output |
+|----------|--------|
+| Successful `print()` calls | Black text |
+| Runtime error with no prior output | Red error message only |
+| `print()` calls followed by a crash | Black lines, then red error appended below |
+
+The interleaved case (black + red in the same output box) is what enables the debugging demo page.
+
+## Demo Page
+
+`docs/skulpt/10-debugging.md` — "Reading Output and Error Messages"
+
+Three labs:
+1. Clean program — all black output
+2. Program that prints two lines then crashes on an undefined variable — black then red
+3. Print-checkpoint debugging technique — students uncomment a broken line to watch where checkpoints stop
+
+Added to `mkdocs.yml` nav under "Beginning Python - Skulpt (self-hosted)" as "Reading Errors".
diff --git a/logs/learning-graph-generator-v0.05-2026-06-28.md b/logs/learning-graph-generator-v0.05-2026-06-28.md
new file mode 100644
index 00000000..59372acb
--- /dev/null
+++ b/logs/learning-graph-generator-v0.05-2026-06-28.md
@@ -0,0 +1,130 @@
+# Learning Graph Generator Session Log
+
+- **Skill Version:** v0.05
+- **Date:** 2026-06-28
+- **Project:** Beginning Python — From Blocks to Code with Monty
+- **Working Directory:** /Users/dan/Documents/ws/python/docs/learning-graph
+
+---
+
+## Python Program Versions Used
+
+| Program | Version | Notes |
+|---------|---------|-------|
+| analyze-graph.py | from skill v0.05 | Quality metrics generation |
+| csv-to-json.py | v0.04 | Generated learning-graph.json |
+| add-taxonomy.py | from skill v0.05 | Reference only; taxonomy added via inline Python |
+| taxonomy-distribution.py | from skill v0.05 | Taxonomy distribution report |
+
+---
+
+## Steps Completed
+
+### Step 0: Setup
+- Confirmed `docs/` directory and `mkdocs.yml` exist
+- Confirmed `docs/learning-graph/` directory exists (already created)
+- Copied Python programs from skill package to working directory
+
+### Step 1: Course Description Assessment (Skipped)
+- Found existing `course-description.md` with `quality_score: 96`
+- Score above 85 threshold — step skipped to save tokens
+
+### Step 2: Concept List Generation
+- **Target:** Up to 450 concepts (user specified)
+- **Source:** All 350 concepts from `concept-list-v1.md` preserved and expanded
+- **Result:** 450 concepts in 14 thematic sections
+- **Additional concepts added:** Computational thinking foundations (decomposition, abstraction,
+  algorithm design, pseudocode), debugging strategies, event queue concept, timer events,
+  additional string/list/math coverage, image processing details, Google Colab, command line basics
+- **Output:** `concept-list.md`
+
+### Step 3: Dependency Graph Generation
+- Generated 838 dependency edges for 450 concepts
+- Identified 2 foundational (root) concepts: Python Interpreter Overview (1), Command Line Basics (19)
+- **Initial issues found and fixed:**
+  - 4 self-dependencies removed (concepts 43, 100, 150, 406)
+  - Label with commas renamed: "range(start, stop, step)" → "Range with Start Stop Step"
+  - 8 circular dependency cycles broken by removing redundant back-edges (65↔184, 72↔152, 101↔185→102, 110↔195, 111↔196, 153↔365, 154↔366, 205↔211)
+- **Output:** `learning-graph.csv`
+
+### Step 4: Quality Validation
+- Ran `analyze-graph.py learning-graph.csv quality-metrics.md`
+- **Result:** Valid DAG ✅
+- 0 cycles, 0 orphaned nodes, 1 connected component
+- Maximum chain length: 13 steps
+- Top dependency hub: List Type (indegree 34), String Type (33), Defining a Function (29)
+- **Output:** `quality-metrics.md`
+- **Quality score estimate:** 82/100 (valid structure; terminal node % slightly high at 52%)
+
+### Step 5: Concept Taxonomy
+- Created 14 categories covering all 450 concepts
+- No category exceeds 15.1% (well under 30% threshold)
+- **Output:** `concept-taxonomy.md`
+
+### Step 5b: Taxonomy Names JSON
+- **Output:** `taxonomy-names.json` (14 entries)
+
+### Step 6: Add Taxonomy to CSV
+- Added TaxonomyID column using concept ID range mapping
+- **Output:** `learning-graph.csv` (updated with TaxonomyID)
+
+### Step 7: Metadata
+- **Output:** `metadata.json`
+
+### Step 8: Color Config
+- Selected 14 colors from the recommended 24-color palette
+- **Output:** `color-config.json`
+
+### Step 9: Generate learning-graph.json
+- Command: `python csv-to-json.py learning-graph.csv learning-graph.json color-config.json metadata.json taxonomy-names.json`
+- csv-to-json.py version: v0.04
+- **Result:** 450 nodes, 838 edges, 14 groups
+- **Output:** `learning-graph.json`
+
+### Step 10: Taxonomy Distribution Report
+- Command: `python taxonomy-distribution.py learning-graph.csv taxonomy-distribution.md`
+- All 14 categories under 30%, excellent balance
+- **Output:** `taxonomy-distribution.md`
+
+### Step 11: Create index.md
+- Customized from `index-template.md` for Beginning Python course
+- **Output:** `index.md`
+
+### Navigation Update
+- Updated `mkdocs.yml` Learning Graph section with 7 entries
+
+---
+
+## Files Created / Modified
+
+| File | Type | Status |
+|------|------|--------|
+| concept-list.md | New | 450 concepts |
+| learning-graph.csv | New | 450 rows + TaxonomyID |
+| quality-metrics.md | New | Quality report |
+| concept-taxonomy.md | New | 14 categories |
+| taxonomy-names.json | New | 14 entries |
+| metadata.json | New | Dublin Core metadata |
+| color-config.json | New | 14 color assignments |
+| learning-graph.json | New | 450 nodes, 838 edges |
+| taxonomy-distribution.md | New | Distribution report |
+| index.md | New | Learning graph intro page |
+| analyze-graph.py | Copied | From skill v0.05 |
+| csv-to-json.py | Copied | From skill v0.05 (v0.04) |
+| add-taxonomy.py | Copied | From skill v0.05 |
+| taxonomy-distribution.py | Copied | From skill v0.05 |
+| learning-graph-schema.json | Copied | From skill v0.05 |
+| ../../mkdocs.yml | Modified | Added Learning Graph nav entries |
+
+---
+
+## Key Statistics
+
+- **Total Concepts:** 450
+- **Total Edges:** 838
+- **Foundational Concepts:** 2
+- **Taxonomy Categories:** 14
+- **Longest Learning Path:** 13 steps
+- **Cycles:** 0
+- **Orphaned Nodes:** 0
+- **Connected Components:** 1
diff --git a/logs/text-area-scroll-height-fix.md b/logs/text-area-scroll-height-fix.md
new file mode 100644
index 00000000..c6f6c540
--- /dev/null
+++ b/logs/text-area-scroll-height-fix.md
@@ -0,0 +1,91 @@
+# Textarea Auto-Height Fix: scrollHeight Approach
+
+**Date:** 2026-06-28  
+**Files changed:** `docs/js/skulpt.js`, `docs/css/skulpt.css`, `CONTENT-GENERATION-GUIDELINES.md`
+
+---
+
+## Problem
+
+All Skulpt lab textareas had a fixed `height: 260px` set in CSS. Short programs
+(3–5 lines) had too much empty space; long programs (20+ lines) required scrolling.
+A first attempt at auto-sizing used a line-count formula (`lineCount × 22 + 24 px`)
+but still left several blank rows at the bottom of the textarea for programs like
+the 27-line stop-sign example.
+
+Two bugs combined to cause the over-sizing:
+
+1. **Trailing newline inflation** — every textarea in the markdown source has a
+   `\n` immediately before ``. `value.split('\n')` counts this as an
+   extra empty line, inflating the calculated height by one full line-height.
+
+2. **Incorrect line-height estimate** — the formula assumed 22 px per line, but
+   the browser renders Courier New at 14 px with an actual line-height of roughly
+   17–18 px. The 4 px over-estimate per line compounded across 27 lines produced
+   ~108 px of extra blank space (≈ 6 blank rows).
+
+---
+
+## Solution
+
+Replace the manual formula with `scrollHeight`, which lets the browser measure
+the exact pixel height of the textarea content at its actual font metrics.
+
+### Step 1 — Strip trailing newlines before measuring
+
+```javascript
+var saved = code.value;
+code.value = code.value.replace(/\n+$/, '');  // remove trailing blank line(s)
+```
+
+The original value is saved and restored immediately after measurement so the
+**Reset** button still works correctly.
+
+### Step 2 — Collapse the textarea and read scrollHeight
+
+```javascript
+code.style.height = '0px';
+code.style.height = Math.max(120, code.scrollHeight + 4) + 'px';
+code.value = saved;
+```
+
+- Setting `height: 0px` (inline style, overrides CSS) forces the browser to
+  make all content overflow, so `scrollHeight` reflects the full content height.
+- `scrollHeight` returns **content height + padding** but does **not** include
+  borders. Adding `+4` compensates for the 2 px top + 2 px bottom border under
+  `box-sizing: border-box`.
+- `Math.max(120, ...)` guarantees a minimum height of 120 px for very short
+  programs (1–4 lines).
+
+### Step 3 — Remove fixed height from CSS
+
+`skulpt.css` was changed from `height: 260px` to `min-height: 120px`. The CSS
+minimum acts as a fallback if JavaScript is slow or unavailable; the JS inline
+style always takes over and sets the exact height.
+
+---
+
+## Result
+
+| Program | Lines | Old height | New height (approx) |
+|---------|-------|-----------|---------------------|
+| Hello World (3 lines) | 3 | 260 px | 120 px (min) |
+| Simple square (9 lines) | 9 | 260 px | ~182 px |
+| Stop sign (27 lines) | 27 | 260 px | ~510 px |
+| Colored square (18 lines) | 18 | 260 px | ~346 px |
+
+The textarea now fits exactly the initial code with no blank rows, no scrollbar,
+and students can still drag the resize handle to expand it if they add more lines.
+
+---
+
+## Why scrollHeight is better than a formula
+
+| Approach | Handles wrapping? | Accurate line-height? | Trailing-newline safe? |
+|----------|------------------|----------------------|----------------------|
+| `lineCount × 22 + 24` | No | No (estimate) | No |
+| `scrollHeight` (trimmed) | Yes | Yes (browser measures) | Yes (trimmed before read) |
+
+The `scrollHeight` approach is immune to font changes, browser zoom differences,
+and long lines that wrap inside the textarea — all cases where a px-per-line
+formula would give the wrong answer.
diff --git a/mkdocs.yml b/mkdocs.yml
index 2a05bca5..1d99bb30 100755
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,6 +1,52 @@
-site_name: 'CoderDojo TC Python'
+site_name: 'Beginning Python'
+site_description: 'Resources for teaching Python to beginning programmers.'
+site_author: 'Dan McCreary'
+repo_name: 'GitHub Repo'
+repo_url: 'https://github.com/dmccreary/python'
+site_url: 'https://dmccreary.github.io/python/'
+
 nav:
-  - CoderDojo TC: https://coderdojotc.github.io/CoderDojoTC/
+  - Course Description: course-description.md
+  - Chapters:
+    - List of Chapters: chapters/index.md
+    - 1. Welcome to Python and Skulpt: chapters/01-welcome-to-python/index.md
+    - 2. Python Code Structure: chapters/02-python-code-structure/index.md
+    - 3. Variables and Numbers: chapters/03-variables-and-numbers/index.md
+    - 4. Functions and Objects: chapters/04-functions-and-objects/index.md
+    - 5. Drawing with Turtle Graphics: chapters/05-drawing-with-turtle/index.md
+    - 6. Math and Arithmetic: chapters/06-math-and-arithmetic/index.md
+    - 7. For Loops and Drawing Shapes: chapters/07-for-loops-and-shapes/index.md
+    - 8. Working with Strings: chapters/08-working-with-strings/index.md
+    - 9. Making Decisions with If/Else: chapters/09-decisions-if-else/index.md
+    - 10. While Loops and Animation: chapters/10-while-loops-and-animation/index.md
+    - 11. Functions with Parameters and Scope: chapters/11-functions-parameters-scope/index.md
+    - 12. Colors, Fill, and Turtle Art: chapters/12-colors-fill-turtle-art/index.md
+    - 13. User Input and Type Conversion: chapters/13-user-input-type-conversion/index.md
+    - 14. String Methods and Formatting: chapters/14-string-methods-formatting/index.md
+    - 15. Lists - Basics: chapters/15-lists-basics/index.md
+    - 16. Lists - Methods and Patterns: chapters/16-lists-methods-patterns/index.md
+    - 17. Modules and Random Numbers: chapters/17-modules-and-random/index.md
+    - 18. Math Module and Turtle Projects: chapters/18-math-module-turtle-projects/index.md
+    - 19. More Booleans and Conditionals: chapters/19-booleans-and-conditionals/index.md
+    - 20. Tuples and Sets: chapters/20-tuples-and-sets/index.md
+    - 21. Dictionaries: chapters/21-dictionaries/index.md
+    - 22. Advanced Collections and Built-in Functions: chapters/22-advanced-collections/index.md
+    - 23. Error Handling and Debugging: chapters/23-error-handling-debugging/index.md
+    - 24. Recursion and Fractals: chapters/24-recursion-and-fractals/index.md
+    - 25. Object-Oriented Programming: chapters/25-object-oriented-programming/index.md
+    - 26. File Input and Output: chapters/26-file-input-output/index.md
+    - 27. Standard Library and JSON: chapters/27-standard-library-json/index.md
+    - 28. Python Development Tools: chapters/28-python-dev-tools/index.md
+    - 29. Text Processing and Regular Expressions: chapters/29-text-processing-regex/index.md
+    - 30. Algorithms and Data Structures: chapters/30-algorithms-data-structures/index.md
+    - 31. Advanced Functions and OOP: chapters/31-advanced-functions-oop/index.md
+    - 32. Data Visualization with matplotlib: chapters/32-data-visualization-matplotlib/index.md
+    - 33. NumPy and Scientific Computing: chapters/33-numpy-scientific-computing/index.md
+    - 34. Image Processing with Pillow: chapters/34-image-processing-pillow/index.md
+    - 35. Advanced Turtle and Event-Driven Programming: chapters/35-advanced-turtle-event-driven/index.md
+    - 36. Computational Thinking and Best Practices: chapters/36-computational-thinking-best-practices/index.md
+    - 37. Machine Learning Foundations: chapters/37-machine-learning-foundations/index.md
+    - 38. Neural Networks and MNIST: chapters/38-neural-networks-and-mnist/index.md
   - Beginning Python - Trinket:
     - Introduction: trinket/00-introduction.md
     - Setting Up Trinket: trinket/01a-trinket-account.md
@@ -25,6 +71,21 @@ nav:
     - Changing background: trinket/16-changing-background.md
     - Controlling mouseclicks: trinket/17-controlling-mouseclicks.md
     - Other examples: trinket/examples.m 
+  - Beginning Python - Skulpt (self-hosted):
+    - Draw a Square: skulpt/02-simple-square.md
+    - Stop Sign: skulpt/04a-stop-sign.md
+    - Reading Errors: skulpt/10-debugging.md
+    - Text-Only Example: skulpt/text-only-example.md
+  - Reference:
+    - Mascot Style Guide: learning-graph/mascot-test.md
+  - Learning Graph:
+    - Introduction: learning-graph/index.md
+    - Course Description Assessment: learning-graph/course-description-assessment.md
+    - Concept List v1: learning-graph/concept-list-v1.md
+    - Concept List: learning-graph/concept-list.md
+    - Graph Quality Analysis: learning-graph/quality-metrics.md
+    - Concept Taxonomy: learning-graph/concept-taxonomy.md
+    - Taxonomy Distribution Report: learning-graph/taxonomy-distribution.md
   - Beginning Python - Repl.it:
     - Square: repl/02-square.md
     - Flower: repl/07-flower.md
@@ -59,36 +120,52 @@ nav:
   - Advanced Python:
     - Stock Ticker Analysis: advanced/stocks.md
     - MNIST Digit Prediction: advanced/mnist.md
-    
+  - Strategy:
+    - Introduction: strategy/index.md
+    - Order of Concepts: order-of-cocepts.,d
+  - MicroSims:
+    - Learning Graph Viewer: sims/graph-viewer/index.md
   - Contributing:
     - How to Contribute Examples: contribute.md
+  - About: about.md
   - Contact:
     - Contact: contact.md
 
-site_description: 'Resources for teaching Python to CoderDojo Twin Cities students.'
-site_author: 'Dan McCreary'
-repo_name: 'python'
-repo_url: 'https://github.com/CoderDojoTC/python'
 
-# CoderDojo Standards from here down
+
+# Site configuration
 edit_uri: 'blob/master/docs'
 theme:
   name: material
-  logo: img/coderdojo-logo.png
+  logo: img/python-logo.jpeg
   palette:
     primary: '#642580'
     accent: '#41BAC1'
-  feature:
-    tabs: true
+  features:
+    - content.code.copy
   custom_dir: 'theme'
   include_sidebar: true
 markdown_extensions:
   - admonition
+  - attr_list
   - footnotes
+  - md_in_html
+  - pymdownx.details
   - pymdownx.highlight
   - pymdownx.superfences
   - toc:
       permalink: true
 plugins:
     - search
+extra_css:
+  - css/skulpt.css
+  - css/mascot.css
+extra_javascript:
+  - js/skulpt.js
+# Google Analytics Site ID: G-EP38Z3PVD5
+extra:
+  analytics:
+    provider: google
+    # https://analytics.google.com/analytics/web/#/p368752593/reports/intelligenthome
+    property: G-EP38Z3PVD5
 
diff --git a/src/draw-for-squares-input-colors.py b/src/draw-for-squares-input-colors.py
new file mode 100644
index 00000000..c52d21f0
--- /dev/null
+++ b/src/draw-for-squares-input-colors.py
@@ -0,0 +1,36 @@
+# J.E. Tannenbaum
+# Released: 11/10/2021 - Initial release
+# 11/10/2021 - Cleaned up and added comments
+# https://trinket.io/python/94326b4743
+
+import turtle		      # Load the library
+jet = turtle.Turtle()	# Create the turtle object and name it
+jet.shape("turtle")	  # Set the shape
+
+def drawIt(color, distance, angle):
+  jet.color(color)
+  jet.begin_fill()
+  jet.forward(distance)
+  jet.right(angle)
+  jet.forward(distance)
+  jet.right(angle)
+  jet.forward(distance)
+  jet.right(angle)
+  jet.forward(distance)
+  jet.end_fill()
+  
+# Set the distance and angle variables
+distance = 40
+angle = 90
+
+colors = []
+for i in range(4):
+  color = input("Enter a color:")
+  colors = colors + [color]
+
+for color in colors:
+  drawIt(color, distance, angle)
+
+# We are done, so hide the turtle
+jet.hideturtle()
+