1 Commits

Author SHA1 Message Date
df5b34216c Solution for assignment3. 2022-12-04 23:34:33 +01:00
4 changed files with 134 additions and 116 deletions

View File

@@ -1,6 +1,12 @@
# Advent of Code 2022 - Assignment7 javascript # Advent of Code 2022 - Assignment3 javascript solution
Assignment 7 involves parsing linux directory commands/results into a tree. The solution defines a root TreeNode first and sets it as currentdirectory. Whenever a cd command is found a new node is created if it does not exist and set to currentdir. Whenever a cd .. is found currentdirectory is set to parent. Whenever a file is found size is recursively increased for current node and parent nodes. This problem is all about searching for duplicates in strings. The solution is implemented using slice to split the string in half.
The priority is retrieved using the ASCII charcode character for convienence. How to retrieve inputs differs between part1 and 2, therefore a checkbox is provided to toggle between different parsing methods.
## References ## References
- https://adrianmejia.com/data-structures-for-beginners-trees-binary-search-tree-tutorial/ - https://stackoverflow.com/questions/94037/convert-character-to-ascii-code-in-javascript
- https://stackoverflow.com/questions/8376525/get-value-of-a-string-after-last-slash-in-javascript - https://stackoverflow.com/questions/20474257/split-string-into-two-parts
- https://www.folkstalk.com/2022/10/find-common-characters-in-two-strings-javascript-with-code-examples.html
- https://stackoverflow.com/questions/351409/how-to-append-something-to-an-array
- https://stackoverflow.com/questions/9862761/how-to-check-if-character-is-a-letter-in-javascript
- https://stackoverflow.com/questions/1966476/how-can-i-process-each-letter-of-text-using-javascript
- https://www.w3schools.com/js/js_arrays.asp

View File

@@ -8,6 +8,8 @@
<body> <body>
<p>Assignment:</p> <p>Assignment:</p>
<textarea rows="15" cols="50" id="assignment"></textarea> <textarea rows="15" cols="50" id="assignment"></textarea>
<input type="checkbox" id="algorithm"/>
<label for="algorithm">Solution by compartiment.</label>
<p>Answer:</p> <p>Answer:</p>
<div id="answer">Provide input first</div> <div id="answer">Provide input first</div>

230
script.js
View File

@@ -1,85 +1,18 @@
const ASSIGNMENT = 'assignment'; const ASSIGNMENT = 'assignment';
const ANSWER = 'answer'; const ANSWER = 'answer';
const ALGORITHM_CHECKBOX = 'algorithm';
const CHARCODE_START=64;
const CHARCODE_UPPER_CORRECTION=6;
const ERROR_MESSAGE_INVALID_INPUT_SIZE = "Invalid input size, should be higher than 2 for: ";
const ERROR_MESSAGE_INVALID_ITEM_CHARACTER = "Invalid item character found: ";
const NEWLINE_CHARACTER = '\n'; const NEWLINE_CHARACTER = '\n';
const MAX_SIZE = 100000;
const UPDATE_SIZE = 30000000;
const TOTAL_SPACE = 70000000;
/** /**
* Main function * Main function
*/ */
window.onload = function() { window.onload = function() {
document.getElementById(ASSIGNMENT).addEventListener("input", calculateAnswer); document.getElementById(ASSIGNMENT).addEventListener("input", calculateAnswer);
} document.getElementById(ALGORITHM_CHECKBOX).addEventListener("click", calculateAnswer);
class TreeNode {
constructor(value, parent) {
console.debug(((!parent)?"Root ":"") + "node created: " + value);
this.parent = parent;
this.value = value;
this.size = 0;
this.descendants = [];
}
getDir = function(path) {
for(let descendant of this.descendants) {
if(descendant.value == path) {
return descendant;
}
}
}
contains = function(path) {
// Recursive case
let subPathIndex = path.indexOf('/');
let subPath = path.substring(0, subPathIndex-1);
let leftOverPath = path.substring(subPathIndex);
// Base case
if(subPath == '') {
return false;
}
for(let descendant of this.descendants) {
if(descendant.value == subPath) {
return descendant.contains(subPath);
}
}
}
findClosestNodeToSize = function(minSize) {
let closest = this;
for(let descendant of this.descendants) {
let closestDescendant = descendant.findClosestNodeToSize(minSize);
if (closestDescendant.size > minSize && closestDescendant.size < closest.size) {
console.debug("New closest:" + closestDescendant.size);
closest = closestDescendant;
}
}
return closest;
}
increaseSize = function(size) {
// TODO: Wat doen we met duplicate files?
this.size += size;
if(this.parent) {
this.parent.increaseSize(size);
}
}
getSum = function(maxSize) {
let result = (this.size < maxSize) ? this.size: 0;
for(let descendant of this.descendants) {
result += descendant.getSum(maxSize);
}
return result;
}
} }
/** /**
@@ -88,7 +21,9 @@ class TreeNode {
*/ */
function calculateAnswer(event) { function calculateAnswer(event) {
console.info("Calculating answer for input..."); console.info("Calculating answer for input...");
let answer = algorithm(event.target.value); let assignment = document.getElementById(ASSIGNMENT).value;
let byCompartiments = document.getElementById(ALGORITHM_CHECKBOX).checked;
let answer = algorithm(assignment, byCompartiments);
document.getElementById(ANSWER).innerText = answer; document.getElementById(ANSWER).innerText = answer;
} }
@@ -98,50 +33,121 @@ function calculateAnswer(event) {
* @param assignment the input from the assignment. * @param assignment the input from the assignment.
* @return string the answer * @return string the answer
*/ */
function algorithm(assignment) { function algorithm(assignment, byCompartiments) {
let lines = assignment.trim().split(NEWLINE_CHARACTER); let priorityScoreSum = 0;
console.info("Linecount:" + lines.length); let lines = assignment.trim().split(NEWLINE_CHARACTER);
console.info("Linecount:" + lines.length);
let root = new TreeNode('/'); let increment = (byCompartiments)? 1:3;
let currentdir = root; for(let i=0; i<lines.length; i+=increment) {
let inputs = [];
let rucksack = lines[i].replace(/\s/g, ''); // Remove whitespace
for(let i=0; i<lines.length; i++) { if(byCompartiments) {
let terminalLine = lines[i].trim(); let compartiment1 = rucksack.slice(0, rucksack.length/2);
let compartiment2 = rucksack.slice(rucksack.length/2);
inputs = [compartiment1, compartiment2];
} else {
inputs = [rucksack, lines[i+1].replace(/\s/g, ''), lines[i+2].replace(/\s/g, '')];
}
if(terminalLine.substring(0, 4) == "$ cd") { let duplicate = getDuplicateCharacter(inputs);
let changeDirectory = terminalLine.substring(5).trim(); if(duplicate < 0) {
if(changeDirectory == "..") { console.error(ERROR_MESSAGE_INVALID_INPUT_SIZE + inputs + " on line: " + i);
console.debug("One directory up from: " + currentdir.value); }
currentdir = currentdir.parent;
console.debug("navigates to: " + currentdir.value);
continue;
}
if(changeDirectory == "/") { let priorityScore = getPriorityScore(duplicate);
currentdir = root; if(priorityScore < 0) {
continue; console.error(ERROR_MESSAGE_INVALID_ITEM_CHARACTER + duplicate + " on line: " + i);
} continue;
}
if(!currentdir.contains(changeDirectory)) { priorityScoreSum += priorityScore;
currentdir.descendants.push(new TreeNode(changeDirectory, currentdir));
}
currentdir = currentdir.getDir(changeDirectory);
} else if(terminalLine.substring(0, 3) != 'dir' && !terminalLine.includes('$')) {
console.debug(terminalLine);
spaceIndex = terminalLine.indexOf(' ');
size = parseInt(terminalLine.substring(0, spaceIndex));
currentdir.increaseSize(size);
} }
}
let freeDiskSpace = TOTAL_SPACE - root.size; return "SUM priorityscore: " + priorityScoreSum;
console.debug("Free disk space: " + freeDiskSpace); }
console.debug("Root size:" + root.size); /**
console.debug("Value to find: " + (UPDATE_SIZE - freeDiskSpace)); * Calculate the answer to assignment.
let closestNode = root.findClosestNodeToSize(UPDATE_SIZE - freeDiskSpace); * @param assignment the input from the assignment.
console.debug("Closest value: " + closestNode.size); * @return string the answer
*/
function algorithm1(assignment) {
let priorityScoreSum = 0;
let lines = assignment.trim().split(NEWLINE_CHARACTER);
console.info("Linecount:" + lines.length);
return "Sum below maxSize " + MAX_SIZE + ": " + root.getSum(MAX_SIZE); for(let i=0; i<lines.length; i++) {
let rucksack = lines[i].replace(/\s/g, ''); // Remove whitespace
let compartiment1 = rucksack.slice(0, rucksack.length/2);
let compartiment2 = rucksack.slice(rucksack.length/2);
console.debug("Check rucksack" + i, ": " + rucksack + " \n with compartiment1: " + compartiment1 + "\n and compartiment2: " + compartiment2);
for(item of compartiment2) {
if(compartiment1.includes(item)) {
console.debug("Found duplicate: " + item + " in rucksack" + i);
let priorityScore = getPriorityScore(item);
if(priorityScore < 0) {
console.error(ERROR_MESSAGE_INVALID_ITEM_CHARACTER + item + " on line: " + i);
continue;
}
priorityScoreSum += priorityScore;
break;
}
}
}
return "SUM priorityscore: " + priorityScoreSum;
}
/**
* Find duplicate character in inputs.
* @param string[] inputs the inputs to find duplicates in.
* @return char the duplicate character
*/
function getDuplicateCharacter(inputs) {
console.debug("Checking inputs: " + inputs);
if(inputs.length < 2) {
return -1;
}
for(let item of inputs[0]) {
let duplicate = true
for(let j=1; j<inputs.length; j++) {
duplicate = duplicate && inputs[j].includes(item);
}
if(duplicate) {
console.debug("Found duplicate: " + item);
return item;
}
}
}
/**
* Returns priorityscore for given character.
* @param char character the character
* @return int the priorityscore for character or -1 if invalid
*/
function getPriorityScore(character) {
let result=0;
let uppercase = character.toUpperCase();
let lowercase = character.toLowerCase();
// validate character
if( uppercase == lowercase ) {
return -1;
}
if(character == uppercase) { // Switch results for upper and lowercase characters
result -= CHARCODE_UPPER_CORRECTION;
character = lowercase;
} else {
character = uppercase;
}
result += character.charCodeAt() - CHARCODE_START;
return result;
} }

View File

@@ -6,6 +6,10 @@ body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
} }
textarea {
display: block;
}
#answer { #answer {
color: purple color: purple
} }