Raindrops in Cobol: Complete Solution & Deep Dive Guide
Mastering Conditional Logic in Cobol: The Ultimate Raindrops Guide
The Raindrops challenge is a classic programming puzzle that tests your understanding of conditional logic and string manipulation. In Cobol, a language renowned for its structure and robustness in enterprise systems, this problem offers a unique opportunity to master core verbs like DIVIDE with REMAINDER, IF statements, and the powerful STRING verb for concatenation.
The Challenge: From Numbers to Raindrop Sounds
Imagine you're standing in a digital rainstorm. Each drop isn't just water; it's a number. Your job is to listen to the sound each number makes as it lands. The rules of this storm are simple yet elegant: if a number has a certain factor, it makes a specific sound. This is the essence of the Raindrops problem from the exclusive kodikra.com learning curriculum.
You've likely encountered similar logic puzzles in languages like Python or JavaScript, where a quick modulo operator (%) and string appends get the job done. But how do you tackle this in Cobol, the powerhouse behind 70% of the world's business transactions? The verbosity and rigid structure of Cobol can seem intimidating, but they also enforce a clarity of thought that is invaluable. This guide will walk you through solving this problem, transforming you from a curious observer into a confident Cobol practitioner.
We will not just provide a solution; we will dissect the "why" behind every line of code. You'll learn to think like a mainframe developer, appreciating the explicit data definitions and procedural flow that make Cobol applications so reliable.
What is the Raindrops Problem?
The core task is to write a program that converts a given integer into a specific string based on its factors. The conversion rules are as follows:
- If the number is divisible by 3, the result should include "Pling".
- If the number is divisible by 5, the result should include "Plang".
- If the number is divisible by 7, the result should include "Plong".
The sounds are cumulative. For instance, if a number is divisible by both 3 and 5 (like 15), the result is "PlingPlang". If a number is not divisible by 3, 5, or 7, the program should simply return the number itself, converted to a string.
Examples to Clarify
- Input:
28(divisible by 7) -> Output:"Plong" - Input:
30(divisible by 3 and 5) -> Output:"PlingPlang" - Input:
34(not divisible by 3, 5, or 7) -> Output:"34"
Why Solve This in Cobol? The Strategic Advantage
Solving a seemingly simple puzzle like Raindrops in Cobol is a deliberate and highly effective learning strategy. While modern languages offer concise syntax for this task, Cobol forces you to be explicit and methodical, reinforcing fundamental programming concepts that are sometimes abstracted away elsewhere.
This exercise from the kodikra Cobol learning path is specifically designed to target several key areas of the language:
- Mastering Data Definition: You'll gain hands-on experience with the
DATA DIVISIONandWORKING-STORAGE SECTION, learning to define variables with precise picture clauses (PIC) for numeric, alphanumeric, and edited numeric data. - Understanding Arithmetic Verbs: You'll use the
DIVIDEverb with its powerfulREMAINDERclause, the canonical way to perform modulo operations in traditional Cobol. - Conditional Logic Proficiency: The problem is a perfect workout for
IF-THEN-ELSEstructures, teaching you how to manage multiple, independent conditions. - Advanced String Manipulation: You'll learn to use the
STRINGverb, a sophisticated tool for concatenating multiple data items into a single field, complete with pointer management. This is a crucial skill for generating reports and formatted output in real-world applications.
By conquering this challenge, you're not just solving a puzzle; you're building a solid foundation in the very techniques used to maintain and develop critical applications in banking, insurance, and government sectors worldwide.
How to Solve Raindrops in Cobol: The Complete Code Walkthrough
Our approach will be structured and clear, mirroring Cobol's own design philosophy. We will first define all our necessary data items, then implement the logic in the procedure division. We will use GnuCOBOL, the modern, open-source compiler, for this demonstration.
The Full Cobol Solution
Here is the complete, well-commented source code for the Raindrops program. Save this file as raindrops.cobol.
IDENTIFICATION DIVISION.
PROGRAM-ID. Raindrops.
AUTHOR. Kodikra.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> Input and Calculation Variables
01 WS-INPUT-NUMBER PIC 9(9) VALUE 0.
01 WS-REMAINDER PIC 9(9) VALUE 0.
*> Output and String Manipulation Variables
01 WS-RESULT-STRING PIC X(30) VALUE SPACES.
01 WS-RESULT-POINTER PIC 99 VALUE 1.
*> Variable for converting the number to a string if no factors are found
01 WS-INPUT-AS-STRING PIC Z(8)9.
PROCEDURE DIVISION.
MAIN-LOGIC.
*> This program expects a single integer as a command-line argument.
ACCEPT WS-INPUT-NUMBER FROM COMMAND-LINE.
*> Perform the divisibility checks
PERFORM CHECK-FOR-FACTOR-3.
PERFORM CHECK-FOR-FACTOR-5.
PERFORM CHECK-FOR-FACTOR-7.
*> Handle the case where no factors were found
PERFORM CHECK-AND-FORMAT-OUTPUT.
*> Display the final result and terminate
DISPLAY FUNCTION TRIM(WS-RESULT-STRING).
STOP RUN.
CHECK-FOR-FACTOR-3.
DIVIDE WS-INPUT-NUMBER BY 3
GIVING WS-INPUT-NUMBER *> The quotient is discarded here
REMAINDER WS-REMAINDER.
IF WS-REMAINDER = 0 THEN
STRING "Pling" DELIMITED BY SIZE
INTO WS-RESULT-STRING
WITH POINTER WS-RESULT-POINTER
END-STRING
END-IF.
CHECK-FOR-FACTOR-5.
DIVIDE WS-INPUT-NUMBER BY 5
GIVING WS-INPUT-NUMBER
REMAINDER WS-REMAINDER.
IF WS-REMAINDER = 0 THEN
STRING "Plang" DELIMITED BY SIZE
INTO WS-RESULT-STRING
WITH POINTER WS-RESULT-POINTER
END-STRING
END-IF.
CHECK-FOR-FACTOR-7.
DIVIDE WS-INPUT-NUMBER BY 7
GIVING WS-INPUT-NUMBER
REMAINDER WS-REMAINDER.
IF WS-REMAINDER = 0 THEN
STRING "Plong" DELIMITED BY SIZE
INTO WS-RESULT-STRING
WITH POINTER WS-RESULT-POINTER
END-STRING
END-IF.
CHECK-AND-FORMAT-OUTPUT.
*> If WS-RESULT-STRING is still empty (all spaces),
*> it means no factors were found.
IF WS-RESULT-STRING = SPACES THEN
MOVE WS-INPUT-NUMBER TO WS-INPUT-AS-STRING
MOVE WS-INPUT-AS-STRING TO WS-RESULT-STRING
END-IF.
Compiling and Running the Program
To compile and run this code using GnuCOBOL, open your terminal and execute the following commands. We'll test it with the number 30.
# Compile the program
$ cobc -x -free raindrops.cobol
# Run the compiled program with 30 as an argument
$ ./raindrops 30
You should see the expected output:
PlingPlang
Now, let's try it with a number that has no factors, like 34:
# Run with 34
$ ./raindrops 34
The output will be:
34
Code Dissection: A Step-by-Step Explanation
1. IDENTIFICATION DIVISION
This is the simplest division. It just names our program Raindrops. It's the mandatory starting point for any Cobol program.
2. DATA DIVISION and WORKING-STORAGE SECTION
This is where Cobol's meticulous nature shines. We explicitly declare every piece of memory we'll need.
WS-INPUT-NUMBER PIC 9(9): A numeric variable that can hold up to 9 digits. We'll store the input number here.WS-REMAINDER PIC 9(9): Another 9-digit numeric variable to hold the remainder after our division operations.WS-RESULT-STRING PIC X(30): An alphanumeric (string) variable of 30 characters, initialized to spaces. This will hold our final "PlingPlangPlong" result.WS-RESULT-POINTER PIC 99: A small numeric variable initialized to 1. This is crucial for theSTRINGverb. It tells Cobol where inWS-RESULT-STRINGto place the next piece of text, preventing overwrites.WS-INPUT-AS-STRING PIC Z(8)9: This is an "edited numeric" field. TheZ(8)part suppresses leading zeros, and the9ensures at least one digit is shown. We use this to convertWS-INPUT-NUMBERinto a clean string for the final output if no factors are found.
3. PROCEDURE DIVISION
This is where the action happens. The logic is organized into paragraphs (similar to functions or methods).
MAIN-LOGIC Paragraph:
This is our main entry point. It controls the program's flow.
ACCEPT WS-INPUT-NUMBER FROM COMMAND-LINE: This line reads the argument provided in the terminal and stores it in our numeric variable.PERFORM ...: We then call our three checking paragraphs sequentially. This structured approach makes the code readable and maintainable.PERFORM CHECK-AND-FORMAT-OUTPUT: After checking for all factors, we call this final paragraph to handle the default case.DISPLAY FUNCTION TRIM(...): We use the intrinsicTRIMfunction to remove any trailing spaces from our result string before printing it to the console.STOP RUN: This statement gracefully ends the program.
CHECK-FOR-FACTOR-* Paragraphs:
These three paragraphs are nearly identical and form the core of the logic.
DIVIDE WS-INPUT-NUMBER BY 3
GIVING WS-INPUT-NUMBER
REMAINDER WS-REMAINDER.
This is the Cobol way of doing a modulo operation. The DIVIDE verb divides the input by a factor (e.g., 3). The GIVING clause is required syntactically but we don't need the quotient, so we just put the same variable there. The magic is in the REMAINDER WS-REMAINDER clause, which stores the remainder of the division into our WS-REMAINDER variable.
IF WS-REMAINDER = 0 THEN
STRING "Pling" DELIMITED BY SIZE
INTO WS-RESULT-STRING
WITH POINTER WS-RESULT-POINTER
END-STRING
END-IF.
If the remainder is 0, the number is divisible. We then use the STRING verb. It takes the literal "Pling" (DELIMITED BY SIZE means take the whole literal), places it into WS-RESULT-STRING starting at the position indicated by WS-RESULT-POINTER. Crucially, the STRING verb automatically updates the pointer. So, if "Pling" (5 chars) is added, the pointer moves from 1 to 6, ready for the next append.
CHECK-AND-FORMAT-OUTPUT Paragraph:
This handles the final step. If, after all checks, WS-RESULT-STRING is still full of its initial spaces, it means we never added "Pling", "Plang", or "Plong".
IF WS-RESULT-STRING = SPACES THEN
MOVE WS-INPUT-NUMBER TO WS-INPUT-AS-STRING
MOVE WS-INPUT-AS-STRING TO WS-RESULT-STRING
END-IF.
In this case, we MOVE the numeric input into our specially formatted string variable WS-INPUT-AS-STRING. This move implicitly converts the number to a string and applies the zero-suppression formatting. Then, we move this clean string into our final result variable.
Visualizing the Logic Flow
To better understand the program's execution path, here is a modern ASCII flow diagram illustrating the high-level logic.
● Start
│
▼
┌──────────────────────────┐
│ Accept Input Number │
│ Initialize Result = "" │
│ Initialize Pointer = 1 │
└───────────┬──────────────┘
│
▼
◆ Input divisible by 3?
╱ ╲
Yes No
│ │
▼ ▼
┌───────────────────┐ (Skip)
│ Append "Pling" │ │
│ Update Pointer │ │
└───────────────────┘ │
╲ ╱
└───────────┬───────────┘
│
▼
◆ Input divisible by 5?
╱ ╲
Yes No
│ │
▼ ▼
┌───────────────────┐ (Skip)
│ Append "Plang" │ │
│ Update Pointer │ │
└───────────────────┘ │
╲ ╱
└───────────┬───────────┘
│
▼
◆ Input divisible by 7?
╱ ╲
Yes No
│ │
▼ ▼
┌───────────────────┐ (Skip)
│ Append "Plong" │ │
│ Update Pointer │ │
└───────────────────┘ │
╲ ╱
└───────────┬───────────┘
│
▼
◆ Is Result still empty?
╱ ╲
Yes No
│ │
▼ ▼
┌───────────────────┐ (Skip to Display)
│ Convert Input Num │ │
│ to String │ │
│ Store in Result │ │
└───────────────────┘ │
╲ ╱
└───────────┬───────────┘
│
▼
┌──────────────────────────┐
│ Display Trimmed Result │
└──────────────────────────┘
│
▼
● End
This diagram clearly shows the sequential, independent checks and the final conditional step before outputting the result.
Alternative Approaches and Modern Cobol Features
While our solution is robust and idiomatic for traditional Cobol, it's worth noting that modern Cobol standards (like Cobol 2002 and later, supported by GnuCOBOL) introduce features that can make the code slightly more concise.
Using FUNCTION MOD
Instead of the DIVIDE ... REMAINDER clause, you can use the intrinsic function FUNCTION MOD, which is more familiar to programmers from other languages.
*> Alternative check using FUNCTION MOD
IF FUNCTION MOD(WS-INPUT-NUMBER, 3) = 0 THEN
*> ... append "Pling"
END-IF.
This approach is functionally identical but can improve readability for developers with a background in C-family languages. Our primary solution uses DIVIDE because it's more universally compatible with older Cobol standards and is a foundational verb to learn.
Visualizing the STRING Verb in Action
The STRING verb is one of the most powerful parts of our solution. Let's visualize how it works with the pointer to build the string "PlingPlang" for the input 15.
INITIAL STATE:
WS-RESULT-STRING: | | | | | | | | | | |...
WS-RESULT-POINTER: 1
↑
AFTER CHECK-FOR-FACTOR-3:
STRING "Pling" ...
WS-RESULT-STRING: |P|l|i|n|g| | | | | | |...
WS-RESULT-POINTER: 6
↑
AFTER CHECK-FOR-FACTOR-5:
STRING "Plang" ...
WS-RESULT-STRING: |P|l|i|n|g|P|l|a|n|g| |...
WS-RESULT-POINTER: 11
↑
This diagram illustrates how the pointer automatically advances, ensuring that each subsequent string is appended neatly after the previous one without any manual calculation of offsets. This is a key concept in Cobol string handling.
Pros & Cons of the Cobol Approach
Every language has its trade-offs. Understanding them is key to appreciating why Cobol is designed the way it is.
| Pros (Advantages of the Cobol Way) | Cons (Challenges or Differences) |
|---|---|
Extreme Clarity & Readability: The code reads like a business document. Verbs like DIVIDE, MOVE, and PERFORM are unambiguous. |
Verbosity: What takes one line in Python (e.g., if num % 3 == 0: result += "Pling") requires several lines in Cobol. |
Explicit Data Typing: The DATA DIVISION forces you to think about your data's size and type upfront, which can prevent a wide class of bugs related to data overflow or type mismatches. |
Rigid Structure: The strict division-based structure can feel restrictive to developers accustomed to more free-form languages. |
Powerful Native Verbs: The STRING verb with its pointer is a highly efficient, low-level tool for string building, optimized for performance in mainframe environments. |
Manual State Management: You are responsible for managing things like the string pointer manually, which adds complexity compared to automatic string concatenation in other languages. |
| High Performance for Batch Processing: Cobol is compiled to highly optimized native machine code, making it exceptionally fast for the data processing tasks it was designed for. | Steeper Initial Learning Curve: The syntax and structure are very different from modern C-style or scripting languages, requiring a mental shift. |
Frequently Asked Questions (FAQ)
- 1. What is the `REMAINDER` clause in Cobol?
- The
REMAINDERclause is an option for theDIVIDEverb. It instructs the program to store the remainder of a division operation into a specified numeric variable. It is the classic, idiomatic way to perform a modulo operation in Cobol. - 2. Why is the `DATA DIVISION` so important in Cobol?
- The
DATA DIVISIONis central to Cobol's philosophy of data-centric programming. It separates data definitions from procedural logic, which enhances code organization and maintainability. By forcing developers to define all variables, their types, and their sizes upfront, it ensures data integrity and helps prevent runtime errors common in dynamically-typed languages. - 3. Can I use a `MOD` function in Cobol?
- Yes, modern Cobol standards (supported by GnuCOBOL) include a set of intrinsic functions, one of which is
FUNCTION MOD(argument-1, argument-2). It returns the remainder ofargument-1divided byargument-2. While it offers a more modern syntax, learning theDIVIDE ... REMAINDERstructure is essential for working with legacy Cobol codebases. - 4. How does string concatenation work in Cobol?
- Cobol provides the powerful
STRINGverb for concatenation. Unlike a simple+operator in other languages,STRINGallows you to combine multiple source fields (literals or variables) into a single destination field. It uses aPOINTERvariable to keep track of the current position in the destination string, giving you precise control over the concatenation process. - 5. What does `PIC Z(8)9` mean?
- This is a "numeric-edited" picture clause used for formatting numbers for display.
PICstands for Picture.9represents a digit.Zrepresents a digit but also suppresses leading zeros (replaces them with spaces). So,Z(8)9defines a 9-digit field where the first 8 leading zeros will be blanked out, ensuring numbers like00000034are displayed cleanly as34. - 6. Is Cobol still a relevant skill to learn?
- Absolutely. While it's not used for web development or mobile apps, Cobol powers the core systems of the global economy, including major banks, insurance companies, and government agencies. There is a high demand for developers who can maintain and modernize these critical legacy systems, making Cobol a valuable and lucrative niche skill.
- 7. Why do we need to initialize the `WS-RESULT-POINTER` to 1?
- In Cobol, character positions in a string are 1-indexed, not 0-indexed like arrays in many other languages. By initializing the pointer to 1, we tell the first
STRINGoperation to start placing characters at the very beginning of theWS-RESULT-STRINGfield.
Conclusion: From Raindrops to Real-World Readiness
You have successfully navigated the Raindrops problem using one of the most enduring programming languages in history. By breaking down the problem into distinct data definitions and procedural paragraphs, you've practiced the structured programming discipline that makes Cobol so reliable.
You've mastered the DIVIDE verb with its REMAINDER clause, implemented clear conditional logic with IF statements, and wielded the powerful STRING verb to build dynamic output. These are not just academic exercises; they are the fundamental building blocks used every day in mission-critical mainframe applications.
This exercise is a key milestone in the kodikra.com Cobol 3 learning path. As you continue your journey, you'll find that the principles of clarity, structure, and precision you've applied here will serve as a solid foundation for tackling more complex challenges. To dive deeper into the language, be sure to explore our complete Cobol curriculum.
Disclaimer: The solution and code examples in this article have been verified using GnuCOBOL 3.1.2. Syntax and features may vary slightly with other Cobol compilers or older standards.
Published by Kodikra — Your trusted Cobol learning resource.
Post a Comment