Skip to main content
0 / 7
Chapter IV of VI

Sorting Shapes with Conditionals

Use if, else, and Boolean logic to sort triangles, quadrilaterals, and angles by their properties. Meet Input() — an interactive value you can change on the fly — so you can test each classifier against dozens of shapes without rewriting a single line.

If It's True

Sometimes you want code to run only when a certain condition is met. Swift's if statement does exactly that — it's the gateway from data into decisions.

An if statement checks a condition — an expression that's either true or false — and runs one block of code if it's true, and optionally a different block (else) if it's false.

Swift
let sides = 4

if sides == 4 {
    // this block runs only when sides equals 4
    print("This is a quadrilateral")
} else {
    // this block runs for any other value
    print("Not a quadrilateral")
}

Notice the == (two equals signs). In Swift, = means "assign a value" while == means "are these equal?" — it's a common beginner trap.

Here are all of Swift's comparison operators:

Operators
a == b   // equal to
a != b   // not equal to
a <  b   // less than
a <= b   // less than or equal to
a >  b   // greater than
a >= b   // greater than or equal to

Conditions that evaluate to true or false are called Boolean expressions, named after the 19th-century mathematician George Boole who invented the algebra of logic.

Only two values. A Boolean can be one of exactly two things: true or false. No "maybe", no "sort of", no "null". This two-valued logic is the foundation of all digital circuits — every electronic device you use is built from billions of tiny switches, each one in one of exactly two states. Boolean logic is also the foundation of mathematical proof: a statement is either true or it isn't.
Comparison makes a Boolean. Writing sides == 4 doesn't do anything by itself — it just produces a value, either true or false. The if statement then looks at that value and decides which block to run. You can even store the result: let isQuad = (sides == 4) — now isQuad is a Boolean variable you can reuse.
Same-type rule. Swift is strict about types — you can only compare values of the same type. 5 == 5.0 is a compile error because 5 is an Int and 5.0 is a Double. To compare them, convert one: Double(5) == 5.0. You'll see this again in Section 02 when we start mixing integer inputs with decimal values.
Curriculum Connections
ConceptConnection
Logic & ReasoningBoolean expressions are the foundation of mathematical logic. A condition is either true or false — there's no middle ground — mirroring two-valued logic in proofs and set theory. Swift's ==, !=, <, >, <=, >= are direct translations of the mathematical comparison symbols =, , <, >, , .

Classify an Angle

Write code that classifies an angle as acute, right, or obtuse based on its value in degrees. Then we'll meet Input() — an interactive value that lets you test every angle without editing your code.

  • Acute: less than 90°
  • Right: exactly 90°
  • Obtuse: greater than 90° and less than 180°

New tool: Input()

Up to this point, whenever you wanted to test with a different value you had to edit your code:

Old way — edit to test
let angle = 45   // change this number every time you want to try a different angle

Swift Playgrounds gives you a better way: Input(). It creates an interactive slider or text field right next to your code that you can drag or type into, and your code re-runs automatically with the new value. No more editing!

New way — Input()
let angle = Input(number: 45, id: "angle")

There are three flavours of Input, one per type:

Three types
let count  = Input(number: 5,       id: "count")   // Int — whole numbers
let side   = Input(decimal: 3.5,   id: "side")    // Double — decimals
let name   = Input(text: "square", id: "name")    // String — text

The first parameter is the default value (what Input shows before you change it), and id is the label Swift uses to identify this particular input on screen — give each input a unique id.

Playing with types. Notice that each flavour of Input produces a value of a different type: Input(number:) gives you an Int, Input(decimal:) gives you a Double, and Input(text:) gives you a String. This matters because Swift is strict — you can't compare a Double with an Int directly. For whole-number angles like 45 or 90, use Input(number:). For lengths like 3.6 or 10.5, use Input(decimal:).
Unique ids. Each Input in your program needs its own id — otherwise Swift can't tell them apart. Use descriptive names like "angle", "side a", "sides", so when you're looking at the interactive controls you know which one is which.
Boundary cases. When classifying a continuous range (angles from 0° to 180°), think carefully about the boundaries. Is 90° "acute" or "right"? Is 180° "obtuse" or "straight"? Pick explicit rules (right = exactly 90°, obtuse = strictly between 90° and 180°) and make your if/else if chain match them exactly. Off-by-one or boundary bugs are among the most common errors in classification code.

Try your code with the values 45, 90, and 120 by dragging the Input slider.

Solution
let angle = Input(number: 45, id: "angle")

if angle < 90 {
    print("Acute")
} else if angle == 90 {
    print("Right")
} else {
    print("Obtuse")
}
What about angles above 180°? This solution labels anything > 90 as "Obtuse" — including 200° or 350°, which are actually reflex angles. Section 05 ("And & Or") extends this classification to the full 0°–360° range using compound conditions like angle > 90 && angle < 180. For this exercise, assume the angle is between 0° and 180°.
Curriculum Connections
ConceptConnection
Geometry — Angle ClassificationAngles are classified by measure: acute (0°–90°), right (90°), obtuse (90°–180°), straight (180°), reflex (180°–360°). Identifying angle types is fundamental to geometry. The Swift if/else if chain mirrors the mutually exclusive categories — an angle can only fall into one.

Else If

When you have more than two possible outcomes, chain multiple conditions with else if. Swift checks them in order and takes the first branch that's true.

You already used else if in Section 02 to handle three angle types. Let's look at the pattern more carefully — and use Input() so you can test any number of sides interactively.

Swift
let sides = Input(number: 5, id: "sides")

if sides == 3 {
    print("Triangle")
} else if sides == 4 {
    print("Quadrilateral")
} else if sides == 5 {
    print("Pentagon")
} else if sides == 6 {
    print("Hexagon")
} else {
    print("Other polygon")
}
Top-to-bottom, first match wins. Swift evaluates each condition in order from top to bottom. As soon as it finds one that's true, it runs that block and skips all the rest. That means order matters — if two conditions could both be true, only the first one runs. You'll see this matter a lot in the triangle and quadrilateral classifiers coming up.
Mutually exclusive vs. overlapping. The polygon example is mutually exclusive: sides can only be one value, so only one branch can ever match. The triangle classifier in Section 04 is overlapping: an equilateral triangle is also isosceles (by definition). In the overlapping case, the order of your else if chain decides which label you give it — more specific categories must come first.
Always think about the else. The final else catches everything that didn't match. If you forget it, inputs you haven't thought of will silently do nothing. A common trick is to put a sanity-check print in the final else, so you'll notice when an unexpected value sneaks through.
Curriculum Connections
ConceptConnection
Geometry — Polygon ClassificationPolygons are classified by number of sides: 3 = triangle, 4 = quadrilateral, 5 = pentagon, 6 = hexagon, 7 = heptagon, 8 = octagon, … Each classification is a mutually exclusive category — a shape can only have one number of sides. The if/else if/else chain mirrors this partition exactly.

Triangle Classifier

Given three side lengths (using Input(decimal:) so you can try different combinations), classify the triangle as equilateral, isosceles, or scalene, and check whether it's also a right triangle.

  • Equilateral: all three sides equal (e.g. 5, 5, 5)
  • Isosceles: at least two sides equal (e.g. 5, 5, 8)
  • Scalene: all three sides different (e.g. 3, 4, 5)

You can also check if the triangle is a right triangle using the Pythagorean theorem: a² + b² = c², where c is the longest side. Test with (3, 4, 5), (5, 5, 5), and (5, 5, 8).

You'll need && (AND) and || (OR) to combine side comparisons. We'll formalise these logical operators in Section 05 — for now, just know that a == b && b == c means "all three are equal" and a == b || b == c || a == c means "at least two are equal".

Triangle inequality. Not every triple of positive numbers is a valid triangle! For three sides to form a triangle, each side must be shorter than the sum of the other two: a + b > c, a + c > b, b + c > a. Try (1, 2, 10) — those three lengths can't close into a triangle, because the longest side is longer than the other two combined. This is a built-in property of geometric space, not just a rule someone made up.
Order of checks matters here. Every equilateral triangle is also isosceles (isosceles means "at least two sides equal", and equilateral means "all three equal" — which certainly includes "at least two"). So if you check isosceles first, an equilateral triangle will be labelled "isosceles" — technically true but not specific enough. Check the most specific category first (equilateral), then the less specific one (isosceles), then the default (scalene). This is the same pattern you'll use for the quadrilateral classifier in Section 06.
Squaring vs. pow(). To test a² + b² = c², you can write a*a + b*b == c*c — just multiply the variable by itself. Swift does have a pow() function, but for simple squaring, x*x is clearer and slightly faster.
Double comparison is exact. When you compare two Double values with ==, Swift checks whether they're exactly equal bit-for-bit. If you try (0.1 + 0.2) == 0.3, you'll get false due to how decimal fractions are stored in binary. For this exercise's whole-number test cases (3, 4, 5) it's fine, but for real-world floating-point geometry you'd check whether the difference is smaller than a tiny "epsilon" value.
Solution
let a = Input(decimal: 3, id: "side a")
let b = Input(decimal: 4, id: "side b")
let c = Input(decimal: 5, id: "side c")

// ── 1. Triangle inequality check ─────────────────────
if a + b <= c || a + c <= b || b + c <= a {
    print("Not a valid triangle!")
} else {
    // ── 2. Side classification (most specific first) ────
    if a == b && b == c {
        print("Equilateral")
    } else if a == b || b == c || a == c {
        print("Isosceles")
    } else {
        print("Scalene")
    }

    // ── 3. Right triangle check (find the longest side) ─
    var longest = a
    var x = b
    var y = c
    if b > longest {
        longest = b
        x = a
        y = c
    }
    if c > longest {
        longest = c
        x = a
        y = b
    }
    if x*x + y*y == longest*longest {
        print("Also a right triangle!")
    }
}
Why the extra "longest side" hunt? The Pythagorean theorem a² + b² = c² only holds when c is the longest side (the hypotenuse). If your inputs are (5, 3, 4), you need to recognise that 5 is the longest and compare 3² + 4² = 5². If you just naively used whichever variable you called c, you'd miss right triangles whose longest side is in a different variable.
Curriculum Connections
ConceptConnection
Geometry — TrianglesTriangle classification by sides: equilateral (all equal), isosceles (two equal), scalene (all different). The triangle inequality (each side shorter than the sum of the other two) is a necessary condition for three lengths to form a triangle. The Pythagorean theorem a² + b² = c² identifies right triangles when c is the hypotenuse.

And & Or

Swift's logical operators let you combine conditions: && (AND), || (OR), and ! (NOT). Use them to classify an angle across the full 0°–360° range.

Operators
a && b   // AND: true only if BOTH a and b are true
a || b   // OR:  true if AT LEAST ONE of a or b is true
!a       // NOT: inverts the truth value

Truth tables — the complete specification of each operator:

Truth tables
// AND (&&)
// a     | b     | a && b
// true  | true  | true
// true  | false | false
// false | true  | false
// false | false | false

// OR (||)
// a     | b     | a || b
// true  | true  | true
// true  | false | true
// false | true  | true
// false | false | false

// NOT (!)
// a     | !a
// true  | false
// false | true

Given an angle in degrees, classify it as one of:

  • Zero angle (= 0°)
  • Acute (0° < angle < 90°)
  • Right (= 90°)
  • Obtuse (90° < angle < 180°)
  • Straight (= 180°)
  • Reflex (180° < angle < 360°)
  • Full rotation (= 360°)
Compound inequalities. In mathematical notation you'd write "90° < angle < 180°" — a single expression with two inequalities. Swift doesn't allow that directly; you have to split it into two parts joined by &&: angle > 90 && angle < 180. Same idea, different syntax. The && is essential — it says "both conditions must be true for the angle to count as obtuse".
Short-circuit evaluation. Swift is lazy with && and ||: if the first operand already settles the answer, the second is never evaluated. For a && b, if a is false, the whole expression is false no matter what b is — so Swift skips b. Same for a || b: if a is true, the whole expression is true, so b is skipped. This matters when the second operand has side effects or might crash (e.g. dividing by zero) — you can use short-circuiting to guard against it.
De Morgan's laws. Here's a pair of logical identities that every programmer learns eventually:
  • !(a && b) == !a || !b
  • !(a || b) == !a && !b
In English: "not both" equals "either not the first or not the second". Useful when you want to invert a compound condition — instead of wrapping everything in !(...), you can distribute the ! inside and flip && to || (or vice versa).
Solution
let angle = Input(number: 135, id: "angle")

if angle == 0 {
    print("Zero angle")
} else if angle > 0 && angle < 90 {
    print("Acute")
} else if angle == 90 {
    print("Right")
} else if angle > 90 && angle < 180 {
    print("Obtuse")
} else if angle == 180 {
    print("Straight")
} else if angle > 180 && angle < 360 {
    print("Reflex")
} else if angle == 360 {
    print("Full rotation")
} else {
    print("Out of range (0°–360°)")
}
Why no redundant bounds checks? Notice that the "Obtuse" branch only checks angle > 90 && angle < 180 — it doesn't also check angle != 90. That's because Swift already handled angle == 90 in the previous branch, and "first match wins" means we never reach "Obtuse" if the angle was exactly 90. The else if chain lets you trust that earlier conditions have already been ruled out.
Curriculum Connections
ConceptConnection
Logic & Reasoning — Boolean AlgebraAngles are classified across the full 0°–360° range. Compound inequalities (e.g. 90° < angle < 180°) represent intervals on the number line — a key IM1 concept. Boolean operators &&, ||, ! correspond exactly to the logical connectives ∧, ∨, ¬ in mathematical logic, and De Morgan's laws are the basis for simplifying any Boolean expression.

Quadrilateral Checker

Given four side lengths and two booleans describing whether the sides are parallel and whether the angles are right angles, classify the shape.

  • Square: all sides equal + both pairs parallel + right angles
  • Rhombus: all sides equal + both pairs parallel, but not right angles
  • Rectangle: opposite sides equal + both pairs parallel + right angles
  • Parallelogram: opposite sides equal + both pairs parallel (no angle requirement)
  • Trapezoid: at least one pair of parallel sides
  • Irregular quadrilateral: none of the above
The quadrilateral hierarchy. Quadrilaterals form a nested hierarchy of increasingly specific shapes:
  • Every square is a rhombus (all sides equal) AND a rectangle (all angles 90°)
  • Every rhombus is a parallelogram (opposite sides parallel)
  • Every rectangle is a parallelogram
  • Every parallelogram is a trapezoid (has at least one pair of parallel sides)
  • Every trapezoid is a quadrilateral (4 sides)
So: square ⊂ rhombus ⊂ parallelogram ⊂ trapezoid ⊂ quadrilateral, and also square ⊂ rectangle ⊂ parallelogram. A square lives in the intersection of "rhombus" and "rectangle".
Subclass checks must come first. Because a square is also a rhombus, rectangle, parallelogram, and trapezoid, checking "is it a square?" must come before "is it a rhombus?", which must come before "is it a parallelogram?", and so on. This is the same "most specific first" rule you used in the triangle classifier (Section 04) — an equilateral triangle is also an isosceles triangle, so you checked equilateral first.
Intermediate variables make complex conditions readable. Rather than writing top == right && right == bottom && bottom == left inline three times, store it in a named variable: let allSidesEqual = .... Now your if statements read like English: if allSidesEqual && bothParallel && rightAngles. This is a key technique for keeping classifier code understandable.
Solution
// Four side lengths (in canvas units)
let top    = Input(decimal: 80, id: "top")
let right  = Input(decimal: 80, id: "right")
let bottom = Input(decimal: 80, id: "bottom")
let left   = Input(decimal: 80, id: "left")

// Two boolean properties (change these to test different shapes)
let horizontalParallel = true   // top ∥ bottom
let verticalParallel   = true   // left ∥ right
let rightAngles        = true   // all four corners = 90°

// ── Derived properties (named Booleans) ──────────────
let allSidesEqual    = top == right && right == bottom && bottom == left
let oppositeSidesEqual = top == bottom && left == right
let bothPairsParallel  = horizontalParallel && verticalParallel
let somePairParallel   = horizontalParallel || verticalParallel

// ── Classify (most specific first!) ──────────────────
if allSidesEqual && bothPairsParallel && rightAngles {
    print("Square")
} else if allSidesEqual && bothPairsParallel {
    print("Rhombus")
} else if oppositeSidesEqual && bothPairsParallel && rightAngles {
    print("Rectangle")
} else if oppositeSidesEqual && bothPairsParallel {
    print("Parallelogram")
} else if somePairParallel {
    print("Trapezoid")
} else {
    print("Irregular quadrilateral")
}
What was wrong with the "without rightAngles" version? If you only checked side lengths and parallelism, you couldn't distinguish a square from a rhombus — they share those properties. The rightAngles flag is what separates them: a square has right angles, a rhombus doesn't. Same for rectangle vs parallelogram. This is why real geometry tools need to look at angles, not just side lengths, to classify quadrilaterals fully.
Curriculum Connections
ConceptConnection
Geometry — QuadrilateralsQuadrilaterals form a hierarchy: square ⊂ (rhombus ∩ rectangle) ⊂ parallelogram ⊂ trapezoid ⊂ quadrilateral. Boolean logic mirrors set inclusion — a square satisfies all conditions that a rectangle satisfies, plus more. The order of classification checks encodes the "most specific first" principle from set theory.

Right Angle Test

Given three angles of a triangle (as Input(number:)), write a program that verifies they sum to 180°, checks for a right angle, and checks for equiangularity.

  1. Verifies that all three angles sum to 180° (prints a warning if not)
  2. Checks whether the triangle is right-angled (has at least one 90° angle)
  3. Checks whether it is equiangular (all three angles equal)

Test with (90, 45, 45), (60, 60, 60), (30, 60, 90), and (60, 60, 70) — the last one should fail the sum test.

The triangle angle sum theorem. For any triangle in flat (Euclidean) space, the three interior angles always sum to exactly 180°. This is one of the most important theorems in elementary geometry — it's what distinguishes flat geometry from spherical or hyperbolic geometry (where the sum would be more or less than 180°). A triple of angles that doesn't sum to 180° cannot form a triangle in the plane.
Validation first, then classification. Notice the structure: first check whether the input even makes sense (do the angles sum to 180°?), then classify if it does. This "guard early, process later" pattern is a universal programming technique — don't waste time classifying bad input, and don't let bogus results leak out. You used the same pattern in Section 04 with the triangle inequality check.
Equiangular ↔ equilateral. For triangles specifically, "all angles equal" is logically equivalent to "all sides equal". If all three angles are the same, they must each be 60° (because 60 + 60 + 60 = 180), and that forces all three sides to be the same length. This equivalence is unique to triangles — for other polygons, equiangular and equilateral are independent properties (a rectangle is equiangular but not equilateral; a rhombus is equilateral but not equiangular).
Independent checks need nested ifs, not else if. A triangle can be both right-angled and equiangular only if... well, it can't (a 90° angle prevents equiangularity). But more generally, a triangle could have multiple classifications — right AND isosceles, for example. When classifications aren't mutually exclusive, use separate if statements rather than an else if chain, so each check runs independently.
Solution
let a1 = Input(number: 90, id: "angle 1")
let a2 = Input(number: 45, id: "angle 2")
let a3 = Input(number: 45, id: "angle 3")

// Guard: do the angles sum to 180°?
if a1 + a2 + a3 != 180 {
    print("Warning: angles don't sum to 180°")
} else {
    // Two independent classifications — neither excludes the other
    if a1 == 90 || a2 == 90 || a3 == 90 {
        print("Right triangle")
    }
    if a1 == a2 && a2 == a3 {
        print("Equiangular (therefore equilateral)")
    }
}
A 45-45-90 triangle. The test case (90, 45, 45) is a right isosceles triangle — half of a square cut along its diagonal. It has one 90° angle (hence "right"), and two equal 45° angles (hence "isosceles"). Both properties are true at the same time, which is why the two if statements need to be independent rather than chained with else if.
Curriculum Connections
ConceptConnection
Geometry — Triangle Angle SumThe angle sum property of triangles states that the three interior angles always sum to 180° in Euclidean (flat) geometry. An equiangular triangle has three 60° angles and must also be equilateral — the "equiangular ↔ equilateral" equivalence is a defining property of triangles, not shared by other polygons.

Colour by Rule

Draw a row of squares using a loop, and colour each square based on a rule: squares in positions divisible by 3 get one colour, positions divisible by 2 (but not 3) get another, and the rest get a third colour.

The modulo operator %. Swift's % gives the remainder after division. 7 % 3 is 1 (because 7 = 2·3 + 1). i % 3 == 0 is true exactly when i is divisible by 3. This is the single most useful operator for number theory: divisibility, parity (odd vs even via i % 2), cyclic patterns (i % n wraps around every n steps), and any "every Nth thing" pattern.
Order matters: % 3 must come before % 2. The number 6 is divisible by both 2 and 3, so both i % 3 == 0 and i % 2 == 0 are true for it. With an if/else if chain, only the first matching branch runs — so if you check % 3 first, 6 gets the "divisible by 3" colour; if you check % 2 first, 6 gets the "divisible by 2" colour. The exercise asks for the first behaviour, so the % 3 check comes first. Same principle as "most specific first" from Sections 04 and 06.
Counting from 1 vs. from 0. Swift's for i in 1...12 counts from 1 to 12 inclusive. If you wrote for i in 0..<12 you'd get 0 through 11. For this exercise, the "position" of the square is 1-indexed (human counting), so 1...12 is more natural. Be careful which convention you use — array indices in Swift are 0-indexed, but human "position in a sequence" is usually 1-indexed.
Solution
import UIKit

let count: Int = Input(number: 12, id: "count")
let size: Double = 40
let gap: Double  = 10
let startX: Double = -240

for i in 1...count {
    // Pick a colour based on divisibility
    let color: UIColor
    if i % 3 == 0 {
        color = .blue       // 3, 6, 9, 12, …
    } else if i % 2 == 0 {
        color = .yellow     // 2, 4, 8, 10, … (not also divisible by 3)
    } else {
        color = .red        // 1, 5, 7, 11, …
    }

    // Draw a filled square at the computed x position
    var square = Pen()
    square.penColor  = color
    square.fillColor = color
    square.goto(
        x: startX + Double(i - 1) * (size + gap),
        y: -size / 2
    )
    for _ in 1...4 {
        square.addLine(distance: size)
        square.turn(degrees: 90)
    }
    addShape(pen: square)
}
Why create a new square pen each loop? Each square needs its own colour and its own starting position. Creating a fresh Pen() inside the loop guarantees both — the colour is set once per square, and goto jumps the new pen to the right x position before drawing. This is the "one pen per shape" pattern you learned in Chapter II (Shape Properties with Variables).
Curriculum Connections
ConceptConnection
Number — DivisibilityThe modulo operator checks divisibility — a key number theory concept. Multiples of 3 and multiples of 2 create overlapping sets (their intersection is multiples of 6). The union and intersection of these sets can be described using Boolean logic, and the order of else if checks determines which label overlapping elements receive.

Polygon Properties

Write a program that, given Inputs for the number of sides and the side length of a regular polygon, calculates and prints key properties, then draws the polygon. Drag the sliders to explore any regular polygon from a triangle to a hexagon to a decagon.

Calculate and print all of these:

  1. The exterior angle (360° ÷ n)
  2. The interior angle (180° − exterior)
  3. The perimeter (n × side length)
  4. Whether the polygon is convex (always true for regular polygons — use an if to check and explain why)

Then use a loop (from Chapter III) to draw the polygon with the calculated exterior angle as the turn.

The two angle formulas. For a regular polygon with n sides:
  • Each exterior angle = 360° ÷ n. If you walked all the way around the polygon, your total turning would be exactly 360° (one full rotation) — divide that evenly across n corners.
  • Each interior angle = 180° − exterior = 180° − (360° ÷ n). The interior angle and exterior angle at each vertex sum to 180° because together they form a straight line.
For a triangle (n = 3): exterior = 120°, interior = 60°. For a square: 90° and 90° (the only regular polygon where they're equal). For a hexagon: 60° and 120°. For a decagon: 36° and 144°.
Why are all regular polygons convex? A polygon is convex when every interior angle is less than 180°. For a regular n-gon, the interior angle is 180° − (360° ÷ n) = 180 × (1 − 2/n). For n ≥ 3, 2/n ≤ 2/3, so the interior angle is at most 180 × (1 − 0) = 180° and at least 180 × (1 − 2/3) = 60°. It's strictly less than 180° for any finite n, so the polygon is convex. A concave polygon would have at least one "dent" where an interior angle exceeds 180° — that can only happen in irregular polygons.
Int vs Double: why do we cast n? Input(number:) gives you an Int (whole number), but 360.0 / 3 in Swift won't automatically produce a Double if both sides are Int. You need 360.0 / Double(n) to force floating-point division. This is the same type-casting trick you learned in Chapter III when computing angles for regular polygons — Double(n) converts an integer to a decimal so the division produces a Double result.
Preview of Chapter V. Notice how this code "hardcodes" the specific polygon — you have to rerun it to draw a different shape. In the next chapter, you'll learn to package this logic into a reusable function like drawRegularPolygon(sides:, sideLength:) that you can call with any arguments. For now, Input gets you most of the interactivity without the full function syntax.
Solution
let n = Input(number: 7, id: "sides")
let sideLength = Input(decimal: 60, id: "side length")

// Calculate properties
let exteriorAngle = 360.0 / Double(n)
let interiorAngle = 180.0 - exteriorAngle
let perimeter     = Double(n) * sideLength

print("Exterior angle: \(exteriorAngle)°")
print("Interior angle: \(interiorAngle)°")
print("Perimeter: \(perimeter)")

// Convexity check
if interiorAngle < 180 {
    print("Convex — all interior angles are less than 180°")
} else {
    print("Not convex")
}

// Draw the polygon (using the loop from Chapter III)
for _ in 1...n {
    pen.addLine(distance: sideLength)
    pen.turn(degrees: exteriorAngle)
}
String interpolation with \(). Inside a string literal, \(expression) inserts the value of that expression. "Perimeter: \(perimeter)" becomes "Perimeter: 420.0" (or whatever the current value is). This is Swift's equivalent of printf formatting — clean, type-safe, and readable. You can use any expression inside the parentheses, not just a variable name.
Curriculum Connections
ConceptConnection
Geometry — Regular PolygonsAll interior angles of a regular polygon are equal to 180° − (360° ÷ n). A polygon is convex when all interior angles are less than 180° — a condition satisfied by all regular polygons with n ≥ 3. The relationship between n, interior angle, exterior angle, and perimeter is the classic set of regular polygon formulas from IM1 geometry.