Shape Rule
only odd row widths
Row lengths are 7, 5, 3, 1 — each row prints 1 through i with no even-width lines.

The odd-length descending number triangle teaches how a custom outer-loop step (i -= 2) skips even row widths. This tutorial covers the shape rule, loop structure, a live preview, algorithm steps, worked PHP examples, edge cases, and complexity.
only odd row widths
Row lengths are 7, 5, 3, 1 — each row prints 1 through i with no even-width lines.
Rows
for ($i = $max; $i >= 1; $i -= 2) visits only odd row lengths from the top down.
1..i ascending
for ($j = 1; $j <= $i; $j++) prints digits 1 through $i on every row.
Same line / next line
Digits use echo $j; end each row with echo PHP_EOL.
1–20 max
Pick an odd maximum and draw the odd-length descending triangle instantly in the browser.
Complexity
Total digit prints still = n(n+1)/2; extra memory stays O(1).
An odd-length descending number triangle prints ascending digits on each row, but only for odd row widths. With max = 7, the output is 1234567, 12345, 123, 1.
In PHP you solve it with a descending outer loop that steps by 2: for ($i = $max; $i >= 1; $i -= 2), an inner loop for ($j = 1; $j <= $i; $j++) that prints each digit, then echo PHP_EOL; ends each row.
It shows how changing the loop step creates entirely new shapes — not just different bounds.
i -= 2 skips even row widths.
Inner loop always prints 1..i on every row.
echo $j in the inner loop; echo PHP_EOL after.
Follow Program 13; continue to Program 15 (binary triangle).
In short: for each odd row length i from max down to 1 stepping by 2, print 1..i with echo $j, then call echo PHP_EOL.
Given a positive odd integer max (or adjusted to odd), print an odd-length descending number triangle: row length i prints digits 1 through i, with the outer loop stepping i -= 2 from max down to 1.
// max = 7 (conceptual shape)
// 1234567
// 12345
// 123
// 1 | Item | Type | Description |
|---|---|---|
max | int | Maximum (odd) row width — first row prints 1..max. |
| Printed output | text | Only odd-length rows; each prints ascending digits 1..i. |
for i from max down to 1 step -2:
for j from 1 to i:
print j (no newline)
print newline | Approach | Idea | Best for |
|---|---|---|
i -= 2 outer loop | Skip even row widths | Learning and interviews |
i-- outer loop | Print every width (7, 6, 5, …, 1) | Full descending triangle comparison |
| Goal | Pattern | |
|---|---|---|
| Walk each row | Walk odd row lengths | for ($i = $max; $i >= 1; $i -= 2) |
Print 1..i | for ($j = 1; $j <= $i; $j++) echo $j; | |
| End the row | echo PHP_EOL; | |
| Force odd max | if ($max % 2 === 0) $max -= 1; | |
| All widths variant | for ($i = $max; $i >= 1; $i--) (step by 1) | |
| Program 13 variant | if (i % 2 == 0) descending else ascending (zigzag) |
Same family of triangles — different outer-loop steps.
odd onlyPrints 7, 5, 3, 1 — skips even widths
all widthsPrints 7, 6, 5, 4, 3, 2, 1 — every row
ascendingAlways prints digits 1 through i on each row
step firstMaster i -= 2 before comparing with i--
Reach for this pattern when teaching custom loop steps and skipped iterations.
Most PHP pattern series start here before pyramids and diamonds.
Outer/inner bound practice with an immediate visual check.
Combine loops with fgets(STDIN) for a flexible row count.
Compare Program 13 (zigzag) and Program 15 (binary triangle) next.
This is a console teaching pattern — not how you build modern app screens.
Key benefit: one small program that locks in nested loops, output sequencing, and O(n²) thinking.
Enter an odd maximum between 1 and 20 and draw the odd-length descending triangle in the browser.
Three complete PHP programs — fixed maximum, configurable user input, and a step-by-1 comparison. Click View Output to reveal sample console results.
Print four odd-length rows starting from max = 7 with i -= 2.
max = 7Hard-coded height — ideal for first demos and screenshots.
<?php
for ($i = 7; $i >= 1; $i -= 2) {
for ($j = 1; $j <= $i; $j++) {
echo $j;
}
echo PHP_EOL;
} When i = 7, the inner loop prints 1234567. When i = 5, it prints 12345, and so on until i = 1 prints 1. The outer loop skips even lengths because of i -= 2. echo PHP_EOL; after the inner loop starts the next row.
Let the user choose the maximum row width at runtime.
Read an odd maximum with (int) trim(fgets(STDIN)); if the user enters an even number, subtract 1.
<?php
echo "Enter an odd maximum (e.g., 9): ";
$max = (int) trim(fgets(STDIN));
if ($max % 2 === 0) $max -= 1;
for ($i = $max; $i >= 1; $i -= 2) {
for ($j = 1; $j <= $i; $j++) {
echo $j;
}
echo PHP_EOL;
} Same nested-loop core as Example 1; $max comes from input and is forced odd with if ($max % 2 === 0) $max -= 1. Non-numeric input leaves max unset if you skip is_numeric() checks — always check it in safer labs.
Same ascending inner loop, but outer loop steps by 1 to include every width.
i--)Print every row width from 7 down to 1 — includes even-length rows for comparison.
<?php
$max = 7;
for ($i = $max; $i >= 1; $i--) {
for ($j = 1; $j <= $i; $j++) {
echo $j;
}
echo PHP_EOL;
} Changing i -= 2 to i-- includes every row width — even lengths like 123456 and 12 appear. Same inner loop; only the outer step changes the shape.
Set $max = 7; and use fgets(STDIN) when reading input. Set max (fixed or from input, forced odd if needed).
for ($i = $max; $i >= 1; $i -= 2) picks odd row lengths only; inner loop prints 1..$i.
for ($j = 1; $j <= $i; $j++) prints ascending digits with echo $j on every row.
echo PHP_EOL ends the row so the next outer iteration starts fresh.
Total digit prints: 1+2+…+n = n(n+1)/2 — O(n²) time, O(1) extra memory.
max = 7Trace each outer-loop value of i and note the ascending digits printed on each odd-length row.
i | Step from prev | Inner j range | Printed row |
|---|---|---|---|
7 | start | 1..7 | 1234567 |
5 | -2 | 1..5 | 12345 |
3 | -2 | 1..3 | 123 |
1 | -2 | 1..1 | 1 |
Skipped even lengths: 6, 4, 2. Total digit prints: 7+5+3+1 = 16.
Where this tiny pattern (and its loop structure) shows up beyond the homework prompt.
Clearest visual proof that outer and inner bounds interact.
Example: change j <= i and watch the shape change.
Foundation for inverted, pyramid, diamond, and hollow variants.
Example: change i -= 2 to i-- for a full descending triangle.
Practice echo vs PHP_EOL without complex math.
Example: put echo PHP_EOL inside the inner loop by mistake.
Swap digits for letters, stars, or spaced output once the loop works.
Example: use echo $j . " "; for spaced digits on each row.
Triangular totals make O(n²) concrete for beginners.
Example: count printed digits for n = 10 still → 55.
Pair the pattern with fgets(STDIN) and is_numeric() checks and positive-row validation.
Example: reject max <= 0 and re-prompt.
Pro Tip: when an interviewer asks for patterns, explain the outer/inner roles first — then write the loops. The story matters as much as the code.
Why this pattern earns a permanent spot in beginner C courses.
Wrong bounds show up immediately as a broken staircase.
Only loops and console output — no arrays or math libraries.
Invert, center, hollow, or change the fill character with small edits.
Streaming output needs no storage beyond loop counters.
Pro Tip: learn i -= 2 first; compare with i-- to see how the loop step changes the whole shape.
Small habits that keep number-pattern code clean.
Use max (or n) and keep i/j for row/column — or rename to row/col.
Call is_numeric(trim($line)) so bad input does not leave max uninitialized.
Only call echo PHP_EOL after the inner loop finishes the row.
if ($max % 2 === 0) $max -= 1; keeps the first row odd-length when reading input.
Trace max = 7 on paper before coding larger demos.
Pro Tip: if the output is a vertical list of single digits per line, you almost certainly put echo PHP_EOL inside the inner loop.
Mistakes that commonly break odd-length descending number patterns.
Each digit lands on its own line — you get a column, not a triangle.
→ Use echo $j for digits; echo PHP_EOL only after the inner loop.
i-- prints every width; i -= 2 starting from an even max skips the intended first row.
→ For odd-only rows, use for ($i = $max; $i >= 1; $i -= 2) with odd $max.
Omitting echo PHP_EOL glues every digit onto one endless line.
→ Always end the row after the inner loop.
Letters or empty input leave max uninitialized.
→ Prefer is_numeric() and re-prompt on failure.
Switching to i = 0 without adjusting the inner bound prints an empty first row or wrong counts.
→ If 0-based, print i with wrong inner bound (e.g. j <= i + 1).
Check these inputs before calling the solution done.
Output is just 1 on one line.
Outer loop never runs — print nothing or show a message.
max < 0Treat as invalid; re-prompt instead of silent empty output.
Output grows as n²/2 characters — fine for labs, noisy for huge n.
Unchecked fgets(STDIN) leaves max unset — call is_numeric(trim($line)) first.
Subtract 1 or prompt again — otherwise the first row may not match the odd-only rule.
Try these variations to lock in the pattern.
i % 2j % 2 on each rowmax and use i -= 2n.echo $j stays on the line; echo PHP_EOL advances — mix them carefully.max > 0 for interactive programs; max = 1 should print a single 1.Quick Takeaway: outer loop steps by 2 for odd widths, inner loop prints 1..i, then break the line.
| Program | Time | Extra space |
|---|---|---|
| Nested loops (Examples 1–2) | O(max²) | O(1) |
| Step by 1 (Example 3) | O(max²) | O(1) |
The odd-length descending number triangle is a compact lesson in loop steps: i -= 2 skips even widths while the inner loop always prints 1..i. Master the odd-only version, then compare with i-- for a full descending triangle.
Practice the three examples above, then continue to Program 15 for the alternating binary triangle.
Use $i -= 2 for odd-only rows and for ($j = 1; $j <= $i; $j++) for ascending digits — validate $max when reading input.
i -= 2 skips even widths before codingecho $j for digits and echo PHP_EOL after each rowmax ≥ 1 for interactive programsis_numeric(trim($line)) before using maxecho PHP_EOL inside the inner digit loopi-- when you meant odd-only rowsmax = 1 edge casePrint the pattern the beginner-friendly way.
Only odd row widths
DefinitionSteps by 2 downward
CodeAlways prints 1..i
CodeEnds each row
I/OO(n²) time
AnalysisOnly odd-length rows print. The outer loop uses $i −= 2 (7, 5, 3, 1) and the inner loop prints 1..$i — still O(n²) total digit prints for maximum width n.
Move on to the alternating binary number triangle in the PHP number-pattern series.
12 people found this page helpful