Shape Rule
Hollow border
Only cells on the border print numbers — top, right, bottom, and left sides use different counter sequences.

Program 59 prints a hollow square border: a 5×5 grid where only the boundary shows consecutive numbers 1–16 and the inside stays blank — a shift from Program 58’s diagonal diamond to rectangular border logic. This tutorial covers border detection, fixed-width formatting, separate side counters, a live preview, worked JavaScript examples, edge cases, and complexity.
Hollow border
Only cells on the border print numbers — top, right, bottom, and left sides use different counter sequences.
i, j = 1..5
for (let i = 1; i <= 5; i++) { for (let j = 1; j <= 5; j++) } — visit every cell in the 5×5 grid.
if / elif
i === 1, j === 5, i === 5, j === 1 — detect which side of the border the cell belongs to.
k, l, m
k = 6 (right), l = 13 (bottom), m = 16 (left) — track values for non-top sides.
:3d
String(value).padStart(3, " ") and " " for inner cells — columns stay aligned.
Complexity
Every cell in the n×n grid is visited once — total work grows as O(n²).
A hollow square border number pattern prints consecutive numbers only on the boundary of a square grid, leaving the interior blank. For a 5×5 square, the top row shows 1..5, the right column continues 6..9, the bottom row shows 13..9, and the left column finishes with 16..13.
In JavaScript use nested loops over rows and columns, then branch with if / else if to detect border sides. Use String(value).padStart(3, " ") for numbers and three spaces for inner cells.
It bridges Program 58’s diagonal symmetry to rectangular grids — combining border detection, multiple counters, and fixed-width formatting.
i == 1 prints j (1..5).
j == 5 prints k++ (6..9).
Program 58 uses diagonal mirror loops; Program 59 uses rectangular border checks.
Follow Program 58; continue to Program 60 next.
In short: nested i, j loops, border if checks, counters k, l, m, fixed width 3, then console.log(line) per row.
Print a 5×5 hollow square where the border shows numbers 1–16 clockwise and inner cells are blank spaces of width 3.
// 5×5 hollow border (numbers 1..16)
//1 2 3 4 5
//16 6
//15 7
//14 8
//13 12 11 10 9 | Item | Type | Description |
|---|---|---|
| Grid size | int | 5×5 in the fixed demo — 25 cells total, 16 on the border. |
i (outer) | int | Row index — runs 1 to 5. |
j (inner) | int | Column index — runs 1 to 5. |
k | int | Right column counter — starts at 6, increments. |
l | int | Bottom row counter — starts at 13, decrements. |
m | int | Left column counter — starts at 16, decrements. |
init k, l, m for right, bottom, left sides
for i from 1 to n:
for j from 1 to n:
if top row: print j
else if right column: print k++
else if bottom row: print l--
else if left column: print m--
else: print three spaces
print newline | Approach | Idea | Best for |
|---|---|---|
| if / elif chain | Detect top, right, bottom, left border per cell | Learning and interviews |
| Separate counters | k, l, m for non-top sides | Clockwise numbering |
| Fixed-width format | String(value).padStart(3, " ") for numbers, " " inside | Aligned columns |
| Configurable size | Read n from input | Flexible grid size |
| Compact trace | n = 3 on paper first | Quick dry-runs before 5×5 demo |
| Goal | Pattern |
|---|---|
| Outer loop | for (let i = 1; i <= 5; i++) |
| Inner loop | for (let j = 1; j <= 5; j++) |
| Top row | if (i === 1) line += String(j).padStart(3, " ") |
| Right column | else if (j === 5) line += String(k).padStart(3, " "); k++ |
| Bottom row | else if (i === 5) line += String(l).padStart(3, " "); l-- |
| Left column | else if (j === 1) line += String(m).padStart(3, " "); m-- |
| Inner cell | else line += " " |
| Program 58 contrast | Program 58 uses diagonal mirror; Program 59 uses rectangular border checks |
Same hollow border idea — three ways to set grid size and trace the logic.
n = 5Numbers 1–16 on border
parseInt(prompt())Read square size from console
n = 39-cell grid dry-run
i == 1Print column index j
" "Three spaces, width 3
Reach for this pattern when teaching 2D grids, border detection, fixed-width formatting, and multiple counters.
Natural follow-up after Program 58’s diamond — introduces rectangular grids and border-only printing.
Fixed-width String(value).padStart(3, " ") keeps columns aligned — essential for multi-digit borders.
Separate k, l, m for right, bottom, left — concrete state-tracking practice.
Compare this hollow border with the next pattern in the series.
This is a console teaching pattern — not how you build modern app screens.
Key benefit: one small program that locks in border checks, formatting, and O(n²) grid thinking.
Choose row count between 3 and 9 and draw the centered hollow square border number pattern in the browser.
Three complete JavaScript programs — fixed 5×5 border, configurable size, and a compact 3×3 trace demo. Click View Output to reveal sample console results, or Try it Yourself to run in the browser.
Print a 5×5 hollow border with numbers 1–16 clockwise — top, right, bottom, and left sides with separate counters.
Hard-coded grid — use if / else if to detect border sides and padStart(3) formatting for alignment.
let k = 6;
let l = 13;
let m = 16;
for (let i = 1; i <= 5; i++) {
let line = "";
for (let j = 1; j <= 5; j++) {
if (i === 1) {
line += String(j).padStart(3, " ");
} else if (j === 5) {
line += String(k).padStart(3, " ");
k++;
} else if (i === 5) {
line += String(l).padStart(3, " ");
l--;
} else if (j === 1) {
line += String(m).padStart(3, " ");
m--;
} else {
line += " ";
}
}
console.log(line);
} Row 1 prints j for every column. Rows 2–4 print m-- on the left, k++ on the right, and spaces inside. Row 5 prints l-- across the bottom.
Read square size with prompt() and Number.isFinite validation.
Read n with prompt() — append column index on border cells, spaces inside. Counter rules can be customized for larger grids.
const nInput = prompt("Enter square size (n):");
const n = parseInt(nInput, 10);
if (!Number.isFinite(n) || n < 2) {
console.log("Please enter an integer >= 2.");
} else {
for (let i = 1; i <= n; i++) {
let line = "";
for (let j = 1; j <= n; j++) {
const isBorder = i === 1 || i === n || j === 1 || j === n;
if (isBorder) {
line += String(j).padStart(3, " ");
} else {
line += " ";
}
}
console.log(line);
}
} Uses a simple isBorder flag instead of side-specific counters — good starting point before adding clockwise numbering for arbitrary n.
Smaller 3×3 grid for quick tracing on paper or in interviews.
Use n = 3 with scaled counter starts — trace all four sides before scaling to 5×5.
const n = 3;
let k = n + 1;
let l = 3 * n - 2;
let m = 4 * (n - 1);
for (let i = 1; i <= n; i++) {
let line = "";
for (let j = 1; j <= n; j++) {
if (i === 1) {
line += String(j).padStart(3, " ");
} else if (j === n) {
line += String(k).padStart(3, " ");
k++;
} else if (i === n) {
line += String(l).padStart(3, " ");
l--;
} else if (j === 1) {
line += String(m).padStart(3, " ");
m--;
} else {
line += " ";
}
}
console.log(line);
} With only nine cells and one inner gap, you can trace every border branch on paper before running the full 5×5 demo.
k = 6, l = 13, m = 16 — starting values for right, bottom, and left borders.
for (let i = 1; i <= 5; i++) { for (let j = 1; j <= 5; j++) } — visit every cell.
if i == 1 top, elif j == 5 right, elif i == 5 bottom, elif j == 1 left — else inner space.
String(value).padStart(3, " ") for border digits, " " for inner cells — then console.log(line).
25 cells visited — O(n²) time, O(1) extra memory.
Trace which branch runs for representative cells in the 5×5 grid.
(i, j) | Branch | Prints | Notes |
|---|---|---|---|
(1, 3) | i == 1 | 3 | Top row uses column index |
(2, 5) | j == 5 | 6 | First right-column value (k++) |
(3, 3) | else (inner) | | Three spaces — hollow interior |
(4, 1) | j == 1 | 15 | Left column (m--) |
(5, 3) | i == 5 | 11 | Bottom row (l--) |
Check order matters: top row is tested first, then right column, then bottom, then left — corners belong to the first matching branch.
Where this tiny pattern (and its loop structure) shows up beyond the homework prompt.
Nested i, j loops with per-cell decisions — foundation for matrix problems.
Example: trace cell (3,3) in the walkthrough — inner branch prints spaces.
String(value).padStart(3, " ") keeps columns aligned when border numbers have 1 or 2 digits.
Example: compare output with and without formatting — columns drift without width 3.
Separate k, l, m track different sides — state management in a small program.
Example: right column starts at 6 and increments through row 4.
Hollow patterns print only on the boundary — compare with filled square variants.
Example: replace inner spaces with * to fill the square.
Every cell visited once — makes O(n²) concrete for n×n grids.
Example: 5×5 = 25 cell checks — see the walkthrough table.
Pair the pattern with Number.isFinite and minimum-size validation after parseInt(prompt()).
Example: reject n < 2 in Example 2.
Pro Tip: in grid patterns, consistent spacing matters as much as the numbers — use fixed-width formatting from the start.
Why this pattern earns a permanent spot in beginner JavaScript courses.
The hollow border is instantly recognizable — numbers ring the square while the interior stays blank.
Fixed-width String(value).padStart(3, " ") formatting teaches real console grid alignment — not abstract loop drill.
Fill the interior with * for a solid square, or scale counter formulas for larger grids.
Streaming output needs no storage beyond loop counters.
Pro Tip: trace the 3×3 compact example on paper — only one inner cell to mark as spaces.
Small habits that keep number-pattern code clean.
Set k = 6, l = 13, m = 16 before the nested loops for the 5×5 demo.
Avoid crashing when the user types letters instead of a number.
Only call console.log(line) after the inner loop finishes each row.
Check top row (i == 1) before side columns so corner cells get the right branch.
Trace the compact example on paper before coding the full 5×5 demo.
Pro Tip: if the output is a vertical list of single numbers, you almost certainly called console.log() inside the inner loop.
Mistakes that commonly break hollow square border number pattern patterns.
Each number lands on its own line — you get a column, not a square row.
→ Use line += String(j).padStart(3, " ") or line += " "; call console.log(line) only after the inner loop.
Checking side columns before the top/bottom row puts counter digits on corner cells.
→ Check i == 1 and i == 5 before j == 1 or j == 5 on shared rows.
Printing bare digits without fixed width makes columns drift out of alignment.
→ Use String(value).padStart(3, " ") for border numbers and " " for inner cells.
All numbers print on one long line without row breaks.
→ Call console.log(line) after the inner loop completes each row.
Letters or empty input yield NaN or leave n invalid.
→ Validate with Number.isFinite(n) and check n >= 2 before drawing.
Check these inputs before calling the solution done.
Output is a single cell — for n = 1 every position is border; validate n >= 2 in user input.
Outer loop never runs — print nothing or show a message.
rows < 0Treat as invalid; re-prompt instead of silent empty output.
Center cell (3,3) is the only inner cell — good for tracing the else branch.
Bare parseInt(prompt()) returns NaN — validate with Number.isFinite.
Row 9 scans 17 character positions (2×9-1) — total work grows as O(n²).
Try these variations to lock in the pattern.
" " with a digit or *i == 1. Right: j == n. Bottom: i == n. Left: j == 1. Else: three spaces.line string per row with += — call console.log(line) only after the inner loop finishes each row.n >= 2 for interactive programs; n = 2 has no inner cells — all border.O(n²) for square size n.Quick Takeaway: nested i, j loops, border if chain, counters k, l, m, width 3, then console.log(line).
| Program | Time | Extra space |
|---|---|---|
| Nested loops (Examples 1–3) | O(n²) | O(1) |
| Digits on row i | 2i - 1 | No storage beyond loop counters |
The hollow square border number pattern is a natural follow-up to Program 58: rectangular grids with border detection and fixed-width formatting replace diagonal mirror loops. Master the fixed 5×5 version, then try user input and the compact 3×3 trace.
Practice the three examples above, then continue to Program 60 for the next pattern in the series.
Border shows numbers 1–16 clockwise on a 5×5 grid — inner cells stay blank with width-3 spacing.
if (i === 1) line += String(j).padStart(3, " ")else if (j === 5) line += String(k).padStart(3, " "); k++else if (i === 5) line += String(l).padStart(3, " "); l--else if (j === 1) line += String(m).padStart(3, " "); m--console.log(line) after the inner loopNumber.isFinite after parseInt(prompt()) for user inputelif order at corners — top/bottom rows get side digitsconsole.log() inside the inner looprows = 3 dry-run before coding rows = 5Print the hollow border square the beginner-friendly way.
border only
Definitionj = rows..1
Codek = 2..rows
Codei == j or i == k
LogicO(n²) time
AnalysisThis pattern is a hollow 5×5 border: top row 1..5, right side 6..9, bottom row 13..9, left side 16..13 — inner cells are blank spaces with fixed width 3.
Move on to the next pattern in the JavaScript number-pattern series.
12 people found this page helpful