Shape Rule
Shrinking rows
Row 1 prints five 1s, row 2 prints four 2s, row 5 prints a single 1.

The bidirectional number triangle prints 11111, 2222, 333, 22, 1 — a natural step after the centered pyramid in Program 24. This tutorial covers shrinking rows, if/else digit mapping, a live preview, algorithm steps, worked PHP examples, edge cases, and complexity.
Shrinking rows
Row 1 prints five 1s, row 2 prints four 2s, row 5 prints a single 1.
i = 1..rows
for ($i = 1; $i <= $rows; $i++) walks each row top to bottom.
j = i..rows
for ($j = $i; $j <= $rows; $j++) prints fewer digits as i grows.
6 - i mirror
i < 4 prints i; else prints 6 - i for rows 4 and 5.
3–9 rows
Pick a row count and draw the bidirectional triangle instantly in the browser.
Complexity
Total prints are triangular — scales as n² for n rows.
A bidirectional number triangle prints repeated digits per row with shrinking length — digits rise then mirror down. With rows = 5, the output is 11111, 2222, 333, 22, 1.
In PHP you use an outer loop for rows, a shrinking inner loop j = i..rows, and an if/else to pick which digit to repeat.
It combines shrinking inner loops with conditional mapping — a step up from Program 24’s spacing logic.
j = i..rows — each row prints fewer digits.
i < 4 repeats 1, 2, 3.
6 - i produces 2 and 1 on last rows.
Follow Program 24; continue to Program 26 (diagonal asterisk) next.
In short: for each i, repeat a digit (rows - i + 1) times — use i when i < rows - 1, else rows + 1 - i.
Given a positive integer rows (e.g. 5), print a shrinking triangle where each row repeats one digit — rising on early rows, mirroring down on the last rows.
// rows = 5 (conceptual shape)
// 11111
// 2222
// 333
// 22
// 1 | Item | Type | Description |
|---|---|---|
rows | int | Number of rows — outer loop runs from 1 to rows. |
i | int | Outer loop — current row number (also the digit for early rows). |
j | int | Inner loop — j = i..rows controls shrinking row length. |
val | int | Digit to repeat — i or rows + 1 - i via if/else. |
for i from 1 to rows:
if i < rows - 1:
val = i
else:
val = rows + 1 - i
for j from i to rows:
print val
print newline | Approach | Idea | Best for |
|---|---|---|
| If/else mapping | 11111, 2222, … 1 | Learning and interviews |
| User-input rows | (int) trim(fgets(STDIN)); | Flexible console programs |
| Ternary val | val = ($i < $rows - 1) ? $i : ($rows + 1 - $i) | Compact generalized version |
| Goal | Pattern |
|---|---|
| Walk rows | for ($i = 1; $i <= $rows; $i++) |
| Shrink inner loop | for ($j = $i; $j <= $rows; $j++) |
| Pick digit (fixed) | if ($i < 4) echo $i; else echo 6 - $i; |
| Pick digit (general) | val = ($i < $rows - 1) ? $i : ($rows + 1 - $i); |
| End the row | echo PHP_EOL; |
| User input | (int) trim(fgets(STDIN)); |
Same bidirectional triangle — different ways to control rows and formatting.
i = 1..rowsOne row per outer iteration
j = i..rowsShrinking row length each row
6 - iMirrors digits on last rows
if/elseCompute val once per row, not per column
Reach for this pattern when teaching shrinking inner loops, conditional digit mapping, and bidirectional output.
Natural follow-up after Program 24 — introduces if/else mapping and shrinking rows.
Outer/inner bound practice with an immediate visual check.
Combine loops with fgets(STDIN) for a flexible row count.
Compare Program 24 (centered pyramid) and Program 26 (diagonal asterisk) 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.
Choose a row count between 3 and 9 and draw the bidirectional number triangle in the browser.
Three complete PHP programs — fixed rows, user input, and spaced output variant. Click View Output to reveal sample console results.
Print five rows of the bidirectional triangle with if/else mapping.
rows = 5Hard-coded row count — ideal for first demos and screenshots.
<?php
for ($i = 1; $i <= 5; $i++) {
for ($j = $i; $j <= 5; $j++) {
if ($i < 4) {
echo $i;
} else {
echo 6 - $i;
}
}
echo PHP_EOL;
} When i = 1, print five 1s — output 11111. When i = 3, print three 3s — output 333. When i = 4, the else branch prints 6 - 4 = 2 twice — output 22. When i = 5, print 6 - 5 = 1 once.
Read the row count with fgets(STDIN) instead of hard-coding 5.
Read rows with (int) trim(fgets(STDIN)); use a ternary to generalize the digit mapping.
<?php
echo "Enter rows: ";
$rows = (int) trim(fgets(STDIN));
for ($i = 1; $i <= $rows; $i++) {
$val = ($i < $rows - 1) ? $i : ($rows + 1 - $i);
for ($j = $i; $j <= $rows; $j++) {
echo $val;
}
echo PHP_EOL;
} Same shrinking inner loop as Example 1; the ternary ($i < $rows - 1) ? $i : ($rows + 1 - $i) generalizes the if/else mapping for any row count. Non-numeric input leaves rows unset if you skip is_numeric() checks — always check it in safer labs.
Add a space between repeated digits for easier reading.
Keep rows = 5 but print each digit followed by a space.
<?php
$rows = 5;
for ($i = 1; $i <= $rows; $i++) {
$val = ($i < $rows - 1) ? $i : ($rows + 1 - $i);
for ($j = $i; $j <= $rows; $j++) {
echo $val . " ";
}
echo PHP_EOL;
} Only the print statement changes — echo $val . " " instead of echo $val. The shrinking loop and digit mapping stay the same.
Set $rows = 5; and use fgets(STDIN) when reading input. Set loop variables $i, $j.
for ($i = 1; $i <= $rows; $i++) — one row per iteration.
for ($j = $i; $j <= $rows; $j++) — row length shrinks as i grows.
if ($i < 4) prints i; else echo 6 - $i mirrors down.
echo PHP_EOL ends the row after the inner loop.
Digits rise then mirror down — O(n²) time, O(1) extra memory.
rows = 5Trace each outer-loop value of i, the digit chosen, inner-loop count, and row output.
i | Digit (val) | Inner loop (j) | Prints | Row output |
|---|---|---|---|---|
1 | 1 (i < 4) | 1..5 (5 times) | 5 | 11111 |
2 | 2 | 2..5 (4 times) | 4 | 2222 |
3 | 3 | 3..5 (3 times) | 3 | 333 |
4 | 2 (6 - i) | 4..5 (2 times) | 2 | 22 |
5 | 1 (6 - i) | 5..5 (1 time) | 1 | 1 |
Prints per row = rows - i + 1 — total prints = n(n+1)/2 for n rows.
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 to j = 1 and watch rows stop shrinking.
Foundation for inverted, pyramid, diamond, and hollow variants.
Example: use rows + 1 - i for a fully symmetric variant.
Practice print vs row newline without complex math.
Example: put echo PHP_EOL inside the inner loop by mistake.
Swap digits for letters or add spaces once the loop works.
Example: print val + " " for spaced repeated digits.
Triangular totals make O(n²) concrete for beginners.
Example: count printed numbers for rows = 5 → 5 + 4 + 3 + 2 + 1 = 15.
Pair the pattern with fgets(STDIN) return checks and positive-row checks.
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 PHP 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: trace the shrinking inner loop on paper for rows = 3 before coding — mapping bugs hide in the 6 - i threshold.
Small habits that keep number-pattern code clean.
Do not reset val inside the inner loop — compute it once per row.
is_numeric()Call is_numeric(trim($line)) so bad input does not leave rows uninitialized.
Only call echo PHP_EOL after the inner loop finishes the row.
Write each i, digit chosen, and print count before coding.
Trace rows = 3 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 bidirectional number triangle patterns.
Each digit lands on its own line — you get a column, not a triangle.
→ Use echo $val; echo PHP_EOL only after the inner loop.
Putting the if/else inside the inner loop works but is wasteful — compute val once per row.
→ Set $val before the inner loop, then just echo $val.
Using j = 1 to rows prints full-width rows — no shrinking.
→ Use for ($j = $i; $j <= $rows; $j++) so each row is shorter.
Using i < rows instead of i < rows - 1 skips the mirror on the last row.
→ For generalized code use ($i < $rows - 1) ? $i : ($rows + 1 - $i).
Letters or empty input leave rows uninitialized.
→ Call is_numeric(trim($line)) and re-prompt on failure.
Check these inputs before calling the solution done.
Output is just 1 — one digit, one row.
Outer loop never runs — print nothing or show a message.
rows < 0Treat as invalid; re-prompt instead of silent empty output.
Two rows: 11 and 1.
Unchecked fgets(STDIN) input leaves rows unset — call is_numeric(trim($line)) first.
Output grows as n² characters — fine for labs, noisy for huge n.
Try these variations to lock in the pattern.
* on diagonalPrintTriangle(int rows)Main with user inputrows + 1 - i for all rows, not just last twoj = i..rows — row length = rows - i + 1 digits per row.echo $val repeats the digit; echo PHP_EOL advances — mix them carefully.rows > 0 for interactive programs; rows = 1 prints a single 1.val once per row outside the inner loop — cleaner and slightly faster.Quick Takeaway: outer loop i = 1..rows, shrinking inner loop j = i..rows, if/else digit mapping, then echo PHP_EOL after each row.
| Program | Time | Extra space |
|---|---|---|
| Nested loops (Examples 1–2) | O(n²) | O(1) |
| Spaced output (Example 3) | O(n²) | O(1) |
The bidirectional number triangle is a compact lesson in shrinking loops and conditional mapping: repeat a digit per row with j = i..rows, then mirror down with 6 - i. Master the fixed-rows version, then try user input and spaced output.
Practice the three examples above, then continue to Program 26 for the descending pattern with diagonal asterisk.
Compute val once per row — validate rows when reading from the console.
for ($i = 1; $i <= $rows; $i++) in the outer loopfor ($j = $i; $j <= $rows; $j++)val once per row before the inner loopis_numeric(trim($line)) before using rowsecho PHP_EOL inside the inner loopj = 1 in the inner loop — rows won’t shrink6 - i in generalized code — use rows + 1 - irows = 1 edge casePrint the pattern the beginner-friendly way.
Shrink + repeat
DefinitionShrinking rows
Code6 - i mirror
Code1,2,3 then 2,1
ShapeO(n²) time
AnalysisThis pattern prints repeated digits per row. The inner loop runs from $j = $i to $rows, shrinking each row. The row digit is $i for the first half, then switches to $rows + 1 - $i to produce 22 and 1.
Move on to the descending number pattern with diagonal asterisk in the PHP number-pattern series.
12 people found this page helpful