pig's diary

何でも忘れるので万年初心者ね

マージャンのやつ JavaScript

あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定
http://www.itmedia.co.jp/enterprise/articles/1004/03/news002_2.html

※トータルで1週間以上かかっているorz

var assert = require('assert');



var test = function(results, answers) {
    if (results == null && answers == null) return;
    assert.equal(results.length, answers.length);
    answers.forEach(function(answer) {
        assert(~results.indexOf(answer));
    });
};



var machi = (function() {
        
    var format = function(answer) {
        var s = '';
        answer.grouped.sort().forEach(function(g) {
            s += '(' + g + ')';
        });
        return s + (answer.rest ? '[' + answer.rest + ']' : '');
    };

    var collectFlattens = function(input, enough) {
        var regexp = new RegExp('(.)\\1{' + (enough - 1) +'}', 'g');
        return input.match(regexp);
    };
    test(collectFlattens('112224588899', 2), ['11', '22', '88', '99']);
    test(collectFlattens('12345', 2), null);
    test(collectFlattens('1112224588899', 3), ['111', '222', '888']);
    test(collectFlattens('124589', 3), null);

    var collectAscendings = function(input, enough) {
        var results = [];
        var collected;
        var curr;
        var foundIndex;
        var isEnough = function() {
            return collected && collected.length >= enough;
        };
        while (input.length >= 2) {
            collected = '';
            curr = 0;
            foundIndex = -1;
            while (~(foundIndex = input.indexOf(+input[curr] + 1, curr + 1))) {
                if (!collected) collected = input[curr];
                collected += input[foundIndex];
                if (isEnough()) break;
                curr = foundIndex;
            }
            if (isEnough()) results.push(collected);
            input = input.slice(1);
        }
        return results.length >= 1 ? results : null;
    };
    test(collectAscendings('1122335556799', 3), ['123', '123', '567', '567', '567']);
    test(collectAscendings('112255578', 3), null);

    var getRest = function(collected, original) {
        collected.split('').forEach(function(letter) {
            original = original.replace(letter, '');
        });
        return original;
    };
    assert.equal(getRest('123', '1122335556799'), '1235556799');
    assert.equal(getRest('567', '11225556799'), '11225599');
    assert.equal(getRest('789', '1122555789'), '1122555');

    var hasHead = function(grouped) {
        return grouped.some(function(group) {
            return group.length == 2;
        });
    };
    assert.equal(hasHead(['234', '555', '888']), false);
    assert.equal(hasHead(['234', '555', '88']), true);



    return function(original) {
        var answers = [];
        (function collect(grouped, input) {

            var finalizer = function(candidates) {
                if (!candidates) return;
                candidates.forEach(function(newGroup) {
                    var newGrouped = grouped.slice(0);
                    newGrouped.push(newGroup);
                    var rest = getRest(newGroup, input);
                    if (rest && (
                            collectFlattens(rest, 3) ||
                            collectAscendings(rest, 3))) {
                        collect(newGrouped.slice(0), rest);
                    } else if (rest.length <= 3) {
                        var heads = collectFlattens(rest, 2);
                        if (rest.length == 1 ||
                                (heads && heads.length >= 1) ||
                                collectAscendings(rest, 2)) {
                            var a = format({
                                grouped: newGrouped,
                                rest: rest
                            });
                            if (!~answers.indexOf(a)) answers.push(a);
                        }
                    }
                });
            };

            if (!hasHead(grouped)) {
                finalizer(collectFlattens(input, 2));
            }
            finalizer(collectFlattens(input, 3));
            finalizer(collectAscendings(input, 3));

        })([], original);
        return answers;
    };

})();

test(machi('1112224588899'), [
    '(111)(222)(888)(99)[45]'
]);
test(machi('1122335556799'), [
    '(123)(123)(55)(567)[99]',
    '(123)(123)(555)(99)[67]',
    '(123)(123)(567)(99)[55]'
]);
test(machi('1112223335559'), [
    '(123)(123)(123)(555)[9]',
    '(111)(222)(333)(555)[9]'
]);
test(machi('1223344888999'), [
    '(123)(44)(888)(999)[23]',
    '(123)(234)(888)(999)[4]',
    '(234)(234)(888)(999)[1]'
]);
test(machi('1112345678999'), [
    '(11)(123)(456)(999)[78]',
    '(11)(123)(678)(999)[45]',
    '(11)(345)(678)(999)[12]',
    '(11)(123)(456)(789)[99]',
    '(111)(234)(567)(99)[89]',
    '(111)(234)(789)(99)[56]',
    '(111)(456)(789)(99)[23]',
    '(123)(456)(789)(99)[11]',
    '(111)(234)(567)(999)[8]',
    '(111)(234)(678)(999)[5]',
    '(111)(345)(678)(999)[2]'
]);