Diamond in Cobol: Complete Solution & Deep Dive Guide
Learn Cobol Logic: Building the Diamond Pattern from Zero to Hero
The Cobol Diamond Kata is a classic programming challenge designed to build a symmetrical diamond shape out of letters. Given an input letter, the program generates a diamond starting with 'A' at the top and bottom points, with the input letter forming the widest horizontal line. This exercise sharpens core skills in procedural logic, loop control, and string manipulation within the structured environment of Cobol.
You've probably heard the whispers about Cobol. "It's a relic," some say. "A language of the past, confined to dusty mainframes." You might even be staring at a Cobol learning module, wondering how this verbose, rigidly structured language could possibly be used for something as creative as generating a visual pattern. The frustration is real; its syntax feels alien compared to modern languages, and simple tasks seem to require an ocean of code.
But what if that perceived weakness is actually its greatest strength? Cobol's rigidity forces you to think algorithmically, to plan every variable, every loop, and every calculation with precision. Mastering this challenge isn't just about printing a pretty shape; it's about proving you can command one of the most powerful and enduring programming languages ever created. This guide will transform your apprehension into confidence, walking you step-by-step through the logic, syntax, and execution of the Diamond Kata, revealing the elegant power hidden within Cobol's structure.
What is the Diamond Kata?
The Diamond Kata is a programming exercise from the exclusive kodikra.com Cobol curriculum that challenges a developer to write a program that accepts a single letter (e.g., 'E') and outputs a diamond shape made of letters. The pattern must adhere to a specific set of rules, making it an excellent test of algorithmic thinking and attention to detail.
The Core Requirements
- Starting and Ending Point: The very first and very last rows of the output must contain a single 'A'.
- Widest Point: The input letter determines the widest point of the diamond. For an input of 'C', the middle row would be `C C`.
- Symmetry: The diamond must be both horizontally and vertically symmetrical. The top half is a mirror image of the bottom half (excluding the middle row), and each row is a mirror image of itself.
- Letter Count: All rows, with the exception of the 'A' rows, must contain exactly two identical letters.
- Spacing: Every row must have an equal number of leading and trailing spaces to ensure proper alignment. The number of spaces between the letters on a given row increases as the letters advance through the alphabet.
For example, an input of 'C' should produce the following output:
A
B B
C C
B B
A
This challenge forces you to deconstruct the visual pattern into a mathematical and logical sequence, a fundamental skill in any programming language, but especially in the highly structured world of Cobol.
Why is This Challenge Important in Cobol?
Solving the Diamond Kata in a language like Python or JavaScript might seem trivial due to their powerful built-in string manipulation functions and dynamic data structures. In Cobol, however, the exercise is a profound lesson in the language's core principles. It's not just about getting the right output; it's about mastering the "Cobol way" of thinking.
This challenge directly teaches you:
- Structured Programming: You must use paragraphs (`PROCEDURE` blocks) and `PERFORM` statements to create a clean, readable, and maintainable program flow. This is the bedrock of Cobol application design.
- Data Definition Mastery: The `DATA DIVISION` is paramount. You learn to meticulously define variables with `PIC` clauses, pre-allocate memory for your output lines, and understand the difference between numeric (`PIC 9`), alphanumeric (`PIC X`), and alphabetic (`PIC A`) data types.
- Loop Control with `PERFORM VARYING`: This is Cobol's primary looping mechanism. You'll use it to iterate through the rows for both the top and bottom halves of the diamond, gaining precise control over the loop counters.
- Character and String Manipulation: While Cobol lacks the simple string concatenation of other languages, it has powerful verbs like `STRING` and `INSPECT`. This exercise provides a practical use case for `STRING` to carefully assemble each output line piece by piece, controlling the exact position of every character and space.
- Algorithmic Translation: You must translate a visual pattern into mathematical formulas. Calculating the leading spaces and inner spaces for each row requires you to find the relationship between a letter's position in the alphabet and the required spacing, a core skill for any data processing or report generation task.
In enterprise environments, Cobol is the engine behind batch processing and report generation. The logic used to build the diamond—calculating positions, formatting lines, and looping through data—is directly analogous to creating formatted financial reports, generating customer statements, or laying out data on a CICS terminal screen.
How to Build the Diamond: The Complete Cobol Solution
Breaking down the problem is the key to success. We can divide the logic into three main parts: calculating the diamond's dimensions, building the top half (including the middle row), and building the bottom half.
The Logical Flow
Before we dive into the code, let's visualize the program's high-level execution flow. This helps in understanding how the different procedures connect.
● Start Program
│
▼
┌───────────────────┐
│ Accept Input Letter │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ Calculate Max Index │
│ (e.g., 'C' -> 2) │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ Build Top Half │
│ (Loop 0 to Max) │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ Build Bottom Half │
│ (Loop Max-1 to 0) │
└─────────┬─────────┘
│
▼
● End Program
The Full Cobol Code
Here is a complete, well-commented Cobol program that solves the Diamond Kata. This solution is designed for clarity and adherence to structured programming principles, and it can be compiled with a modern compiler like GnuCOBOL.
IDENTIFICATION DIVISION.
PROGRAM-ID. DiamondKata.
AUTHOR. Kodikra.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CONSTANTS.
05 WS-ALPHABET PIC X(26) VALUE 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
01 WS-INPUT-DATA.
05 WS-INPUT-LETTER PIC A(1).
01 WS-CALCULATION-VARS.
05 WS-MAX-IDX PIC 9(2) COMP.
05 WS-ROW-IDX PIC 9(2) COMP.
05 WS-POINTER PIC 9(2) COMP.
01 WS-SPACING-VARS.
05 WS-LEADING-SPACES PIC 9(2) COMP.
05 WS-INNER-SPACES PIC 9(2) COMP.
01 WS-OUTPUT-LINE.
05 WS-LINE-BUFFER PIC X(51).
PROCEDURE DIVISION.
MAIN-PROCEDURE.
*> 1. Get the target letter from the user (or environment).
DISPLAY "Enter the diamond's widest letter (A-Z): "
WITH NO ADVANCING.
ACCEPT WS-INPUT-LETTER.
*> 2. Calculate the 0-based index of the input letter.
*> 'A' -> 0, 'B' -> 1, 'C' -> 2, etc.
MOVE 0 TO WS-MAX-IDX.
INSPECT WS-ALPHABET TALLYING WS-MAX-IDX
FOR CHARACTERS BEFORE INITIAL WS-INPUT-LETTER.
*> 3. Build the top half of the diamond, including the middle row.
PERFORM BUILD-AND-DISPLAY-LINE
VARYING WS-ROW-IDX FROM 0 BY 1
UNTIL WS-ROW-IDX > WS-MAX-IDX.
*> 4. Build the bottom half of the diamond.
PERFORM BUILD-AND-DISPLAY-LINE
VARYING WS-ROW-IDX FROM WS-MAX-IDX - 1 BY -1
UNTIL WS-ROW-IDX < 0.
*> 5. End the program.
STOP RUN.
BUILD-AND-DISPLAY-LINE.
*> This paragraph is the core logic engine. It's called for
*> every row of the diamond.
*> Calculate the number of leading spaces.
*> For 'C' (max_idx=2): Row 0 ('A') needs 2-0=2 spaces.
*> Row 1 ('B') needs 2-1=1 space.
*> Row 2 ('C') needs 2-2=0 spaces.
COMPUTE WS-LEADING-SPACES = WS-MAX-IDX - WS-ROW-IDX.
*> Clear the output buffer for the new line.
INITIALIZE WS-LINE-BUFFER.
*> Start the pointer for the STRING command at 1.
MOVE 1 TO WS-POINTER.
*> Add the leading spaces to the buffer.
IF WS-LEADING-SPACES > 0
STRING FUNCTION REPEAT(" ", WS-LEADING-SPACES)
DELIMITED BY SIZE
INTO WS-LINE-BUFFER
WITH POINTER WS-POINTER
END-STRING
END-IF.
*> Add the first letter of the row.
*> The letter is at index WS-ROW-IDX + 1 in our alphabet string.
STRING WS-ALPHABET(WS-ROW-IDX + 1 : 1)
DELIMITED BY SIZE
INTO WS-LINE-BUFFER
WITH POINTER WS-POINTER
END-STRING.
*> Handle the second letter and inner spacing (skip for 'A').
IF WS-ROW-IDX > 0
*> Calculate inner spaces.
*> Row 1 ('B') needs 1 space: (1*2)-1 = 1
*> Row 2 ('C') needs 3 spaces: (2*2)-1 = 3
COMPUTE WS-INNER-SPACES = (WS-ROW-IDX * 2) - 1
IF WS-INNER-SPACES > 0
STRING FUNCTION REPEAT(" ", WS-INNER-SPACES)
DELIMITED BY SIZE
INTO WS-LINE-BUFFER
WITH POINTER WS-POINTER
END-STRING
END-IF
*> Add the second letter.
STRING WS-ALPHABET(WS-ROW-IDX + 1 : 1)
DELIMITED BY SIZE
INTO WS-LINE-BUFFER
WITH POINTER WS-POINTER
END-STRING
END-IF.
*> Display the fully constructed line.
DISPLAY WS-LINE-BUFFER.
Code Walkthrough: A Deep Dive
Let's dissect the program section by section to understand the purpose of every line.
IDENTIFICATION DIVISION
This is the simplest division. It just names the program (PROGRAM-ID. DiamondKata.). It's mandatory boilerplate for any Cobol program.
DATA DIVISION
This is where we declare all our variables. Careful planning here is crucial in Cobol.
WS-ALPHABET: A constant holding all 26 uppercase letters. This acts as our lookup table.WS-INPUT-LETTER: A single-character variable to store the user's input.WS-MAX-IDX: This will store the 0-based index of the input letter. For 'A', it's 0; for 'C', it's 2. We declare it asCOMP(Computational) for performance, as it's used heavily in calculations.WS-ROW-IDX: Our main loop counter, representing the current row being built (0 for 'A', 1 for 'B', etc.).WS-POINTER: A special variable required by theSTRINGverb to keep track of the current position in the output buffer.WS-SPACING-VARS: Holds the calculated number of leading and inner spaces for each row.WS-LINE-BUFFER: A 51-character string that acts as a canvas. We build each line of the diamond here before displaying it. The size 51 is calculated for the widest possible diamond ('Z'), which has a width of `(25 * 2) + 1 = 51`.
PROCEDURE DIVISION
This is where the action happens. The logic is contained within the `MAIN-PROCEDURE` and a reusable paragraph `BUILD-AND-DISPLAY-LINE`.
- Accept Input: The program prompts the user and stores the input letter in
WS-INPUT-LETTER. - Calculate Max Index: The line
INSPECT WS-ALPHABET TALLYING WS-MAX-IDX FOR CHARACTERS BEFORE INITIAL WS-INPUT-LETTERis a powerful Cobol idiom. It scans the alphabet string and counts how many characters come *before* the user's input letter. This efficiently gives us the 0-based index we need for all our calculations. - Top Half Loop:
PERFORM BUILD-AND-DISPLAY-LINE VARYING WS-ROW-IDX FROM 0 BY 1 UNTIL WS-ROW-IDX > WS-MAX-IDX.This loop starts withWS-ROW-IDXat 0 and increments it by 1 until it's greater than our max index. For an input of 'C' (max index 2), it will run for `WS-ROW-IDX` = 0, 1, and 2. - Bottom Half Loop:
PERFORM ... VARYING WS-ROW-IDX FROM WS-MAX-IDX - 1 BY -1 UNTIL WS-ROW-IDX < 0.This loop handles the symmetrical bottom part. It starts one row *below* the middle and decrements by 1 until it goes below 0. For 'C', it will run for `WS-ROW-IDX` = 1 and 0. STOP RUN: This command terminates the program.
The BUILD-AND-DISPLAY-LINE Paragraph Logic
This is the heart of the program. It's a self-contained procedure for creating and printing a single line of the diamond, based on the current WS-ROW-IDX.
Let's visualize the logic for a single row construction, for example, the 'B' row when the input is 'C'. (WS-MAX-IDX = 2, WS-ROW-IDX = 1).
● Start BUILD-AND-DISPLAY-LINE (Row Index = 1)
│
▼
┌───────────────────────────┐
│ Calculate Leading Spaces │
│ (Result = 2 - 1 = 1) │
└────────────┬──────────────┘
│
▼
┌───────────────────────────┐
│ Initialize Line Buffer │
│ (Buffer = "...") │
└────────────┬──────────────┘
│
▼
┌───────────────────────────┐
│ Add Leading Space │
│ (Buffer = " ...") │
└────────────┬──────────────┘
│
▼
┌───────────────────────────┐
│ Add First Letter ('B') │
│ (Buffer = "B...") │
└────────────┬──────────────┘
│
▼
◆ Is Row Index > 0? (Yes)
╱
Yes
│
▼
┌───────────────────────────┐
│ Calculate Inner Spaces │
│ (Result = (1*2)-1 = 1) │
└────────────┬──────────────┘
│
▼
┌───────────────────────────┐
│ Add Inner Space │
│ (Buffer = "B ...") │
└────────────┬──────────────┘
│
▼
┌───────────────────────────┐
│ Add Second Letter ('B') │
│ (Buffer = "B B...") │
└────────────┬──────────────┘
│
▼
┌───────────────────────────┐
│ Display Final Buffer │
│ (Output: " B B") │
└────────────┬──────────────┘
│
▼
● End Paragraph
The STRING verb is used sequentially. The WITH POINTER WS-POINTER clause is crucial; it tells STRING where to start placing the next piece of data in the WS-LINE-BUFFER, automatically updating the pointer's position after each operation. This allows us to build the line piece by piece: leading spaces, first letter, inner spaces, and second letter.
Compiling and Running the Program
To run this code, you'll need a Cobol compiler. The most accessible modern compiler is GnuCOBOL (formerly OpenCOBOL), which is free and available for Windows, macOS, and Linux.
Assuming you have saved the code as diamond.cbl, you can compile and run it from your terminal with these commands:
# Compile the Cobol source file into an executable
$ cobc -x -free diamond.cbl
# Run the generated executable
$ ./diamond
The -x flag tells the compiler to create an executable file, and -free specifies that the source code uses a more modern, free-form format (though the code provided is also compatible with fixed format).
Pros and Cons of This Cobol Approach
Every language brings its own trade-offs to a problem. Understanding them is key to becoming a well-rounded developer.
| Pros | Cons |
|---|---|
| Extreme Clarity and Structure: The separation of data and procedures (`DATA DIVISION` vs. `PROCEDURE DIVISION`) forces a highly organized and readable coding style. Anyone can understand the variables before even looking at the logic. | Verbosity: Cobol requires significantly more lines of code to accomplish what modern languages do in a fraction of the space. Simple operations like string building require multi-line `STRING` statements. |
| Performance: For its domain (data processing), Cobol is highly optimized. Using `COMP` data types for numeric variables and having fixed memory layouts can lead to very efficient execution on mainframe systems. | Limited Built-in Functions: Cobol lacks a rich standard library. While GnuCOBOL adds some intrinsic functions like `FUNCTION REPEAT`, traditional Cobol would require manual loops even for simple tasks like creating a string of spaces. |
| Excellent for Learning Fundamentals: Cobol's explicitness is a powerful teaching tool. It forces you to manage memory (via `PIC` clauses), control program flow meticulously, and think algorithmically without high-level abstractions. | Rigid Syntax: The syntax is strict, with rules about divisions, sections, paragraphs, and even punctuation (the period `.` is a critical statement terminator). This can feel restrictive to developers accustomed to more flexible languages. |
Frequently Asked Questions (FAQ)
Why is my Cobol diamond not symmetrical or aligned properly?
The most common cause is an error in the space calculation logic. Double-check your formulas for `WS-LEADING-SPACES` and `WS-INNER-SPACES`. Another frequent issue is failing to `INITIALIZE` the `WS-LINE-BUFFER` to `SPACES` before building each new line, which can cause leftover characters from the previous line to appear in the output.
What does `PIC 9(2) COMP` mean and why use it?
PIC 9(2) defines a numeric variable that can hold two digits. The `COMP` (or `COMPUTATIONAL`) clause is a usage declaration that tells the compiler to store the number in a binary format native to the machine, rather than a character-based format. This makes arithmetic operations on the variable significantly faster, which is a best practice for loop counters and calculation-heavy variables.
Can I use dynamic arrays in Cobol for this problem?
Standard Cobol does not support dynamic arrays in the way modern languages do. The language is built on the principle of pre-defined, fixed memory allocation. You must define the maximum size of your tables (arrays) and strings in the `DATA DIVISION` using the `OCCURS` clause for tables or a fixed size in the `PIC` clause for strings. This is why we calculated the maximum possible width of the diamond (51 characters) beforehand.
What's the difference between `PERFORM VARYING` and `PERFORM UNTIL`?
PERFORM UNTIL` is a simple conditional loop, equivalent to a `while` loop in other languages. It repeatedly executes a block of code until a condition is true. `PERFORM VARYING` is Cobol's equivalent of a `for` loop. It initializes a counter, specifies an increment/decrement value (`BY`), and defines the exit condition, all in one statement, making it ideal for iterating a set number of times.
Is Cobol still a relevant language to learn?
Absolutely. While it's not used for web or mobile development, Cobol powers the global financial system. Trillions of dollars in transactions are processed daily by Cobol programs running on mainframes in banks, insurance companies, and government agencies. There is a high demand for Cobol developers to maintain and modernize these critical legacy systems, making it a stable and lucrative career path. Learning it through the kodikra.com learning path provides a unique and valuable skill set.
Why use the `STRING` verb instead of `MOVE`?
The `MOVE` verb overwrites the destination variable completely. If you were to `MOVE` the leading spaces, then `MOVE` the first letter, the letter would replace the spaces. The `STRING` verb, on the other hand, is designed for concatenation. It appends data to a destination variable at a specific position, managed by the `WITH POINTER` clause, allowing you to build a string piece by piece without overwriting previous parts.
Conclusion: From Pattern to Principle
Successfully completing the Diamond Kata in Cobol is a significant milestone. You've moved beyond simple data manipulation and have orchestrated a complete, logical procedure to produce a complex output. You have wrangled the `DATA DIVISION` to define your memory layout, commanded `PERFORM` loops with precision, and mastered the `STRING` verb to build formatted output—a skill set directly applicable to real-world mainframe development.
This exercise proves that Cobol, despite its age, is a language of immense power and structure. It teaches a discipline and an algorithmic rigor that are valuable assets for any programmer. The patterns you've learned here are not just for making shapes; they are the fundamental building blocks for processing the data that runs the world's most critical industries.
Disclaimer: The code in this article was developed and tested using GnuCOBOL 3.1.2. While it uses standard Cobol syntax, behavior may vary slightly with other compilers like those from IBM or Micro Focus.
Ready to tackle the next challenge? Explore our complete Cobol Learning Path to continue your journey from novice to mainframe expert. For more language-specific guides, dive deeper into our Cobol language resources.
Published by Kodikra — Your trusted Cobol learning resource.
Post a Comment