Thursday, March 16, 2023

Coding Challenge #23

 // Daily Coding Challenge #28
// justify text with extra spaces between words to make sure the spacing per line is even (or as even as can be. If an odd number of spaces are added, the extra should be on the left side of where the words are broken)
// (new lines act as spaces, so no spaces on the left/right side of the line)
// (if there is only 1 word on a line, no justification is done to that line)

function justify(str, LL){ // LL=line length(in chars), str is the text input
    if(LL < 2) return; // won't work for strings < 2 chars... can't put a hyphen at the end of a line if it takes a whole line.
    // step 1: break up words longer than 12 chars into 12 chars long and '-' plus the rest of the word
    var words_raw = str.split(' '); // split text into words
    var words = []; // where max length is LL (-1, so we can add '-' for words >LL length)
    var lines = []; // output
    for(var xint = 0, len = words_raw.length;xint < len;xint++){
        var w = words_raw[xint];
        if(w.length > LL){
            var start = 0;
            var step = LL - 1;
            while(start < w.length){
                words.push(w.substr(start,step) + "-");
                start += step;
                step = Math.min(LL - 1, w.length - start);
            }
        }else words.push(w);
    }

    // step 2: go through and keep adding words to the sentence until the total length of the line is 11 (there must be 1 space between words) or less. End lines with a newline char.
    for(var xint = 0, len = words.length;xint < len;xint++){
        // xint is the start point for the next word
        var sentLen = 0; // total chars
        var startWord = xint; // index of first word
        var lastWord = xint; // index of last word
        for(var yint = xint;yint < len;yint++){ // add words until line is full
            sentLen += words[yint].length;
            lastWord = yint;
            if(sentLen >= LL) break; // line full
        }
        sentLen += (lastWord-startWord); // # of spaces = # of words - 1
        
        // line length (sentLen) might be too much now. Remove words until it is short enough
        if(sentLen > LL){
            while(sentLen > 0 && lastWord > startWord && sentLen > LL){
                sentLen -= words[lastWord].length - 1; // - len of word + space
                lastWord--;
            }
        }
        
        // now we have as many words as we can rightfully fit.
        // if the line length is < LL, pad it with spaces to justify.
        var spacesPerWord = []; // len of words in line - 1
        var spacesAdded = 0;
        var finLine = ""; // finished line
        // A: add a value for each word
        for(var yint = startWord, len2 = lastWord;yint < len2;yint++){
            spacesPerWord.push(0);
        }
        // B: go around cyclically, add 1 space to spacesPerWord at that index
        var curIdx = 0;
        var max = spacesPerWord.length;
        if(sentLen < LL){
            while(sentLen + spacesAdded < LL){
                spacesPerWord[curIdx]++;
                spacesAdded++;
                curIdx++;
                if(curIdx >= max) curIdx = 0; // loop around
            }
        }
        // C: create the finished line with words and spaces
        for(var yint = startWord, len2 = lastWord + 1;yint < len2;yint++){
            finLine += words[yint];
            if(yint != lastWord){
                finLine += " "; // normal space between words
                // now add padding spacing for justification
                for(var zint = 0;zint < spacesPerWord[yint-startWord];zint++){
                    finLine += " ";
                }
            }
        }
        // D: store finished line
        lines.push(finLine);
        // E: remember to skip all written words this line so we don't repeat them
        xint = lastWord;
    }

    // step 3: print output
    lines.forEach((line)=>{console.log(line);});
}
console.log('TEST 1:');
justify('hi there', 12);
console.log('============');
console.log('TEST 2:');
justify('I was walking my dog at the park, when my mother arrived.', 12);
console.log('============');
console.log('TEST 3:');
justify('booger brains... Abracadabra\'ing', 12);
console.log('============');

No comments:

Post a Comment

Coding Challenge #54 C++ int to std::string (no stringstream or to_string())

Gets a string from an integer (ejemplo gratis: 123 -> "123") Wanted to come up with my own function for this like 10 years ago ...