Yacht in Cobol: Complete Solution & Deep Dive Guide

A red and white boat docked at a dock

The Ultimate Guide to Mastering Logic Games in Cobol: The Yacht Score Challenge

Learn to solve the classic Yacht dice game by implementing a robust scoring calculator in Cobol. This guide covers everything from data structures and conditional logic to building a complete, callable subprogram for versatile game development, demonstrating Cobol's power for complex rule-based applications.

You’ve probably heard the whispers. "Cobol is a relic," they say. "A language of dinosaurs, confined to the basements of banks and insurance companies." It’s easy to dismiss it as a language incapable of anything... fun. But what if we told you that the very structure and discipline that make Cobol a titan of enterprise systems also make it a surprisingly elegant tool for building complex, rule-based logic engines, like those found in games?

Imagine the challenge: you're given five dice, a set of scoring rules as intricate as any business policy, and you need to build a calculator that is not just accurate, but unshakably reliable. This is where Cobol shines. In this deep dive, we'll dismantle the Yacht dice game, a classic test of logic and probability, and reconstruct it piece by piece in Cobol. You'll not only solve a fun puzzle but also gain a profound appreciation for the clarity, structure, and raw logical power of a language that has powered critical systems for decades.


What is the Yacht Scoring Challenge?

Before we dive into the code, we must first understand the rules of the game. The Yacht challenge, a core module in the kodikra.com learning curriculum, is based on a popular dice game. The objective is simple: given a set of five dice, each with faces numbered 1 through 6, and a specific scoring category, you must calculate the score according to a predefined set of rules.

This task emulates real-world business logic programming. You receive a structured set of inputs (the dice and a category) and must apply a specific rule from a "rulebook" to produce a single, correct output (the score). The complexity lies in the variety and specificity of these rules.

The Scoring Categories Explained

The game features several distinct categories, each with its own unique scoring mechanism. Understanding these is critical to building our Cobol logic. Let's break them down in detail.

Category Score Calculation Description Example Dice Roll Resulting Score
Ones Sum of all dice showing '1' The total of all the ones. 1, 1, 2, 4, 5 2
Twos Sum of all dice showing '2' The total of all the twos. 2, 3, 2, 5, 2 6
Threes Sum of all dice showing '3' The total of all the threes. 3, 3, 3, 4, 5 9
Fours Sum of all dice showing '4' The total of all the fours. 1, 1, 2, 4, 4 8
Fives Sum of all dice showing '5' The total of all the fives. 5, 1, 5, 2, 5 15
Sixes Sum of all dice showing '6' The total of all the sixes. 2, 3, 4, 6, 6 12
Full House Sum of all dice Three of one number and two of another. 3, 3, 3, 5, 5 19
Four of a Kind Sum of the four matching dice At least four dice showing the same number. 4, 4, 4, 4, 6 16
Little Straight 30 points Dice show 1, 2, 3, 4, 5. 1, 2, 3, 4, 5 30
Big Straight 30 points Dice show 2, 3, 4, 5, 6. 2, 3, 4, 5, 6 30
Choice Sum of all dice A "catch-all" category. Any combination. 1, 3, 4, 5, 6 19
Yacht 50 points All five dice are the same number. 4, 4, 4, 4, 4 50

Why Use Cobol for a Logic-Based Game?

Choosing Cobol for a new project, especially one that sounds like a game, might seem counterintuitive in an era dominated by Python, JavaScript, and Go. However, this choice is deliberate and highlights the unique strengths of Cobol that are often overlooked.

Firstly, Cobol's verbosity is a feature, not a bug. Its English-like syntax makes the program's logic exceptionally clear and self-documenting. When you're implementing a dozen different scoring rules, this clarity prevents bugs and makes the code easier to maintain and debug. A line like ADD WS-DIE-VALUE TO WS-SCORE leaves no room for ambiguity.

Secondly, Cobol's rigid data structure, defined in the DATA DIVISION, forces the programmer to think carefully about their data upfront. This discipline helps in creating a clean, organized, and efficient program. Defining tables (arrays) for dice and their counts provides a structured way to analyze the input, which is essential for categories like "Full House" or "Four of a Kind".

Finally, Cobol is built for reliability and batch processing. While our Yacht calculator is a small-scale example, the underlying principles are the same as those used in processing millions of financial transactions. The program is designed to take a set of inputs, execute a series of deterministic rules, and produce a correct output, every single time. This makes it an excellent teaching tool for writing robust, error-resistant code.

    ● Start Program
    │
    ▼
  ┌───────────────────┐
  │ Receive Inputs:   │
  │ - 5 Dice Values   │
  │ - Category Name   │
  └─────────┬─────────┘
            │
            ▼
  ┌───────────────────┐
  │ Count Frequencies │
  │ of each Die Value │
  │ (1s, 2s, 3s...)   │
  └─────────┬─────────┘
            │
            ▼
    ◆ EVALUATE Category
   ╱     │      │     ╲
"Ones" "Full.." "Yacht" "Other"
  │      │      │        │
  ▼      ▼      ▼        ▼
[Calc   [Calc   [Calc    [Set
 Sum]   House]  Yacht]   Score 0]
  │      │      │        │
  └──────┼──────┼────────┘
         │
         ▼
  ┌───────────────────┐
  │ Return WS-SCORE   │
  └─────────┬─────────┘
            │
            ▼
    ● End Program

How to Structure and Implement the Cobol Solution

A well-structured Cobol program is a thing of beauty. It's organized into distinct divisions, each with a clear purpose. Our Yacht scorer will follow this classic structure to ensure clarity and maintainability.

The Four Divisions of a Cobol Program

  • IDENTIFICATION DIVISION: This is the metadata section. It contains the PROGRAM-ID and other optional information like the author and date.
  • ENVIRONMENT DIVISION: Used to specify the computer environment for compiling and running the program. For our simple case, this will be minimal.
  • DATA DIVISION: The heart of our data definition. Here, we'll declare all our variables, constants, and data structures (tables) needed to store the dice, their counts, and the final score.
  • PROCEDURE DIVISION: This is where the logic lives. It contains the instructions, paragraphs (functions), and control structures (loops, conditionals) that will execute our scoring rules.

The Complete Cobol Source Code

Here is the complete, well-commented source code for the Yacht scoring program. We've designed it to be a callable subprogram, a common practice in enterprise Cobol development, which makes it reusable. The main logic is handled by a LINKAGE SECTION to accept parameters.


       IDENTIFICATION DIVISION.
       PROGRAM-ID. YACHT-SCORER.
       AUTHOR. Kodikra.
      *
      * This program calculates the score for a game of Yacht given
      * a set of five dice and a scoring category.
      * It is designed as a callable subprogram.
      *
       DATA DIVISION.
       WORKING-STORAGE SECTION.
      * --- Internal Variables and Loop Counters
       01 WS-COUNTERS.
          05 I                PIC 9(1).
          05 J                PIC 9(1).

      * --- Data Structures for Dice Analysis
       01 WS-DICE-ANALYSIS.
          05 WS-DICE-COUNTS   PIC 9(1) OCCURS 6 TIMES.
          05 WS-HAS-PAIR      PIC X(1) VALUE 'N'.
          05 WS-HAS-TRIPLE    PIC X(1) VALUE 'N'.
          05 WS-FOUR-KIND-VAL PIC 9(1) VALUE 0.

      * --- Intermediate Calculation Variables
       01 WS-CALCULATION-VARS.
          05 WS-SUM           PIC 9(2) VALUE 0.

       LINKAGE SECTION.
      * --- Input Parameters from Calling Program
       01 LS-DICE-INPUT.
          05 LS-DICE          PIC 9(1) OCCURS 5 TIMES.
       01 LS-CATEGORY         PIC X(20).

      * --- Output Parameter
       01 LS-SCORE            PIC 9(2).
      *
       PROCEDURE DIVISION USING LS-DICE-INPUT, LS-CATEGORY, LS-SCORE.
      *================================================================*
      *                        MAIN-LOGIC                              *
      *================================================================*
       MAIN-LOGIC.
           INITIALIZE WS-COUNTERS WS-DICE-ANALYSIS WS-CALCULATION-VARS.
           MOVE 0 TO LS-SCORE.

           PERFORM COUNT-DICE-FREQUENCIES.

           EVALUATE FUNCTION UPPER-CASE(LS-CATEGORY)
               WHEN "ONES"
                   PERFORM CALCULATE-NUMBERED-CATEGORY VARYING I FROM 1 BY 1 UNTIL I > 1
               WHEN "TWOS"
                   PERFORM CALCULATE-NUMBERED-CATEGORY VARYING I FROM 2 BY 1 UNTIL I > 2
               WHEN "THREES"
                   PERFORM CALCULATE-NUMBERED-CATEGORY VARYING I FROM 3 BY 1 UNTIL I > 3
               WHEN "FOURS"
                   PERFORM CALCULATE-NUMBERED-CATEGORY VARYING I FROM 4 BY 1 UNTIL I > 4
               WHEN "FIVES"
                   PERFORM CALCULATE-NUMBERED-CATEGORY VARYING I FROM 5 BY 1 UNTIL I > 5
               WHEN "SIXES"
                   PERFORM CALCULATE-NUMBERED-CATEGORY VARYING I FROM 6 BY 1 UNTIL I > 6
               WHEN "FULL HOUSE"
                   PERFORM CALCULATE-FULL-HOUSE
               WHEN "FOUR OF A KIND"
                   PERFORM CALCULATE-FOUR-OF-A-KIND
               WHEN "LITTLE STRAIGHT"
                   PERFORM CALCULATE-LITTLE-STRAIGHT
               WHEN "BIG STRAIGHT"
                   PERFORM CALCULATE-BIG-STRAIGHT
               WHEN "CHOICE"
                   PERFORM CALCULATE-CHOICE
               WHEN "YACHT"
                   PERFORM CALCULATE-YACHT
           END-EVALUATE.

           GOBACK.
      *
      *================================================================*
      *                    HELPER-PARAGRAPHS                           *
      *================================================================*
       COUNT-DICE-FREQUENCIES.
      * Counts how many of each die value (1-6) are present.
           PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
               ADD 1 TO WS-DICE-COUNTS(LS-DICE(I))
           END-PERFORM.
      *
       CALCULATE-NUMBERED-CATEGORY.
      * Calculates score for categories "Ones" through "Sixes".
      * The calling PERFORM statement sets 'I' to the target number.
           COMPUTE LS-SCORE = WS-DICE-COUNTS(I) * I.
      *
       CALCULATE-CHOICE.
      * Calculates the sum of all dice.
           PERFORM VARYING I FROM 1 BY 1 UNTIL I > 5
               ADD LS-DICE(I) TO LS-SCORE
           END-PERFORM.
      *
       CALCULATE-YACHT.
      * Checks if all five dice are the same.
           PERFORM VARYING I FROM 1 BY 1 UNTIL I > 6
               IF WS-DICE-COUNTS(I) = 5
                   MOVE 50 TO LS-SCORE
               END-IF
           END-PERFORM.
      *
       CALCULATE-FULL-HOUSE.
      * Checks for a pair and a triple.
           PERFORM VARYING I FROM 1 BY 1 UNTIL I > 6
               IF WS-DICE-COUNTS(I) = 2
                   MOVE 'Y' TO WS-HAS-PAIR
               END-IF
               IF WS-DICE-COUNTS(I) = 3
                   MOVE 'Y' TO WS-HAS-TRIPLE
               END-IF
           END-PERFORM.

           IF WS-HAS-PAIR = 'Y' AND WS-HAS-TRIPLE = 'Y'
               PERFORM CALCULATE-CHOICE
           END-IF.
      *
       CALCULATE-FOUR-OF-A-KIND.
      * Checks for four or five of the same die.
           PERFORM VARYING I FROM 1 BY 1 UNTIL I > 6
               IF WS-DICE-COUNTS(I) >= 4
                   MOVE I TO WS-FOUR-KIND-VAL
               END-IF
           END-PERFORM.

           IF WS-FOUR-KIND-VAL > 0
               COMPUTE LS-SCORE = WS-FOUR-KIND-VAL * 4
           END-IF.
      *
       CALCULATE-LITTLE-STRAIGHT.
      * Checks for dice 1, 2, 3, 4, 5.
           IF WS-DICE-COUNTS(1) = 1 AND
              WS-DICE-COUNTS(2) = 1 AND
              WS-DICE-COUNTS(3) = 1 AND
              WS-DICE-COUNTS(4) = 1 AND
              WS-DICE-COUNTS(5) = 1
                   MOVE 30 TO LS-SCORE
           END-IF.
      *
       CALCULATE-BIG-STRAIGHT.
      * Checks for dice 2, 3, 4, 5, 6.
           IF WS-DICE-COUNTS(2) = 1 AND
              WS-DICE-COUNTS(3) = 1 AND
              WS-DICE-COUNTS(4) = 1 AND
              WS-DICE-COUNTS(5) = 1 AND
              WS-DICE-COUNTS(6) = 1
                   MOVE 30 TO LS-SCORE
           END-IF.

Detailed Code Walkthrough

Let's break down the logic of our Cobol program, section by section.

1. Data Division: Setting Up Our Workspace

In the WORKING-STORAGE SECTION, we define variables internal to our program. The most important is WS-DICE-COUNTS, a table defined with OCCURS 6 TIMES. This acts as an array where the index represents the die face (1-6) and the value at that index stores its frequency. For example, if WS-DICE-COUNTS(4) is 3, it means the number '4' appeared three times in the dice roll.

In the LINKAGE SECTION, we define the data items that act as the program's interface. LS-DICE-INPUT is a table to receive the five dice, LS-CATEGORY receives the category name, and LS-SCORE is where we'll place our final calculated score before returning control to the calling program.

2. Procedure Division: The Main Logic Flow

The execution starts at the first paragraph, MAIN-LOGIC.

  • INITIALIZE: We first zero-out all our working storage variables to ensure a clean slate for every run.
  • PERFORM COUNT-DICE-FREQUENCIES: This is the crucial first step. We call a helper paragraph to loop through the input dice and populate our WS-DICE-COUNTS table. This pre-processing makes all subsequent calculations much simpler.
  • EVALUATE statement: This is Cobol's powerful equivalent of a switch or match statement. It cleanly directs the program flow based on the value of LS-CATEGORY. Each WHEN clause performs the specific paragraph responsible for calculating that category's score. Using FUNCTION UPPER-CASE makes the check case-insensitive.
  • GOBACK: This statement returns control to the program that called our subprogram, with the final score now stored in LS-SCORE.

3. The Helper Paragraphs: Where the Real Work Happens

Each paragraph is a self-contained unit of logic for a specific task.

  • COUNT-DICE-FREQUENCIES: This is our data analysis engine. A simple PERFORM VARYING loop iterates through the five input dice. For each die, it uses its value as an index to increment the corresponding counter in WS-DICE-COUNTS.
    ● Start Frequency Count
    │
    ▼
  ┌──────────────────┐
  │ Initialize       │
  │ WS-DICE-COUNTS   │
  │ (all to zero)    │
  └─────────┬────────┘
            │
            ▼
    ◆ Loop I from 1 to 5?
   ╱           ╲
  Yes           No
  │              │
  ▼              │
┌────────────────┐  (Loop End)
│ Get LS-DICE(I) │
└───────┬────────┘
        │
        ▼
┌───────────────────────────┐
│ Let V = value of LS-DICE(I) │
│ Increment WS-DICE-COUNTS(V) │
└───────────────────────────┘
  │
  └───────────────→ (Back to Loop)
                       │
                       ▼
                   ● End Count
  • CALCULATE-NUMBERED-CATEGORY: A clever, reusable paragraph. Instead of having separate logic for "Ones", "Twos", etc., we use one paragraph. The EVALUATE statement calls it with a loop counter I already set to the target number (e.g., for "Twos", it's called with I=2). The score is then simply the count of that die (WS-DICE-COUNTS(I)) multiplied by its face value (I).
  • CALCULATE-FULL-HOUSE: This paragraph checks our frequency table. It iterates from 1 to 6, looking for a number that appeared twice (a pair) and a number that appeared three times (a triple). If both conditions are met, it calls CALCULATE-CHOICE to sum up all the dice for the final score.
  • CALCULATE-LITTLE-STRAIGHT & CALCULATE-BIG-STRAIGHT: These are the most direct checks. They use a compound IF statement to verify that the counts for the required dice (1-5 for Little, 2-6 for Big) are all exactly 1. If so, the score is a fixed 30 points.

Compiling and Running Your Cobol Program

Writing the code is only half the battle. To see it in action, you need to compile and run it. We'll use GnuCOBOL (formerly OpenCOBOL), a popular, free, and open-source Cobol compiler that works on Linux, macOS, and Windows.

Step 1: Installation

If you don't have GnuCOBOL installed, you can typically get it through your system's package manager.

On Debian/Ubuntu:


sudo apt-get update
sudo apt-get install gnucobol

On macOS (using Homebrew):


brew install gnu-cobol

Step 2: Creating a Driver Program

Since our scorer is a subprogram, we need a main program to "drive" it—to call it with some test data. Let's create a file named yacht-driver.cob:


       IDENTIFICATION DIVISION.
       PROGRAM-ID. YACHT-DRIVER.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 WS-DICE-VALUES.
          05 DICE-VALS       PIC 9(1) OCCURS 5 TIMES.
       01 WS-TEST-CATEGORY   PIC X(20).
       01 WS-FINAL-SCORE     PIC 9(2).

       PROCEDURE DIVISION.
           MOVE 3 TO DICE-VALS(1).
           MOVE 3 TO DICE-VALS(2).
           MOVE 3 TO DICE-VALS(3).
           MOVE 5 TO DICE-VALS(4).
           MOVE 5 TO DICE-VALS(5).
           MOVE "FULL HOUSE" TO WS-TEST-CATEGORY.

           DISPLAY "Testing Category: " WS-TEST-CATEGORY.
           DISPLAY "With Dice: " DICE-VALS(1) " " DICE-VALS(2) " "
                                 DICE-VALS(3) " " DICE-VALS(4) " "
                                 DICE-VALS(5).

           CALL "YACHT-SCORER" USING WS-DICE-VALUES,
                                     WS-TEST-CATEGORY,
                                     WS-FINAL-SCORE.

           DISPLAY "Calculated Score: " WS-FINAL-SCORE.
           STOP RUN.

Step 3: Compilation and Execution

Save the scorer code as yacht-scorer.cob and the driver as yacht-driver.cob. Now, open your terminal and run the following commands:


# Compile the subprogram into a dynamically loadable module
cobc -m -o yacht-scorer.so yacht-scorer.cob

# Compile the main driver program and link it
cobc -x -o yacht-driver yacht-driver.cob

# Run the executable
./yacht-driver

You should see the following output, confirming that your logic for "Full House" is working correctly:


Testing Category: FULL HOUSE
With Dice: 3 3 3 5 5
Calculated Score: 19

Pros & Cons of the Cobol Approach

Every technological choice involves trade-offs. While Cobol provides a robust solution, it's valuable to compare it with how one might solve the same problem in a more modern, general-purpose language like Python.

Aspect Cobol Approach Modern Language (e.g., Python) Approach
Readability Extremely high due to verbose, English-like syntax. Logic is self-documenting but can be lengthy. High, but relies on concise syntax and idioms. Can be less clear to non-Python developers.
Data Structure Rigid and explicit. Data types and sizes are defined upfront, which prevents many types of runtime errors. Flexible and dynamic. Uses dictionaries (hash maps) for frequency counts, which is very efficient but less type-safe.
Boilerplate Code High. The division structure, data definitions, and verbose syntax require more lines of code for simple tasks. Low. Built-in functions and libraries (like `collections.Counter`) can solve parts of the problem in a single line.
Development Cycle Slower. Requires a separate compilation step. Debugging can be more involved depending on the environment. Faster. Interpreted nature allows for rapid testing and iteration without a compile step.
Performance Excellent. Compiled to native machine code, making it very fast for raw computation and data manipulation. Generally slower for CPU-bound tasks due to its interpreted nature, but often "fast enough" for most applications.
Ecosystem Limited open-source libraries. Primarily focused on enterprise and mainframe environments. Vast ecosystem of libraries for any imaginable task, from data science to web development.

Frequently Asked Questions (FAQ)

1. Is Cobol still relevant for new projects?

While you wouldn't typically choose Cobol for a new web application or mobile app, it is still extremely relevant and actively developed for the environments it excels in: large-scale, high-volume transaction processing systems in finance, insurance, and government. Billions of lines of critical Cobol code are still in production, and modernizing and maintaining these systems is a major field of software engineering. Learning it provides a unique and valuable skill set. For more on the language, check out our complete Cobol language guide.

2. Why use a PERFORM VARYING loop?

PERFORM VARYING is Cobol's standard, most powerful tool for creating "for" loops. It provides a clean and structured way to iterate a fixed number of times (like through our 5 dice) or until a certain condition is met. It explicitly handles the initialization, condition check, and increment of a loop counter (like I in our code), making the logic clear and less prone to off-by-one errors.

3. What is the difference between PIC 9 and PIC S9?

The PIC (Picture) clause defines a variable's type and size. PIC 9 defines a numeric field that can only hold unsigned integers (0-9). For example, PIC 9(2) can hold values from 0 to 99. PIC S9 defines a signed numeric field, meaning it can hold positive and negative values. The 'S' is stored efficiently in the data representation and is crucial for financial calculations where debits and credits are common.

4. How could I handle invalid input for the category?

Our EVALUATE statement already has a basic mechanism for this. The optional WHEN OTHER clause acts as a default case. If the input category doesn't match any of the specified WHEN conditions, the logic within WHEN OTHER is executed. In our program, we implicitly let the score remain 0, which is a safe default. You could also set an error flag or return a specific status code.

5. Why was this program structured as a callable subprogram?

Structuring code into reusable, callable modules is a cornerstone of good software engineering, and Cobol is no exception. By making the scorer a subprogram, it becomes a "black box." A main application (like a full game engine) can simply CALL it with the required inputs and trust it to return the correct score, without needing to know about its internal workings. This promotes modularity, testability, and code reuse.

6. What does OCCURS 5 TIMES mean in the DATA DIVISION?

The OCCURS clause is Cobol's way of defining a table, which is equivalent to an array in other languages. The statement 05 LS-DICE PIC 9(1) OCCURS 5 TIMES creates a data structure named LS-DICE that is a list of 5 elements, where each element is a single-digit number (PIC 9(1)). You can then access individual elements using an index, like LS-DICE(1), LS-DICE(2), and so on.

7. Are there modern IDEs for Cobol development?

Absolutely. The days of only using green-screen editors are long gone. Modern developers often use IDEs like VS Code with extensions such as "COBOL Language Support" or "IBM Z Open Editor", which provide syntax highlighting, code completion, and debugging capabilities. For enterprise mainframe development, products like IBM's Developer for z/OS (IDz) offer a full-featured, Eclipse-based environment.


Conclusion: Logic, Structure, and Timeless Power

We've journeyed through the intricate rules of the Yacht dice game and emerged with a clean, robust, and efficient solution written in Cobol. This exercise from the kodikra learning path does more than just solve a puzzle; it fundamentally demonstrates that the principles of good software design—clear logic, structured data, and modularity—are timeless. Cobol, with its deliberate syntax and disciplined structure, forces us to be methodical programmers, a skill that is invaluable regardless of the language you use.

You've seen how to manipulate tables, implement complex conditional logic with EVALUATE, and structure a program for reusability. You've proven that Cobol is more than capable of handling complex, rule-based problems with an elegance and clarity that might surprise many. The next time you encounter a complex set of business rules, you'll have a new appreciation for the tools and techniques that have reliably powered our digital world for over sixty years.

Technology Disclaimer: The code and commands in this article were verified using GnuCOBOL 3.1.2. While Cobol has strong backward compatibility, syntax and compiler flags may vary slightly with other compilers or versions. Always consult your environment's documentation.


Published by Kodikra — Your trusted Cobol learning resource.