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) | |
}) | |
}) |