"use strict"; // Cleans the scene and spawns an instance of a cube (also updates // the cubies map). function buildCube(data) { clearCubies(scene); cubies.clear(); // Solved configuration cubies.set(0, new Cubie(0,0,[{ key: 0, value: data[0][0] },{ key: 2, value: data[0][1] },{ key: 4, value: data[0][2] }])); cubies.set(1, new Cubie(1,1,[{ key: 0, value: data[1][0] },{ key: 2, value: data[1][1] },{ key: 5, value: data[1][2] }])); cubies.set(2, new Cubie(2,2,[{ key: 1, value: data[2][0] },{ key: 2, value: data[2][1] },{ key: 5, value: data[2][2] }])); cubies.set(3, new Cubie(3,3,[{ key: 1, value: data[3][0] },{ key: 2, value: data[3][1] },{ key: 4, value: data[3][2] }])); cubies.set(4, new Cubie(4,4,[{ key: 0, value: data[4][0] },{ key: 3, value: data[4][1] },{ key: 4, value: data[4][2] }])); cubies.set(5, new Cubie(5,5,[{ key: 0, value: data[5][0] },{ key: 3, value: data[5][1] },{ key: 5, value: data[5][2] }])); cubies.set(6, new Cubie(6,6,[{ key: 1, value: data[6][0] },{ key: 3, value: data[6][1] },{ key: 5, value: data[6][2] }])); cubies.set(7, new Cubie(7,7,[{ key: 1, value: data[7][0] },{ key: 3, value: data[7][1] },{ key: 4, value: data[7][2] }])); // Adding cubies to scene for (var i = 0; i < cubies.size; i++) { scene.add(cubies.get(i).mesh); } needsRender = true; } var solvedConfig = [ ["white", "green", "red"], ["white", "green", "orange"], ["yellow", "green", "orange"], ["yellow", "green", "red"], ["white", "blue", "red"], ["white", "blue", "orange"], ["yellow", "blue", "orange"], ["yellow", "blue", "red"], ]; function solvedCube() { buildCube(solvedConfig); } function scramble() { var moves = []; var rotations = ["pitchA", "pitchB", "rollA", "rollB", "yawA", "yawB"]; for(var i = 0; i < Math.random()*10+10; i++) { moves.push({ move: rotations[Math.floor(Math.random() * rotations.length)], dir: (Math.random() < 0.5) ? 1 : -1 }); } if (! animator) { scramb = true; animator = new Animator(moves); animator.goOn(); } } function clearCubies(node) { cubies.forEach(function(value) { node.remove(value.mesh); }); } // Get the contents of the file "fname". // Returns an object with two attributes: // - succeeded: true if the function was able to retrieve the file. // - contents: the contents retrieved or an empty string. function getFileContents(fname) { /* // Request file content via HTTP's GET request var xmlhttp = new XMLHttpRequest(); xmlhttp.responseType = "text/plain"; // Content is not XML! xmlhttp.open("GET", "file:\\\\" + fname, false); // NOTE: This can take some time if the server is remote // which means the UI might freeze for some time... xmlhttp.send(); var status = true; var contents = ""; if (xmlhttp.status != 200) { status = false; } else { contents = xmlhttp.responseText; } return {succeeded: status, contents: contents}; */ } function loadShaders() { var tmp,vs,fs; tmp = getFileContents("vs.glsl"); if (!tmp.succeeded) { window.alert('Failed to load Blinn-Phong vertex shader: vs.glsl'); } vs = tmp.contents; tmp = getFileContents("fs.glsl"); if (!tmp.succeeded) { window.alert('Failed to load Blinn-Phong fragment shader: fs.glsl'); } fs = tmp.contents; return { vertex: vs, fragment: fs }; } // Updates position after a complete animation. // Don't touch it, if you can't understand it! function updatePositions() { scene.remove(face); var temp = cubies.get(current_animation.cubies[0]); for(var i = 0; Math.abs(i) < 4; i += current_animation.dir) { var keys, colors; var c_new, c_old = temp; switch (current_animation.cubies[mod(i+current_animation.dir,4)]) { case 0: keys = [0,2,4]; break; case 1: keys = [0,2,5]; break; case 2: keys = [1,2,5]; break; case 3: keys = [1,2,4]; break; case 4: keys = [0,3,4]; break; case 5: keys = [0,3,5]; break; case 6: keys = [1,3,5]; break; case 7: keys = [1,3,4]; break; } switch (current_animation.name) { case "pitch": colors = [0,2,1]; break; case "roll": colors = [1,0,2]; break; case "yaw": colors = [2,1,0]; break; } c_new = new Cubie(c_old.key, current_animation.cubies[mod(i+current_animation.dir,4)], [{ key: keys[0], value: c_old.colors[colors[0]].value }, { key: keys[1], value: c_old.colors[colors[1]].value }, { key: keys[2], value: c_old.colors[colors[2]].value } ]); temp = cubies.get(current_animation.cubies[mod(i+current_animation.dir,4)]); cubies.set(current_animation.cubies[mod(i+current_animation.dir,4)], c_new); scene.add(c_new.mesh); } needsRender = true } // Right module operator. // Beware the Javascript module! (it doesn't work with negative integers) function mod(n, m) { return ((n % m) + m) % m; } // Open a local file. function selectFile(loop) { var element = document.createElement('div'); element.innerHTML = ''; var fileInput = element.firstChild; fileInput.addEventListener('change', function() { var file = fileInput.files[0]; if (file.name.match(/\.(txt)$/)) { var reader = new FileReader(); reader.onload = function() { var data = parseData(reader.result); buildCube(data.cube); if (data.solutions[0].length > 0) { animator = new Animator(data.solutions[0]); animator.goOn(); } }; reader.readAsText(file); } else { alert("File not supported, .txt files only"); } }); fileInput.click(); } function saveToFile(filename, content) { var elem = document.createElement('a'); elem.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content)); elem.setAttribute('download', filename); document.body.appendChild(elem); elem.click(); document.body.removeChild(elem); } // Parse a local file function parseData(text) { var data = [], instance; var moves = [], predicates; var i = -1, pred; var lines = text.split("\n"); instance = new Array(8); // Look for the first line with an answer while(lines[++i].search(/Answer:/g) !== 0) { } // Parse answers while(i < lines.length && lines[i++].search(/Answer:/g) === 0) { predicates = lines[i++].split(" "); pred = predicates[predicates.length-1]; if (pred.search(/solved/i) === 0) { moves = new Array(parseInt(pred.substring(pred.indexOf("(") + 1,pred.indexOf(")")))); } for(var j = 0; j < predicates.length; j++) { pred = predicates[j].split(","); if(predicates[j].search(/move/i) === 0) { switch (pred[1]) { case "pitch": var move = (parseInt(pred[2]) == 0) ? "pitchA" : "pitchB"; break; case "roll": var move = (parseInt(pred[2]) == 0) ? "rollA" : "rollB"; break; case "yaw": var move = (parseInt(pred[2]) == 0) ? "yawA" : "yawB"; break; } var ind = parseInt(pred[0].substring(pred[0].indexOf("(")+1)); if(ind < moves.length) { moves[ind] = { move: move, dir: parseInt(pred[3].substr(0,pred[3].length-1)) }; } } else if(predicates[j].search(/is/i) === 0) { if(parseInt(pred[0].substring(pred[0].indexOf("(")+1)) === 0) { instance[parseInt(pred[1])] = [ pred[2], pred[3], pred[4].substr(0,pred[4].length-1) ]; } } } data.push(moves); } return { cube: instance, solutions: data }; }