├── .npmrc ├── .gitignore ├── static └── configure-debug.gif ├── .editorconfig ├── problems ├── __tests__ │ ├── 011.js │ ├── 003.js │ ├── 001.js │ ├── 004.js │ ├── 029.js │ ├── 009.js │ ├── 021.js │ ├── 007.js │ ├── 002.js │ ├── 020.js │ ├── 030.js │ ├── 005.js │ ├── 006.js │ ├── 008.js │ ├── 012.js │ ├── 025.js │ ├── 013.js │ ├── 014.js │ ├── 026.js │ ├── 010.js │ ├── 015.js │ ├── 017.js │ ├── 019.js │ ├── 023.js │ ├── 018.js │ ├── 028.js │ ├── 016.js │ ├── 022.js │ ├── 027.js │ ├── 031.js │ └── 024.js ├── 020-rle.js ├── 030-flatten.js ├── 001-sum.js ├── 010-power-of-two.js ├── 027-has.js ├── 008-palindrome.js ├── 016-sort-timestamps.js ├── 015-fibonacci-2.js ├── 019-search-anagrams.js ├── 026-vacation.js ├── 028-more-parentheses.js ├── 014-fibonacci.js ├── 005-union.js ├── 003-ticket.js ├── 023-hex-to-rgb.js ├── 007-bus-tour.js ├── 017-census.js ├── 018-anagram.js ├── 029-map-parseInt.js ├── 022-parentheses.js ├── 025-metro.js ├── 024-timeago.js ├── 021-repair.js ├── 009-time-delta.js ├── 002-basketball.js ├── 012-password.js ├── 011-decrypt.js ├── 013-ip.js ├── 004-orizuru.js ├── 031-circular-dependency.js └── 006-spring-melt.js ├── package.json ├── LICENSE ├── .vscode └── launch.json ├── README.md └── jest.config.js /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /static/configure-debug.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbelsky/js-problems/HEAD/static/configure-debug.gif -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /problems/__tests__/011.js: -------------------------------------------------------------------------------- 1 | const decrypt = require('../011-decrypt'); 2 | 3 | test('Тестирование задачи "011-decrypt"', () => { 4 | expect(decrypt('bnqqdbs')).toBe('correct'); 5 | expect(decrypt('zmc vd hfmnqd rozbdr')).toBe('and we ignore spaces'); 6 | }); 7 | -------------------------------------------------------------------------------- /problems/__tests__/003.js: -------------------------------------------------------------------------------- 1 | const checkTicket = require('../003-ticket'); 2 | 3 | test('Тестирование задачи "003-ticket"', () => { 4 | expect(checkTicket('005212')).toBe(true); 5 | expect(checkTicket('133700')).toBe(true); 6 | expect(checkTicket('123032')).toBe(false); 7 | }); 8 | -------------------------------------------------------------------------------- /problems/__tests__/001.js: -------------------------------------------------------------------------------- 1 | const sum = require('../001-sum'); 2 | 3 | test('Тестирование задачи "001-sum"', () => { 4 | expect(sum(-100)).toBe(1); 5 | expect(sum(0)).toBe(1); 6 | expect(sum(1)).toBe(1); 7 | expect(sum(2)).toBe(3); 8 | expect(sum(5)).toBe(15); 9 | }); 10 | -------------------------------------------------------------------------------- /problems/__tests__/004.js: -------------------------------------------------------------------------------- 1 | const computeOrizurus = require('../004-orizuru'); 2 | 3 | test('Тестирование задачи "004-orizuru"', () => { 4 | expect(computeOrizurus(6)).toEqual([1, 4, 1]); 5 | expect(computeOrizurus(24)).toEqual([4, 16, 4]); 6 | expect(computeOrizurus(60)).toEqual([10, 40, 10]); 7 | }); 8 | -------------------------------------------------------------------------------- /problems/__tests__/029.js: -------------------------------------------------------------------------------- 1 | const map = require('../029-map-parseInt'); 2 | 3 | test('Тестирование задачи "029-map-parseInt"', () => { 4 | expect(map()).toEqual([]); 5 | expect(map([])).toEqual([]); 6 | expect(map(['128'])).toEqual([128]); 7 | expect(map(['128', '64', '32'])).toEqual([128, 64, 32]); 8 | }); 9 | -------------------------------------------------------------------------------- /problems/__tests__/009.js: -------------------------------------------------------------------------------- 1 | const getTimeDelta = require('../009-time-delta'); 2 | 3 | test('Тестирование задачи "009-time-delta"', () => { 4 | expect(getTimeDelta('00:00:00', '00:00:01')).toBe(1); 5 | expect(getTimeDelta('01:01:01', '02:02:02')).toBe(3661); 6 | expect(getTimeDelta('01:19:30', '01:20:20')).toBe(50); 7 | }); 8 | -------------------------------------------------------------------------------- /problems/__tests__/021.js: -------------------------------------------------------------------------------- 1 | const repair = require('../021-repair'); 2 | 3 | test('Тестирование задачи "021-repair"', () => { 4 | expect(repair(1, 1, 3)).toBe(1); 5 | expect(repair(4, 4, 2)).toBe(2); 6 | expect(repair(4, 4, 3)).toBe(3); 7 | expect(repair(4, 4, 4)).toBe(4); 8 | expect(repair(10, 4, 4)).toBe(7); 9 | }); 10 | -------------------------------------------------------------------------------- /problems/020-rle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию rle(value) реализующую алгоритм сжатия строки. 3 | * 4 | * Пример: 5 | * 6 | * rle('AAABC') === '3ABC' 7 | * rle('AAAaaB') === '3A2aB' 8 | * 9 | * @param {string} value 10 | * @returns {string} 11 | */ 12 | function rle(value) { 13 | return undefined; 14 | } 15 | 16 | module.exports = rle; 17 | -------------------------------------------------------------------------------- /problems/__tests__/007.js: -------------------------------------------------------------------------------- 1 | const checkBusTour = require('../007-bus-tour'); 2 | 3 | test('Тестирование задачи "007-bus-tour"', () => { 4 | expect(checkBusTour([600, 1024])).toBeUndefined(); 5 | expect(checkBusTour([600, 512])).toBe(2); 6 | expect(checkBusTour([600, 512, 100])).toBe(2); 7 | expect(checkBusTour([600, 512, 600, 100])).toBe(2); 8 | }); 9 | -------------------------------------------------------------------------------- /problems/__tests__/002.js: -------------------------------------------------------------------------------- 1 | const getWinner = require('../002-basketball'); 2 | 3 | test('Тестирование задачи "002-basketball"', () => { 4 | expect(getWinner(['23-26', '24-30', '30-27', '35-31'])).toBe(2); 5 | expect(getWinner(['36-32', '32-24', '20-28', '30-26'])).toBe(1); 6 | expect(getWinner(['36-18', '22-31', '27-21', '19-34'])).toBeUndefined(); 7 | }); 8 | -------------------------------------------------------------------------------- /problems/__tests__/020.js: -------------------------------------------------------------------------------- 1 | const rle = require('../020-rle'); 2 | 3 | test('Тестирование задачи "020-rle"', () => { 4 | expect(rle('AAABC')).toBe('3ABC'); 5 | expect(rle('AAaaB')).toBe('2A2aB'); 6 | expect(rle('aAAaaB')).toBe('a2A2aB'); 7 | expect(rle('aAAaaBBB')).toBe('a2A2a3B'); 8 | expect(rle('false')).toBe('false'); 9 | expect(rle('')).toBe(''); 10 | }); 11 | -------------------------------------------------------------------------------- /problems/__tests__/030.js: -------------------------------------------------------------------------------- 1 | const flatten = require('../030-flatten'); 2 | 3 | test('Тестирование задачи "030-flatten"', () => { 4 | expect(flatten([])).toEqual([]); 5 | expect(flatten([1])).toEqual([1]); 6 | expect(flatten([1, 1])).toEqual([1, 1]); 7 | expect(flatten([1, [2, [3, [4]], 5]])).toEqual([1, 2, 3, 4, 5]); 8 | expect(flatten([[], [[]], [[], [[[]]]]])).toEqual([]); 9 | }); 10 | -------------------------------------------------------------------------------- /problems/030-flatten.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию flatten(array) которая делает вложенный массив плоским 3 | * 4 | * Пример: 5 | * 6 | * flatten([1, [2, 3]]) === [1, 2, 3] 7 | * flatten([1, [2, [3, 4]]]) === [1, 2, 3, 4] 8 | * 9 | * @param {Array.} array 10 | * @returns {number[]} 11 | */ 12 | function flatten(array) { 13 | return undefined; 14 | } 15 | 16 | module.exports = flatten; 17 | -------------------------------------------------------------------------------- /problems/001-sum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию sum(n) возвращающую положительное целое число – сумму чисел, 3 | * расположенных между 1 и N включительно. 4 | * 5 | * Пример: 6 | * 7 | * sum(0) === 1 8 | * sum(5) === 15 9 | * 10 | * Больше примеров в тестах 11 | * 12 | * @param {number} n целое число 13 | * @returns {number} 14 | */ 15 | function sum(n) { 16 | return undefined; 17 | } 18 | 19 | module.exports = sum; 20 | -------------------------------------------------------------------------------- /problems/__tests__/005.js: -------------------------------------------------------------------------------- 1 | const union = require('../005-union'); 2 | 3 | test('Тестирование задачи "005-union"', () => { 4 | expect(union([1, 1, 3, 2, 5], [5, 3, 7, 7])).toEqual([3, 5]); 5 | expect(union([5, 3], [5, 3, 7, 7])).toEqual([3, 5]); 6 | expect( 7 | union([2, 4, 6, 8, 10, 12, 10, 8, 6, 4, 2], [3, 6, 9, 12, 15, 18]) 8 | ).toEqual([6, 12]); 9 | expect(union([1, 2, 3], [11, 0, -1])).toEqual([]); 10 | }); 11 | -------------------------------------------------------------------------------- /problems/__tests__/006.js: -------------------------------------------------------------------------------- 1 | const getSpringMeltStreak = require('../006-spring-melt'); 2 | 3 | test('Тестирование задачи "006-spring-melt"', () => { 4 | expect(getSpringMeltStreak([-20, 30, -40, 50, 10, -10])).toBe(2); 5 | expect(getSpringMeltStreak([10, 20, 30, 1, -10, 1, 2, 3])).toBe(4); 6 | expect(getSpringMeltStreak([10, 20, 30, 0, -10, 5, 8, 1, 2, 3])).toBe(5); 7 | expect(getSpringMeltStreak([-10, 0, -10, 0, -10])).toBe(0); 8 | }); 9 | -------------------------------------------------------------------------------- /problems/__tests__/008.js: -------------------------------------------------------------------------------- 1 | const isPalindrome = require('../008-palindrome'); 2 | 3 | test('Тестирование задачи "008-palindrome"', () => { 4 | expect(isPalindrome('true')).toBe(false); 5 | expect(isPalindrome('')).toBe(true); 6 | expect(isPalindrome('7')).toBe(true); 7 | expect(isPalindrome('42')).toBe(false); 8 | expect(isPalindrome('121')).toBe(true); 9 | expect(isPalindrome('boob')).toBe(true); 10 | expect(isPalindrome('шалаш')).toBe(true); 11 | }); 12 | -------------------------------------------------------------------------------- /problems/__tests__/012.js: -------------------------------------------------------------------------------- 1 | const validatePassword = require('../012-password'); 2 | 3 | test('Тестирование задачи "012-password"', () => { 4 | expect(validatePassword('abc4DEFG')).toBe(true); 5 | expect(validatePassword('abc456F')).toBe(true); 6 | expect(validatePassword('aBC456F')).toBe(true); 7 | expect(validatePassword('abcdefg')).toBe(false); 8 | expect(validatePassword('abcdefG')).toBe(false); 9 | expect(validatePassword('abcdef7')).toBe(false); 10 | }); 11 | -------------------------------------------------------------------------------- /problems/010-power-of-two.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию getPower(n) возвращающую целочисленное значение степени >= 0, 3 | * в которую нужно возвести двойку, чтобы получить n 4 | * 5 | * Пример: 6 | * 7 | * getPower(2) === 1 # 2^1 = 2 8 | * getPower(3) === undefined 9 | * getPower(256) === 8 # 2^8 = 256 10 | * 11 | * @param {number} n 12 | * @returns {number|undefined} 13 | */ 14 | function getPower(n) { 15 | return -1; 16 | } 17 | 18 | module.exports = getPower; 19 | -------------------------------------------------------------------------------- /problems/__tests__/025.js: -------------------------------------------------------------------------------- 1 | const metro = require('../025-metro'); 2 | 3 | test('Тестирование задачи "025-metro"', () => { 4 | expect(metro(1, 2)).toBe(0); 5 | expect(metro(1, 3)).toBe(1); 6 | expect(metro(2, 7)).toBe(4); 7 | expect(metro(11, 7)).toBe(3); 8 | expect(metro(1, 13)).toBe(0); 9 | expect(metro(13, 1)).toBe(0); 10 | expect(metro(1, 7)).toBe(5); 11 | expect(metro(1, 8)).toBe(5); 12 | expect(metro(13, 6)).toBe(5); 13 | expect(metro(13, 7)).toBe(5); 14 | }); 15 | -------------------------------------------------------------------------------- /problems/027-has.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию has(path, object) возвращающую true, если в объекте есть свойство 3 | * описанное массивом path, иначе false 4 | * 5 | * Пример: 6 | * 7 | * has(['a'], { a: 1 }) === true 8 | * has(['b'], { a: 1 }) === false 9 | * has(['o', 'a'], { o: { a: 2 } }) === true 10 | * 11 | * @param {string[]} path 12 | * @param {object} object 13 | * @returns {boolean} 14 | */ 15 | function has(path, object) { 16 | return undefined; 17 | } 18 | 19 | module.exports = has; 20 | -------------------------------------------------------------------------------- /problems/__tests__/013.js: -------------------------------------------------------------------------------- 1 | const isIpValid = require('../013-ip'); 2 | 3 | test('Тестирование задачи "013-ip"', () => { 4 | expect(isIpValid('127.0.0.0')).toBe(true); 5 | expect(isIpValid('192.168.0.01')).toBe(true); 6 | expect(isIpValid('255.000.255.0255')).toBe(true); 7 | expect(isIpValid('192.255.000.255.0255')).toBe(false); 8 | expect(isIpValid('127.-127.0.0')).toBe(false); 9 | expect(isIpValid('256.-128.256.0256')).toBe(false); 10 | expect(isIpValid('Hello world')).toBe(false); 11 | }); 12 | -------------------------------------------------------------------------------- /problems/__tests__/014.js: -------------------------------------------------------------------------------- 1 | const fibonacci = require('../014-fibonacci'); 2 | 3 | test('Тестирование задачи "014-fibonacci"', () => { 4 | expect(fibonacci(0)).toBe(0); 5 | expect(fibonacci(1)).toBe(1); 6 | expect(fibonacci(2)).toBe(1); 7 | expect(fibonacci(3)).toBe(2); 8 | expect(fibonacci(4)).toBe(3); 9 | expect(fibonacci(5)).toBe(5); 10 | expect(fibonacci(6)).toBe(8); 11 | expect(fibonacci(7)).toBe(13); 12 | expect(fibonacci(8)).toBe(21); 13 | expect(fibonacci(9)).toBe(34); 14 | }); 15 | -------------------------------------------------------------------------------- /problems/008-palindrome.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию isPalindrome(value) определяющую, 3 | * является ли переданная строка палиндромом, то есть строкой, 4 | * которая одинаково читается слева направо и справа налево. 5 | * 6 | * Пример: 7 | * 8 | * isPalindrome('121') === true 9 | * isPalindrome('boob') === true 10 | * isPalindrome('true') === false 11 | * 12 | * @param {string} value 13 | * @returns {boolean} 14 | */ 15 | function isPalindrome(value) { 16 | return undefined; 17 | } 18 | 19 | module.exports = isPalindrome; 20 | -------------------------------------------------------------------------------- /problems/016-sort-timestamps.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию sortTimestamps(list) сортирующую список временных моментов. 3 | * 4 | * Пример: 5 | * 6 | * sortTimestamps(['23:02:59', '02:07:00']) === ['02:07:00', '23:02:59'] 7 | * 8 | * @param {string[]} list массив временных моментов представленных в виде строк в формате 'HH:MM:SS' 9 | * @returns {string[]} отсортированный по возрастанию массив временных моментов 10 | */ 11 | function sortTimestamps(list) { 12 | return undefined; 13 | } 14 | 15 | module.exports = sortTimestamps; 16 | -------------------------------------------------------------------------------- /problems/015-fibonacci-2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * С числами Фибоначчи мы уже познакомились в прошлой задаче. 3 | * 4 | * Напишите функцию isFibonacci(value) которая определяет, является ли value числом Фибоначчи. 5 | * 6 | * Пример: 7 | * 8 | * isFibonacci(1) === 1 9 | * isFibonacci(2) === 3 10 | * isFibonacci(55) === 10 11 | * isFibonacci(52) === undefined 12 | * 13 | * @param {number} value 14 | * @returns {undefined|number} 15 | */ 16 | function isFibonacci(value) { 17 | return undefined; 18 | } 19 | 20 | module.exports = isFibonacci; 21 | -------------------------------------------------------------------------------- /problems/019-search-anagrams.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Со словами-анаграммами мы познакомились в прошлой задаче. 3 | * 4 | * Напишите функцию searchAnagrams(value) возвращающую слова-анаграммы из предложения, 5 | * сохраняя их порядок и регистр букв 6 | * 7 | * Пример: 8 | * 9 | * searchAnagrams('Вижу апельсин значит живу. Спаниель') === 'Вижу апельсин живу Спаниель' 10 | * 11 | * @param {string} value 12 | * @returns {string} 13 | */ 14 | function searchAnagrams(value) { 15 | return undefined; 16 | } 17 | 18 | module.exports = searchAnagrams; 19 | -------------------------------------------------------------------------------- /problems/026-vacation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Лена планирует свой двухнедельный отпуск. 3 | * 4 | * Напишите функцию vacation(date) вычисляющую день следующий за отпуском Лены 5 | * 6 | * Примечание: вместо ручного подсчета используй класс Date и его методы 7 | * 8 | * Пример: 9 | * 10 | * vacation('01.01.2020') === '15.01.2020' 11 | * vacation('27.01.2020') === '10.02.2020' 12 | * 13 | * @param {string} date 14 | * @returns {string} 15 | */ 16 | function vacation(date) { 17 | return undefined; 18 | } 19 | 20 | module.exports = vacation; 21 | -------------------------------------------------------------------------------- /problems/__tests__/026.js: -------------------------------------------------------------------------------- 1 | const vacation = require('../026-vacation'); 2 | 3 | test('Тестирование задачи "026-vacation"', () => { 4 | expect(vacation('01.01.2020')).toBe('15.01.2020'); 5 | expect(vacation('27.01.2020')).toBe('10.02.2020'); 6 | expect(vacation('24.02.2020')).toBe('09.03.2020'); 7 | expect(vacation('29.02.2020')).toBe('14.03.2020'); 8 | expect(vacation('16.11.2020')).toBe('30.11.2020'); 9 | expect(vacation('22.02.2021')).toBe('08.03.2021'); 10 | expect(vacation('30.12.2019')).toBe('13.01.2020'); 11 | }); 12 | -------------------------------------------------------------------------------- /problems/028-more-parentheses.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ранее мы уже решали задачу валидации последовательности скобок в строке. 3 | * 4 | * На этот раз напишите функцию parentheses(value) валидирующую строку с несколькими типами скобок. 5 | * 6 | * Пример: 7 | * 8 | * parentheses('<>') === true 9 | * parentheses('<}') === false 10 | * 11 | * @param {string} value – строка из набора символов (, ), {, }, <, >. 12 | * @returns {boolean} 13 | */ 14 | function parentheses(value) { 15 | return undefined; 16 | } 17 | 18 | module.exports = parentheses; 19 | -------------------------------------------------------------------------------- /problems/__tests__/010.js: -------------------------------------------------------------------------------- 1 | const getPower = require('../010-power-of-two'); 2 | 3 | test('Тестирование задачи "010-power-of-two"', () => { 4 | expect(getPower(1)).toBe(0); 5 | expect(getPower(2)).toBe(1); 6 | expect(getPower(3)).toBeUndefined(); 7 | expect(getPower(4)).toBe(2); 8 | expect(getPower(6)).toBeUndefined(); 9 | expect(getPower(7)).toBeUndefined(); 10 | expect(getPower(8)).toBe(3); 11 | expect(getPower(10)).toBeUndefined(); 12 | expect(getPower(256)).toBe(8); 13 | expect(getPower(1024)).toBe(10); 14 | }); 15 | -------------------------------------------------------------------------------- /problems/__tests__/015.js: -------------------------------------------------------------------------------- 1 | const isFibonacci = require('../015-fibonacci-2'); 2 | 3 | test('Тестирование задачи "015-fibonacci-2"', () => { 4 | expect(isFibonacci(0)).toBe(0); 5 | expect(isFibonacci(1)).toBe(1); 6 | expect(isFibonacci(2)).toBe(3); 7 | expect(isFibonacci(3)).toBe(4); 8 | expect(isFibonacci(5)).toBe(5); 9 | expect(isFibonacci(8)).toBe(6); 10 | expect(isFibonacci(13)).toBe(7); 11 | expect(isFibonacci(21)).toBe(8); 12 | expect(isFibonacci(34)).toBe(9); 13 | expect(isFibonacci(42)).toBeUndefined(); 14 | }); 15 | -------------------------------------------------------------------------------- /problems/014-fibonacci.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Последовательностью Фибоначчи называется последовательность чисел 3 | * a0, a1, ..., an, ..., где 4 | * a0 = 0, 5 | * a1 = 1, 6 | * ak = ak-1 + ak-2 (k > 1). 7 | * 8 | * Напишите функцию fibonacci(n) вычисляющую n-ное число последовательности 9 | * 10 | * Пример: 11 | * 12 | * fibonacci(2) === 1 13 | * fibonacci(3) === 2 14 | * fibonacci(7) === 13 15 | * 16 | * @param {number} n >= 0 17 | * @returns {number} 18 | */ 19 | function fibonacci(n) { 20 | return undefined; 21 | } 22 | 23 | module.exports = fibonacci; 24 | -------------------------------------------------------------------------------- /problems/005-union.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию union(a, b) возвращающую упорядоченный по возрастанию массив 3 | * состоящий из чисел встречающихся в обоих наборах. 4 | * 5 | * Пример: 6 | * 7 | * union([1, 1, 3, 2, 5], [5, 3, 7, 7]) === [3, 5] 8 | * union([2, 4, 6, 8, 10, 12, 10, 8, 6, 4, 2], [3, 6, 9, 12, 15, 18]) === [6, 12] 9 | * union([1, 2, 3], [11, 0, -1]) === [] 10 | * 11 | * @param {number[]} a 12 | * @param {number[]} b 13 | * @returns {number[]} 14 | */ 15 | function union(a, b) { 16 | return undefined; 17 | } 18 | 19 | module.exports = union; 20 | -------------------------------------------------------------------------------- /problems/__tests__/017.js: -------------------------------------------------------------------------------- 1 | const census = require('../017-census'); 2 | 3 | test('Тестирование задачи "017-census"', () => { 4 | expect(census([{ age: 40, gender: 'Female' }])).toBeUndefined(); 5 | expect( 6 | census([{ age: 12, gender: 'Male' }, { age: 40, gender: 'Male' }]) 7 | ).toBe(2); 8 | expect( 9 | census([ 10 | { age: 39, gender: 'Male' }, 11 | { age: 4, gender: 'Female' }, 12 | { age: 40, gender: 'Female' }, 13 | { age: 38, gender: 'Male' } 14 | ]) 15 | ).toBe(1); 16 | }); 17 | -------------------------------------------------------------------------------- /problems/003-ticket.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Счастливым билетом называют такой билет с шестизначным номером, 3 | * где сумма первых трех цифр равна сумме последних трех. 4 | * 5 | * Напишите функцию checkTicket(number) которая проверяет счастливость билета. 6 | * 7 | * Пример: 8 | * 9 | * checkTicket('005212') === true 10 | * checkTicket('133700') === true 11 | * checkTicket('123032') === false 12 | * 13 | * @param {string} number 14 | * @returns {boolean} 15 | */ 16 | function checkTicket(number) { 17 | return undefined; 18 | } 19 | 20 | module.exports = checkTicket; 21 | -------------------------------------------------------------------------------- /problems/023-hex-to-rgb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hex и RGB - текстовые форматы для представления цвета в коде. 3 | * 4 | * Напишите функцию hexToRgb(color) конвертирующую цвет закодированный в формате HEX 5 | * в RGB кодированную строку. 6 | * 7 | * Пример: 8 | * 9 | * hexToRgb('#000000') === 'rgb(0, 0, 0)' 10 | * hexToRgb('#fff') === 'rgb(255, 255, 255)' 11 | * hexToRgb('#800080') === 'rgb(128, 0, 128)' 12 | * 13 | * @param {string} color 14 | * @returns {string} 15 | */ 16 | function hexToRgb(color) { 17 | return undefined; 18 | } 19 | 20 | module.exports = hexToRgb; 21 | -------------------------------------------------------------------------------- /problems/__tests__/019.js: -------------------------------------------------------------------------------- 1 | const searchAnagrams = require('../019-search-anagrams'); 2 | 3 | test('Тестирование задачи "019-search-anagrams"', () => { 4 | expect(searchAnagrams('')).toBe(''); 5 | expect(searchAnagrams('Вяжу и вижу')).toBe(''); 6 | expect(searchAnagrams('Вижу вижу')).toBe('Вижу вижу'); 7 | expect(searchAnagrams('Вижу апельсин значит живу. Спаниель')).toBe( 8 | 'Вижу апельсин живу Спаниель' 9 | ); 10 | expect( 11 | searchAnagrams('Какой резон убирать зерно, если его негде хранить?') 12 | ).toBe('резон зерно'); 13 | }); 14 | -------------------------------------------------------------------------------- /problems/007-bus-tour.js: -------------------------------------------------------------------------------- 1 | /** 2 | * На экскурсионном маршруте автобусу высотой 512 см встречаются несколько мостов. 3 | * 4 | * Напишите функцию checkBusTour(bridges) вычисляющую номер моста под которым не сможет проехать автобус. 5 | * 6 | * Пример: 7 | * 8 | * checkBusTour([600, 512]) === 2 9 | * checkBusTour([600, 1024]) === undefined # Автобус успешно проедет по маршруту 10 | * 11 | * @param {number[]} bridges высоты мостов встречающихся на маршруте 12 | * @returns {undefined|number} 13 | */ 14 | function checkBusTour(bridges) { 15 | return -1; 16 | } 17 | 18 | module.exports = checkBusTour; 19 | -------------------------------------------------------------------------------- /problems/__tests__/023.js: -------------------------------------------------------------------------------- 1 | const hexToRgb = require('../023-hex-to-rgb'); 2 | 3 | test('Тестирование задачи "023-hex-to-rgb"', () => { 4 | expect(hexToRgb('#000')).toBe('rgb(0, 0, 0)'); 5 | expect(hexToRgb('#000000')).toBe('rgb(0, 0, 0)'); 6 | expect(hexToRgb('#fff')).toBe('rgb(255, 255, 255)'); 7 | expect(hexToRgb('#FFFFFF')).toBe('rgb(255, 255, 255)'); 8 | expect(hexToRgb('#F00')).toBe('rgb(255, 0, 0)'); 9 | expect(hexToRgb('#0f0')).toBe('rgb(0, 255, 0)'); 10 | expect(hexToRgb('#0000C0')).toBe('rgb(0, 0, 192)'); 11 | expect(hexToRgb('#800080')).toBe('rgb(128, 0, 128)'); 12 | }); 13 | -------------------------------------------------------------------------------- /problems/017-census.js: -------------------------------------------------------------------------------- 1 | /** 2 | * В доме решили провести перепись всех жильцов и составили список, 3 | * в котором указали возраст и пол каждого жильца. 4 | * 5 | * Напишите функцию census(list) возвращающую номер в списке самого старшего жителя мужского пола. 6 | * 7 | * Пример: 8 | * 9 | * census([{ age: 12, gender: 'Male' }, { age: 40, gender: 'Male' }]) === 2 10 | * census([{ age: 40, gender: 'Female' }]) === undefined 11 | * 12 | * @param {{age: number, gender: string}[]} list 13 | * @returns {undefined|number} 14 | */ 15 | function census(list) { 16 | return -1; 17 | } 18 | 19 | module.exports = census; 20 | -------------------------------------------------------------------------------- /problems/018-anagram.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Слова-анаграммы — это слова, записанные одними и теми же буквами в разном порядке, 3 | * регистр букв при этом игнорируется. 4 | * Анаграммами, например, являются слова «Волос» и «СЛОВО». 5 | * 6 | * Напишите функцию anagram(x, y) проверяющую, являются ли x и y словами-анаграммами. 7 | * 8 | * Пример: 9 | * 10 | * anagram('Волос', 'Слово') === true 11 | * anagram('Живу', 'Вижу') === true 12 | * 13 | * @param {string} x 14 | * @param {string} y 15 | * @returns {boolean} 16 | */ 17 | function anagram(x, y) { 18 | return undefined; 19 | } 20 | 21 | module.exports = anagram; 22 | -------------------------------------------------------------------------------- /problems/029-map-parseInt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Лёня пишет код максимально коротко. Чтобы конвертировать массив строк в числа он написал следующий код: 3 | * 4 | * array.map(parseInt) 5 | * 6 | * Но что-то пошло не так и в результате получаются совсем не те числа, что ожидает Лёня. 7 | * 8 | * Разбиритесь, что не так с Лёниным кодом и напишите функцию map(array) 9 | * в которой будет исправленна эта проблема. 10 | * 11 | * Пример: 12 | * 13 | * map(['0', '1', '2']) === [0, 1, 2] 14 | * 15 | * @param {string[]} array 16 | * @returns {number[]} 17 | */ 18 | function map(array = []) { 19 | return array.map(parseInt); 20 | } 21 | 22 | module.exports = map; 23 | -------------------------------------------------------------------------------- /problems/022-parentheses.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Строка со скобками считается валидной, если на каждую закрывающую скобку имеется ранее открытая 3 | * и на каждую ранее открытую имеется закрывающая. 4 | * 5 | * Напишите функцию parentheses(value) проверяющую строку со скобками на валидность. 6 | * 7 | * Пример: 8 | * 9 | * parentheses('') === false 10 | * parentheses('()()') === true 11 | * parentheses('(()())') === true 12 | * parentheses('(()') === false 13 | * parentheses(')') === false 14 | * 15 | * @param {string} value 16 | * @returns {boolean} 17 | */ 18 | function parentheses(value) { 19 | return undefined; 20 | } 21 | 22 | module.exports = parentheses; 23 | -------------------------------------------------------------------------------- /problems/025-metro.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Витя из дома до работы добирается по кольцевой линии метро. 3 | * 4 | * Напишите функцию metro(x,y) вычисляющую минимальное количество промежуточных станций 5 | * (не считая станции посадки и высадки), которые необходимо проехать Вите, 6 | * если на кольцевой линии 13 станций. 7 | * 8 | * Пример: 9 | * 10 | * metro(1, 2) === 0 11 | * metro(1, 3) === 1 12 | * metro(13, 1) === 0 13 | * metro(1, 13) === 0 14 | * 15 | * @param {number} x – станция посадки 16 | * @param {number} y - станция высадки 17 | * @returns {number} 18 | */ 19 | function metro(x, y) { 20 | return undefined; 21 | } 22 | 23 | module.exports = metro; 24 | -------------------------------------------------------------------------------- /problems/024-timeago.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Петя опубликовал картинку X секунд назад. 3 | * 4 | * Напишите функцию timeago(seconds) возвращаю текстовое представление периода прошедшего со времени публикации. 5 | * Для публикаций опубликованных более четырёх недель назад возвращайте строку 'undefined', ведь их никто не увидит. 6 | * 7 | * Пример: 8 | * 9 | * timeago(0) === 'just now' 10 | * timeago(10) === '10 seconds ago' 11 | * timeago(60) === '1 minute ago' 12 | * timeago(3600) === '1 hour ago' 13 | * 14 | * @param {number} seconds 15 | * @returns {string} 16 | */ 17 | function timeago(seconds) { 18 | return undefined; 19 | } 20 | 21 | module.exports = timeago; 22 | -------------------------------------------------------------------------------- /problems/021-repair.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Одной банки с краской хватает на покраску 16 квадратных метров стен офиса. 3 | * 4 | * Напишите функцию repair(width, length, height) вычисляющую минимальное количество банок краски, 5 | * необходимых для покраски стен в офисе. Размерами дверей и окон можно пренебречь. 6 | * 7 | * Пример: 8 | * 9 | * repair(1, 1, 3) === 1 10 | * repair(4, 4, 3) === 3 11 | * repair(4, 4, 4) === 4 12 | * 13 | * @param {number} width – ширина офиса 14 | * @param {number} length - длина офиса 15 | * @param {number} height - высота стен в офисе 16 | * @returns {number} 17 | */ 18 | function repair(width, length, height) { 19 | return undefined; 20 | } 21 | 22 | module.exports = repair; 23 | -------------------------------------------------------------------------------- /problems/__tests__/018.js: -------------------------------------------------------------------------------- 1 | const anagram = require('../018-anagram'); 2 | 3 | test('Тестирование задачи "018-anagram"', () => { 4 | expect(anagram('Волос', 'Слово')).toBe(true); 5 | expect(anagram('Живу', 'живу')).toBe(true); 6 | expect(anagram('Живу', 'Вижу')).toBe(true); 7 | expect(anagram('апельсин', 'спаниель')).toBe(true); 8 | expect(anagram('Волосы', 'Слово')).toBe(false); 9 | expect(anagram('Волос', 'Словоъ')).toBe(false); 10 | expect(anagram('Волос', 'Волас')).toBe(false); 11 | expect(anagram('Волос', 'Волоз')).toBe(false); 12 | expect(anagram('11222', '11122')).toBe(false); 13 | expect(anagram('123', '234')).toBe(false); 14 | expect(anagram('', '')).toBe(false); 15 | }); 16 | -------------------------------------------------------------------------------- /problems/009-time-delta.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Напишите функцию getTimeDelta(x, y) определяющую, 3 | * сколько секунд прошло между двумя моментами времени x и y. 4 | * 5 | * Время передается в формате 'HH:MM:SS'. Минимальное значение – '00:00:00', максимальное – '23:59:59'. 6 | * 7 | * По условию x всегда меньше y. 8 | * 9 | * Пример: 10 | * 11 | * getTimeDelta('00:00:00', '00:00:01') === 1 12 | * getTimeDelta('01:01:01', '02:02:02') === 3661 13 | * getTimeDelta('01:19:30', '01:20:20') === 50 14 | * 15 | * @param {string} x 16 | * @param {string} y 17 | * @returns {number} разница между x и y в секундах 18 | */ 19 | function getTimeDelta(x, y) { 20 | return undefined; 21 | } 22 | 23 | module.exports = getTimeDelta; 24 | -------------------------------------------------------------------------------- /problems/__tests__/028.js: -------------------------------------------------------------------------------- 1 | const parentheses = require('../028-more-parentheses'); 2 | 3 | test('Тестирование задачи "028-more-parentheses"', () => { 4 | expect(parentheses('')).toBe(false); 5 | expect(parentheses('(')).toBe(false); 6 | expect(parentheses('<')).toBe(false); 7 | expect(parentheses('{')).toBe(false); 8 | expect(parentheses('<>')).toBe(true); 9 | expect(parentheses('{}}')).toBe(false); 10 | expect(parentheses('{})')).toBe(false); 11 | expect(parentheses('{}>')).toBe(false); 12 | expect(parentheses('(){}<>')).toBe(true); 13 | expect(parentheses('({(){}<()>}){(<>)}<(<>)>')).toBe(true); 14 | expect(parentheses('(){><}')).toBe(false); 15 | expect(parentheses('()}<>{')).toBe(false); 16 | }); 17 | -------------------------------------------------------------------------------- /problems/002-basketball.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Известны результаты каждой из 4х четвертей баскетбольной встречи. 3 | * Нужно определить победителя матча. Побеждает команда, 4 | * набравшая больше очков в течение всего матча. 5 | * 6 | * Напишите функцию getWinner(points) возвращающую номер победившей команды, 7 | * либо undefined в случае ничьей. 8 | * 9 | * Пример: 10 | 11 | * getWinner(['23-26', '24-30', '30-27', '35-31']) === 2 12 | * getWinner(['36-32', '32-24', '20-28', '30-26']) === 1 13 | * getWinner(['36-18', '22-31', '27-21', '19-34']) === undefined 14 | * 15 | * @param {string[]} points 16 | * @returns {(number|undefined)} 17 | */ 18 | function getWinner(points) { 19 | return undefined; 20 | } 21 | 22 | module.exports = getWinner; 23 | -------------------------------------------------------------------------------- /problems/012-password.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Пароль называется криптостойким, 3 | * если он включает в себя хотя бы одну строчную английскую букву, 4 | * хотя бы одну заглавную английскую букву и хотя бы одну цифру, 5 | * при этом его длина должна быть не менее 7 символов. 6 | * 7 | * Напишите функцию validatePassword(password) определяющую, 8 | * является ли переданный пароль криптостойким. 9 | * 10 | * Пример: 11 | * 12 | * validatePassword('abc4DEFG') === true 13 | * validatePassword('abcdefg') === false 14 | * validatePassword('abcdefG') === false 15 | * validatePassword('abcdef7') === false 16 | * 17 | * @param {string} password 18 | * @returns {boolean} 19 | */ 20 | function validatePassword(password) { 21 | return undefined; 22 | } 23 | 24 | module.exports = validatePassword; 25 | -------------------------------------------------------------------------------- /problems/011-decrypt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Самый простой способ зашифровать строку – сдвиг букв. 3 | * Под сдвигом понимается замена буквы на предыдущую в алфавите. 4 | * Если предыдущей буквы нет, она заменяется на последнюю букву алфавита (в этой задаче мы имеем дело с английским алфавитом). 5 | * 6 | * Вам прислали секретное сообщение, зашифрованное способом, описанным выше и состоящее из строчных английских букв. 7 | * 8 | * Напишите функцию decrypt(secret) которая расшифрует и вернет его. 9 | * 10 | * Пример: 11 | * 12 | * decrypt('bnqqdbs') === 'correct' 13 | * decrypt('zmc vd hfmnqd rozbdr') === 'and we ignore spaces' 14 | * 15 | * @param {string} secret 16 | * @returns {string} 17 | */ 18 | function decrypt(secret) { 19 | return undefined; 20 | } 21 | 22 | module.exports = decrypt; 23 | -------------------------------------------------------------------------------- /problems/__tests__/016.js: -------------------------------------------------------------------------------- 1 | const sortTimestamps = require('../016-sort-timestamps'); 2 | 3 | test('Тестирование задачи "016-sort-timestamps"', () => { 4 | expect(sortTimestamps([])).toEqual([]); 5 | expect(sortTimestamps(['00:13:37'])).toEqual(['00:13:37']); 6 | expect(sortTimestamps(['00:00:42', '00:00:07'])).toEqual([ 7 | '00:00:07', 8 | '00:00:42' 9 | ]); 10 | expect(sortTimestamps(['00:13:37', '00:04:20'])).toEqual([ 11 | '00:04:20', 12 | '00:13:37' 13 | ]); 14 | expect(sortTimestamps(['19:00:00', '00:59:59'])).toEqual([ 15 | '00:59:59', 16 | '19:00:00' 17 | ]); 18 | expect(sortTimestamps(['19:00:00', '00:04:20', '00:59:59'])).toEqual([ 19 | '00:04:20', 20 | '00:59:59', 21 | '19:00:00' 22 | ]); 23 | }); 24 | -------------------------------------------------------------------------------- /problems/013-ip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Для того чтобы выходить в Интернет, каждому компьютеру присваивается так называемый IP-адрес. 3 | * Он состоит из четырех целых чисел в диапазоне от 0 до 255, разделенных точками. 4 | * В следующих трех строках показаны три правильных IP-адреса: 5 | * 127.0.0.0 6 | * 192.168.0.01 7 | * 255.000.255.0255 8 | * 9 | * Напишите функцию isIpValid(address) опредяляющую является ли переданная строка правильным IP-адресом. 10 | * 11 | * Пример: 12 | * 13 | * isIpValid('127.0.0.1') === true 14 | * isIpValid('127.0.0.0255') === true 15 | * isIpValid('127.0.256.0255') === false 16 | * isIpValid('Hello world') === false 17 | * 18 | * @param {string} address 19 | * @returns {boolean} 20 | */ 21 | function isIpValid(address) { 22 | return undefined; 23 | } 24 | 25 | module.exports = isIpValid; 26 | -------------------------------------------------------------------------------- /problems/__tests__/022.js: -------------------------------------------------------------------------------- 1 | const parentheses = require('../022-parentheses'); 2 | 3 | test('Тестирование задачи "022-parentheses"', () => { 4 | expect(parentheses('')).toBe(false); 5 | expect(parentheses('()')).toBe(true); 6 | expect(parentheses('())(')).toBe(false); 7 | expect(parentheses('()()')).toBe(true); 8 | expect(parentheses('(())')).toBe(true); 9 | expect(parentheses('(()())')).toBe(true); 10 | expect(parentheses('((()))((()()))')).toBe(true); 11 | expect(parentheses('(())((()())())')).toBe(true); 12 | expect(parentheses('(')).toBe(false); 13 | expect(parentheses(')')).toBe(false); 14 | expect(parentheses('(()')).toBe(false); 15 | expect(parentheses(')()')).toBe(false); 16 | expect(parentheses('())')).toBe(false); 17 | expect(parentheses('()(')).toBe(false); 18 | expect(parentheses('(())((()()))()))')).toBe(false); 19 | }); 20 | -------------------------------------------------------------------------------- /problems/004-orizuru.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Петя, Катя и Сережа делают из бумаги журавликов. 4 | * Вместе они сделали X журавликов. Сколько журавликов сделал каждый ребенок, если известно, 5 | * что Петя и Сережа сделали одинаковое количество журавликов, 6 | * а Катя сделала в два раза больше журавликов, чем Петя и Сережа вместе? 7 | * 8 | * Напишите функцию computeOrizurus(total) которая вычислит 9 | * сколько журавликов сделал каждый ребенок. 10 | * 11 | * Пример: 12 | * 13 | * computeOrizurus(6) === [1, 4, 1] 14 | * computeOrizurus(24) === [4, 16, 4] 15 | * computeOrizurus(60) === [10, 40, 10] 16 | * 17 | * @param {number} total общее количество сделанных журавликов 18 | * @returns {number[]} массив чисел, где первый элемент это количество журавликов сделанных Петей, 19 | * второй элемент – Катей, третий – Сережей 20 | */ 21 | function computeOrizurus(total) { 22 | return undefined; 23 | } 24 | 25 | module.exports = computeOrizurus; 26 | -------------------------------------------------------------------------------- /problems/031-circular-dependency.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Сара пишет сложные клиентские приложения на ангуляре. Поэтому ей часто приходится создавать и модифицировать сервисы. 3 | * Сервисы могут использовать другие сервисы. Однако они не должны быть взаимозависимыми. 4 | * 5 | * Напишите функцию которая определяет есть ли цикличная зависимость между сервисами в проекте Сары. 6 | * Зависимости описаны объектом, ключи которого являются именами сервисов, а значения—это сервисы-зависимости. 7 | * 8 | * Пример: 9 | * 10 | * hasCircularDependency({ 11 | * http: [], 12 | * apiClient: ['http'], 13 | * }) === false 14 | * 15 | * hasCircularDependency({ 16 | * http: ['dogsApi'], 17 | * apiClient: ['http'], 18 | * dogsApi: ['apiClient'], 19 | * }) === true 20 | * 21 | * @param {Object.>} servicesMap 22 | * @returns {boolean} 23 | */ 24 | function hasCircularDependency(servicesMap) { 25 | return false; 26 | } 27 | 28 | module.exports = hasCircularDependency; 29 | -------------------------------------------------------------------------------- /problems/006-spring-melt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Уставшие от необычно теплой зимы, жители решили узнать, 3 | * действительно ли это самая длинная оттепель за всю историю наблюдений за погодой. 4 | * Они обратились к синоптикам, а те, в свою очередь, 5 | * занялись исследованиями статистики за прошлые годы. 6 | * Их интересует, сколько дней длилась самая длинная оттепель. 7 | * 8 | * Напишите функцию getSpringMeltStreak(temperature) помогающую синоптикам вычислить самый длинный период, 9 | * в который среднесуточная температура ежедневно превышала 0 градусов Цельсия 10 | * 11 | * Пример: 12 | * 13 | * getSpringMeltStreak([-20, 30, -40, 50, 10, -10]) === 2 14 | * getSpringMeltStreak([10, 20, 30, 1, -10, 1, 2, 3]) === 4 15 | * getSpringMeltStreak([-10, 0, -10, 0, -10]) === 0 16 | * 17 | * @param {number[]} temperature массив чисел, где каждое – среднесуточная температура в соответствующий день 18 | * @returns {number} 19 | */ 20 | function getSpringMeltStreak(temperature) { 21 | return undefined; 22 | } 23 | 24 | module.exports = getSpringMeltStreak; 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-problems", 3 | "version": "0.1.0", 4 | "private": true, 5 | "description": "", 6 | "homepage": "https://github.com/mbelsky/js-problems#readme", 7 | "bugs": { 8 | "url": "https://github.com/mbelsky/js-problems/issues" 9 | }, 10 | "author": "Max Belsky ", 11 | "license": "MIT", 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/mbelsky/js-problems.git" 15 | }, 16 | "engines": { 17 | "node": ">=10.13.0" 18 | }, 19 | "scripts": { 20 | "test": "jest -o", 21 | "test:watch": "jest --watch" 22 | }, 23 | "husky": { 24 | "hooks": { 25 | "pre-commit": "lint-staged --relative" 26 | } 27 | }, 28 | "lint-staged": { 29 | "*.js": [ 30 | "jest --bail --findRelatedTests" 31 | ] 32 | }, 33 | "devDependencies": { 34 | "husky": "^4.3.8", 35 | "jest": "^26.6.3", 36 | "lint-staged": "^10.5.4" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Max Belsky 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /problems/__tests__/027.js: -------------------------------------------------------------------------------- 1 | const has = require('../027-has'); 2 | 3 | const testObject = { 4 | a: 1, 5 | o: { 6 | a: 2 7 | }, 8 | n: null, 9 | 'a.b.c': undefined 10 | }; 11 | 12 | test('Тестирование задачи "027-has"', () => { 13 | expect(has(['a'], testObject)).toBe(true); 14 | expect(has(['b'], testObject)).toBe(false); 15 | expect(has(['o', 'a'], testObject)).toBe(true); 16 | expect(has(['o', 'b'], testObject)).toBe(false); 17 | expect(has(['a.b.c'], testObject)).toBe(true); 18 | expect(has(['n'], testObject)).toBe(true); 19 | expect(has(['b', 'a'], testObject)).toBe(false); 20 | expect(has(['b', 'n'], testObject)).toBe(false); 21 | 22 | expect(has(['n'], {})).toBe(false); 23 | expect(has(['n'], null)).toBe(false); 24 | expect(has(['n'], undefined)).toBe(false); 25 | 26 | function Foo() {} 27 | Foo.prototype.a = 1; 28 | // false для наследуемых свойств 29 | expect(has(['a'], new Foo())).toBe(false); 30 | Foo.prototype.hasOwnProperty = null; 31 | // Должен использоваться hasOwnProperty из Object.prototype с привязкой контекста 32 | expect(has(['a'], new Foo())).toBe(false); 33 | }); 34 | -------------------------------------------------------------------------------- /problems/__tests__/031.js: -------------------------------------------------------------------------------- 1 | const hasCircularDependency = require('../031-circular-dependency'); 2 | 3 | test('Тестирование задачи "031-circular-dependency"', () => { 4 | expect(hasCircularDependency({})).toBe(false); 5 | expect(hasCircularDependency({ 6 | http: [], 7 | })).toBe(false); 8 | expect(hasCircularDependency({ 9 | http: [], 10 | apiClient: ['http'], 11 | })).toBe(false); 12 | expect(hasCircularDependency({ 13 | http: ['http'], 14 | })).toBe(true); 15 | expect(hasCircularDependency({ 16 | http: [], 17 | apiClient: ['http'], 18 | weatherService: ['apiClient', 'http'], 19 | weatherTrackingService: ['weatherService', 'apiClient'], 20 | })).toBe(false); 21 | expect(hasCircularDependency({ 22 | http: [], 23 | apiClient: ['http'], 24 | weatherService: ['apiClient', 'deliveryService', 'http'], 25 | weatherTrackingService: ['apiClient', 'weatherService'], 26 | deliveryService: ['apiClient', 'weatherTrackingService'], 27 | })).toBe(true); 28 | expect(hasCircularDependency({ 29 | http: ['catsApi'], 30 | apiClient: ['http'], 31 | catsApi: ['apiClient'], 32 | })).toBe(true); 33 | }); 34 | -------------------------------------------------------------------------------- /problems/__tests__/024.js: -------------------------------------------------------------------------------- 1 | const timeago = require('../024-timeago'); 2 | 3 | test('Тестирование задачи "024-timeago"', () => { 4 | expect(timeago(0)).toBe('just now'); 5 | expect(timeago(9)).toBe('just now'); 6 | 7 | expect(timeago(10)).toBe('10 seconds ago'); 8 | expect(timeago(19)).toBe('10 seconds ago'); 9 | expect(timeago(20)).toBe('20 seconds ago'); 10 | expect(timeago(29)).toBe('20 seconds ago'); 11 | expect(timeago(59)).toBe('50 seconds ago'); 12 | 13 | expect(timeago(60)).toBe('1 minute ago'); 14 | expect(timeago(119)).toBe('1 minute ago'); 15 | expect(timeago(120)).toBe('2 minutes ago'); 16 | expect(timeago(179)).toBe('2 minutes ago'); 17 | expect(timeago(600)).toBe('10 minutes ago'); 18 | expect(timeago(1500)).toBe('25 minutes ago'); 19 | expect(timeago(1800)).toBe('30 minutes ago'); 20 | expect(timeago(2690)).toBe('30 minutes ago'); 21 | expect(timeago(3599)).toBe('30 minutes ago'); 22 | 23 | expect(timeago(3600)).toBe('1 hour ago'); 24 | expect(timeago(7199)).toBe('1 hour ago'); 25 | expect(timeago(7200)).toBe('2 hours ago'); 26 | expect(timeago(10799)).toBe('2 hours ago'); 27 | expect(timeago(43200)).toBe('12 hours ago'); 28 | expect(timeago(86399)).toBe('12 hours ago'); 29 | 30 | expect(timeago(86400)).toBe('1 day ago'); 31 | expect(timeago(172799)).toBe('1 day ago'); 32 | expect(timeago(172800)).toBe('a few days ago'); 33 | expect(timeago(604799)).toBe('a few days ago'); 34 | 35 | expect(timeago(604800)).toBe('1 week ago'); 36 | expect(timeago(1209599)).toBe('1 week ago'); 37 | expect(timeago(1209600)).toBe('2 weeks ago'); 38 | expect(timeago(2419199)).toBe('3 weeks ago'); 39 | 40 | expect(timeago(2419200)).toBe('undefined'); 41 | }); 42 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug js-problems", 9 | "type": "node", 10 | "request": "launch", 11 | "console": "integratedTerminal", 12 | "internalConsoleOptions": "neverOpen", 13 | "port": 9229, 14 | "runtimeArgs": [ 15 | "--inspect-brk", 16 | "${workspaceFolder}/node_modules/.bin/jest", 17 | "--runInBand", 18 | "--onlyChanged" 19 | ], 20 | "windows": { 21 | "runtimeArgs": [ 22 | "--inspect-brk", 23 | "${workspaceFolder}/node_modules/jest/bin/jest.js", 24 | "--runInBand", 25 | "--onlyChanged" 26 | ] 27 | } 28 | }, 29 | // OUTDATED 30 | { 31 | "name": "Debug on Linux/MacOS", 32 | "type": "node", 33 | "request": "launch", 34 | "runtimeArgs": [ 35 | "--inspect-brk", 36 | "${workspaceFolder}/node_modules/.bin/jest", 37 | "--runInBand", 38 | "--onlyChanged" 39 | ], 40 | "console": "integratedTerminal", 41 | "internalConsoleOptions": "neverOpen", 42 | "port": 9229 43 | }, 44 | { 45 | "name": "Debug on Windows", 46 | "type": "node", 47 | "request": "launch", 48 | "runtimeArgs": [ 49 | "--inspect-brk", 50 | "${workspaceFolder}/node_modules/jest/bin/jest.js", 51 | "--runInBand", 52 | "--onlyChanged" 53 | ], 54 | "console": "integratedTerminal", 55 | "internalConsoleOptions": "neverOpen", 56 | "port": 9229 57 | } 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # js-problems 2 | 3 | Оттачивай навыки алгоритмики и кодирования. 4 | 5 | В этом репозитории собраны задачи, решение которых поможет закрепить навыки программирования и подготовиться к техническим собеседованиям. 6 | 7 | Вместе с задачами поставляется система для автоматической проверки решений написанных на JavaScript. 8 | 9 | ## Предварительные настройки 10 | 11 | 1. Убедись, что [git](https://git-scm.com/downloads) и [node](https://nodejs.org/en/download/) v10.13.0+ установлены на твоем компьютере 12 | 2. Склонируй репозиторий 13 | 3. В папке с проектом из терминала выполни `npm ci` 14 | 15 | Теперь можно приступать к решению задач! 16 | 17 | ## Задачник 18 | 19 | Задачи находятся в папке [/problems](/problems). Каждая задача оформлена в виде отдельного `.js` файла. 20 | 21 | Каждый файл имеет следующую структуру: 22 | 23 | 1. Комментарий с 24 | - описанием условия задачи 25 | - примером вызова функции, передаваемых аргументов и ожидаемым результатом 26 | - JSDoc для параметров и возвращаемого функцией значения 27 | 2. Заглушка тела функции. Пиши свое решение здесь 28 | 3. Инструкция `module.exports = …` делает функцию доступной для автоматического тестирования 29 | 30 | ## Тестирование решений 31 | 32 | Система автоматичекой проверки решений может быть запущена в одном из трех режимов. 33 | 34 | Рекомендуется использовать автоматическую проверку в связке с pre-commit. А каждую решенную задачу оформлять в виде коммита, чтобы не запускать лишние тесты. 35 | 36 | ### Ручная проверка 37 | 38 | Запускается командой 39 | 40 | ``` 41 | npm run test 42 | ``` 43 | 44 | Эта команда проверит правильность решений для всех файлов в которые были внесены изменения и git статус которых `not staged for commit`. 45 | 46 | ### Автоматическая проверка 47 | 48 | Запускается командой 49 | 50 | ``` 51 | npm run test:watch 52 | ``` 53 | 54 | Эта проверка работает по тому же принципу, что и ручная, только тесты запускаются автоматически на каждое сохранение файла. 55 | 56 | ### Pre-commit проверка 57 | 58 | Каждую решенную задачу рекомендуется оформлять в отдельный коммит. Pre-commit проверка автоматически запускается на выполнение команды `git commit`. Тесты выполняются для всех файлов добавленных в содержание коммита. 59 | 60 | ## Отладка 61 | 62 | При решении задач в IDE [Visual Studio Code](https://code.visualstudio.com/Download) подключение отладчика происходит в пару кликов: 63 | 64 | 1. В меню среды разработки выбрать `View -> Debug`. Слева отобразится панель отладчика 65 | 2. Выбрать `Debug js-problems` как конфигурацию отладчика ([видеоверсия](https://youtu.be/KBzhh87jcXA)) ![Демонстрация выбора конфигурации отладчика](/static/configure-debug.gif) 66 | 3. Через меню запустить отладчик `Debug -> Start Debugging`. git статус отлаживаемого файла должен быть `not staged for commit`. 67 | 68 | ## Альтернативы 69 | 70 | Данный ресурс создавался, преимущественно, для тех, кто испытывает проблемы с английским языком. Невходящие в их число могут попробовать свои силы на следующих сайтах: 71 | 72 | - [LeetCode](https://leetcode.com/problemset/all/) 73 | - [Codewars](https://www.codewars.com/?language=javascript) 74 | - [Hackerrank](https://www.hackerrank.com/dashboard) 75 | - [CheckIO](https://js.checkio.org/) 76 | 77 | Как альтернативный русскоязычный сборник задач можно рассматривать сайт ["Школа программиста"](http://acmp.ru/), но без системы для автоматической проверки JavaScript решений. 78 | 79 | ## Содействия 80 | 81 | Любой желающий может помочь проекту, например: 82 | 83 | - добавлением новых задач в сборник 84 | - расширением тест-кейсов 85 | 86 | Для этого оформляйте свои предложения в виде [задач](https://github.com/mbelsky/js-problems/issues/new). 87 | 88 | ## Лицензия 89 | 90 | Проект разрабатывается под лицензией [MIT](LICENSE). 91 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after `n` failures 9 | // bail: 0, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/private/var/folders/dk/j304_bpj6gb8srsmjn3hrbk80000gn/T/jest_dx", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | // clearMocks: false, 19 | 20 | // Indicates whether the coverage information should be collected while executing the test 21 | // collectCoverage: false, 22 | 23 | // An array of glob patterns indicating a set of files for which coverage information should be collected 24 | // collectCoverageFrom: null, 25 | 26 | // The directory where Jest should output its coverage files 27 | // coverageDirectory: null, 28 | 29 | // An array of regexp pattern strings used to skip coverage collection 30 | // coveragePathIgnorePatterns: [ 31 | // "/node_modules/" 32 | // ], 33 | 34 | // A list of reporter names that Jest uses when writing coverage reports 35 | // coverageReporters: [ 36 | // "json", 37 | // "text", 38 | // "lcov", 39 | // "clover" 40 | // ], 41 | 42 | // An object that configures minimum threshold enforcement for coverage results 43 | // coverageThreshold: null, 44 | 45 | // A path to a custom dependency extractor 46 | // dependencyExtractor: null, 47 | 48 | // Make calling deprecated APIs throw helpful error messages 49 | // errorOnDeprecated: false, 50 | 51 | // Force coverage collection from ignored files using an array of glob patterns 52 | // forceCoverageMatch: [], 53 | 54 | // A path to a module which exports an async function that is triggered once before all test suites 55 | // globalSetup: null, 56 | 57 | // A path to a module which exports an async function that is triggered once after all test suites 58 | // globalTeardown: null, 59 | 60 | // A set of global variables that need to be available in all test environments 61 | // globals: {}, 62 | 63 | // An array of directory names to be searched recursively up from the requiring module's location 64 | // moduleDirectories: [ 65 | // "node_modules" 66 | // ], 67 | 68 | // An array of file extensions your modules use 69 | // moduleFileExtensions: [ 70 | // "js", 71 | // "json", 72 | // "jsx", 73 | // "ts", 74 | // "tsx", 75 | // "node" 76 | // ], 77 | 78 | // A map from regular expressions to module names that allow to stub out resources with a single module 79 | // moduleNameMapper: {}, 80 | 81 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 82 | // modulePathIgnorePatterns: [], 83 | 84 | // Activates notifications for test results 85 | // notify: false, 86 | 87 | // An enum that specifies notification mode. Requires { notify: true } 88 | // notifyMode: "failure-change", 89 | 90 | // A preset that is used as a base for Jest's configuration 91 | // preset: null, 92 | 93 | // Run tests from one or more projects 94 | // projects: null, 95 | 96 | // Use this configuration option to add custom reporters to Jest 97 | // reporters: undefined, 98 | 99 | // Automatically reset mock state between every test 100 | // resetMocks: false, 101 | 102 | // Reset the module registry before running each individual test 103 | // resetModules: false, 104 | 105 | // A path to a custom resolver 106 | // resolver: null, 107 | 108 | // Automatically restore mock state between every test 109 | // restoreMocks: false, 110 | 111 | // The root directory that Jest should scan for tests and modules within 112 | // rootDir: null, 113 | 114 | // A list of paths to directories that Jest should use to search for files in 115 | // roots: [ 116 | // "" 117 | // ], 118 | 119 | // Allows you to use a custom runner instead of Jest's default test runner 120 | // runner: "jest-runner", 121 | 122 | // The paths to modules that run some code to configure or set up the testing environment before each test 123 | // setupFiles: [], 124 | 125 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 126 | // setupFilesAfterEnv: [], 127 | 128 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 129 | // snapshotSerializers: [], 130 | 131 | // The test environment that will be used for testing 132 | testEnvironment: "node", 133 | 134 | // Options that will be passed to the testEnvironment 135 | // testEnvironmentOptions: {}, 136 | 137 | // Adds a location field to test results 138 | // testLocationInResults: false, 139 | 140 | // The glob patterns Jest uses to detect test files 141 | // testMatch: [ 142 | // "**/__tests__/**/*.[jt]s?(x)", 143 | // "**/?(*.)+(spec|test).[tj]s?(x)" 144 | // ], 145 | 146 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 147 | // testPathIgnorePatterns: [ 148 | // "/node_modules/" 149 | // ], 150 | 151 | // The regexp pattern or array of patterns that Jest uses to detect test files 152 | // testRegex: [], 153 | 154 | // This option allows the use of a custom results processor 155 | // testResultsProcessor: null, 156 | 157 | // This option allows use of a custom test runner 158 | // testRunner: "jasmine2", 159 | 160 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 161 | // testURL: "http://localhost", 162 | 163 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 164 | // timers: "real", 165 | 166 | // A map from regular expressions to paths to transformers 167 | // transform: null, 168 | 169 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 170 | // transformIgnorePatterns: [ 171 | // "/node_modules/" 172 | // ], 173 | 174 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 175 | // unmockedModulePathPatterns: undefined, 176 | 177 | // Indicates whether each individual test should be reported during the run 178 | // verbose: null, 179 | 180 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 181 | // watchPathIgnorePatterns: [], 182 | 183 | // Whether to use watchman for file crawling 184 | // watchman: true, 185 | }; 186 | --------------------------------------------------------------------------------