these are some samples of coding excercises I have resolved in past interviews
See also:
https://github.com/tincho/trivia-react-challenge
https://github.com/tincho/acme-panel
these are some samples of coding excercises I have resolved in past interviews
See also:
https://github.com/tincho/trivia-react-challenge
https://github.com/tincho/acme-panel
| // final version after 3 refactors is at line 118 | |
| // iteracion 0 | |
| function validate_old(input) { | |
| var balanced = true; | |
| var lastopen = []; | |
| for (var i=0; i<input.length; i++) { | |
| switch(input[i]) { | |
| case '(': | |
| balanced = false; | |
| lastopen.push('('); | |
| break; | |
| case ')': | |
| if (lastopen.slice(-1) =='(') { | |
| lastopen.pop(); | |
| balanced = true | |
| } else { | |
| return false; | |
| } | |
| break; | |
| case '[': | |
| balanced = false; | |
| lastopen.push('['); | |
| break; | |
| case ']': | |
| if (lastopen.slice(-1) == '[') { | |
| lastopen.pop(); | |
| balanced = true; | |
| } else { | |
| return false; | |
| } | |
| break; | |
| case '{': | |
| balanced = false; | |
| lastopen.push('{'); | |
| break; | |
| case '}': | |
| if (lastopen.slice(-1) == '{') { | |
| lastopen.pop(); | |
| balanced = true; | |
| } else { | |
| return false; | |
| } | |
| break; | |
| } | |
| } | |
| return balanced; | |
| } | |
| // iteracion 2 | |
| function validate_(input) { | |
| var openers = ["(", "[", "{"]; | |
| var closers = [")", "]", "}"] | |
| var balanced = true; | |
| var lastopen = []; | |
| for (var i=0; i<input.length; i++) { | |
| if (openers.indexOf(input[i]) !== -1) { | |
| balanced = false; | |
| lastopen.push(input[i]); | |
| } else if (closers.indexOf(input[i]) !== -1) { | |
| var opener = openers[closers.indexOf(input[i])]; | |
| if (lastopen.slice(-1) == opener) { | |
| lastopen.pop(); | |
| balanced = true | |
| } else return false; | |
| } | |
| } | |
| return balanced; | |
| } | |
| // iteracion 3 | |
| function validate__(input) { | |
| var openers = ["(", "[", "{"]; | |
| var closers = [")", "]", "}"]; | |
| var balanced = true; | |
| var lastopen = []; | |
| for (var i=0; i<input.length; i++) { | |
| var c = input[i]; | |
| if (openers.indexOf(c) !== -1) { | |
| balanced = false; | |
| lastopen.push(c); | |
| continue; | |
| } | |
| // "else": | |
| var inClosers = closers.indexOf(c); | |
| if (inClosers !== -1) { | |
| if (lastopen.pop() === openers[inClosers]) { | |
| balanced = true; | |
| continue; | |
| } | |
| // "else": | |
| return false; | |
| } | |
| } | |
| return balanced; | |
| } | |
| // iteracion 4 | |
| function validate(input) { | |
| var openers = ["(", "[", "{"]; | |
| var closers = [")", "]", "}"]; | |
| var balanced = true; | |
| var lastopen = []; | |
| for (var i=0; i<input.length; i++) { | |
| var c = input[i]; | |
| if (openers.indexOf(c) !== -1) { | |
| balanced = false; | |
| lastopen.push(c); | |
| continue; | |
| } | |
| var inClosers = closers.indexOf(c); | |
| if (inClosers === -1) continue; | |
| if (lastopen.pop() !== openers[inClosers]) | |
| return false; | |
| balanced = true; | |
| } | |
| return balanced; | |
| } | |
| /* | |
| to run on tddbin.com | |
| describe('balanced brackets', function() { | |
| it('only parenthesis', function() { | |
| assert.equal(validate("()"), true); | |
| }); | |
| it('paren brack curly', function() { | |
| assert.equal(validate("[]{}()"), true); | |
| }); | |
| it('paren brack curly, nested', function() { | |
| assert.equal(validate("[]({}())"), true); | |
| }); | |
| it('close before parent', function() { | |
| assert.equal(validate("({)}"), false); | |
| }); | |
| it('open and not closed', function() { | |
| assert.equal(validate("("), false); | |
| }); | |
| it('complex', function() { | |
| assert.equal(validate("text outside (inside, [nested and {deep nested}])"), true); | |
| }); | |
| it('complex but broken', function() { | |
| assert.equal(validate("text outside (inside}, [nested and {deep nested])"), false); | |
| }); | |
| it('more', function() { | |
| assert.equal(validate("(())]["), false); | |
| }) | |
| it('extra close', function() { | |
| assert.equal(validate("(no open not closed))"), false); | |
| }) | |
| }); | |
| */ | 
| /** | |
| * beautifulDays | |
| * a day number is "beautiful" if result of `(number - reversed number) / divisor` is integer | |
| * reversed examples 12: 21 | 120: 21 | 7450: 547 | |
| * | |
| * @returns {Number} integer, count of beautiful numbers between i and j | |
| * @param {Number} i first day of the range | |
| * @param {Number} j last day of the range | |
| * @param {Number} k the beautiful divisor | |
| */ | |
| function beautifulDays(i, j, k) { | |
| return range(i, j).reduce((count, n) => isBeautiful(n) ? count + 1 : count, 0) | |
| function range(a, b) { | |
| const length = Math.abs(b - a) + 1 // abs() just in case. Despites specific program constraints, this fn is generic | |
| return Array.from({ length }, (v, id) => a + id) | |
| } | |
| function reverse(n) { | |
| return parseInt(Array.from(String(n)).reverse().join(''), 10) | |
| } | |
| function isBeautiful(n) { | |
| const nreverse = reverse(n) | |
| return Math.abs(n - nreverse) % k === 0 | |
| } | |
| } | 
| /* | |
| * Complete the 'getTime' function below. | |
| * | |
| * The function is expected to return a LONG_INTEGER. | |
| * The function accepts STRING s as parameter. | |
| */ | |
| function getTime(s) { | |
| return Array.from(s.toUpperCase()).reduce((time, letter, i, str) => { | |
| const getPosition = l => l.charCodeAt(0) - 65 // (ascii code for uppercase A) | |
| const currPosition = getPosition(letter) | |
| let distanceForwards = currPosition | |
| let distanceBackwards = 26 - currPosition | |
| const prevLetter = str[i - 1] | |
| if (typeof prevLetter === 'string') { | |
| const prevPosition = getPosition(prevLetter) | |
| distanceBackwards = 26 - Math.max(currPosition, prevPosition) + Math.min(currPosition, prevPosition) | |
| distanceForwards = Math.max(currPosition, prevPosition) - Math.min(currPosition, prevPosition) | |
| } | |
| return time + Math.min(distanceForwards, distanceBackwards) | |
| }, 0) | |
| } | |
| // paste and run on http://tddbin.com | |
| // Reverse Polish Notation | |
| function evaluateRPN(expression) { | |
| const isOperator = c => ["+","-","*","/"].indexOf(c) !== -1; | |
| const tokens = expression.split(" ").filter(t => t !== ''); | |
| return tokens.reduce((stack, token, i, arr) => { | |
| // is operand, push to stack and continue to evaluate next token | |
| if (!isOperator(token)) { | |
| stack.push(token); | |
| return stack; | |
| } | |
| // else, is operator, so operate: | |
| if (stack.length < 2) throw new Error("Not enough operands"); | |
| let a = stack.pop(); | |
| let b = stack.pop(); | |
| let c = eval(`${b} ${token} ${a}`); | |
| stack.push(c); | |
| // if we reach the final result return only the value | |
| let finish = (i+1 === arr.length); | |
| return finish ? stack.pop() : stack; | |
| }, []); | |
| } | |
| describe('reverse polish notation', () => { | |
| it('should eval simple expressions', () => { | |
| const a = evaluateRPN('3 4 +'); | |
| assert.equal(a, 7); | |
| const b = evaluateRPN('3 6 +'); | |
| assert.equal(b, 9) | |
| }); | |
| it('should eval very complex' , () => { | |
| var exp = '15 7 1 1 + - / 3 * 2 1 1 + + -'; | |
| assert.equal(evaluateRPN(exp), 5) | |
| }); | |
| it('should fail if operator before enough operands', () => { | |
| assert.throws(function() { | |
| const c = evaluateRPN('3 + 6 +'); | |
| }, Error, "Not enough operands"); | |
| }); | |
| }); | 
| /** | |
| * given a 2 dimension matrix of chars, find "connected groups" (i.e in touch vertically, horizontally, or diagonally, bidirectionally) of the groupable items | |
| */ | |
| function matrixGroups(matrix, side, groupable = '0') { | |
| // utilities | |
| const inRange = (n, min,max) => ((n-min)*(n-max) <= 0); | |
| const inMatrixRange = n => inRange(n, 0, side-1); | |
| const inMatrix = ([x, y]) => inMatrixRange(x) && inMatrixRange(y); | |
| const isConnected = (x, y) => ([_x, _y]) => matrix[x][y] == matrix[_x][_y]; | |
| // given a spot, return an array of connected spots containing its same value | |
| const lookAround = ([x, y]) => { | |
| // all potential posibilities surounding an x,y combination | |
| const around = ([ | |
| [x-1, y-1], | |
| [x-1, y ], | |
| [x-1, y+1], | |
| [x , y-1], | |
| [x , y+1], | |
| [x+1, y-1], | |
| [x+1, y ], | |
| [x+1, y+1], | |
| ]).filter(inMatrix); | |
| // select those whose content matches | |
| return around.filter(isConnected(x, y)); | |
| }; | |
| function Group() { | |
| this.points = []; | |
| this.size = () => this.points.length; | |
| } | |
| Group.prototype.hasPoint = function([nx, ny]) { | |
| return !!this.points.find(([x,y]) => nx == x && ny == y); | |
| }; | |
| Group.prototype.addPoint = function(p, matches) { | |
| if (this.hasPoint(p)) return; | |
| this.points.push(p); | |
| // recursively add all the matches of the matches | |
| let ms = (typeof matches === 'undefined') ? lookAround(p) : matches; | |
| ms.forEach(m => this.addPoint(m)); | |
| } | |
| const groups = []; | |
| const matchingGroup = matches => groups.find(g => matches.some(p => g.hasPoint(p))); | |
| const addToGroup = (point) => { | |
| // check if it fits into an existing group, else create a new one | |
| const matches = lookAround(point); | |
| let group = matchingGroup(matches); | |
| if (!group) { | |
| group = new Group(); | |
| groups.push(group); | |
| } | |
| group.addPoint(point, matches); | |
| } | |
| const alreadyInGroup = point => groups.find(g => g.hasPoint(point)); | |
| for(let x = 0; x < side; x++) { | |
| for(let y = 0; y < side; y++) { | |
| // we dont care about anything else in the matrix except out groupable character | |
| if (matrix[x][y] != groupable) continue; | |
| // if the point is already in some group, move on | |
| const point = [x, y]; | |
| if (alreadyInGroup(point)) continue; | |
| // try fitting the point in a group | |
| addToGroup(point); | |
| } | |
| } | |
| return groups.map(g => g.size()).sort((a,b) => a-b); | |
| } | |
| describe('find connected groups in square matrix', () => { | |
| it('should return each group sizes, sorted', () => { | |
| const matrix = [ | |
| [ 0, 0, 1, 0, 1 ], | |
| [ 1, 1, 0, 1, 1 ], | |
| [ 0, 1, 0, 1, 0 ], | |
| [ 0, 1, 1, 1, 1 ], | |
| [ 1, 0, 1, 0, 1 ], | |
| ]; | |
| const side = 5; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [1, 1, 3, 5]); | |
| }) | |
| it('should return each group sizes, X-shaped group', () => { | |
| const matrix = [ | |
| [ 0, 1, 1, 1, 0 ], | |
| [ 1, 0, 1, 0, 1 ], | |
| [ 1, 1, 0, 1, 1 ], | |
| [ 1, 0, 1, 0, 1 ], | |
| [ 0, 1, 1, 1, 0 ], | |
| ]; | |
| const side = 5; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [9]); | |
| }) | |
| it('should return each group sizes, X-shaped group', () => { | |
| const matrix = [ | |
| [ 0, 1, 1, 1, 0 ], | |
| [ 1, 0, 1, 0, 1 ], | |
| [ 1, 1, 0, 1, 1 ], | |
| [ 0, 1, 1, 0, 1 ], | |
| [ 0, 0, 1, 1, 0 ], | |
| ]; | |
| const side = 5; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [3,7]); | |
| }) | |
| it('should return each group sizes, smaller matrix', () => { | |
| const matrix = [ | |
| [ 0, 0, 1 ], | |
| [ 1, 1, 0 ], | |
| [ 0, 1, 0 ], | |
| ]; | |
| const side = 3; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [1, 4]); | |
| }) | |
| it('should return each group sizes, smaller matrix 1', () => { | |
| const matrix = [ | |
| [ 1, 0 ], | |
| [ 1, 1 ], | |
| ]; | |
| const side = 2; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [1]); | |
| }) | |
| it('should return each group sizes, smaller matrix 2', () => { | |
| const matrix = [ | |
| [ 0, 0 ], | |
| [ 1, 1 ], | |
| ]; | |
| const side = 2; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [2]); | |
| }) | |
| it('should return each group sizes, smaller matrix 3', () => { | |
| const matrix = [ | |
| [ 0, 0 ], | |
| [ 1, 0 ], | |
| ]; | |
| const side = 2; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [3]); | |
| }) | |
| it('should return each group sizes, bigger matrix', () => { | |
| const matrix = [ | |
| [ 0, 0, 1, 0, 1, 1 ], | |
| [ 1, 1, 0, 1, 1, 1 ], | |
| [ 0, 1, 0, 1, 0, 0 ], | |
| [ 0, 1, 1, 1, 1, 1 ], | |
| [ 0, 0, 1, 0, 1, 1 ], | |
| [ 1, 0, 0, 0, 1, 1 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [2, 5, 8]); | |
| }) | |
| it('should return each group sizes, only one group', () => { | |
| const matrix = [ | |
| [ 0, 1, 1, 1, 1, 1 ], | |
| [ 1, 0, 1, 1, 1, 1 ], | |
| [ 1, 1, 0, 1, 1, 1 ], | |
| [ 1, 1, 1, 0, 1, 1 ], | |
| [ 1, 1, 1, 1, 0, 1 ], | |
| [ 1, 1, 1, 1, 1, 0 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [6]); | |
| }) | |
| it('should return each group sizes, spare groups', () => { | |
| const matrix = [ | |
| [ 1, 1, 1, 1, 0, 0 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 1, 0, 1, 1, 1 ], | |
| [ 1, 1, 1, 0, 1, 1 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 0, 0, 1, 1, 1 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [2, 2, 2]); | |
| }) | |
| it('should return each group sizes, whole matrix is a group', () => { | |
| const matrix = [ | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [36]); | |
| }) | |
| it('should return each group sizes, a few single groups', () => { | |
| const matrix = [ | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 0, 1, 1, 1, 1 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 1, 1, 0, 1, 1 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 1, 1, 1, 1, 0 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [1,1,1]); | |
| }) | |
| it('should return each group sizes, no groups', () => { | |
| const matrix = [ | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, []); | |
| }) | |
| it('should return each group sizes, big H', () => { | |
| const matrix = [ | |
| [ 0, 1, 1, 1, 1, 0 ], | |
| [ 0, 1, 1, 1, 1, 0 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| [ 0, 1, 1, 1, 1, 0 ], | |
| [ 0, 1, 1, 1, 1, 0 ], | |
| [ 0, 1, 1, 1, 1, 0 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [16]); | |
| }) | |
| it('should return each group sizes, horizontal groups', () => { | |
| const matrix = [ | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| [ 1, 1, 1, 1, 1, 1 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [6,6,6]); | |
| }) | |
| it('should return each group sizes, vertical groups', () => { | |
| const matrix = [ | |
| [ 0, 0, 1, 0, 1, 0 ], | |
| [ 0, 0, 1, 0, 1, 0 ], | |
| [ 0, 0, 1, 0, 1, 0 ], | |
| [ 0, 0, 1, 0, 1, 0 ], | |
| [ 0, 0, 1, 0, 1, 0 ], | |
| [ 0, 0, 1, 0, 1, 0 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [6,6,12]); | |
| }) | |
| it('should return each group sizes, spiral group', () => { | |
| const matrix = [ | |
| [ 0, 1, 1, 1, 1, 1 ], | |
| [ 0, 1, 0, 0, 0, 0 ], | |
| [ 0, 1, 0, 1, 1, 0 ], | |
| [ 0, 1, 0, 0, 1, 0 ], | |
| [ 0, 1, 1, 1, 1, 0 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [21]); | |
| }) | |
| it('should return each group sizes, other spiral group', () => { | |
| const matrix = [ | |
| [ 0, 1, 0, 0, 0, 0 ], | |
| [ 0, 1, 0, 1, 1, 0 ], | |
| [ 0, 1, 0, 1, 1, 0 ], | |
| [ 0, 1, 0, 0, 1, 0 ], | |
| [ 0, 1, 1, 1, 1, 0 ], | |
| [ 0, 0, 0, 0, 0, 0 ], | |
| ]; | |
| const side = 6; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [23]); | |
| }) | |
| it('should return each group sizes, bigger spiral group', () => { | |
| const matrix = [ | |
| [ 0, 1, 0, 0, 0, 0, 0, 0 ], | |
| [ 0, 1, 0, 1, 1, 1, 1, 0 ], | |
| [ 0, 1, 0, 1, 0, 0, 1, 0 ], | |
| [ 0, 1, 0, 1, 1, 0, 1, 0 ], | |
| [ 0, 1, 0, 1, 1, 0, 1, 0 ], | |
| [ 0, 1, 0, 0, 0, 0, 1, 0 ], | |
| [ 0, 1, 1, 1, 1, 1, 1, 0 ], | |
| [ 0, 0, 0, 0, 0, 0, 0, 0 ], | |
| ]; | |
| const side = 8; | |
| const result = matrixGroups(matrix, side); | |
| assert.deepEqual(result, [39]); | |
| }) | |
| }); | |
| // ************* last version *********** | |
| // @returns {Boolean} string a is anagram of b (and viceversa, by definition) | |
| const isAnagram = (a, b) => [...a].sort().join('') === [...b].sort().join('') | |
| /** | |
| * given @param input {Array} of {String}s | |
| * @returns {Array} of {String}s filtering out any anagram that is repeated, sorted alphabetically | |
| */ | |
| function funWithAnagrams(input) { | |
| // remove each string that is anagram of earlier string | |
| // output is alphabetically asc | |
| const [first, ...rest] = input | |
| return [ | |
| first, | |
| ...rest.filter( | |
| (str, i) => !input.slice(0, i + 1).some(prevStr => isAnagram(str, prevStr)) | |
| ) | |
| ].sort() | |
| } | |
| // try it at tddbin.com! | |
| // /* | |
| ************* previous version *********** | |
| // @returns {Number} occurences OF item IN collection | |
| const occurences = (item, collection) => collection.reduce((count, currItem) => count + Number(currItem === item), 0) | |
| // mas cheta: | |
| // const occurences = (item, collection, compare = (a, b) => a === b) => collection.reduce((count, currItem) => count + Number(compare(currItem, item)), 0) | |
| // @returns {Boolean} string a is anagram of b (and viceversa, by definition) | |
| const isAnagram = (a, b) => (a.length !== b.length) | |
| ? false | |
| : Array.from(a).every(chr => occurences(chr, Array.from(a)) === occurences(chr, Array.from(b))) | |
| function funWithAnagrams(input) { | |
| // remove each string that is anagram of earlier string | |
| // output is alphabetically asc | |
| const [first, ...rest] = input | |
| return [ | |
| first, | |
| ...rest.filter( | |
| (str, i) => !input.slice(0, i + 1).some(prevStr => isAnagram(str, prevStr)) | |
| ) | |
| ].sort() | |
| } | |
| ************* first version *********** | |
| const occurences = (item, collection) => collection | |
| .reduce((count, currItem) => count + Number(currItem === item), 0) | |
| function isAnagram(a, b) { | |
| if (a.length !== b.length) return false | |
| const arr_a = Array.from(a) | |
| const arr_b = Array.from(b) | |
| return arr_a.every(chr => { | |
| if(!arr_b.includes(chr)) { | |
| return false | |
| } | |
| return occurences(chr, arr_a) === occurences(chr, arr_b) | |
| }) | |
| } | |
| function funWithAnagrams(input) { | |
| return input | |
| .filter((currentString, i) => { | |
| if (i === 0) return true | |
| const earlierValues = input.slice(0, i) | |
| const isAnagramOfAnyEarlier = earlierValues.some(earlierString => isAnagram(currentString, earlierString)) | |
| return !isAnagramOfAnyEarlier | |
| }) | |
| .sort() | |
| } | |
| // */ | 
| // paste and run on http://tddbin.com | |
| function sortInPlace(arr, direction = 'ASC') { | |
| const ASC = (a, b) => a < b; | |
| const DESC = (a, b) => a > b; | |
| let fns = { ASC, DESC }; | |
| const compare = typeof direction === 'function' ? direction: fns[direction] || ASC; | |
| // start from the second element | |
| for (var i = 1; i < arr.length; i++) { | |
| var next; | |
| var nextPos = -1; | |
| // compare backwards until we find the next in the order | |
| for(var j = i-1; j >= 0; j--) { | |
| if (compare(arr[i], arr[j])) { | |
| nextPos = j; | |
| next = arr[j]; | |
| } | |
| } | |
| // didnt found any value to replace: move on to next. | |
| if (nextPos === -1) continue; | |
| // if we've found some item | |
| // place our current element in its place, | |
| arr[nextPos] = arr[i]; | |
| var aux; | |
| // and move 1 place every item until filling the place of current | |
| for(var k = nextPos+1; k <= i; k++) { | |
| aux = arr[k]; | |
| arr[k] = next; | |
| next = aux; | |
| } | |
| } | |
| } | |
| describe('sort in place - ASC', () => { | |
| const not_sorted = [ | |
| [9,2,5,1,7], | |
| [9,2,1,5,7], | |
| [10,9,8,7], | |
| [1,2,3], | |
| [1,1,1,1,1], | |
| [10,1,11,2,13,2,14,5], | |
| [9999,0,0,0,5,2,3,4], | |
| [3,2,1,6,5,4,7,8,4], | |
| ]; | |
| const sorted = [ | |
| [1,2,5,7,9], | |
| [1,2,5,7,9], | |
| [7,8,9,10], | |
| [1,2,3], | |
| [1,1,1,1,1], | |
| [1,2,2,5,10,11,13,14], | |
| [0,0,0,2,3,4,5,9999], | |
| [1,2,3,4,4,5,6,7,8], | |
| ]; | |
| not_sorted.forEach((a, i) => { | |
| const b = sorted[i]; | |
| it(`should sort [${a.join(',')}] to [${b.join(',')}]`, () => { | |
| sortInPlace(a); | |
| assert.deepEqual(a, b); | |
| }); | |
| }); | |
| }); | |
| describe('sort in place - DESC', () => { | |
| const not_sorted = [ | |
| [9,2,5,1,7], | |
| [9,2,1,5,7], | |
| [10,9,8,7], | |
| [1,2,3], | |
| [1,1,1,1,1], | |
| [10,1,11,2,13,2,14,5], | |
| [9999,0,0,0,5,2,3,4], | |
| [3,2,1,6,5,4,7,8,4], | |
| ]; | |
| const sorted = [ | |
| [1,2,5,7,9], | |
| [1,2,5,7,9], | |
| [7,8,9,10], | |
| [1,2,3], | |
| [1,1,1,1,1], | |
| [1,2,2,5,10,11,13,14], | |
| [0,0,0,2,3,4,5,9999], | |
| [1,2,3,4,4,5,6,7,8], | |
| ]; | |
| not_sorted.forEach((a, i) => { | |
| const b = sorted[i].reverse(); | |
| it(`should sort [${a.join(',')}] to [${b.join(',')}]`, () => { | |
| sortInPlace(a, 'DESC'); | |
| assert.deepEqual(a, b); | |
| }); | |
| }); | |
| }); | |
| describe('sort in place - custom', () => { | |
| const not_sorted = [ | |
| [ | |
| {value: 3}, | |
| {value: 11}, | |
| {value: 4}, | |
| {value: 20}, | |
| {value: 2}, | |
| {value: 1}, | |
| ] | |
| ]; | |
| const sorted = [ | |
| [ | |
| {value: 1}, | |
| {value: 2}, | |
| {value: 3}, | |
| {value: 4}, | |
| {value: 11}, | |
| {value: 20}, | |
| ] | |
| ]; | |
| not_sorted.forEach((a, i) => { | |
| const b = sorted[i]; | |
| it(`should sort [${a}] to [${b}]`, () => { | |
| sortInPlace(a, (o1, o2) => o1.value < o2.value); | |
| assert.deepEqual(a, b); | |
| }); | |
| }); | |
| }); | |
| function makeGrid(side) { | |
| return Array.from({ | |
| length: side | |
| }, () => Array.from({ | |
| length: side | |
| })) | |
| } | |
| function makeTicTacToe() { | |
| return makeGrid(3) | |
| } | |
| function checkWinner(grid) { | |
| const checkHorizontal = (y, spot) => { | |
| if (grid[y].every(v => v === spot)) { | |
| return spot | |
| } | |
| } | |
| const checkVertical = (x, spot) => { | |
| if (grid.every(row => row[x] === spot)) { | |
| return spot | |
| } | |
| } | |
| const checkDiagonal = (x, spot) => { | |
| if (x === 0) { | |
| if (grid[1][1] === spot && grid[2][2] === spot) { | |
| return spot | |
| } | |
| } | |
| // else x will be 2 | |
| if (grid[1][1] === spot && grid[2][0] === spot) { | |
| return spot | |
| } | |
| } | |
| let winner = false | |
| grid.forEach( | |
| (row, y) => row | |
| .slice(0, row.length - y) | |
| .forEach((spot, x) => | |
| { | |
| if (winner) { | |
| return | |
| } | |
| if (y === 0) { | |
| const v = checkVertical(x, spot) | |
| if (v) { | |
| winner = v | |
| return | |
| } | |
| if (x === 0 || x === row.length - 1) { | |
| const d = checkDiagonal(x, spot) | |
| if (d) { | |
| winner = d | |
| return | |
| } | |
| } | |
| } | |
| if (x === 0) { | |
| const h = checkHorizontal(y, spot) | |
| if (h) { | |
| winner = h | |
| return | |
| } | |
| } | |
| } | |
| ) | |
| ) | |
| // console.log(lookAround([0, 0])) | |
| return winner | |
| } | |
| function playTurn(grid, player, [x, y]) { | |
| if (grid[x][y]) { | |
| return false | |
| } | |
| grid[x][y] = player | |
| return checkWinner(grid) | |
| } | |
| const playerOne = 'x' | |
| const playerTwo = 'o' | |
| const side = 3 | |
| describe('tic tac toe', () => { | |
| it('empty grid: no winner', () => { | |
| const grid = makeTicTacToe() | |
| expect(checkWinner(grid)).toEqual(false) | |
| }) | |
| describe('horizontal', () => { | |
| it('winner: x horizontal first row', () => { | |
| const grid = makeTicTacToe(); | |
| grid[0][0] = 'x' | |
| grid[0][1] = 'x' | |
| grid[0][2] = 'x' | |
| expect(checkWinner(grid)).toEqual('x') | |
| }) | |
| it('winner: x horizontal second row', () => { | |
| const grid = makeTicTacToe(); | |
| grid[1][0] = 'x' | |
| grid[1][1] = 'x' | |
| grid[1][2] = 'x' | |
| expect(checkWinner(grid)).toEqual('x') | |
| }) | |
| it('winner: x horizontal third row', () => { | |
| const grid = makeTicTacToe(); | |
| grid[2][0] = 'x' | |
| grid[2][1] = 'x' | |
| grid[2][2] = 'x' | |
| expect(checkWinner(grid)).toEqual('x') | |
| }) | |
| }) | |
| describe('vertical', () => { | |
| it('winner: x vertical first col', () => { | |
| const grid = makeTicTacToe(); | |
| grid[0][0] = 'x' | |
| grid[1][0] = 'x' | |
| grid[2][0] = 'x' | |
| expect(checkWinner(grid)).toEqual('x') | |
| }) | |
| it('winner: x vertical second col', () => { | |
| const grid = makeTicTacToe(); | |
| grid[0][1] = 'x' | |
| grid[1][1] = 'x' | |
| grid[2][1] = 'x' | |
| expect(checkWinner(grid)).toEqual('x') | |
| }) | |
| it('winner: x vertical third col', () => { | |
| const grid = makeTicTacToe(); | |
| grid[0][2] = 'x' | |
| grid[1][2] = 'x' | |
| grid[2][2] = 'x' | |
| expect(checkWinner(grid)).toEqual('x') | |
| }) | |
| }) | |
| describe('diagonal', () => { | |
| it('winner: x diagonal first col', () => { | |
| const grid = makeTicTacToe(); | |
| grid[0][0] = 'x' | |
| grid[1][1] = 'x' | |
| grid[2][2] = 'x' | |
| expect(checkWinner(grid)).toEqual('x') | |
| }) | |
| it('winner: x diagonal third col', () => { | |
| const grid = makeTicTacToe(); | |
| grid[0][2] = 'x' | |
| grid[1][1] = 'x' | |
| grid[2][0] = 'x' | |
| expect(checkWinner(grid)).toEqual('x') | |
| }) | |
| }) | |
| it('scenario 1', () => { | |
| const grid = makeTicTacToe(); | |
| playTurn(grid, playerOne, [0, 0]) | |
| playTurn(grid, playerTwo, [0, 1]) | |
| playTurn(grid, playerOne, [2, 2]) | |
| playTurn(grid, playerTwo, [1, 1]) | |
| playTurn(grid, playerOne, [0, 2]) | |
| playTurn(grid, playerTwo, [2, 1]) | |
| console.log(grid) | |
| expect(checkWinner(grid)).toEqual(playerTwo) | |
| }) | |
| }) |