/** * Fill the below function * You'll be scored on character count of the line(s) between the brackets * Bragging rights for the faster function * You cannot use any existing library that solves the heart of the challenge * You cannot read your own source */ /** * Run length encoding is the basis of many methods of compression * We will do a ridiculous implementation of run length encoding * * Given a string, return the compressed string * You must compress runs of the same character >= 4 characters long * The compression of a run is a *, followed by the character, followed by the count * For example, AAAA will compress to *A4 * For example, 111111111111 will compress to *112 * Literal * in the string should be encoded as ** * * * @param string s * * @return string */ let Solutions = { codegolf76_mark: function(s) { return s.replace(/([^*])\1{3,}|\*|./g,p=>p[1]?'*'+p[0]+p.length:p=='*'?'**':p) }, codegolf76_mark2: function(s) { return s.replace(/([^*])\1+|\*|./g,p=>(l=p.length)>3?'*'+p[0]+l:p=='*'?'**':p) }, codegolf76_mark3: function(s) { return s.replace(/\*|(.)\1{3,}|./g,p=>p[1]?'*'+p[0]+p.length:p=='*'?'**':p) }, codegolf76_mark3: function(s) { return s.replace(/\*|(.)\1*/g,p=>p[3]?'*'+p[0]+p.length:p=='*'?p+p:p) }, codegolf76_rick3_golfed: function(s) { r="";for(x of s.match(/([ -~\s])\1*/g)||[]){n=x.length;m=''+n;if(n>=4&&!x.match(/\*/i)){r+="@"+x[0]+m}else r+=x}return r.replace(/\*/g,'**').replace(/@/g,'*') }, codegolf76_andrew: function(s) { return s.replace(/(.)\1*/g,m=>(l=m.length)&&m[0]==(x='*')?x.repeat(2*l):l>3?x+m[0]+l:m) }, codegolf76_karl: function(s) { for(d=[],r='',l='',c=0;c<=s.length;c++){e=s[c];if(e==l){d[e]+=1;}else if(e!=l){if(d[l]>=4){r+='*'+l+d[l];d[l]=0}else{r+=l.repeat(d[l])}d[e]=1;}if(e=='*')r+=e;l=e;}return r }, codegolf76_tyler2: function(s) { return s.replace(/(.)\1*/g,v=>'*'==v[0]?v+v:3<(c=v.length)?'*'+v[0]+c:v) }, }; let tests = [ { 'input': ['*'], 'expect': '**', }, { 'input': ['****'], 'expect': '********', }, { 'input': ['$***'], 'expect': '$******', }, { 'input': [')))))*+'], 'expect': '*)5**+', }, { 'input': ['OoOoOo'], 'expect': 'OoOoOo', }, { 'input': ['BBBB'], 'expect': '*B4', }, { 'input': ['BBB*'], 'expect': 'BBB**', }, { 'input': ['aaa33bbbbb'], 'expect': 'aaa33*b5', }, { 'input': ['aaa33bbbbb'], 'expect': 'aaa33*b5', }, { 'input': ['111111111111'], 'expect': '*112', }, { 'input': ['aaaaaaaaaaaaabbbbbbbbbbbbb'], 'expect': '*a13*b13', }, { 'input': ['999***999'], 'expect': '999******999', }, { 'input': ['This cannot compress'], 'expect': 'This cannot compress', }, { 'input': ['This can compress the 555555555555555'], 'expect': 'This can compress the *515', }, { 'input': ['OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO'], 'expect': '*O100', }, { 'input': ['OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO'], 'expect': '*O111', }, ]; let timerCount = 1, results = [], passed, input, expect, chars, time, actual, fails, prefix = 'codegolf76', handicaps = {}; handicaps[prefix] = { tyler: 1 - 0.170, andrew: 1 - 0.080, tw: 1 + 0.196, karl: 1 + 0.182, rick: 1 + 0.173, mark: 1 - 0.187, adam: 1 + 0.230, }; for (let func in Solutions) { if (prefix !== func.substr(0, 10)) { continue; } print(func + " - "); // Test function against each provide data set fails = []; passed = true; time = +new Date(); for (let test in tests) { for (vv in aa = [...'abcdefghijklmnopqrstuvwxyz_$']) eval('delete ' + aa[vv]) input = JSON.parse(JSON.stringify(tests[test].input)); expect = JSON.parse(JSON.stringify(tests[test].expect)); actual = Solutions[func](...input); if (actual !== expect) { print("\nTest " + test + " Failed\nExpected: "); print(expect); print("Actual : "); print(actual); print("Input : "); print(input); passed = false; fails.push(test) } } time = +new Date() - time; time = time / 1000; print(func + " - " + (passed ? 'Passed' : "Failed") + "\n"); chars = Solutions[func].toString().split('\n'); chars = chars.slice(1, chars.length - 1).map(s => s.trim()).join().length; // Time function if (1 < timerCount) { time = +new Date(); let i; for (i = 0; i < timerCount; i++) { for (test in tests) { input = JSON.parse(JSON.stringify(tests[test].input)); expect = tests[test].expect; actual = Solutions[func](...input); } if ((+new Date() - time) > 10000) { break; } } time = +new Date() - time; time = time / 1000 * (timerCount / i); } let id = func.match(new RegExp(prefix + '_([a-z]+)')) let score = Math.round(chars / (handicaps[prefix][id[1]] || 1)); let result = {}; result['func'] = func; result['passed'] = (passed ? 'Yes' : 'no'); result['chars'] = chars; result['score'] = passed ? score : ''; result['time * ' + timerCount] = time; result['fails'] = fails; results.push(result); } results.sort((a, b) => a.passed != b.passed ? (a.passed > b.passed ? 1 : -1) : a.chars != b.chars ? (a.chars - b.chars) : a.time - b.time ); print(arrayToTextTable(results)); function print(s) { console.log(s); } /** * Render an ASCII table from supplied 2d array * * @param input Data to render * @param keyAsCol1 Whether to include first dimension array key as column one * * @return string A basic ASCII table of the data */ function arrayToTextTable(input, keyAsCol1) { let data = []; let widths = {}; // Determine column widths for (let key in input) { let values = input[key]; if (keyAsCol1) { // Like array_unshift, but force empty string for key values._ = key; } // The actual column width determination for (let col in values) { let datum = values[col]; widths[col] = Math.max(widths[col] || 0, String(datum).length); } data.push(values); } // The above may have added a column, get column widths for headers last let headers = JSON.parse(JSON.stringify(data[data.length - 1])); for (let col in headers) { widths[col] = Math.max(widths[col] || 0, col.length); } // Draw horizontal bars for top and bottom let bar = ''; for (let i in widths) { bar += '+'.padEnd(widths[i] + 3, '-'); } bar += "+\n"; // Draw column headers for (let key in headers) { headers[key] = key.padEnd(widths[key], ' '); } result = bar + '| ' + Object.values(headers).join(' | ') + " |\n" + bar; // Draw data for (let i in data) { let row = data[i]; for (let col in row) { let datum = row[col]; result += '| ' + ('' + datum).padEnd(widths[col] + 1, ' '); } result += "|\n"; } result += bar; return result; }