├── README.md ├── index.js ├── movementKeyMap.json ├── package.json └── player.js /README.md: -------------------------------------------------------------------------------- 1 | # selenium-rubiks-cube-solver 2 | Selenium script to solve online rubik's cube 3 | 4 | # Setup: 5 | 1. install nodejs and firefox browser. 6 | 2. clone the repo. 7 | 3. run npm install. 8 | 4. download firefox driver and update the path player.js file. 9 | 5. run "node index.js" 10 | 11 | # DEMO: 12 | 13 | [![DEMO](https://img.youtube.com/vi/t2o-90eLmXg/0.jpg)](https://www.youtube.com/watch?v=t2o-90eLmXg "Selenium rubik's cube solver") 14 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let player = require("./player.js"); 2 | 3 | (async function () { 4 | await player.init(); 5 | await player.shuffle(); 6 | await player.solve(); 7 | })(); 8 | 9 | -------------------------------------------------------------------------------- /movementKeyMap.json: -------------------------------------------------------------------------------- 1 | { 2 | "F": { 3 | "start": { 4 | "side": "right", 5 | "face": "northWest" 6 | }, 7 | "end": { 8 | "side": "right", 9 | "face": "southWest" 10 | } 11 | }, 12 | "R": { 13 | "start": { 14 | "side": "front", 15 | "face": "southEast" 16 | }, 17 | "end": { 18 | "side": "front", 19 | "face": "northEast" 20 | } 21 | }, 22 | "U": { 23 | "start": { 24 | "side": "front", 25 | "face": "northEast" 26 | }, 27 | "end": { 28 | "side": "front", 29 | "face": "northWest" 30 | } 31 | }, 32 | "L": { 33 | "start": { 34 | "side": "front", 35 | "face": "northWest" 36 | }, 37 | "end": { 38 | "side": "front", 39 | "face": "southWest" 40 | } 41 | }, 42 | "B": { 43 | "start": { 44 | "side": "up", 45 | "face": "northEast" 46 | }, 47 | "end": { 48 | "side": "up", 49 | "face": "northWest" 50 | } 51 | }, 52 | "D": { 53 | "start": { 54 | "side": "right", 55 | "face": "southWest" 56 | }, 57 | "end": { 58 | "side": "right", 59 | "face": "southEast" 60 | } 61 | }, 62 | "M": { 63 | "start": { 64 | "side": "up", 65 | "face": "north" 66 | }, 67 | "end": { 68 | "side": "up", 69 | "face": "south" 70 | } 71 | }, 72 | "E": { 73 | "start": { 74 | "side": "right", 75 | "face": "west" 76 | }, 77 | "end": { 78 | "side": "right", 79 | "face": "east" 80 | } 81 | }, 82 | "E": { 83 | "start": { 84 | "side": "up", 85 | "face": "west" 86 | }, 87 | "end": { 88 | "side": "up", 89 | "face": "east" 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "selenium-rubiks-cube-solver", 3 | "version": "1.0.0", 4 | "description": "Selenium script to solve online rubik's cube", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/sudharsan-selvaraj/selenium-rubiks-cube-solver.git" 12 | }, 13 | "author": "Sudharsan Selvaraj", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/sudharsan-selvaraj/selenium-rubiks-cube-solver/issues" 17 | }, 18 | "homepage": "https://github.com/sudharsan-selvaraj/selenium-rubiks-cube-solver#readme", 19 | "dependencies": { 20 | "rubiks-cube-solver": "^1.2.0", 21 | "selenium-webdriver": "^4.0.0-alpha.7" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /player.js: -------------------------------------------------------------------------------- 1 | const {Builder, By} = require('selenium-webdriver'); 2 | const {ServiceBuilder} = require('selenium-webdriver/firefox'); 3 | const solver = require('rubiks-cube-solver'); 4 | const moveDetails = require("./movementKeyMap.json"); 5 | 6 | function RubiksPlayer() { 7 | 8 | var sides = ["front", "right", "up", "down", "left", "back"]; 9 | var colorToSideMap = {}; 10 | 11 | this.init = async function () { 12 | global.driver = await new Builder() 13 | .forBrowser("firefox") 14 | .setFirefoxService(new ServiceBuilder("/Users/sudharsan/Documents/Applications/geckodriver")) 15 | .build(); 16 | await this.launchApp(); 17 | }; 18 | 19 | 20 | this.shuffle = async function () { 21 | console.log("Shuffling the cube..."); 22 | await driver.findElement(By.css("#actionShuffle")).click(); 23 | await driver.sleep(20000); 24 | await driver.findElement(By.css("#actionShuffle")).click(); 25 | console.log("Shuffling completed...\n"); 26 | await driver.sleep(2000); 27 | }; 28 | 29 | this.launchApp = async function () { 30 | await driver.get("http://iamthecu.be/"); 31 | await driver.findElement(By.css("body")).click(); 32 | await driver.sleep(5000); 33 | }; 34 | 35 | 36 | this.solve = async function () { 37 | let solution = await getSolution(); 38 | await play(solution); 39 | }; 40 | 41 | let getSolution = async function () { 42 | 43 | let traversalOrder = { 44 | "front": ["northWest", "north", "northEast", "west", "origin", "east", "southWest", "south", "southEast"], 45 | "left": ["northEast", "east", "southEast", "north", "origin", "south", "northWest", "west", "southWest"], 46 | "right": ["northWest", "north", "northEast", "west", "origin", "east", "southWest", "south", "southEast"], 47 | "back": ["northEast", "east", "southEast", "north", "origin", "south", "northWest", "west", "southWest"], 48 | "up": ["northWest", "north", "northEast", "west", "origin", "east", "southWest", "south", "southEast"], 49 | "down": ["southWest", "west", "northWest", "south", "origin", "north", "southEast", "east", "northEast"] 50 | }; 51 | 52 | sides.map(async function (side) { 53 | let centerColor = await driver.executeScript(`return cube.${side}.origin.${side}.color.initial`); 54 | colorToSideMap[centerColor] = side.substring(0, 1); 55 | }); 56 | 57 | let finalValue = sides.map(async function (side) { 58 | let traversedColorsPromise = traversalOrder[side].map(async function (pos) { 59 | return driver.executeScript(`return cube.${side}.${pos}.${side}.color.initial`) 60 | }); 61 | 62 | return Promise.all(traversedColorsPromise).then(function (colors) { 63 | let combinedColors = colors.reduce(function (acc, v) { 64 | return acc + colorToSideMap[v]; 65 | }, ''); 66 | 67 | return { 68 | [side]: combinedColors 69 | }; 70 | }) 71 | }); 72 | 73 | return Promise.all(finalValue).then(function (values) { 74 | values = values.reduce(function (acc, v) { 75 | return Object.assign(acc, v); 76 | }, {}); 77 | 78 | let combinedColorsFromAllSides = sides.map(function (side) { 79 | return values[side] 80 | }).join(""); 81 | 82 | return solver(combinedColorsFromAllSides) 83 | }) 84 | }; 85 | 86 | 87 | let play = async function solution(solution) { 88 | 89 | let steps = solution.split(" "); 90 | console.log("Total number of steps:" + steps.length); 91 | 92 | for (let i = 0; i < steps.length; i++) { 93 | let step = steps[i]; 94 | let move = step.substring(0, 1); 95 | let isInverse = false; 96 | let count = 1; 97 | 98 | if (step.indexOf("prime") >= 0) { 99 | isInverse = true; 100 | } else if (step.length === 2) { 101 | count = 2 102 | } 103 | 104 | console.log("current Move: " + step + " count:" + count); 105 | await makeMove(moveDetails[move.toUpperCase()], isInverse, count); 106 | } 107 | }; 108 | 109 | 110 | let makeMove = async function (move, isInverse, noOfTime) { 111 | let startPoint = move.start, 112 | endPoint = move.end; 113 | if (isInverse) { 114 | startPoint = move.end; 115 | endPoint = move.start; 116 | } 117 | while (noOfTime > 0) { 118 | let startElement = await getElement(startPoint), 119 | endElement = await getElement(endPoint); 120 | 121 | await driver.actions().dragAndDrop(startElement, endElement).perform(); 122 | await driver.sleep(500); 123 | noOfTime--; 124 | } 125 | }; 126 | 127 | 128 | let getElement = async function (pointDetails) { 129 | let cubeletId = await driver.executeScript(`return cube.${pointDetails.side}.${pointDetails.face}.id`); 130 | let className = await driver.executeScript(`return cube.${pointDetails.side}.${pointDetails.face}.${pointDetails.side}.element.getAttribute('class')`) 131 | return driver.findElement(By.css(`.cubeletId-${cubeletId}`)).findElement(By.className(className)); 132 | } 133 | 134 | } 135 | 136 | module.exports = new RubiksPlayer(); 137 | 138 | --------------------------------------------------------------------------------