ocamlocaml-core

OCaml implementation of code challenge


I'm doing a daily code challenge that allows for any language to be used. I've recently been working through Real-World OCaml. I'm really interested to see how this particular challenge would be solved in idiomatic OCaml. Below are two of my JavaScript implementations. The challenge is to recognize the pattern in a mathematical pyramid:

1 11 21 1211 111221

(The pattern is One 1, two 1s, one 2, one 1, three 1s, two 2s, one 1, the numbers read form the next "level" or line)

function createNextLevel(previousLevel, currentLevel = 0, finalLevel = 40) {
    let sub = '';
    let level = '';
    // iterate on string
    for (let i = 0; i < previousLevel.length; i++) {
        // if we don't have an element to the left or it's  equal to current element
        if (!previousLevel[i - 1] || previousLevel[i] === previousLevel[i - 1]) {
            sub += previousLevel[i]; // sub '2'
        } else {
            level += String(sub.length) + sub[0]; // ''
            sub = previousLevel[i];
        }

        // if we're at the end
        if (i === previousLevel.length - 1) {
            level += String(sub.length) + sub[0]; // '21'
        }
    }

    console.log(level);

    if (currentLevel < finalLevel) {
        createNextLevel(level, currentLevel + 1)
    }
}

var firstLevel = '1';
createNextLevel(firstLevel);

// A bit simpler approach
function createNextLevelPlus(str, currentLevel = 0, finalLevel = 10) {
    var delimitedStr = '';
    var level = '';

    for (let i = 0; i < str.length; i++) {
        if (!str[i + 1] || str[i] === str[i+1]) {
            delimitedStr += str[i];
        } else {
            delimitedStr += str[i] + '|';
        }
    }

    delimitedStr.split('|').forEach((group, idx, arr) => {
        level += `${String(group.length)}${group[0]}`;
    });

    console.log(level);

    if (currentLevel < finalLevel) {
        createNextLevelPlus(level, currentLevel+1)
    }
}

var firstLevel = '1';
createNextLevelPlus(firstLevel);

I've mused around a bit on how one might solve this in OCaml, but I'm certain I'd just be re-inventing a C-based way. I've considered recursively walking the string and matching on a head and tail... seeing if they're equal and storing the result in some sort of tuple or something... I am kinda having a hard time warping my mind into the proper thinking.


Solution

  • Here's a high level decomposition.

    You want something that iterates a function. There's a looping + displaying part, and an iteration part (how to go from one level to the next level).

    There are two steps in each iteration:

    Now, let's think about types. We never use these numbers as numbers (there are no additions, etc), so they can be seen as lists of integers, or in OCaml int list.

    The counts, on the other hand, are also a list, but each element of the list is a pair (count, value). For example "one one, one two, two ones" can be represented as [(1, 1); (1, 2); (2, 1)]. The type for such things in OCaml is (int * int) list.

    In other words, the important parts of your algorithm will be:

    Once you have these, you should be able to put the pieces together. Have fun!