Mixed Rule
Descend then ascend
Every row prints exactly rows letters: prefix down to A, suffix up from B.

Each row stitches together a descending prefix from the row start letter down to A and an ascending suffix from B up to a shrinking end letter: ABCDE, BABCD, CBABC, DCBAB, EDCBA for five rows. Two inner loops per row teach opposite directions on the same line. Compare with Program 26 (cyclic rotation). Includes a live preview, worked JavaScript examples, edge cases, and complexity.
Descend then ascend
Every row prints exactly rows letters: prefix down to A, suffix up from B.
start → A
for (let code = start; code >= base; code--) appends the descending part.
B → end
for (let code = base + 1; code <= end; code++) fills the ascending tail - skips A.
Letter codes
base = "A".charCodeAt(0), top = base + rows - 1, start = base + r, end = top - r.
1–26 rows
Pick a row count and draw the mixed alphabet pattern in the browser instantly.
Complexity
n rows × n letters per row = n² total characters; extra memory stays O(1).
A mixed alphabet pattern prints fixed-width rows where each line begins with a descending run from the row start letter down to A, then continues with an ascending run from B to a shrinking end letter. Row 1 is pure ascending; the last row is pure descending.
In JavaScript you solve it with an outer loop over row index r, two inner loops (descending prefix then ascending suffix), and charCodeAt(0)/String.fromCharCode() - or build each row in an array and console.log(row.join("")) for clarity.
It teaches opposite loop directions on one row - descending then ascending - and the subtle rule of skipping A in the suffix so the join point is not duplicated. The same split appears in palindrome builders and symmetric string patterns.
Every row prints exactly rows letters - prefix plus suffix always sum to rows.
end = top - r shrinks each row so the suffix gets shorter as the prefix grows.
Suffix starts at B (base + 1) - never duplicate A at the join.
Program 26 wraps cyclically - BCDEA. Here row 2 is BABCD, not BCDEA.
In short: set base = "A".charCodeAt(0) and top = base + rows - 1, loop r from 0 to rows - 1, compute start = base + r and end = top - r, append descending prefix, ascending suffix from B, then console.log(line) for the newline.
Given a positive integer rows, print rows lines of exactly rows uppercase letters each. Row 1 descends from A only in the prefix then ascends to the top; each next row starts one letter later and ends one letter earlier.
// First 5 rows
# ABCDE
# BABCD
# CBABC
# DCBAB
# EDCBA | Item | Type | Description |
|---|---|---|
rows | int | Number of rows and width of each row. Clamp to 1–26 for A–Z demos. |
| Printed output | text | Fixed-width uppercase rows: descending prefix + ascending suffix - no spaces between letters. |
base = "A".charCodeAt(0)
top = base + rows - 1
for r from 0 to rows-1:
start = base + r
end = top - r
line = ""
append letters start..A (descending)
append letters B..end (ascending)
console.log(line) | Approach | Idea | Best for |
|---|---|---|
| Two inner loops | Descend start..base + ascend (base+1)..end | Learning charCodeAt/fromCharCode and opposite loop directions |
| Join array | Build row in an array, console.log(row.join("")) | Clearer debugging and row inspection |
| Program 26 contrast | See Program 26 (ABCDE, BCDEA, …) | Cyclic rotation with wrap-around |
| Goal | Pattern |
|---|---|
| Bound the alphabet | base = "A".charCodeAt(0); top = base + rows - 1 |
| Outer loop (row index) | for (let r = 0; r < rows; r++) |
| Row bounds | start = base + r; end = top - r |
| Prefix (descending) | for (let code = start; code >= base; code--) line += String.fromCharCode(code) |
| Suffix (ascending) | for (let code = base + 1; code <= end; code++) line += String.fromCharCode(code) |
| End the row | console.log(line) |
| List join variant | row.push(String.fromCharCode(code)); console.log(row.join("")) |
Three ways to think about the same mixed rows - pick based on what you are learning.
for (code = start; code >= base; code--)
start..APrints from the row start letter down to A - row 1 prefix is just A.
for (code = base+1; code <= end; code++)
B..endFills the ascending tail from B - skips A to avoid duplication at the join.
row.push(...)
row.join("")Collect letters in an array, then print one string - easier to inspect each row while debugging.
forward + wrap
BCDEAProgram 26 wraps cyclically - row 2 is BCDEA, not BABCD.
Reach for mixed prefix/suffix loops when each row combines a descending run with an ascending tail on fixed-width lines.
Program 26 wraps cyclically - BCDEA. This pattern descends then ascends - BABCD.
Practice descending and ascending ranges on the same row before tackling palindromes.
Building rows in a list mirrors real string assembly in larger programs.
Next pattern in the alphabet series builds on symmetric row ideas.
This is a console teaching pattern - not how you build modern app screens.
Key benefit: one program that proves you can split a row into a descending prefix and ascending suffix - a pattern used in palindromes and symmetric string builders far beyond alphabet demos.
Choose a row count between 1 and 26 and draw the mixed alphabet pattern in the browser.
Three complete JavaScript programs - fixed five rows with dual inner loops, prompt input, and an array-join variant for clarity. Click View Output to reveal sample console results, or Try it Yourself to run in the browser editor.
Print five mixed rows with descending prefix and ascending suffix loops.
rows = 5Hard-coded height - ideal for first demos and screenshots.
let rows = 5;
rows = Math.max(1, Math.min(rows, 26));
const base = "A".charCodeAt(0);
const top = base + rows - 1;
for (let r = 0; r < rows; r++) { // 0..4
const start = base + r; // A, B, C, D, E
const end = top - r; // E, D, C, B, A
let line = "";
// Descending prefix: start..A
for (let code = start; code >= base; code--) {
line += String.fromCharCode(code);
}
// Ascending suffix: B..end (skip A)
for (let code = base + 1; code <= end; code++) {
line += String.fromCharCode(code);
}
console.log(line);
} The outer loop walks row index r from 0 to 4. For each row, start = base + r sets the prefix start and end = top - r shrinks the suffix bound. The first inner loop appends descending from start to A; the second appends ascending from B to end. When end is below B, the suffix loop is empty and the row is pure descending - that is how EDCBA appears.
Let the user choose the height at runtime.
Read rows and clamp to 1–26. Validate parseInt(prompt()) with Number.isFinite in real apps.
let rows = parseInt(prompt("Enter number of rows (1-26):"), 10);
if (!Number.isFinite(rows)) {
console.log("Please enter a whole number.");
} else {
rows = Math.max(1, Math.min(rows, 26));
const base = "A".charCodeAt(0);
const top = base + rows - 1;
for (let r = 0; r < rows; r++) {
const start = base + r;
const end = top - r;
let line = "";
for (let code = start; code >= base; code--) {
line += String.fromCharCode(code);
}
for (let code = base + 1; code <= end; code++) {
line += String.fromCharCode(code);
}
console.log(line);
}
} Same dual-loop core as Example 1; only the row count comes from prompt. Three rows use letters A–C with width 3 on every line - row 2 is BAC, not cyclic BCA.
Build each row in an array, then log with row.join("").
row.join("") VariantCollect letters in an array for clearer row inspection - same logic, easier debugging.
let rows = 5;
rows = Math.max(1, Math.min(rows, 26));
const base = "A".charCodeAt(0);
const top = base + rows - 1;
for (let r = 0; r < rows; r++) {
const start = base + r;
const end = top - r;
const row = [];
for (let code = start; code >= base; code--) {
row.push(String.fromCharCode(code));
}
for (let code = base + 1; code <= end; code++) {
row.push(String.fromCharCode(code));
}
console.log(row.join(""));
} The start/end logic is identical; only formatting changes. row.join("") builds the full string once after both halves finish.
Clamp rows, then set base = "A".charCodeAt(0) and top = base + rows - 1 for the alphabet window.
for (let r = 0; r < rows; r++) walks each row from 0 to rows - 1, computing start and end.
First inner loop appends start down to A; second appends B up to end with line += String.fromCharCode(...).
console.log(line) ends the row after both inner loops finish; the outer loop advances r to the next row.
Total characters: n × n = n² — O(n²) time, O(1) extra memory (loop version).
rows = 5Trace each outer-loop value of r and see how the prefix and suffix combine into each printed row.
r | start | end | Prefix | Suffix | Full row |
|---|---|---|---|---|---|
| 0 | 'A' | 'E' | A | BCDE | ABCDE |
| 1 | 'B' | 'D' | BA | BCD | BABCD |
| 2 | 'C' | 'C' | CBA | BC | CBABC |
| 3 | 'D' | 'B' | DCBA | B | DCBAB |
| 4 | 'E' | 'A' | EDCBA | (empty) | EDCBA |
Total character prints: 5 × 5 = 25 = n² for n = 5 rows.
Where this tiny pattern (and its prefix/suffix split) shows up beyond the homework prompt.
Program 26 wraps cyclically - BCDEA. This descends then ascends - BABCD.
Example: side-by-side ABCDE/BCDEA vs ABCDE/BABCD.
Reinforce descending for (code = start; code >= base; code--) and ascending for (code = base + 1; code <= end; code++) on the same row.
Example: trace prefix and suffix for row 2 (r=1) on paper before coding.
Descend then ascend on one line mirrors half-palindrome construction.
Example: row 3 prefix CBA + suffix BC forms CBABC - almost symmetric.
Swap letters for digits 1..n with the same prefix + suffix logic.
Example: rows=3 gives 123, 212, 321.
Square totals make O(n²) concrete for beginners.
Example: 5 rows → 25 characters printed.
Classic nested-loop question that tests prefix/suffix bounds and the skip-A rule.
Example: explain why row 5 is EDCBA without running code.
Pro Tip: say “descend from start to A, ascend from B to end” before coding - that story prevents duplicating A or skipping the descending loop.
Why this pattern earns a spot after the rotation pattern from Program 26.
Two inner loops run descending then ascending on the same row - a core loop skill.
Every line has the same length - prefix and suffix always sum to rows.
Direct print version for learning; array-join version for clearer debugging.
Streaming output needs no storage beyond loop counters (join variant uses O(n) per row).
Pro Tip: when end is below B, the suffix loop is empty and the row is pure descending - that is how EDCBA appears on the last line.
Small habits that keep mixed alphabet pattern code clean.
Use start = base + r and end = top - r - keep r and code for loop variables.
parseInt(prompt(), 10) in Number.isFiniteAvoid crashes when the user types letters instead of a number.
rows = Math.max(1, Math.min(rows, 26)) keeps demos inside A–Z.
for (let code = base + 1; code <= end; code++) - never start the suffix at A or you duplicate the join letter.
Trace ABC, BAC, CBA on paper before coding larger demos.
Pro Tip: if rows look like Program 26 (BCDEA, CDEBA), you likely used forward + wrap instead of descend + ascend.
Mistakes that commonly break mixed alphabet patterns.
Starting the suffix at A gives BAA, CABA - double A at the join.
→ Suffix must start at B: for (let code = base + 1; code <= end; code++).
Using end = top or end = top + r keeps the suffix too long - rows exceed width rows.
→ Use end = top - r so prefix and suffix lengths always sum to rows.
Only the ascending suffix prints BCD, CD, D - rows are too short and miss the descending prefix.
→ Always run the prefix loop first: for (let code = start; code >= base; code--).
Non-numeric input yields NaN with bare parseInt(prompt(), 10).
→ Validate parseInt(prompt()) with Number.isFinite and validate range.
Program 26 wraps cyclically - row 2 is BCDEA, not BABCD.
→ Here prefix descends and suffix ascends - no cyclic wrap between the two parts.
Check these inputs before calling the solution done.
Output is just A on one line - prefix is A, suffix loop empty because end is below B.
Treat as invalid; re-prompt instead of silent empty output.
26 rows of width 26 - last row is pure descending from Z down to A.
Clamp to 26 or define a wrap/error policy before printing.
Use Number.isFinite before clamping rows.
Same loops work with base = "a".charCodeAt(0) and lowercase output.
Try these variations to lock in the pattern.
row.append and row.join("")n rows is n² - each row prints n letters.for (code = start; code >= base; code--). Suffix loop: for (code = base + 1; code <= end; code++).row.join("") after building in a list is equivalent to the direct-print version - use whichever fits your lesson.Quick Takeaway: outer loop sets r, compute start and end, print descending prefix, ascending suffix from B, then break the line - that is the whole mixed alphabet pattern.
| Program | Time | Extra space |
|---|---|---|
| Two inner loops (Examples 1–2) | O(rows²) | O(1) |
| Join variant (Example 3) | O(rows²) | O(rows) for the row list per line |
The mixed alphabet pattern teaches opposite loop directions on one row - descending prefix from the start letter to A, then ascending suffix from B to end. Master the line-building version, then try the array-join variant for clearer debugging.
Practice the three examples above, then continue to Program 31 in the alphabet pattern series.
Set start and end each row, run prefix then suffix loops, clamp rows to 26, and compare with Program 26 to see the difference from cyclic rotation.
base = "A".charCodeAt(0), top = base + rows - 1start = base + r and end = top - r each rowB (base + 1) - never duplicate Aline += String.fromCharCode(...) in loops; console.log(line) after bothA - duplicates the join letterend bound - rows will be too long or too shortconsole.log(line) inside the letter loopsPrint the mixed rows the beginner-friendly way.
Descend + ascend
Definitionstart down to A
CodeB up to end
Coderow.join("")
AltO(n²) time
AnalysisEach row uses two passes: a descending prefix from the row start letter down to A, then an ascending suffix from B up to end = top - r. Row 1 is pure ascending ABCDE; the last row is pure descending EDCBA.
Next up: the Alphabet X pattern - build on symmetric row ideas from this tutorial.
12 people found this page helpful