Last active
May 12, 2017 14:12
-
-
Save haveric/af6006bb32dff5024eb3f6ab6d40347d to your computer and use it in GitHub Desktop.
Daily Programmer #313 Hard - Embedded Word List
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"/> | |
</head> | |
<body> | |
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script> | |
<script type="text/javascript" src="js/main.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
String.prototype.insertAt=function(index, string) { | |
return this.slice(0, index) + string + this.slice(index); | |
} | |
var alphabet = 'abcdefghijklmnopqrstuvwxyz'.split(''); | |
$(document).ready(function() { | |
//readInput("input/simple.txt", sortInput); | |
readInput("input/challenge_reduced.txt",sortInput); | |
}); | |
function readInput(file, callback) { | |
$.get(file, function(data) { | |
var split = data.split("\n"); | |
var sorted = new Array(); | |
for (var i = 0; i < split.length; i++) { | |
var word = split[i].trim(); | |
split[i] = word; | |
addToSorted(0, word, sorted); | |
} | |
callback(split, sorted); | |
}, "text"); | |
} | |
function addToSorted(wordIndex, word, sorted) { | |
var letter = word[wordIndex]; | |
var index = -1; | |
for (var i = 0; i < sorted.length; i++) { | |
if (letter === sorted[i].letter) { | |
index = i; | |
break; | |
} | |
} | |
if (index === -1) { | |
index = sorted.length; | |
sorted.push({letter: letter, children: new Array()}); | |
} | |
if (wordIndex < word.length) { | |
sorted[index].children = addToSorted(wordIndex + 1, word, sorted[index].children); | |
} | |
return sorted; | |
} | |
var parentPartialTree; | |
function sortInput(data, tree) { | |
var output = ""; | |
//output = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; | |
parentPartialTree = new Array(); | |
//output = mergeTree(0, tree, parentPartialTree, parentPartialTree, output); | |
// Merge Tree Result | |
//output = "actghbodyuriaenlkstmdrphabyoexirftgupnoclvmikjyqaethuowrnlzmaseobticvgudpserhfylmoniktcaewsvbopnruthqildomgajxycokeurnamiclsfzneowgtdaphifvnbleptraiuoxgmceytrnsqdibpchoffkutlaowlmsterpngivckazzldehyvmabdsticomwlouunghipptedrsicablingotilysers"; | |
// Current Merged Best | |
//output = "actghodyuriaenlstmdrphkabyoexirfgupnclvmijqethuowrnyaseosbticvgzudperhfylmoniktcaewsvbopnrcuthqildmgarjxyoeuzraminclskfeowgtdaphifvnbletraiuoxgmceyrnstlqdibpchofuawmsternglivckazzlpdehyabsuticomvwrlounghipedrscalingtilyses"; | |
// Best previous with a-z | |
//output = "acdelkihmnopqrswxytuvzabfecghijlnoprstuyabcdefilmnoprstuvxyabchdkjegilmnopqrstuwcbazydefghilmnoprstuvxabcdeghikmnoprstyzcagfljiedmhnoprstuvwyabcdegilnoqrstuwxacdefhiklmoprstihgyabzveoncutradeinopstghmlioszacemteiadlnrtilyces"; | |
// Best Merged after a-z | |
output = "acdelkihmnopqrswxtuvzabfecghyilnoprstuabcdjefilmnoprstuvxyabchdkegilmnopqrstuwcbazydefghilmnoprstuvxabcdeghikmnoprstyzcagfljiedmhnoprstuvwyabcdegilnoqrstuwxacdefhiklmoprstihgyabzveoncutradeinopstghmlioszacemteriadlntlyces"; | |
// Best of reddit thread | |
//output = "pscbfgrhkimenovaunltderymwibspchogjuexantfrlzeocidskphquymvatbrlienorsgzcptwhfmylueadrbinosctgexphalrdmkvieyusajongcfetbrpalzwhiquomensdctralytwiongvkzabpfiulesrmedcathnipesotcalxlryusmindtegs"; | |
console.log("Valid: " + testIfValid(0, tree, output)); | |
console.log("Final output: ", output, output.length); | |
console.time('optimize'); | |
//output = doubleOptimize(tree, output); | |
console.timeEnd('optimize'); | |
console.log("Initial optimize: ", output, output.length); | |
output = shiftCount(data, tree, output); | |
console.log("Valid: " + testIfValid(0, tree, output)); | |
console.log(output, output.length); | |
} | |
function mergeTree(lastIndex, tree, originalPartial, currentPartial, output) { | |
if (tree !== undefined) { | |
for (var i = 0; i < tree.length; i++) { | |
var letter = tree[i].letter; | |
if (letter !== undefined) { | |
if (!currentPartial[i]) { | |
currentPartial[i] = new Array(); | |
} | |
currentPartial[i].letter = letter; | |
if (!currentPartial[i].children) { | |
currentPartial[i].children = new Array(); | |
} | |
var index = output.indexOf(letter, lastIndex); | |
if (index === -1) { | |
var diff = 0; | |
output = output.insertAt(lastIndex, letter); | |
diff = output.length; | |
output = optimize(originalPartial, output); | |
diff = diff - output.length; | |
index = lastIndex - diff; | |
} | |
output = mergeTree(index + 1, tree[i].children, originalPartial, currentPartial[i].children, output) | |
} | |
} | |
} | |
return output; | |
} | |
function testIfValid(lastIndex, tree, total) { | |
if (tree !== undefined) { | |
for (var i = 0; i < tree.length; i++) { | |
var letter = tree[i].letter; | |
if (letter !== undefined) { | |
var index = total.indexOf(letter, lastIndex); | |
if (index === -1 || !testIfValid(index + 1, tree[i].children, total)) { | |
return false; | |
} | |
} | |
} | |
} | |
return true; | |
} | |
function testIfValidWord(word, total) { | |
var length = word.length; | |
if (length >= total.length) { | |
return false; | |
} | |
var lastIndex = 0; | |
for (var i = 0; i < length; i++) { | |
lastIndex = total.indexOf(word[i], lastIndex); | |
if (lastIndex === -1) { | |
return false; | |
} | |
lastIndex ++; | |
} | |
return true; | |
} | |
function doubleOptimize(tree, total) { | |
var o1 = optimize(tree, total); | |
var o2 = optimizeReverse(tree, total); | |
if (o1.length <= o2.length) { | |
total = o1; | |
} else { | |
total = o2; | |
} | |
console.log("Optimized: " + total.length); | |
return total; | |
} | |
function optimize(tree, total) { | |
for (var i = 0; i < total.length; i++) { | |
var removedString = removeAt(total, i); | |
var valid = testIfValid(0, tree, removedString); | |
if (valid) { | |
total = removedString; | |
i--; | |
} | |
} | |
return total; | |
} | |
function optimizeReverse(tree, total) { | |
for (var i = total.length - 1; i > 0; i--) { | |
var removedString = removeAt(total, i); | |
var valid = testIfValid(0, tree, removedString); | |
if (valid) { | |
total = removedString; | |
} | |
} | |
return total; | |
} | |
function removeAt(word, index) { | |
return word.slice(0,index) + word.slice(index+1); | |
} | |
function reduceEmbedded(data) { | |
var lastprint = 0; | |
for (var i = 0; i < data.length; i++) { | |
var word = data[i]; | |
for (j = 0; j < data.length; j++) { | |
if (i != j) { | |
var total = data[j]; | |
var valid = testIfValidWord(word, total); | |
if (valid) { | |
data.splice(i,1); | |
i--; | |
break; | |
} | |
} | |
} | |
if (i % 1000 == 0 && i != lastprint) { | |
console.log("Reduce: ", (i / data.length) * 100); | |
lastprint = i; | |
} | |
} | |
return data; | |
} | |
function reverseString(str) { | |
return str.split("").reverse().join(""); | |
} | |
function countUses(data, total) { | |
var uses = new Array(total.length); | |
for (var i = 0; i < total.length; i++) { | |
uses[i] = {index: i, count: 0}; | |
} | |
for (var i = 0, len = data.length; i < len; i++) { | |
uses = countUsesWord(data[i], total, uses); | |
} | |
return uses; | |
} | |
function countUsesWord(word, total, uses) { | |
var length = word.length; | |
if (length >= total.length) { | |
return false; | |
} | |
var lastIndex = 0; | |
for (var i = 0; i < length; i++) { | |
lastIndex = total.indexOf(word[i], lastIndex); | |
if (lastIndex > -1) { | |
uses[lastIndex].count ++; | |
} | |
lastIndex ++; | |
} | |
return uses; | |
} | |
function shiftCount(data, tree, total) { | |
var uses = countUses(data, total); | |
for (var i = 0; i < total.length; i++) { | |
var index = getLowestIndex(uses, i); | |
var moved = moveLowest(tree, total, index); | |
if (moved.length < total.length) { | |
console.log("Moved: ", moved, moved.length); | |
moved = shiftCount(data, tree, moved); | |
break; | |
} | |
} | |
for (var i = 0; i < total.length; i++) { | |
var index = getLowestIndex(uses, i); | |
var moved = wiggleLowest(tree, total, index); | |
if (moved.length < total.length) { | |
console.log("Wiggled: ", moved, moved.length); | |
moved = shiftCount(data, tree, moved); | |
break; | |
} | |
} | |
for (var i = 0; i < total.length; i++) { | |
var index = getLowestIndex(uses, i); | |
var moved = swapLowest(tree, total, index); | |
if (moved.length < total.length) { | |
console.log("Swapped: ", moved, moved.length); | |
moved = shiftCount(data, tree, moved); | |
break; | |
} | |
} | |
for (var i = 0; i < total.length; i++) { | |
var index = getLowestIndex(uses, i); | |
var moved = moveLowest(tree, total, index, true); | |
if (moved.length < total.length) { | |
console.log("Moved: ", moved, moved.length); | |
moved = shiftCount(data, tree, moved); | |
break; | |
} | |
} | |
for (var i = 0; i < total.length; i++) { | |
var index = getLowestIndex(uses, i); | |
var moved = wiggleLowest(tree, total, index, true); | |
if (moved.length < total.length) { | |
console.log("Wiggled: ", moved, moved.length); | |
moved = shiftCount(data, tree, moved); | |
break; | |
} | |
} | |
for (var i = 0; i < total.length; i++) { | |
var index = getLowestIndex(uses, i); | |
var moved = swapLowest(tree, total, index, true); | |
if (moved.length < total.length) { | |
console.log("Swapped: ", moved, moved.length); | |
moved = shiftCount(data, tree, moved); | |
break; | |
} | |
} | |
return moved; | |
} | |
function moveLowest(tree, total, index, more) { | |
var original = total; | |
var lowestLetter = total[index]; | |
var least = 5; | |
var most = 25; | |
if (more) { | |
least = 0; | |
most = 5; | |
} | |
for (var i = most; i > least; i--) { | |
var rightIndex = index + 1 + i; | |
var leftIndex = index - i; | |
if (rightIndex < total.length) { | |
var temp = total.insertAt(rightIndex, lowestLetter); | |
temp = optimize(tree, temp); | |
if (testIfValid(0, tree, temp)) { | |
if (temp.length < total.length) { | |
console.log(" Moved R: ", rightIndex, index); | |
return temp; | |
} | |
} | |
} | |
if (leftIndex > -1) { | |
var temp = total.insertAt(leftIndex, lowestLetter); | |
temp = optimizeReverse(tree, temp); | |
if (testIfValid(0, tree, temp)) { | |
if (temp.length < total.length) { | |
console.log(" Moved L: ", leftIndex, index); | |
return temp; | |
} | |
} | |
} | |
} | |
return original; | |
} | |
function wiggleLowest(tree, total, index, more) { | |
var original = total; | |
var least = 5; | |
var most = 25; | |
if (more) { | |
least = 0; | |
most = 5; | |
} | |
for (var i = most; i > least; i--) { | |
var rightIndex = index + 1 + i; | |
var leftIndex = index - i; | |
if (rightIndex < total.length) { | |
var toreorder = original.slice(index, rightIndex); | |
var beforeReverse = toreorder; | |
toreorder = reverseString(toreorder); | |
if (toreorder != beforeReverse) { | |
var temp = original.slice(0,index) + toreorder + original.slice(index + rightIndex); | |
if (testIfValid(0, tree, temp)) { | |
temp = doubleOptimize(tree, temp); | |
if (temp.length < original.length) { | |
console.log("R Found wiggle", temp, temp.length); | |
return temp; | |
} | |
} | |
} | |
} | |
if (leftIndex > -1) { | |
var toreorder = original.slice(leftIndex, index); | |
var beforeReverse = toreorder; | |
toreorder = reverseString(toreorder); | |
if (toreorder != beforeReverse) { | |
var temp = original.slice(0,leftIndex) + toreorder + original.slice(index + leftIndex); | |
if (testIfValid(0, tree, temp)) { | |
temp = doubleOptimize(tree, temp); | |
if (temp.length < original.length) { | |
console.log("L Found wiggle", temp, temp.length); | |
return temp; | |
} | |
} | |
} | |
} | |
} | |
return original; | |
} | |
function swapLowest(tree, total, index, more) { | |
var original = total; | |
var least = 5; | |
var most = 25; | |
if (more) { | |
least = 1; | |
most = 5; | |
} | |
for (var i = most; i > least; i--) { | |
var rightIndex = index + 1 + i; | |
var leftIndex = index - i; | |
if (rightIndex < total.length) { | |
var reorder = total.slice(0,rightIndex) + total.slice(rightIndex+Math.floor(i/2), rightIndex + i) + total.slice(rightIndex, rightIndex+Math.floor(i/2)) + total.slice(rightIndex + i); | |
if (reorder != total && testIfValid(0, tree, reorder)) { | |
var wiggledString = wiggleLowest(tree, reorder, index, more); | |
if (wiggledString.length < total.length) { | |
swapString = wiggledString; | |
if (swapString != total) { | |
return swapString; | |
} | |
} | |
} | |
} | |
if (leftIndex > -1) { | |
var reorder = total.slice(0,leftIndex) + total.slice(leftIndex+Math.floor(i/2), leftIndex + i) + total.slice(leftIndex, leftIndex+Math.floor(i/2)) + total.slice(leftIndex + i); | |
if (reorder != total && testIfValid(0, tree, reorder)) { | |
var wiggledString = wiggleLowest(tree, reorder, index, more); | |
if (wiggledString.length < total.length) { | |
swapString = wiggledString; | |
if (swapString != total) { | |
return swapString; | |
} | |
} | |
} | |
} | |
} | |
return original; | |
} | |
function getLowestIndex(uses, num) { | |
uses = uses.sort(function(a, b) { return a.count-b.count;}); | |
return uses[num].index; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$(document).ready(function() { | |
readInput("input/challenge.txt",sortInput); | |
}); | |
function readInput(file, callback) { | |
$.get(file + ".txt", function(data) { | |
var split = data.split("\n"); | |
var reduced = reduceEmbedded(split); | |
writeFile(file + "_reduced.txt", reduced); | |
readInput(file, callback); | |
}, "text"); | |
} | |
function writeFile(filePath, data) { | |
console.log("Write file: " + filePath); | |
var input_string = ""; | |
for (var i = 0; i < data.length; i++) { | |
input_string += data[i] + "\n"; | |
} | |
saveFile(filePath, "data:text/plain", new Blob([input_string])); | |
} | |
function saveFile (name, type, data) { | |
if (data != null && navigator.msSaveBlob) | |
return navigator.msSaveBlob(new Blob([data], { type: type }), name); | |
var a = $("<a style='display: none;'/>"); | |
var url = window.URL.createObjectURL(new Blob([data], {type: type})); | |
a.attr("href", url); | |
a.attr("download", name); | |
$("body").append(a); | |
a[0].click(); | |
setTimeout(function(){ // fixes firefox html removal bug | |
window.URL.revokeObjectURL(url); | |
a.remove(); | |
}, 500); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment