Awesome hoover javascript
Please click here to see hoovering action.
var hoover = (function(){
"use strict";
var output = {}; //holds output results
output.error = [];
output.warnings = [];
function checkInputs(input){
var checked_input = {};
var checked_input_arr = [];
var isOnlyNumbers, checkSizeofArr;
try{
var input_arr = input.trim().split(/\r\n|\n/); // gets each line's data
checked_input.hooverNavigation = input_arr.pop(); // string
checked_input.roomDimension = input_arr.shift().split(' ').filter(function(i){return i}).map(Number); //1st line array
checked_input.initHooverLoc = input_arr.shift().split(' ').filter(function(i){return i}).map(Number); //2nd line array
// dirt pach location array list
checked_input.dirtLocation = input_arr.map(function(loc){
return loc.split(' ').filter(function(i){return i}).map(Number);
});
//combines all array for checking
checked_input_arr = checked_input_arr.concat([checked_input.roomDimension], [checked_input.initHooverLoc], checked_input.dirtLocation);
// console.log(checked_input_arr);
isOnlyNumbers = checked_input_arr.filter(function(arr_item){
return arr_item.some(isNaN);
});
checkSizeofArr = checked_input_arr.filter(function(arr){
return arr.length > 2;
});
if( isOnlyNumbers.length > 0 ){ //allows only numbers
// console.log('isNAN ', isOnlyNumbers);
output.error.push( 'Only array of numbers are allowed for coordinates: ' + isOnlyNumbers );
}
if( checkSizeofArr.length > 0 ){
output.error.push( 'Invalid location coordinates format- ' );
}
// more checks/validation can be added here!
// warnings
if( checked_input.hooverNavigation.match(/[^NSEW]/g) ){
output.warnings.push( 'Invalid navigation- only accepts N, S, E and W. (North, South, East and West)' );
}
// console.log(checked_input.hooverNavigation, checked_input.initHooverLoc, checked_input.roomDimension, checked_input.dirtLocation);
return checked_input;
}catch(err){
output.error.push( 'Invalid instruction in input file!' );
console.log(err);
return;
}
}
function storeHooverPath(arr){
output.hooverPath = arr;
}
// simulates hoover navigating
function hooverNavigator(hooverLoc, roomDim, direction ){
var direction_arr = direction.split('');
var hLoc = JSON.parse(JSON.stringify(hooverLoc)); //copy of initial hoover location
var tempHooverPath = [];
/** roomDim[0] // vertical or x
roomDim[1] // horizontal or y
hLoc[0] // hoover's x-location
hLoc[1] // hoover's y-location
**/
for(var i=0; i < direction_arr.length; i++){
if( direction_arr[i] == 'N' && hLoc[1] < roomDim[1] ) {hLoc[1]++;}
if( direction_arr[i] == 'S' && hLoc[1] > 0 ) {hLoc[1]--;}
if( direction_arr[i] == 'E' && hLoc[0] < roomDim[0] ) {hLoc[0]++;}
if( direction_arr[i] == 'W' && hLoc[0] > 0 ) {hLoc[0]--;}
//console.log(hLoc, i);
tempHooverPath.push([hLoc[0], hLoc[1]]); //keeps track of hoover's path
}
storeHooverPath(tempHooverPath); //stores the hoover path in output object
return hLoc;
}
// checks if dirt is at hoover's location
function checkDirt(hLoc_path, dirtLocation){
var tempDirtFound = [];
//loop through first array
for(var i = 0; i < hLoc_path.length; i++){
//loop through second array
for(var j = 0; j < dirtLocation.length; j++){
if(hLoc_path[i][0] == dirtLocation[j][0] && hLoc_path[i][1] == dirtLocation[j][1]){
// console.log("matched");
tempDirtFound.push([hLoc_path[i][0], hLoc_path[i][1]]); //match location array
}
}
}
return multiUniqueArray(tempDirtFound); //returns unique multidimensional array
}
// returns unique for multidimensional array
function multiUniqueArray(arr) {
var uniques = [];
var itemsFound = {};
for(var i = 0, l = arr.length; i < l; i++) {
var stringified = JSON.stringify(arr[i]);
if(itemsFound[stringified]) { continue; }
uniques.push(arr[i]);
itemsFound[stringified] = true;
}
return uniques;
}
function checkWarnings(){
if( Array.isArray(output.warnings) && output.warnings.length){
document.querySelector('#output').innerHTML += '<p style="color: orange;"><b>Warnings</b>: ' + JSON.stringify(output.warnings) + '</p>';
output.warnings = []; //clear warnings
}
}
function renderOutput(){
document.querySelector('#output').innerHTML = '<p>Hoover\'s final position: ' + JSON.stringify(output.results.finalHooverPosition) + '</p>';
document.querySelector('#output').innerHTML += '<p>Cleaned patches: ' + output.results.numberOfPatchesCleaned + '</p>';
document.querySelector('#output').innerHTML += '<p>Cleaned patches locations: ' + JSON.stringify(output.results.dirtMatchLocation) + '</p>';
checkWarnings();
document.querySelector('#output').innerHTML += '<p><strong><i>Please see console for more detail...</i></strong></p>';
}
function clearOutput(){
document.querySelector('#output').innerHTML = '';
}
function renderError( error ){
document.querySelector('#output').innerHTML = '<p style="color:red;"><b>Error</b>: ' + JSON.stringify(error) + '</p>';
document.querySelector('#output').innerHTML += '<p><strong><i>Please see console for more detail...</i></strong></p>';
}
// initializes hoover
function startHoover(input){
//initializing variables
var checked_input = checkInputs(input);
var hooverLocation, dirtFound_arr;
clearOutput();//reset output html
//check for input errors
if( Array.isArray(output.error) && output.error.length ){
console.log('Error: ')
console.dir(output.error);
renderError(output.error);
output.error = []; //reset
return;
}
hooverLocation = hooverNavigator(checked_input.initHooverLoc, checked_input.roomDimension, checked_input.hooverNavigation );
dirtFound_arr = checkDirt(output.hooverPath, checked_input.dirtLocation);
//populating helpful output object
output.input = {
'initHooverLocation': checked_input.initHooverLoc,
'roomDimension': checked_input.roomDimension,
'dirtLocation' : checked_input.dirtLocation,
'hooverNavigation' : checked_input.hooverNavigation
};
output.results = {
'finalHooverPosition' : hooverLocation,
'dirtMatchLocation' : dirtFound_arr,
'numberOfPatchesCleaned' : dirtFound_arr.length
};
console.log('hoovering started:');
console.dir(output);
console.log(JSON.stringify(output.results.finalHooverPosition));
console.log(output.results.numberOfPatchesCleaned);
renderOutput();
}
// startHoover(); //vrooommm vrooommm
return {
startHoover: startHoover
};
})();
var hoverAdditionalFunc = {
fileInstruction: '',
uploadInput: function(elem_id, elmen_id_out) {
/** only plain text file allowed **/
var x = document.getElementById(elem_id);
var txt = "";
var err = []; // holds list of errors
var supportedFormats = ['text/plain']; //whitelisting file types
if ('files' in x) {
if (x.files.length == 0) {
txt = "Select one or more files.";
} else {
txt += "<br><strong>" + (1) + ". file</strong><br>";
var file = x.files[0];
if ('name' in file) {
txt += "name: " + file.name + "<br>";
}
if ('size' in file) {
txt += "size: " + file.size + " bytes <br>";
if(file.size > 50000) {
err.push("file size exceeded 50 kb");
}else if( file.size <= 0){
err.push("file is empty!");
}
}
if( 'type' in file ){
if( supportedFormats.indexOf(file.type) < 0 ){
err.push(file.type + ' is not supported');
}
}
if( Array.isArray(err) && err.length ){
document.getElementById(elmen_id_out).innerHTML = 'Error: ' + JSON.stringify(err);
console.log('Error: '); console.dir(err);
document.querySelector('#output').innerHTML += '<p><strong><i>Please see console for more detail...</i></strong></p>';
return
}
this.readInstruction(file); //read input file
}
}
else {
if (x.value == "") {
txt += "Select one or more files.";
} else {
txt += "The files property is not supported by your browser!";
txt += "<br>The path of the selected file: " + x.value; // If the browser does not support the files property, it will return the path of the selected file instead.
}
}
document.getElementById(elmen_id_out).innerHTML += txt;
},
readInstruction: function(file){
if(window.FileReader) { //check if FileReader is available
if (file) {
var reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function (evt) {
// document.getElementById("fileContents").innerHTML = evt.target.result;
this.fileInstruction = evt.target.result;
hoover.startHoover(this.fileInstruction); // vroom vrooom
}
reader.onerror = function (evt) {
// document.getElementById("fileContents").innerHTML = "error reading file";
console.log(error);
}
}
} else {
//the browser doesn't support the FileReader Object, so do this
console.log("browser doesn't support FileReader");
}
},
checkMode: function(){
// Get the checkbox
var checkBox = document.getElementById("instructionMode");
// Get the output text
var inputfile = document.getElementById("instructionFile");
var inputtextContainer = document.getElementById("instructionTextContainer");
var currentMode = document.querySelector(".current-mode");
// If the checkbox is checked, display the output text
if (checkBox.checked == true){
inputtextContainer.style.display = "block";
inputfile.style.display = "none";
currentMode.innerHTML = 'Text Mode';
} else {
inputtextContainer.style.display = "none";
inputfile.style.display = "block";
currentMode.innerHTML = 'File upload Mode';
}
}
};
//initialize js
var init = (function(){
// upload event listener callback
document.querySelector('#instructionFile').onchange = function(){
hoverAdditionalFunc.uploadInput('instructionFile', 'output');
};
document.querySelector('#instructionMode').onclick = function(){
hoverAdditionalFunc.checkMode();
};
document.querySelector('#instructionTextStart').onclick = function(){
hoover.startHoover(document.getElementById('instructionText').value);
}
try{
document.querySelector('#instructionMode').click();
}catch(err){
console.log('error changing initial mode');
}
console.log('please feed instruction to Start!');
})();