├── .npmrc ├── .prettierrc.js ├── .gitattributes ├── basic ├── fizzbuzz │ ├── tiny-teeny.js │ ├── tiny.js │ ├── loop.js │ ├── ternary.js │ ├── map.js │ ├── typed-array.js │ ├── pattern-matching.js │ ├── plus-equals.js │ ├── array-from.js │ ├── while.js │ ├── functionally.js │ ├── recursively.js │ ├── fizzbuzz.js │ ├── README.md │ ├── es6-generator-node.js │ ├── over-engineered.js │ └── lul.js ├── smallest-num.js ├── count-backwards.js ├── array-depth.js ├── is-boolean.js ├── reduce.js ├── map-parseInt.js ├── is-square.js ├── word-count.js ├── swap-in-place.js ├── thenable-checker.js ├── truncate-string.js ├── escape-html-entities.js ├── reverse-a-string.js ├── alphabet.js ├── length-of-average-word-in-a-string.js ├── repeat-a-string.js ├── diff-two-arrays.js ├── logger.js ├── format.js ├── newbind.js ├── multiples-of-3-and-5.js ├── balanced-brackets.js ├── commonFactors.js ├── document.ready.js ├── arrayReverse.js ├── missing-element.js ├── triangle.js ├── sum-primes.js ├── sumRange.js ├── sum-of-array-plus-one.js ├── filter.js ├── title-case-a-sentence.js ├── fibonacci-finder.js ├── map.js ├── count.js ├── vowel-count.js ├── hashtable.js ├── romanNumeralTranslator.js ├── randomize-array.js ├── xor.js ├── bytes-to-friendly-sizes.js ├── fibonacci.js ├── primes.js ├── rps-sol.js ├── combinator.js ├── reverse-array.js ├── primenumbers.js ├── funcArray.js ├── factorial.js ├── functions-only-once.js ├── list.js ├── longest-word-in-string.js ├── palindrome-check.js ├── abcheck.js ├── missingnumber.js └── first-non-repeated-character-in-a-string.js ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── CONTRIBUTING.md ├── node ├── index.html ├── express │ ├── 1 │ │ ├── package.json │ │ └── index.js │ ├── 2 │ │ └── index.js │ ├── 3 │ │ └── index.js │ ├── 4 │ │ └── index.js │ └── README.md ├── README.md ├── pwd.js ├── is-module-installed.js ├── palindrome-checker.js ├── ls.js ├── user-home.js ├── make-file-if-doesnt-exist.js ├── prompt-repeater.js ├── check-up.js ├── gzip.js ├── bare-http-server.js ├── plain-html-server.js ├── cp.js ├── ip-server.js ├── rock-paper-scissors.js ├── cat.js ├── morsecode.js ├── tic-tac-toe.js ├── chat-server.js └── repl.js ├── .eslintrc.json ├── .editorconfig ├── README.md ├── LICENSE ├── intermediate ├── lowercase-and-hyphens.js ├── binary-sort.js ├── array-intersection.js ├── bst-count.js ├── deep-equal.js ├── binary-to-text.js ├── target-sum.js ├── array-reorder.js ├── case-utilities.js ├── invert-binary-tree.js ├── hex-to-dec.js ├── compose-pipe.js ├── flatten-and-uniq.js ├── pig-latin.js ├── array-every-some.js ├── tree.js ├── graph.js ├── bucket-sort.js ├── mad-lib.js ├── eventingLibrary.js ├── ycomb.js ├── insert-at-index.js ├── minimum-stack.js ├── queue.js ├── stack.js ├── max-profit.js ├── throttle-debounce.js ├── debounce.js ├── set.js ├── bubble-sort.js ├── array-flatten.js └── curry.js ├── package.json ├── advanced ├── insertion-sort.js ├── async-map.js ├── queue-stack.js ├── ajax-vanilla.js ├── memoize.js ├── triangle-counter.js ├── clock-angles.js ├── stock-ticker.js ├── lotto.js ├── quicksort.js ├── mergesort.js └── singly-linked-list.js └── .gitignore /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true 2 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('') 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | text eol=lf 3 | package-lock.json -diff 4 | -------------------------------------------------------------------------------- /basic/fizzbuzz/tiny-teeny.js: -------------------------------------------------------------------------------- 1 | for (i = 0; ++i < 101; ) { 2 | console.log((i % 3 ? '' : 'Fizz') + (i % 5 ? '' : 'Buzz') || i) 3 | } 4 | -------------------------------------------------------------------------------- /basic/fizzbuzz/tiny.js: -------------------------------------------------------------------------------- 1 | for (i = 1; i < 101; i++) { 2 | console.log((x = (i % 3 ? '' : 'Fizz') + (i % 5 ? '' : 'Buzz')) ? x : i) 3 | } 4 | -------------------------------------------------------------------------------- /basic/fizzbuzz/loop.js: -------------------------------------------------------------------------------- 1 | for (let i = 1; i < 101; i++) { 2 | console.log( 3 | [i, 'fizz', 'buzz', 'fizzbuzz'][(i % 3 === 0) + 2 * (i % 5 === 0)] 4 | ) 5 | } 6 | -------------------------------------------------------------------------------- /basic/fizzbuzz/ternary.js: -------------------------------------------------------------------------------- 1 | for (let i = 1; i <= 100; i++) { 2 | const fizz = !(i % 3) ? 'Fizz' : '' 3 | const buzz = !(i % 5) ? fizz + 'Buzz' : fizz 4 | console.log(buzz || i) 5 | } 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Is this a feature request or a bug? 2 | 3 | # Expected behavior: 4 | 5 | # Actual behavior: 6 | 7 | # Environment info (relevant browser, OS, etc.; run `npx envinfo`): 8 | -------------------------------------------------------------------------------- /node/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test 6 | 7 | 8 |
hello
9 | 10 | 11 | -------------------------------------------------------------------------------- /basic/fizzbuzz/map.js: -------------------------------------------------------------------------------- 1 | const numGen = (i) => (i ? numGen(i - 1).concat(i) : []) 2 | 3 | console.log( 4 | numGen(100).map((n) => 5 | n % 3 ? (n % 5 ? n : 'Buzz') : n % 5 ? 'Fizz' : 'FizzBuzz' 6 | ) 7 | ) 8 | -------------------------------------------------------------------------------- /basic/fizzbuzz/typed-array.js: -------------------------------------------------------------------------------- 1 | Object.keys(new Int8Array(100)) 2 | .map((x) => (++x % 3 == 0 ? (f = 'fizz') : x)) 3 | .map((x, i) => (++i % 5 == 0 ? (b = 'buzz') : x)) 4 | .map((x, i) => (++i % 15 === 0 ? f + b : x)) 5 | -------------------------------------------------------------------------------- /node/express/README.md: -------------------------------------------------------------------------------- 1 | [Express](https://expressjs.com/) is the most popular web server framework for 2 | Node. It's similar to Sinatra for Ruby and Flask for Python. These problems 3 | assume you already have Node installed and are comfortable with npm. 4 | -------------------------------------------------------------------------------- /basic/fizzbuzz/pattern-matching.js: -------------------------------------------------------------------------------- 1 | for (let i = 1; i <= 100; i++) { 2 | console.log( 3 | { 4 | truefalse: 'Fizz', 5 | falsetrue: 'Buzz', 6 | truetrue: 'FizzBuzz', 7 | }[(i % 3 == 0) + '' + (i % 5 == 0)] || i 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /basic/fizzbuzz/plus-equals.js: -------------------------------------------------------------------------------- 1 | for (let i = 1; i <= 100; i++) { 2 | ;(function (i) { 3 | let output = '' 4 | 5 | if (i % 3 == 0) { 6 | output += 'Fizz' 7 | } 8 | 9 | if (i % 5 == 0) { 10 | output += 'Buzz' 11 | } 12 | 13 | console.log(output || i) 14 | })(i) 15 | } 16 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "plugins": [ 4 | ], 5 | "extends": [ 6 | ], 7 | "env": { 8 | "node": true 9 | }, 10 | "rules": { 11 | "no-console": 0, 12 | "fp/no-nil": 0, 13 | "fp/no-unused-expression": 0, 14 | "fp/no-mutation": 0, 15 | "fp/no-let": 0 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = LF 5 | charset = utf-8 6 | max_line_length = 80 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | indent_size = 2 11 | 12 | [*.{rs,py}] 13 | indent_size = 4 14 | 15 | [*.{md,go}] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Change Type 2 | 3 | * [ ] Feature 4 | * [ ] Chore 5 | * [ ] Bug Fix 6 | 7 | # Change Level 8 | 9 | * [ ] major 10 | * [ ] minor 11 | * [ ] patch 12 | 13 | # Further Information (screenshots, bug report links, etc.) 14 | 15 | # Checklist 16 | 17 | * [ ] Tested in supported environments (common browsers or current and LTS Node) 18 | -------------------------------------------------------------------------------- /basic/fizzbuzz/array-from.js: -------------------------------------------------------------------------------- 1 | console.log( 2 | ((n) => 3 | [...new Array(n)] 4 | .map((_, n) => { 5 | const i = n + 1 6 | return i % 15 === 0 7 | ? 'FizzBuzz' 8 | : i % 5 === 0 9 | ? 'Buzz' 10 | : i % 3 === 0 11 | ? 'Fizz' 12 | : i 13 | }) 14 | .join('\n'))(100) 15 | ) 16 | -------------------------------------------------------------------------------- /basic/fizzbuzz/while.js: -------------------------------------------------------------------------------- 1 | let counter = 0 2 | 3 | while (counter < 100) { 4 | counter += 1 5 | if (counter % 3 === 0 && counter % 5 === 0) { 6 | console.log('FizzBuzz') 7 | } else if (counter % 3 === 0) { 8 | console.log('Fizz') 9 | } else if (counter % 5 === 0) { 10 | console.log('Buzz') 11 | } else { 12 | console.log(counter) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /basic/fizzbuzz/functionally.js: -------------------------------------------------------------------------------- 1 | const range = (n) => [...new Array(n).keys()] 2 | 3 | const fbTest = (n) => { 4 | const by3 = n % 3 === 0, 5 | by5 = n % 5 === 0 6 | 7 | return by3 && by5 ? 'fizz buzz' : by3 ? 'fizz' : by5 ? 'buzz' : n 8 | } 9 | 10 | const fizzBuzz = (n) => 11 | range(n) 12 | .map((x) => fbTest(x + 1)) 13 | .join(', ') 14 | 15 | console.log(fizzBuzz(100)) 16 | -------------------------------------------------------------------------------- /node/README.md: -------------------------------------------------------------------------------- 1 | You'll need Node to try these problems. You can install it with your package 2 | manager if you have one: 3 | 4 | ```shell 5 | # Debian and Ubuntu 6 | apt-get install -y nodejs npm 7 | 8 | # Arch 9 | pacman -Sy nodejs npm 10 | 11 | # Mac 12 | brew install node 13 | 14 | # Windows 15 | choco install nodejs 16 | ``` 17 | 18 | Or directly from the website: . 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # js-drills 2 | 3 | Small code challenges. 4 | 5 | Plan JS problems are in the `basic`, `intermediate`, and `advanced` 6 | directories. Node problems are in the `node` directory. 7 | Possible solutions are included in the same files as the questions, after 8 | long empty comments. Don't jump to the bottom and cheat! Have fun! 9 | 10 | See [CONTRIBUTING](.github/CONTRIBUTING.md) for contribution guidelines. 11 | -------------------------------------------------------------------------------- /basic/fizzbuzz/recursively.js: -------------------------------------------------------------------------------- 1 | const fizzBuzz = (num) => { 2 | if (num % 3 === 0 && num % 5 === 0) { 3 | console.log('FizzBuzz') 4 | } else if (num % 3 === 0) { 5 | console.log('Fizz') 6 | } else if (num % 5 === 0) { 7 | console.log('Buzz') 8 | } else { 9 | console.log(num) 10 | } 11 | 12 | if (num < 100) { 13 | const newNum = num + 1 14 | fizzBuzz(newNum) 15 | } 16 | } 17 | 18 | fizzBuzz(1) 19 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are welcome! New solutions, improvements to problems, and new 4 | problems (with solutions) are especially welcome. 5 | 6 | ## Guidelines 7 | 8 | * Please make sure you fill out the issue or PR template accurately. 9 | * Please use current LTS or above versions for Node and npm. 10 | * Follow the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct). 11 | -------------------------------------------------------------------------------- /basic/fizzbuzz/fizzbuzz.js: -------------------------------------------------------------------------------- 1 | // this (or a slight variation on this) is easily the most common solution 2 | 3 | function fizz_buzz(num) { 4 | if (num % 15 == 0) { 5 | console.log('FizzBuzz') 6 | } else if (num % 5 == 0) { 7 | console.log('Buzz') 8 | } else if (num % 3 == 0) { 9 | console.log('Fizz') 10 | } else { 11 | console.log(num) 12 | } 13 | } 14 | 15 | for (let i = 0; i <= 100; i++) { 16 | fizz_buzz(i) 17 | } 18 | -------------------------------------------------------------------------------- /basic/fizzbuzz/README.md: -------------------------------------------------------------------------------- 1 | Write a program that prints numbers from 1 to 100, but for multiples of 2 | three print 'fizz,' for multiples of five print 'buzz,' and for multiples 3 | of both three and five print 'fizzbuzz.' 4 | 5 | Some good reading on fizzbuzz: 6 | 7 | * http://c2.com/cgi/wiki?FizzBuzzTest 8 | * https://www.rosettacode.org/wiki/FizzBuzz 9 | * http://www.tomdalling.com/blog/software-design/fizzbuzz-in-too-much-detail/ 10 | 11 | Check all the examples in this directory! 12 | -------------------------------------------------------------------------------- /basic/smallest-num.js: -------------------------------------------------------------------------------- 1 | // what's the smaller of two numbers passed in? 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | */ 52 | 53 | const min = (a, b) => (a < b ? a : b) 54 | -------------------------------------------------------------------------------- /basic/fizzbuzz/es6-generator-node.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const max = process.argv[2] || 100 4 | 5 | const FizzBuzz = (function* () { 6 | let num = 1 7 | while (num <= max) { 8 | let value = num 9 | num++ 10 | if (value % 15 === 0) { 11 | value = 'FizzBuzz' 12 | } else if (value % 3 === 0) { 13 | value = 'Fizz' 14 | } else if (value % 5 === 0) { 15 | value = 'Buzz' 16 | } 17 | yield value 18 | } 19 | })() 20 | 21 | for (const n of FizzBuzz) { 22 | console.log(n) 23 | } 24 | -------------------------------------------------------------------------------- /node/express/1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "0.1.0", 4 | "description": "bar quux baz", 5 | "main": "", 6 | "scripts": { 7 | "test": "", 8 | "start": "" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/zautumnz/foo.git" 13 | }, 14 | "keywords": [ 15 | "", 16 | "" 17 | ], 18 | "author": { 19 | "name": "Autumn Z" 20 | }, 21 | "license": "0BSD", 22 | "dependencies": { 23 | "express": "^4.13.4" 24 | }, 25 | "devDependencies": {} 26 | } 27 | 28 | -------------------------------------------------------------------------------- /basic/count-backwards.js: -------------------------------------------------------------------------------- 1 | // count backwards from 100 to 1, and print 2 | // out each number. 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | */ 57 | 58 | for (let i = 100; i > 0; i--) { 59 | console.log(i) 60 | } 61 | -------------------------------------------------------------------------------- /basic/array-depth.js: -------------------------------------------------------------------------------- 1 | // if a is an array, return max depth 2 | // of each element in array 3 | // add 1 to increase depth 4 | // if a is int, return 0 5 | 6 | /* 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | */ 56 | 57 | const f = (a) => (a[0] ? Math.max(...a.map(f)) + 1 : 0) 58 | -------------------------------------------------------------------------------- /basic/is-boolean.js: -------------------------------------------------------------------------------- 1 | // write a function that just checks if what you pass it is a boolean 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | */ 65 | 66 | const isBool = (a) => typeof a === 'boolean' 67 | -------------------------------------------------------------------------------- /basic/reduce.js: -------------------------------------------------------------------------------- 1 | // rewrite reduce (fold) as a standalone function 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | */ 54 | 55 | const reduce = (fn, start, arr) => { 56 | let acc = start 57 | for (const element of arr) { 58 | acc = fn(element, acc) 59 | } 60 | return acc 61 | } 62 | -------------------------------------------------------------------------------- /node/pwd.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // rewrite pwd(1) in node! 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | */ 74 | 75 | console.log(process.cwd()) 76 | -------------------------------------------------------------------------------- /basic/map-parseInt.js: -------------------------------------------------------------------------------- 1 | // mapping parseInt over an array will lead to some funky results. 2 | const a = ['10', '10', '10'] 3 | a.map(parseInt) // [10, NaN, 2] 4 | // fix this so it does what you'd expect! 5 | 6 | /* 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | */ 58 | 59 | a.map((n) => parseInt(n, 10)) 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted. 5 | 6 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 7 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 8 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 9 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 10 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 11 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 12 | PERFORMANCE OF THIS SOFTWARE. 13 | -------------------------------------------------------------------------------- /basic/is-square.js: -------------------------------------------------------------------------------- 1 | // write a function that determines if an argument is a square 2 | // you can assume you're passed a number 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | */ 61 | 62 | const isSquare = (n) => Number.isInteger(Math.sqrt(n)) 63 | 64 | const isSquare = (n) => n > 0 && Math.sqrt(n) % 1 === 0 65 | -------------------------------------------------------------------------------- /basic/word-count.js: -------------------------------------------------------------------------------- 1 | // write a function that takes a string and returns the total number 2 | // of words in that string. assume that all words are separated by 3 | // spaces. example: 4 | // countWords('Built in methods are your friend!') // => 6 5 | 6 | /* 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | */ 57 | 58 | function countWords(str) { 59 | return str.split(' ').length 60 | } 61 | -------------------------------------------------------------------------------- /node/is-module-installed.js: -------------------------------------------------------------------------------- 1 | // write a function that checks to see if a module is locally installed 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | */ 59 | 60 | const isInstalled = (pkgName) => { 61 | try { 62 | require.resolve(pkgName) 63 | return true 64 | } catch { 65 | return false 66 | } 67 | } 68 | 69 | export default isInstalled 70 | -------------------------------------------------------------------------------- /basic/swap-in-place.js: -------------------------------------------------------------------------------- 1 | // given two variables, swap them in place 2 | // this means swap their values, without creating a 3 | // third temp variable 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | */ 51 | 52 | let a = 1 53 | let b = 2 54 | 55 | // your code here 56 | 57 | a = b - a 58 | b = b - a 59 | a = a + b 60 | 61 | // alternatively 62 | a = a + b 63 | b = a - b 64 | a = a - 65 | b[ 66 | // or with es2015 67 | (b, a) 68 | ] = [a, b] 69 | -------------------------------------------------------------------------------- /basic/thenable-checker.js: -------------------------------------------------------------------------------- 1 | // write a 'thenable checker' function that takes an argument 2 | // and finds out if it returns a promise 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | */ 69 | 70 | const thenable = (a) => { 71 | if (typeof a.then === 'function') { 72 | return true 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /basic/truncate-string.js: -------------------------------------------------------------------------------- 1 | // write a function that truncates a string. 2 | // it should accept a string and a character count. 3 | // test with: 4 | // truncate('The quick brown fox jumps over the lazy dog', 16) 5 | 6 | /* 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | */ 62 | 63 | function truncate(str, num) { 64 | return str.length <= num ? str : str.substr(0, num - 3) + '…' 65 | } 66 | -------------------------------------------------------------------------------- /node/palindrome-checker.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // make a palindrome-checking tool that works on the command line 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | */ 64 | 65 | const str = process.argv[2] || 'tacocat' 66 | const pal = (str) => str == str.split('').reverse().join('') 67 | console.log(`is ${str} a palindrome? that's ${pal(str)}`) 68 | -------------------------------------------------------------------------------- /basic/escape-html-entities.js: -------------------------------------------------------------------------------- 1 | // write a function that escapes some html entities (like & to &, etc.) 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | */ 57 | 58 | function convert(str) { 59 | return str 60 | .replace(/&/g, '&') 61 | .replace(/'/g, ''') 62 | .replace(//g, '>') 64 | .replace(/"/g, '"') 65 | } 66 | 67 | convert('Dolce & Gabbana') 68 | -------------------------------------------------------------------------------- /basic/reverse-a-string.js: -------------------------------------------------------------------------------- 1 | // reverse a string 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | */ 54 | 55 | function reverseString(str) { 56 | let newStr = '' 57 | for (let i = str.length - 1; i >= 0; i--) { 58 | newStr += str[i] 59 | } 60 | return newStr 61 | } 62 | 63 | reverseString('hello') 64 | 65 | function reverseStringShort(str) { 66 | return str.split('').reverse().join('') 67 | } 68 | 69 | reverseStringShort('hello') 70 | -------------------------------------------------------------------------------- /basic/alphabet.js: -------------------------------------------------------------------------------- 1 | // write a functin that takes in a string, and returns that string with all 2 | // its letters in alphabetal order. assume there will be no punctuation or 3 | // numbers. example: `alphabet('hello')` // => 'ehllo' 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | */ 69 | 70 | function alphabet(str) { 71 | return str.split('').sort().join('') 72 | } 73 | -------------------------------------------------------------------------------- /basic/length-of-average-word-in-a-string.js: -------------------------------------------------------------------------------- 1 | // find the average length of each word in a string 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | */ 59 | 60 | const lengthOfString = function (myString) { 61 | const words = myString.split(' ') 62 | let average = 0 63 | let total = 0 64 | for (const element of words) { 65 | total += element.length 66 | } 67 | average = total / words.length 68 | return average 69 | } 70 | -------------------------------------------------------------------------------- /basic/repeat-a-string.js: -------------------------------------------------------------------------------- 1 | // repeat a string n amount of times 2 | // example: 3 | // repeat('foo', 2) // foo foo 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | */ 58 | 59 | const r = (s, n) => s.repeat(n) 60 | 61 | // 62 | function repeat(str, num) { 63 | let newStr = '' 64 | if (num <= 0) { 65 | return newStr 66 | } 67 | for (let i = 0; i < num; i++) { 68 | newStr += str 69 | } 70 | return newStr 71 | } 72 | 73 | repeat('abc', 3) 74 | -------------------------------------------------------------------------------- /node/ls.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // write ls(1) in node! 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | */ 59 | 60 | const fs = require('fs') 61 | const path = require('path') 62 | const dirPath = process.argv[2] || '.' 63 | const files = [] 64 | 65 | fs.readdir(dirPath, (err, list) => { 66 | if (err) { 67 | throw err 68 | } 69 | for (const [i, element] of list.entries()) { 70 | console.log(element) 71 | files.push[i] 72 | } 73 | }) 74 | -------------------------------------------------------------------------------- /node/user-home.js: -------------------------------------------------------------------------------- 1 | // write a function that checks to see what ~/ 2 | // is called on a given machine. hint: it's not the same 3 | // on windows and not-windows. 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | */ 61 | 62 | // either of these will work 63 | const home = process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME'] 64 | const home2 = 65 | process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE 66 | 67 | console.log(home, home2) 68 | -------------------------------------------------------------------------------- /intermediate/lowercase-and-hyphens.js: -------------------------------------------------------------------------------- 1 | // function that replaces spaces with hyphens and lowercases everything 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | */ 66 | 67 | function spinalCase(str) { 68 | if (str.match(/ [A-Z]/g)) { 69 | } 70 | return str 71 | .replace(/[ _]/g, '-') 72 | .replace(/([^\n\-])([A-Z])/g, '$1-$2') 73 | .toLowerCase() 74 | } 75 | 76 | spinalCase('This Is Spinal Tap') 77 | -------------------------------------------------------------------------------- /basic/diff-two-arrays.js: -------------------------------------------------------------------------------- 1 | // diff two arrays 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | */ 56 | 57 | function diff(arr1, arr2) { 58 | const newArr = [] 59 | for (var i = 0; i < arr1.length; i++) { 60 | if (!arr2.includes(arr1[i])) { 61 | newArr.push(arr1[i]) 62 | } 63 | } 64 | for (var i = 0; i < arr2.length; i++) { 65 | if (!arr1.includes(arr2[i])) { 66 | newArr.push(arr2[i]) 67 | } 68 | } 69 | return newArr 70 | } 71 | 72 | diff([1, 2, 3, 5], [1, 2, 3, 4, 5]) 73 | -------------------------------------------------------------------------------- /basic/fizzbuzz/over-engineered.js: -------------------------------------------------------------------------------- 1 | function fizzbuzz() { 2 | let i = 1 3 | const result = [] 4 | 5 | ;(function loop() { 6 | let str = '' 7 | str += fizz(i) 8 | str += buzz(i) 9 | result.push(ifFalsy(str, i)) 10 | if (isLt100(i++)) { 11 | loop() 12 | } 13 | })() 14 | print(result.join(', ')) 15 | } 16 | 17 | function fizz(num) { 18 | return isDivBy3(num) ? 'fizz' : '' 19 | } 20 | 21 | function buzz(num) { 22 | return isDivBy5(num) ? 'buzz' : '' 23 | } 24 | 25 | function isDivBy3(num) { 26 | return num % 3 === 0 27 | } 28 | 29 | function isDivBy5(num) { 30 | return num % 5 === 0 31 | } 32 | 33 | function isLt100(num) { 34 | return num < 100 35 | } 36 | 37 | function ifFalsy(value, fallback) { 38 | return !value ? fallback : value 39 | } 40 | 41 | function print(str) { 42 | console.log(str) 43 | } 44 | 45 | fizzbuzz() 46 | -------------------------------------------------------------------------------- /basic/logger.js: -------------------------------------------------------------------------------- 1 | // create an object (call it logger) with two methods 2 | // method one: logs out msg with word INFO: prefixed 3 | // method two: logs err to console with ERROR: prefixed 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | */ 71 | 72 | const logger = { 73 | info(msg) { 74 | console.log(`INFO: ${msg}`) 75 | }, 76 | 77 | error(err) { 78 | console.error(`ERROR: ${err}`) 79 | }, 80 | } 81 | -------------------------------------------------------------------------------- /intermediate/binary-sort.js: -------------------------------------------------------------------------------- 1 | // binary sort 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | */ 50 | 51 | function binarySort(collection, target, cb, min, max) { 52 | min = min || 0 53 | max = max || collection.length 54 | const median = Math.floor((min + max) / 2) 55 | const result = collection[median] 56 | 57 | if (result === target) { 58 | cb(median) 59 | return 60 | } else if (result > target) { 61 | max = median 62 | } else if (result < target) { 63 | min = median 64 | } 65 | binarySort(collection, target, cb, min, max) 66 | } 67 | -------------------------------------------------------------------------------- /basic/fizzbuzz/lul.js: -------------------------------------------------------------------------------- 1 | ;(function (window) { 2 | let counter = 1, 3 | limit = 100, 4 | options = { 5 | 3: 'Fizz', 6 | 5: 'Buzz', 7 | default: function (input) { 8 | return input 9 | }, 10 | } 11 | 12 | const noop = function () { 13 | return 14 | } 15 | 16 | const print = function (input) { 17 | const output = [] 18 | Object.keys(options).map(function (key) { 19 | ;(typeof options[key] !== 'function' && 20 | parseInt(input, 10) % parseInt(key, 10) === 0 21 | ? Array.prototype.push 22 | : noop 23 | ).call(output, options[key]) 24 | }) 25 | return console.log.call( 26 | console, 27 | output.length ? output.join('') : options.default.call(this, input) 28 | ) 29 | } 30 | 31 | for (; counter <= limit; counter += 1) { 32 | print.call(this, counter) 33 | } 34 | })(this) 35 | -------------------------------------------------------------------------------- /basic/format.js: -------------------------------------------------------------------------------- 1 | // node has a `util.format`. this works like so: 2 | // `console.log('some stuff and %s', things)` 3 | // reimplement this in ES5 (no template strings) 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | */ 63 | 64 | function format() { 65 | const args = [].slice.call(arguments) 66 | const initial = args.shift() 67 | 68 | function replacer(text, replacement) { 69 | return text.replace('%s', replacement) 70 | } 71 | 72 | return args.reduce(replacer, initial) 73 | } 74 | -------------------------------------------------------------------------------- /intermediate/array-intersection.js: -------------------------------------------------------------------------------- 1 | // write fn that takes two arrays and returns 2 | // array with their intersection 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | */ 73 | 74 | module.exports = (firstArray, secondArray) => { 75 | const hash = {} 76 | 77 | firstArray.forEach((item) => { 78 | hash[item] = true 79 | }) 80 | 81 | const intersection = secondArray.filter((item) => hash[item]) 82 | 83 | return intersection 84 | } 85 | -------------------------------------------------------------------------------- /intermediate/bst-count.js: -------------------------------------------------------------------------------- 1 | // Given a binary search tree root, count the total number of nodes in the tree. 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | */ 75 | 76 | function BSTNode(value) { 77 | this.value = value 78 | this.left = null 79 | this.right = null 80 | } 81 | 82 | function countNodes(root) { 83 | if (!root) { 84 | return 0 85 | } 86 | return countNodes(root.left) + 1 + countNodes(root.right) 87 | } 88 | -------------------------------------------------------------------------------- /basic/newbind.js: -------------------------------------------------------------------------------- 1 | // Recreate the `.bind` method on the Function prototype. 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | */ 54 | 55 | Function.prototype.newBind = function () { 56 | const _this = this 57 | const context = arguments[0] 58 | const args = [] 59 | for (let i = 1; i < arguments.length; i++) { 60 | args.push(arguments[i]) 61 | } 62 | 63 | return function () { 64 | const innArgs = [] 65 | for (let i = 1; i < arguments.length; i++) { 66 | innerArgs.push(arguments[i]) 67 | } 68 | 69 | return _this.call(context, args.concat(innerArgs)) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /node/make-file-if-doesnt-exist.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // write a little cli tool to create a file 4 | // if it doesn't already exist. 5 | // assume it'll be a js file, and if it doesn't 6 | // already exist you want it to just contain 'use strict' 7 | 8 | /* 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | */ 73 | 74 | const fs = require('fs') 75 | const file = process.argv[2] || 'something.js' 76 | 77 | try { 78 | fs.statSync(file) 79 | } catch { 80 | fs.writeFileSync(file, "'use strict'") 81 | } 82 | -------------------------------------------------------------------------------- /basic/multiples-of-3-and-5.js: -------------------------------------------------------------------------------- 1 | // If we list all the natural numbers below 10 that are multiples 2 | // of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. 3 | // Find the sum of all the multiples of 3 or 5 below 1000. 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | */ 66 | 67 | function threeAndFive(limit) { 68 | let sum = 0 69 | for (let i = 0; i < limit; i++) { 70 | if (!(i % 3) || !(i % 5)) { 71 | sum += i 72 | } 73 | } 74 | return sum 75 | } 76 | 77 | // threeAndFive(1000) 78 | // Should return 233168 79 | -------------------------------------------------------------------------------- /node/express/1/index.js: -------------------------------------------------------------------------------- 1 | // write an express server! 2 | // you'll need to run `npm i` in this directory (the package.json is done for you). 3 | // your only dependency is express, here. 4 | // let's have this server just serve a string to the client, rather than a file 5 | 6 | /* 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | */ 69 | 70 | const express = require('express') 71 | const app = express() 72 | const port = process.env.PORT || 3000 73 | 74 | app 75 | .get('/', (req, res) => { 76 | res.send('Hello World') 77 | }) 78 | .listen(port) 79 | -------------------------------------------------------------------------------- /basic/balanced-brackets.js: -------------------------------------------------------------------------------- 1 | // Write a function that accepts a string consisting entirely of brackets ([](){}) 2 | // and returns whether or not it is balanced. Every 'opening' bracket must be followed 3 | // by a closing bracket of the same type. There can also be nested brackets, which adhere to the same rule. 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | */ 52 | 53 | function balance(str) { 54 | str = str.split('') 55 | const parens = ['(', ')'] 56 | const square = ['[', ']'] 57 | const curly = ['{', '}'] 58 | 59 | for (let i = 0; i < str.length; i++) { 60 | if (str[i] === parens[0]) { 61 | if (str[i + 1] !== parens[1]) { 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /node/prompt-repeater.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // write a small node script 4 | // when you run it, it should say 'received data:' followed by anything you type in 5 | // if you type 'quit', it should say 'bye', and then exit 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | */ 60 | 61 | process.stdin.resume() 62 | process.stdin.setEncoding('utf8') 63 | 64 | const { inspect } = require('util') 65 | 66 | const done = () => { 67 | console.log('bye') 68 | process.exit() 69 | } 70 | 71 | process.stdin.on('data', (text) => { 72 | console.log('received data:', inspect(text)) 73 | if (text === 'quit\n') { 74 | done() 75 | } 76 | }) 77 | -------------------------------------------------------------------------------- /node/check-up.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // write a small cli app you can call to check 4 | // if a website is up. 5 | // usage: check-up.js google.com 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | */ 64 | 65 | const http = require('http') 66 | const host = process.argv[2] 67 | const opts = { 68 | host, 69 | port: 80, 70 | path: '/', 71 | } 72 | 73 | http 74 | .get(opts, (res) => { 75 | if (res.statusCode === 200) { 76 | console.log(`${host} is up`) 77 | } else { 78 | console.log(`${host} is down`) 79 | } 80 | }) 81 | .on('error', (err) => { 82 | console.warn(`Error: ${err.message}`) 83 | }) 84 | -------------------------------------------------------------------------------- /basic/commonFactors.js: -------------------------------------------------------------------------------- 1 | // write a function that finds the common factors of two numbers, 2 | // and returns them sorted from highest to lowest. 3 | // example with 12 and 18: 4 | // factors of 12 are 12, 6, 4, 3, 2, 1 5 | // factors of 18 are 18, 9, 6, 3, 2, 1 6 | // so the common factors of 12 and 18 are 6, 3, 2, 1 7 | // another example: console.log(commonFactors(20, 25)) // => [5, 1] 8 | 9 | /* 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | */ 57 | 58 | function commonFactors(num1, num2) { 59 | const factors = [] 60 | let max 61 | max = num1 > num2 ? num1 : num2 62 | for (let i = max; i >= 1; i--) { 63 | if (num1 % i === num2 % i) { 64 | factors.push(i) 65 | } 66 | } 67 | return factors 68 | } 69 | -------------------------------------------------------------------------------- /basic/document.ready.js: -------------------------------------------------------------------------------- 1 | // can you rewrite document.ready (without jquery)? 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | */ 69 | 70 | // document.ready w/o jq 71 | document.onreadystatechange = function () { 72 | if (document.readyState == 'complete') { 73 | // do all the stuff here 74 | } 75 | } 76 | 77 | // or 78 | document.addEventListener('DOMContentLoaded', function () { 79 | // do all the stuff here 80 | }) 81 | 82 | // or, smaller, with older (IE) support 83 | function r(f) { 84 | ;/in/.test(document.readyState) ? setTimeout('r(' + f + ')', 9) : f() 85 | } 86 | -------------------------------------------------------------------------------- /intermediate/deep-equal.js: -------------------------------------------------------------------------------- 1 | // write a function that checks for deep equality 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | */ 73 | 74 | const deepEqual = (a, b) => { 75 | if (a === b) { 76 | return true 77 | } 78 | if (!a || !b) { 79 | return false 80 | } 81 | if (Array.isArray(a)) { 82 | return a.every((item, i) => deepEqual(item, b[i])) 83 | } 84 | if (typeof a === 'object') { 85 | return Object.keys(a).every((key) => deepEqual(a[key], b[key])) 86 | } 87 | return false 88 | } 89 | 90 | export default deepEqual 91 | -------------------------------------------------------------------------------- /basic/arrayReverse.js: -------------------------------------------------------------------------------- 1 | // reverse an array 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | */ 46 | 47 | const r = (a) => a.reverse() 48 | 49 | function reverseArray(array) { 50 | const inverseArr = [] 51 | for (let i = array.length - 1; i >= 0; i--) { 52 | inverseArr.push(array[i]) 53 | } 54 | return inverseArr 55 | } 56 | 57 | function reverseArrayInPlace(array) { 58 | let temp 59 | for (let i = 0; i < Math.floor(array.length / 2); i++) { 60 | temp = array[i] 61 | array[i] = array[array.length - 1 - i] 62 | array[array.length - 1 - i] = temp 63 | } 64 | return array 65 | } 66 | 67 | console.log(reverseArray(['A', 'B', 'C'])) 68 | const arrayValue = [1, 2, 3, 4, 5] 69 | reverseArrayInPlace(arrayValue) 70 | console.log(arrayValue) 71 | -------------------------------------------------------------------------------- /basic/missing-element.js: -------------------------------------------------------------------------------- 1 | // There is an array of non-negative integers. A second array is formed by 2 | // shuffling the elements of the first array and deleting a random element. 3 | // Given these two arrays, find which element is missing in the second array. 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | */ 57 | 58 | function findMissing(arr1, arr2) { 59 | const hash1 = {} 60 | const hash2 = {} 61 | for (var i = 0; i < arr1.length; i++) { 62 | hash1[arr1[i]] = true 63 | } 64 | 65 | for (var i = 0; i < arr2.length; i++) { 66 | hash2[arr2[i]] = true 67 | } 68 | 69 | for (const key in hash1) { 70 | if (!hash2[key]) { 71 | return key 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /node/gzip.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // write a compression cli tool using node's built-in gzip 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | */ 72 | 73 | const fs = require('fs') 74 | const zl = require('zlib') 75 | const ag = process.argv[2] 76 | const ar = process.argv[3] 77 | const zc = zl.createGzip() 78 | const ot = process.stdout 79 | 80 | if (!ar || !ag) { 81 | ot.write('please provide an input (file to compress) and an output\n') 82 | } else { 83 | const rs = fs.createReadStream(ag) 84 | const ws = fs.createWriteStream(ar) 85 | rs.pipe(zc).pipe(ws) 86 | } 87 | -------------------------------------------------------------------------------- /basic/triangle.js: -------------------------------------------------------------------------------- 1 | // log out a triangle of hashes (#) 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | */ 54 | 55 | const txt = '#######' 56 | for (let i = txt.length; i >= 0; i--) { 57 | console.log(txt.slice(i)) 58 | } 59 | 60 | // or, taking an argument for size 61 | const num = process.argv[2] 62 | let str = '' 63 | for (let i = num; i >= 1; i--) { 64 | str += '#' 65 | console.log(str) 66 | } 67 | 68 | // log out an equilateral triangle 69 | const equiTri = (size = 10) => { 70 | const hash = ' #' 71 | const space = ' ' 72 | for (let i = 0; i < size; i++) { 73 | const temp = 74 | space.repeat(size - 1) + hash.repeat(i) + space.repeat(size - i) 75 | console.log(temp) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /node/express/4/index.js: -------------------------------------------------------------------------------- 1 | // write an express server that removes the x-powered-by header 2 | // it doesn't need to send anything specific 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | */ 52 | 53 | const express = require('express') 54 | const port = 8000 55 | const app = express() 56 | 57 | app.disable('x-powered-by') 58 | // in older versions (pre 3) of express, this would be: 59 | // app.use((req, res, next) => { 60 | // res.removeHeader('x-powered-by') 61 | // next() 62 | // }) 63 | app.get('/', (req, res) => { 64 | res.send('hi') 65 | }) 66 | // you could also do: 67 | app.set('x-powered-by', false) 68 | // or if you wanted to get fancy 69 | app.use((req, res, next) => { 70 | res.setHeader('x-powered-by', 'something custom') 71 | }) 72 | app.listen(port) 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-drills", 3 | "description": "Small code challenges.", 4 | "version": "0.0.1", 5 | "private": true, 6 | "author": "Autumn Z", 7 | "license": "0BSD", 8 | "main": "index.js", 9 | "scripts": { 10 | "format": "sortpack && prettier --write \"**/*.js\"", 11 | "test:lint": "eslint -c .eslintrc.json ." 12 | }, 13 | "homepage": "https://github.com/zautumnz/js-drills#readme", 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/zautumnz/js-drills.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/zautumnz/js-drills/issues" 20 | }, 21 | "keywords": [], 22 | "devDependencies": { 23 | "eslint": "7.15.0", 24 | "husky": "4.3.5", 25 | "lint-staged": "10.5.3", 26 | "prettier": "2.2.1", 27 | "sortpack": "2.1.11" 28 | }, 29 | "lint-staged": { 30 | "*.js": [ 31 | "prettier --write" 32 | ], 33 | "package.json": [ 34 | "sortpack" 35 | ] 36 | }, 37 | "husky": { 38 | "hooks": { 39 | "pre-commit": "lint-staged" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /basic/sum-primes.js: -------------------------------------------------------------------------------- 1 | // write a function that sums all the prime numbers 2 | // below what you pass to it. example: 3 | // sumPrimes(10) // => 17 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | */ 63 | 64 | function sumPrimes(num) { 65 | function isPrime(number) { 66 | for (let current = number - 1; current > 1; current--) { 67 | if (number % current === 0) { 68 | return false 69 | } 70 | } 71 | return true 72 | } 73 | 74 | const arr = [] 75 | const counter = 0 76 | for (let i = num; i > 1; i--) { 77 | if (isPrime(i)) { 78 | arr.push(i) 79 | } 80 | } 81 | return arr.reduce(function (a, b) { 82 | return a + b 83 | }) 84 | } 85 | -------------------------------------------------------------------------------- /basic/sumRange.js: -------------------------------------------------------------------------------- 1 | // get the sum of a range of numbers 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | */ 59 | 60 | function range(start, end, step) { 61 | const arr = [] 62 | if (step < 0) { 63 | for (var i = start; i >= end; acum) { 64 | arr.push(i) 65 | var acum = typeof step !== 'undefined' ? (i += step) : i++ 66 | } 67 | } else { 68 | var acum = 0 69 | for (var i = start; i <= end; acum) { 70 | arr.push(i) 71 | var acum = typeof step !== 'undefined' ? (i += step) : i++ 72 | } 73 | } 74 | return arr 75 | } 76 | 77 | function sum(arr) { 78 | console.log(arr) 79 | let count = 0 80 | for (const element of arr) { 81 | count += element 82 | } 83 | return count 84 | } 85 | -------------------------------------------------------------------------------- /node/bare-http-server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // write a bare node HTTP server, and serve a string to the client! 4 | 5 | // this shebang is so we don't have to run this with 6 | // `node index.js` 7 | // in your terminal, `chmod +x index.js`, then you can just 8 | // do `./index.js` 9 | 10 | // you'll need to require node's built-in `http` module 11 | // which has a method calld `createServer` 12 | 13 | /* 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | */ 73 | 74 | const http = require('http') 75 | const port = 4444 76 | 77 | http 78 | .createServer((req, res) => { 79 | res.end('ok', 200) 80 | console.log('hi!') 81 | }) 82 | .listen(port) 83 | 84 | console.log(`listening on ${port}`) 85 | -------------------------------------------------------------------------------- /basic/sum-of-array-plus-one.js: -------------------------------------------------------------------------------- 1 | // Write a function that takes an array of integers and returns the sum of the 2 | // integers after adding 1 to each. || plusOneSum([1, 2, 3, 4]) // 14 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | */ 63 | 64 | var plusOneSum = function (arr) { 65 | var newArr = arr.slice() 66 | var sum = 0 67 | for (var i = 0; i < newArr.length; i++) { 68 | sum += newArr[i] + 1 69 | } 70 | return sum 71 | } 72 | 73 | var plus = function (arr) { 74 | var total = arr.reduce(function (a, b) { 75 | return a + b 76 | }) 77 | return (total += arr.length) 78 | } 79 | 80 | function plusOneSum(arr) { 81 | return arr.reduce(function (a, b) { 82 | return a + ++b 83 | }, 0) 84 | } 85 | -------------------------------------------------------------------------------- /basic/filter.js: -------------------------------------------------------------------------------- 1 | // rewrite filter as a standalone function 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | */ 63 | 64 | const filter = (pred, arr) => { 65 | let newArr = [] 66 | 67 | for (let i = 0; i < arr.length; ++i) { 68 | if (pred(arr[i])) { 69 | newArr[newArr.length] = arr[i] 70 | } 71 | } 72 | return newArr 73 | } 74 | 75 | const filter = (arr, cb) => { 76 | if (arr == null) return [] 77 | if (typeof cb !== 'function') { 78 | throw new TypeError('Boom!') 79 | } 80 | 81 | let len = arr.length 82 | let res = arr.slice() 83 | let i = 0 84 | 85 | while (len--) { 86 | if (!cb(arr[len], i++)) { 87 | res.splice(len, 1) 88 | } 89 | } 90 | 91 | return res 92 | } 93 | -------------------------------------------------------------------------------- /advanced/insertion-sort.js: -------------------------------------------------------------------------------- 1 | // implement an insertion sort 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | */ 51 | 52 | const insertionSort = (nums) => { 53 | for (let i = 1; i < nums.length; i++) { 54 | for (let j = 0; j < i; j++) { 55 | snapshot(nums) 56 | if (nums[i] < nums[j]) { 57 | let spliced = nums.splice(i, 1) 58 | nums.splice(j, 0, spliced[0]) 59 | } 60 | } 61 | } 62 | } 63 | 64 | const insertionSort = (array) => { 65 | if (array.length === 0 || !Array.isArray(array)) { 66 | throw new Error() 67 | } 68 | for (let i = 1; i < array.length; i++) { 69 | var tester = array[i], 70 | j = i 71 | while (j > 0 && tester <= array[j - 1]) { 72 | array[j] = array[j - 1] 73 | j-- 74 | } 75 | array[j] = tester 76 | } 77 | return array 78 | } 79 | -------------------------------------------------------------------------------- /basic/title-case-a-sentence.js: -------------------------------------------------------------------------------- 1 | // write a function that takes a string and capitalizes the first 2 | // letter of each word. words will be separated by one space. 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | */ 59 | 60 | function titleCase(str) { 61 | str = str.toLowerCase() 62 | str = str.split(' ') 63 | var newStr = '' 64 | for (var i = 0; i < str.length; i++) { 65 | str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1) 66 | newStr += str[i] + ' ' 67 | } 68 | return newStr.trim() 69 | } 70 | 71 | function titleCase(str) { 72 | var words = str.split(' ') 73 | for (var i = 0; i < words.length; i++) { 74 | var capitalized = words[i].charAt(0).toUpperCase() 75 | words[i] = capitalized + words[i].substring(1) 76 | } 77 | return words.join(' ') 78 | } 79 | -------------------------------------------------------------------------------- /intermediate/binary-to-text.js: -------------------------------------------------------------------------------- 1 | // write a function that converts binary to text 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | */ 56 | 57 | function binaryToText(str) { 58 | str = str.split(' ') 59 | let result = '' 60 | const current = 0 61 | for (const element of str) { 62 | const binary = parseInt(element, 2) 63 | const decimal = binary.toString(10) 64 | result += String.fromCharCode(decimal) 65 | } 66 | 67 | return result 68 | } 69 | 70 | binaryToText( 71 | '01001001 00100000 01100110 01100101 01100101 01101100 00100000 01101100 01101001 01101011 01100101 00100000 01100001 00100000 01110010 01100101 01100001 01101100 00101100 00100000 00110001 00110011 00110011 00110111 00100000 01001000 00110100 01011000 01011000 00110000 01010010 00100000 01101110 01101111 01110111 00101110' 72 | ) 73 | -------------------------------------------------------------------------------- /intermediate/target-sum.js: -------------------------------------------------------------------------------- 1 | // Given an array of integers and a target integer `sum`, return whether there 2 | // exist a pair of integers in the array which add up to `sum`. 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | */ 61 | 62 | function canMakeSum(array, targetSum) { 63 | array.sort() 64 | 65 | let left = 0 66 | let right = array.length - 1 67 | 68 | while (left < right) { 69 | const currentSum = array[left] + array[right] 70 | if (currentSum < targetSum) { 71 | left++ 72 | } else if (currentSum > targetSum) { 73 | right-- 74 | } else { 75 | return true 76 | } 77 | } 78 | 79 | return false 80 | } 81 | 82 | console.log(canMakeSum([-1, -2, 5, 0], -1)) 83 | console.log(canMakeSum([-1, -2, 5, 0], 6)) 84 | console.log(canMakeSum([], 6)) 85 | -------------------------------------------------------------------------------- /basic/fibonacci-finder.js: -------------------------------------------------------------------------------- 1 | // Write a function that accepts a number, n, and returns the nth Fibonacci 2 | // number. Use an interative solution to this problem; if you finish with 3 | // time left over, implement a recursive solution. 4 | // * nthFibonacci(2); // => 2 5 | // * nthFibonacci(3); // => 3 6 | // * nthFibonacci(4); // => 5 7 | 8 | /* 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | */ 71 | 72 | // iterative 73 | function fibIt(n) { 74 | const arr = [0, 1] 75 | for (let i = 2; i <= n + 1; i++) { 76 | arr.push(arr[i - 1] + arr[i - 2]) 77 | if (i === n + 1) { 78 | return arr[i] 79 | break 80 | } 81 | } 82 | } 83 | 84 | // recursive 85 | function fibRec(n) { 86 | return n < 2 ? n : fibRec(n - 2) + fibRec(n - 1) 87 | } 88 | -------------------------------------------------------------------------------- /intermediate/array-reorder.js: -------------------------------------------------------------------------------- 1 | // write fn that takes two arrays as 2 | // and reorders with respect to order 3 | // array = ['C', 'D', 'E', 'F', 'G'] 4 | // order = [3, 0, 4, 1, 2] 5 | // result = ['D', 'F', 'G', 'C', 'E'] 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | */ 63 | 64 | module.exports = (array, order) => { 65 | for (let i = 0, l = order.length; i < l; i += 1) { 66 | if (order[i] !== i) { 67 | const orderIndex = order[i] 68 | order[i] = order[orderIndex] 69 | order[orderIndex] = orderIndex 70 | ;[array[i], array[orderIndex]] = [array[orderIndex], array[i]] 71 | } 72 | } 73 | return array 74 | } 75 | 76 | const reorder = (arr, order) => { 77 | const res = [] 78 | order.forEach((i) => { 79 | res.push(arr[i]) 80 | }) 81 | return res 82 | } 83 | -------------------------------------------------------------------------------- /intermediate/case-utilities.js: -------------------------------------------------------------------------------- 1 | // convert camelCase to lisp-case 2 | // convert camelCase to snake_case 3 | // convert lisp-case to camelCase 4 | // convert snake_case to camelCase 5 | 6 | /* 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | */ 74 | 75 | export const camelToLisp = (str) => 76 | str.replace(/[A-Z]/g, (match) => '-' + match.toLowerCase()).toLowerCase() 77 | 78 | export const camelToSnake = (str) => 79 | str.replace(/[A-Z]/g, (match) => '_' + match.toLowerCase()).toLowerCase() 80 | 81 | export const lispToCamel = (str) => 82 | str.toLowerCase().replace(/-[a-z]/g, (match) => match.slice(1).toUpperCase()) 83 | 84 | export const snakeToCamel = (str) => 85 | str.replace(/(_\w)/g, (match) => match[1].toUpperCase()) 86 | -------------------------------------------------------------------------------- /intermediate/invert-binary-tree.js: -------------------------------------------------------------------------------- 1 | // invert a binary tree 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | * 82 | * 83 | * 84 | * 85 | * 86 | * 87 | * 88 | * 89 | * 90 | * 91 | * 92 | * 93 | * 94 | * 95 | * 96 | * 97 | * 98 | */ 99 | 100 | const invertTree = (tree) => { 101 | if (tree) { 102 | if (tree.left || tree.right) { 103 | const tmp = tree.left 104 | tree.left = tree.right 105 | tree.right = tmp 106 | invertTree(tree.left) 107 | invertTree(tree.right) 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /basic/map.js: -------------------------------------------------------------------------------- 1 | // rewrite map as a standalone function 2 | // usage: 3 | // const numbers = [1, 2, 3] 4 | // const doubles = map(numbers, number => number * 2) 5 | // console.log(doubles) // [2, 4, 6] 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | */ 57 | 58 | const map = (arr, mapper, ctx) => { 59 | const foo = [] 60 | for (let i = 0; i < arr.length; i++) { 61 | foo.push(mapper.call(ctx, arr[i], i, arr)) 62 | } 63 | return foo 64 | } 65 | 66 | const map = (fn, arr) => { 67 | let newArr = [] 68 | for (let i = 0; i < arr.length; ++i) { 69 | newArr[i] = fn(arr[i]) 70 | } 71 | return newArr 72 | } 73 | 74 | const map = (arr, fn) => { 75 | if (arr == null) return [] 76 | 77 | let len = arr.length 78 | let res = new Array(len) 79 | let i = -1 80 | 81 | while (++i < len) { 82 | res[i] = fn(arr[i], i, arr) 83 | } 84 | 85 | return res 86 | } 87 | -------------------------------------------------------------------------------- /intermediate/hex-to-dec.js: -------------------------------------------------------------------------------- 1 | // convert hex to decimal (base 16 to base 10) 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | */ 63 | 64 | const h2d = { 65 | 0: 0, 66 | 1: 1, 67 | 2: 2, 68 | 3: 3, 69 | 4: 4, 70 | 5: 5, 71 | 6: 6, 72 | 7: 7, 73 | 8: 8, 74 | 9: 9, 75 | A: 10, 76 | B: 11, 77 | C: 12, 78 | D: 13, 79 | E: 14, 80 | F: 15, 81 | } 82 | 83 | const hexToDecimal = (hex) => { 84 | const hexString = hex.split('') 85 | const len = hexString.length 86 | let result = 0 87 | let current 88 | for (let i = len - 1; i >= 0; i--) { 89 | if (typeof hexString[i] === 'string') { 90 | hexString[i] = hexString[i].toUpperCase() 91 | } 92 | current = hexString[i] 93 | result += h2d[current] * Math.pow(16, len - i - 1) 94 | } 95 | return result 96 | } 97 | -------------------------------------------------------------------------------- /intermediate/compose-pipe.js: -------------------------------------------------------------------------------- 1 | // write compose and pipe functions 2 | // compose should return a function that is the composition 3 | // of a list of functions, right to left 4 | // pipe should return the a function that is the result 5 | // of a series of functions called on the result of the previous 6 | // function, left to right 7 | 8 | /* 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | */ 66 | 67 | function compose() { 68 | const args = Array.prototype.slice.call(arguments) 69 | return function (val) { 70 | return args.reduceRight(function (memo, func) { 71 | return func(memo) 72 | }, val) 73 | } 74 | } 75 | 76 | function pipe() { 77 | const args = Array.prototype.slice.call(arguments) 78 | return function (val) { 79 | return args.reduce(function (memo, func) { 80 | return func(memo) 81 | }, val) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /intermediate/flatten-and-uniq.js: -------------------------------------------------------------------------------- 1 | // given an array of objects, flatten into an array of unique values 2 | const original = [ 3 | { a: 'foo', b: 10 }, 4 | { a: 'bar', b: 100 }, 5 | { a: 'foo', b: 101 }, 6 | ] 7 | 8 | // result should be: [ 'foo', 'bar' ] 9 | 10 | /* 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | * 82 | * 83 | * 84 | * 85 | * 86 | * 87 | * 88 | * 89 | * 90 | * 91 | * 92 | * 93 | * 94 | * 95 | * 96 | * 97 | */ 98 | 99 | const res = [...new Set(original.map(({ a }) => a))] 100 | 101 | // 102 | const uniq = (val, idx, self) => self.indexOf(val) === idx 103 | const res = original.map(({ a }) => a).filter(uniq) 104 | -------------------------------------------------------------------------------- /node/plain-html-server.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | 3 | // here we're going to serve the `index.html` file using just 4 | // built-in node modules 5 | // you'll be using `http` again, and also node's `fs` (filesystem). 6 | // remember `__dirname`? you'll want to use that, too. 7 | 8 | /* 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | */ 57 | 58 | const http = require('http') 59 | const fs = require('fs') 60 | const path = require('path') 61 | const index = path.resolve(__dirname, './index.html') 62 | const port = 4444 63 | 64 | http 65 | .createServer((req, res) => { 66 | const stream = fs.createReadStream(index) 67 | stream.on('open', () => { 68 | res.writeHead(200, { 'Content-Type': 'text/html' }) 69 | }) 70 | stream.on('error', () => { 71 | res.writeHead(400) 72 | res.end() 73 | }) 74 | stream.pipe(res) 75 | }) 76 | .listen(port) 77 | 78 | console.log(`running on ${port}`) 79 | -------------------------------------------------------------------------------- /basic/count.js: -------------------------------------------------------------------------------- 1 | // make this work 2 | var count = counter() 3 | count() // 1 4 | count() // 2 5 | count() // 3 6 | count() // 4 7 | 8 | // bonus: log the iterator after that many seconds 9 | var count = counter() 10 | count() 11 | count() 12 | count() 13 | count() 14 | // 1 (after 1 second) 15 | // 2 (after 2 seconds) 16 | // 3 (after 3 seconds) 17 | // 4 (after 4 seconds) 18 | 19 | function counter() { 20 | var x = 0 21 | return function () { 22 | return ++x 23 | } 24 | } 25 | 26 | function counter() { 27 | var count = 0 28 | return function () { 29 | count++ 30 | var delay = count * 1000 31 | setTimeout(function () { 32 | console.log(count) 33 | console.log('delay: ' + delay + ' ms') 34 | }, delay) 35 | } 36 | } 37 | 38 | function counter() { 39 | var count = 0 40 | return function () { 41 | count++ 42 | setTimeout( 43 | function (i) { 44 | console.log(i) 45 | }, 46 | count * 1000, 47 | count 48 | ) 49 | } 50 | } 51 | 52 | function counter() { 53 | var count = 0 54 | return function () { 55 | count++ 56 | setTimeout( 57 | function (i) { 58 | console.log(i) 59 | }.bind(null, count), 60 | count * 1000 61 | ) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /basic/vowel-count.js: -------------------------------------------------------------------------------- 1 | // write a function that takes a string and returns the total number of 2 | // vowels that the string contains. don't count `y`. example: 3 | // vowels('Hey, how are you?') // => 6 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | */ 67 | 68 | function vowels(str) { 69 | var vowels = 0 70 | for (var i = 0; i < str.length; i++) { 71 | switch (str[i].toLowerCase()) { 72 | case 'a': 73 | vowels++ 74 | break 75 | case 'e': 76 | vowels++ 77 | break 78 | case 'i': 79 | vowels++ 80 | break 81 | case 'o': 82 | vowels++ 83 | break 84 | case 'u': 85 | vowels++ 86 | } 87 | } 88 | return vowels 89 | } 90 | 91 | // regex version 92 | const vowels = (str = '') => (str.match(/[aeiou]/gi) || []).length 93 | -------------------------------------------------------------------------------- /intermediate/pig-latin.js: -------------------------------------------------------------------------------- 1 | // write a function that translates english to pig-latin 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | */ 60 | 61 | function translate(str) { 62 | const strArr = str.split('') 63 | const vowel = /[aeiou]/ 64 | if (vowel.test(strArr[0])) { 65 | return str + 'way' 66 | } 67 | while (true) { 68 | if (!vowel.test(strArr[0])) { 69 | strArr.push(strArr.splice(0, 1)) 70 | } else if (vowel.test(strArr[0])) { 71 | break 72 | } 73 | } 74 | return strArr.join('') + 'ay' 75 | } 76 | 77 | console.log(translate('consonant')) 78 | 79 | const pigLatin = (str) => { 80 | const a = [] 81 | str.split(' ').map((w) => { 82 | const b = w.split('') 83 | b.shift() 84 | const s = b.join('') 85 | a.push(`${s}${w[0]}ay`) 86 | }) 87 | return a.join(' ') 88 | } 89 | console.log(pigLatin('consonant')) 90 | -------------------------------------------------------------------------------- /basic/hashtable.js: -------------------------------------------------------------------------------- 1 | // implement a hash table using a class 2 | // it doesn't need to worry about collisions 3 | // it should have hashing, get, set, and remove methods 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | */ 60 | 61 | export default class HashTable { 62 | constructor() { 63 | this.memory = [] 64 | } 65 | 66 | hashKey(k) { 67 | let hash = 0 68 | for (let i = 0; i < k.length; i++) { 69 | const code = k.charCodeAt(i) 70 | hash = ((hash << 5) - hash + code) | 0 71 | } 72 | return hash 73 | } 74 | 75 | get(k) { 76 | const addr = this.hashKey(k) 77 | return this.memory[addr] 78 | } 79 | 80 | set(k, v) { 81 | const addr = this.hashKey(k) 82 | this.memory[addr] = v 83 | } 84 | 85 | remove(k) { 86 | const addr = this.hashKey(k) 87 | if (this.memory[addr]) { 88 | delete this.memory[addr] 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /intermediate/array-every-some.js: -------------------------------------------------------------------------------- 1 | // Write a function that takes a list of valid users and returns 2 | // a function that returns true if all of the list of users matches 3 | // a list of supplied users. 4 | // Use Array.some and Array.every 5 | // Do not use any for, while, or forEach loops. 6 | // Do not create any extra helper functions. 7 | 8 | // This is the array of known good users 9 | const goodUsers = [{ id: 1 }, { id: 4 }, { id: 12 }, { id: 9 }, { id: 123 }] 10 | 11 | /* 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | */ 61 | 62 | const checkUsers = (users) => (submittedUsers) => 63 | submittedUsers.every((maybeUser) => 64 | users.some((validUser) => validUser.id === maybeUser.id) 65 | ) 66 | 67 | // Test it 68 | const checkIfValid = checkUsers(goodUsers) // checkUsers is your function 69 | console.log('Should return true:', checkIfValid([{ id: 1 }, { id: 123 }])) 70 | 71 | console.log('Should return false:', checkIfValid([{ id: 5 }, { id: 999 }])) 72 | -------------------------------------------------------------------------------- /intermediate/tree.js: -------------------------------------------------------------------------------- 1 | // implement a tree 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | */ 76 | 77 | export class Tree { 78 | constructor() { 79 | this.root = null 80 | } 81 | 82 | traverse(cb) { 83 | function walk(node) { 84 | cb(node) 85 | node.children.forEach(walk) 86 | } 87 | walk(this.root) 88 | } 89 | 90 | add(val, parentVal) { 91 | const newNode = { 92 | value: val, 93 | children: [], 94 | } 95 | if (this.root === null) { 96 | this.root = newNode 97 | return 98 | } 99 | this.traverse((node) => { 100 | if (node.value === parentVal) { 101 | node.children.push(newNode) 102 | } 103 | }) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /basic/romanNumeralTranslator.js: -------------------------------------------------------------------------------- 1 | // take roman numeral as input. write function that converts this to regular number. 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | */ 54 | 55 | const numeralVals = { 56 | I: 1, 57 | V: 5, 58 | X: 10, 59 | L: 50, 60 | C: 100, 61 | D: 500, 62 | M: 1000, 63 | } 64 | 65 | function translateRomanNumeral(romanNumeral) { 66 | if (typeof romanNumeral !== 'string') { 67 | throw 'only strings acceptable!' 68 | } 69 | const text = romanNumeral.toUpperCase() 70 | for (var i = 0; i < text.length; i++) { 71 | if (!numeralVals[text[i]]) { 72 | throw 'enter valid numeral!' 73 | } 74 | } 75 | if (romanNumeral === '') { 76 | return 0 77 | } 78 | let sum = numeralVals[text[text.length - 1]] 79 | for (var i = text.length - 2; i >= 0; i--) { 80 | sum += 81 | getsign(numeralVals[text[i]] - numeralVals[text[i + 1]]) * 82 | numeralVals[text[i]] 83 | } 84 | return sum 85 | } 86 | 87 | function getsign(a) { 88 | return a < 0 ? -1 : 1 89 | } 90 | -------------------------------------------------------------------------------- /intermediate/graph.js: -------------------------------------------------------------------------------- 1 | // implement a basic graph using a class 2 | // it should have addNode, find, and addLine methods 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | */ 80 | 81 | export default class Graph { 82 | constructor() { 83 | this.nodes = [] 84 | } 85 | 86 | addNode(value) { 87 | this.nodes.push({ 88 | value, 89 | lines: [], 90 | }) 91 | } 92 | 93 | find(value) { 94 | return this.nodes.find((node) => node.value === value) 95 | } 96 | 97 | addLine(start, end) { 98 | const startNode = this.find(start) 99 | const endNode = this.find(end) 100 | if (!startNode || !endNode) { 101 | throw new Error('Need both nodes.') 102 | } 103 | startNode.lines.push(endNode) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /basic/randomize-array.js: -------------------------------------------------------------------------------- 1 | // given the following array, randomize (shuffle) it. 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | */ 64 | 65 | const students = [ 66 | 'Dan', 67 | 'Brack', 68 | 'Erin', 69 | 'Geordyn', 70 | 'Jess', 71 | 'Sarah', 72 | 'Andrew', 73 | 'Ryan', 74 | 'Tim', 75 | 'Stephen', 76 | 'David', 77 | 'Mark', 78 | ] 79 | 80 | function randomArray(arr) { 81 | function randomNumber() { 82 | return Math.floor(Math.random() * arr.length - 1) 83 | } 84 | const newArr = [] 85 | while (arr.length > 0) { 86 | newArr.push(arr.splice(randomNumber(), 1)[0]) 87 | } 88 | return newArr 89 | } 90 | 91 | function randomize(arr) { 92 | const randArr = [] 93 | function randomNum() { 94 | return Math.floor(Math.random() * arr.length - 1) 95 | } 96 | while (arr.length > 0) { 97 | randArr.push(arr.splice(randomNum(), 1)[0]) 98 | } 99 | return randArr 100 | } 101 | -------------------------------------------------------------------------------- /intermediate/bucket-sort.js: -------------------------------------------------------------------------------- 1 | // implement a bucket sort 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | */ 53 | 54 | const randomArray = function (size) { 55 | const array = [] 56 | for (let i = 0; i < size; i++) { 57 | array.push(parseInt(Math.random() * 100)) 58 | } 59 | return array 60 | } 61 | const bucketSort = function (array) { 62 | const buckets = [] 63 | for (var i = 0; i < 100; i++) { 64 | buckets[i] = 0 65 | } 66 | for (var i = 0; i < array.length; i++) { 67 | buckets[number]++ 68 | } 69 | let currentIndex = 0 70 | for (var number = 0; number < buckets.length; number++) { 71 | const count = buckets[number] 72 | for (let j = 0; j < count; j++) { 73 | array[currentIndex] = number 74 | currentIndex++ 75 | } 76 | } 77 | return array 78 | } 79 | const array = randomArray(5000) 80 | console.log(array) 81 | console.log('\n#########################################\n') 82 | bucketSort(array) 83 | console.log(array) 84 | console.log('\n#########################################\n') 85 | console.time('bucketSort') 86 | console.timeEnd('bucketSort') 87 | -------------------------------------------------------------------------------- /basic/xor.js: -------------------------------------------------------------------------------- 1 | // write a xor function (exclusive 'or'). example usage: 2 | // xor(false, false) // => false 3 | // xor(true, false) // => true 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | */ 73 | 74 | const xor = (a, b) => !a != !b 75 | 76 | // the above, just in more words 77 | function xor(x, y) { 78 | return !x != !y 79 | } 80 | 81 | // verbosely 82 | const xor = (val1, val2) => { 83 | if ((val1 && val2) || (!val1 && val2)) { 84 | return false 85 | } else { 86 | return true 87 | } 88 | } 89 | 90 | if ((foo && !bar) || (!foo && bar)) { 91 | // quux, baz 92 | } 93 | 94 | // ternary operator 95 | const xor = (thingOne, thingTwo) => { 96 | if (thingOne ? !thingTwo : thingTwo) { 97 | return true 98 | } 99 | return false 100 | } 101 | 102 | // using the bitwise XOR 103 | function XOR(x, y) { 104 | return (x ? 1 : 0) ^ (y ? 1 : 0) 105 | } 106 | -------------------------------------------------------------------------------- /intermediate/mad-lib.js: -------------------------------------------------------------------------------- 1 | // Write a mad-lib text generator. You're provided with a template 2 | // and some words. Your function should fill the appropriate type 3 | // of word into the template, at random. 4 | 5 | const template = 6 | 'The ${adjective} brown ${noun} ${adverb} ' + 7 | '${verb} the ${adjective} yellow ' + 8 | '${noun}, who ${adverb} ${verb} his ' + 9 | '${noun} and looks around.' 10 | 11 | const words = { 12 | adjective: ['quick', 'lazy', 'sleepy', 'noisy', 'hungry'], 13 | noun: ['fox', 'dog', 'head', 'leg', 'tail'], 14 | verb: ['jumps', 'lifts', 'bites', 'licks', 'pats'], 15 | adverb: ['easily', 'lazily', 'noisily', 'excitedly'], 16 | } 17 | 18 | /* 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | */ 76 | 77 | const madLib = () => { 78 | const replaceText = (match) => { 79 | const key = match.replace(/[^a-z]/g, '') 80 | const index = Math.floor(Math.random() * words[key].length) 81 | return words[key][index] 82 | } 83 | 84 | return template.replace(/\${[a-z]+}/g, replaceText) 85 | } 86 | 87 | console.log(madLib()) 88 | -------------------------------------------------------------------------------- /basic/bytes-to-friendly-sizes.js: -------------------------------------------------------------------------------- 1 | // convert long numbers to friendly, readable sizes 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | */ 50 | 51 | function bytesToSize(bytes) { 52 | const size = ['Bytes', 'KB', 'MB', 'GB', 'TB'] 53 | if (bytes === 0) { 54 | return '0 Bytes' 55 | } 56 | const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))) 57 | return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes 58 | } 59 | 60 | function formatBytes(bytes, decimals) { 61 | if (bytes === 0) { 62 | return '0 Bytes' 63 | } 64 | const k = 1000 65 | const dm = decimals + 1 || 3 66 | const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] 67 | const i = Math.floor(Math.log(bytes) / Math.log(k)) 68 | return (bytes / Math.pow(k, i)).toPrecision(dm) + ' ' + sizes[i] 69 | } 70 | 71 | function convertBytes(input, precision) { 72 | const suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] 73 | let index = 0 74 | const factor = Math.pow(10, precision > 0 ? precision : 2) 75 | 76 | while (input >= 1024 && suffixes[++index]) { 77 | input /= 1024 78 | } 79 | return Math.round(input * factor) / factor + ' ' + suffixes[index] 80 | } 81 | -------------------------------------------------------------------------------- /basic/fibonacci.js: -------------------------------------------------------------------------------- 1 | // write a function that generates an array of fibonacci numbers 2 | // the length of the array should be user selectable 3 | 4 | // bonus: the function should let the user select fibonacci, tribonacci, etc..., as well as length 5 | // bonus: make it recursive 6 | // fib(11,2) would give [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ] (first 11 fib #'s) 7 | // fib(11,3) would give [ 0, 1, 1, 2, 4, 7, 13, 24, 44, 81, 149 ] (first 11 trib #'s) 8 | 9 | /* 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | */ 61 | 62 | function nFib(len, n, res) { 63 | let temp = n 64 | if (!arguments[2]) { 65 | res = [0, 1] 66 | } 67 | if (len === res.length) { 68 | return res 69 | } 70 | if (n > res.length) { 71 | temp = res.length 72 | } 73 | let pushArr = 0 74 | for (let i = res.length - 1; i > res.length - temp - 1; i--) { 75 | pushArr += res[i] 76 | } 77 | res.push(pushArr) 78 | return nFib(len, n, res) 79 | } 80 | 81 | function fib(len, res) { 82 | if (!arguments[1]) { 83 | res = [0, 1] 84 | } 85 | if (len === res.length) { 86 | return res 87 | } 88 | res.push(res[res.length - 1] + res[res.length - 2]) 89 | return fib(len, res) 90 | } 91 | -------------------------------------------------------------------------------- /basic/primes.js: -------------------------------------------------------------------------------- 1 | // sum the first 1000 primes: 2 | // determine if number is prime, 3 | // the loop through and summarize all primes until we have 1000 of them. 4 | // var numPrimes = 0 5 | // , sumPrimes = 0 6 | // , i = 2 7 | // function isPrime(num){ 8 | // for(var x = 2; x <= Math.rount(num/2); x++){ 9 | // if(num % x === 0){ 10 | // return false 11 | // } 12 | // } return true 13 | // } 14 | // while(numPrimes < 1000){ 15 | // if(isPrime(i)){ 16 | // sumPrimes += 1 17 | // numPrimes++ 18 | // } 19 | // i++ 20 | // } 21 | 22 | /* 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | */ 78 | 79 | let numPrimes = 1 80 | let sumPrimes = 2 81 | let i = 3 82 | function isPrime(num) { 83 | if (num % 2 === 0) { 84 | return false 85 | } 86 | for (let x = 3; x <= Math.round(num / 2); x += 2) { 87 | if (num % x === 0) { 88 | return false 89 | } 90 | return true 91 | } 92 | } 93 | while (numPrimes < 1000) { 94 | if (isPrime(i)) { 95 | sumPrimes += 1 96 | numPrimes++ 97 | } 98 | i++ 99 | } 100 | -------------------------------------------------------------------------------- /intermediate/eventingLibrary.js: -------------------------------------------------------------------------------- 1 | // make an event system function that adds a .on() and .trigger() 2 | // to any object passed to it 3 | 4 | // example usage: 5 | // const z = { name : 'z' , age : 0 } 6 | // z.on('growingOlder', () => console.log(`i'm now ${z.age}`)) 7 | // z.age++ 8 | // z.trigger('growingOlder') 9 | 10 | /* 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | * 82 | * 83 | * 84 | * 85 | * 86 | * 87 | * 88 | * 89 | */ 90 | 91 | const mixEvents = (obj) => { 92 | const eventsMap = {} 93 | 94 | obj.on = (eventName, cb) => { 95 | eventsMap[eventName] = eventsMap[eventName] || [] 96 | eventsMap[eventName].push(cb) 97 | } 98 | 99 | obj.trigger = (eventName) => { 100 | const args = Array.prototype.slice.call(arguments, 1) 101 | const arrayOfCb = eventsMap[eventName] || [] 102 | arrayOfCb.forEach(function (cb) { 103 | cb.apply(obj, args) 104 | }) 105 | } 106 | return obj 107 | } 108 | -------------------------------------------------------------------------------- /basic/rps-sol.js: -------------------------------------------------------------------------------- 1 | // write a function that generates every sequence 2 | // a single player could throw over a 3-round game 3 | // of rock-paper-scissors 4 | // 5 | // Example: 6 | // [ 7 | // [ // one possible three round game outcome 8 | // 'rock', // round 1 9 | // 'paper', // round 2 10 | // 'scissors' // round 3 11 | // ], 12 | // [ // next possible three round game outcome 13 | // 'rock', // round 1 14 | // 'paper', // round 2 15 | // 'rock' // round 3 16 | // ], 17 | // etc... 18 | // ] 19 | // 20 | 21 | /* 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | */ 77 | 78 | function rps() { 79 | const rounds = 3 80 | let combinations = 0 81 | const result = [] 82 | const options = ['rock', 'paper', 'scissors'] 83 | for (let i = 0; i < rounds; i++) { 84 | for (let j = 0; j < rounds; j++) { 85 | for (let k = 0; k < options.length; k++) { 86 | result.push([options[i], options[j], options[k]]) 87 | combinations++ 88 | } 89 | } 90 | } 91 | console.log('combinations:', combinations) 92 | console.log(result) 93 | return result 94 | } 95 | 96 | rps() 97 | -------------------------------------------------------------------------------- /basic/combinator.js: -------------------------------------------------------------------------------- 1 | // Write a function called combinator that is given two arrays as arguments. 2 | // The first array is an array of first names, and the second array is an 3 | // array of last names. Have the function return a new array combining 4 | // the first names and the last names. 5 | 6 | // combinator([‘Jason', ‘Dan’, ‘Cahlan’], [‘Turner’, ‘Kesler’, ‘Sharp’]); → 7 | // [‘Jason Turner’, ‘Dan Kesler’, ‘Cahlan Sharp’] 8 | 9 | /* 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | */ 57 | 58 | function combinator(arr1, arr2) { 59 | var newArr = [] 60 | for (var i = 0; i < arr1.length; i++) { 61 | for (var j = 0; j < arr2.length; j++) { 62 | if (i === j) { 63 | newArr.push(arr1[i] + ' ' + arr2[j]) 64 | } 65 | } 66 | } 67 | 68 | return newArr 69 | } 70 | 71 | function combinator(arr1, arr2) { 72 | var newArr = [] 73 | for (var i = 0; i < arr1.length; i++) { 74 | newArr.push(arr1[i] + ' ' + arr2[i]) 75 | } 76 | 77 | return newArr 78 | } 79 | 80 | function combinator(arr1, arr2) { 81 | return arr1.map(function (val, i, arr) { 82 | return val + ' ' + arr2[i] 83 | }) 84 | } 85 | 86 | const combinator = (first, last) => 87 | first.map((item, index) => `${item} ${last[index]}`) 88 | -------------------------------------------------------------------------------- /basic/reverse-array.js: -------------------------------------------------------------------------------- 1 | // write a function that reverses the contents of an array 2 | // bonus points: 3 | // try reversing it in place (without creating a new array). example: 4 | // reverseArray([1, 8, 39, null, 2, 9, 'bob'])[0] // should equal => 'bob' 5 | 6 | /* 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | * 82 | * 83 | */ 84 | 85 | const reverse = (a) => a.reverse() 86 | 87 | // 88 | var reverseArray = function (array) { 89 | const result = [] 90 | while (array.length > 0) { 91 | result.push(array.pop()) 92 | } 93 | return result 94 | } 95 | 96 | // 97 | var reverseArray = function (array) { 98 | let start = 0 99 | let end = array.length - 1 100 | while (start < end) { 101 | swap(array, start, end) 102 | start += 1 103 | end -= 1 104 | } 105 | return array 106 | } 107 | 108 | var swap = function (array, i, j) { 109 | const temp = array[i] 110 | array[i] = array[j] 111 | array[j] = temp 112 | } 113 | -------------------------------------------------------------------------------- /basic/primenumbers.js: -------------------------------------------------------------------------------- 1 | // write a function that accepts a number and returns a boolean based on whether it's a prime number 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | */ 75 | 76 | function primeFinder(num) { 77 | for (let i = 2; i < num; i++) { 78 | if (num % i === 0 && i !== num) { 79 | return false 80 | } 81 | } 82 | return true 83 | } 84 | 85 | function primeFinder(num) { 86 | if (num % 2 === 0) { 87 | return false 88 | } 89 | let middle = ~~Math.sqrt(num) 90 | for (let i = 3; i <= middle; i += 2) { 91 | if (num % i === 0) { 92 | return false 93 | } 94 | } 95 | return true 96 | } 97 | 98 | function primeFinder(num) { 99 | if (num === 2) { 100 | return true 101 | } 102 | if (num < 2 || !(num & 1)) { 103 | return false 104 | } 105 | for (let i = 3, l = Math.floor(Math.pow(num, 0.5)); i <= l; i += 2) { 106 | if (num % i === 0) { 107 | return false 108 | } 109 | } 110 | return true 111 | } 112 | -------------------------------------------------------------------------------- /advanced/async-map.js: -------------------------------------------------------------------------------- 1 | // implement a function asyncMap. 2 | // takes two params: array of tasks, callback. 3 | // each task takes separate cb, invokes when complete. 4 | // cb passed to asyncMap is performed on results of cbs of tasks. 5 | // order of results should be same as order of tasks. 6 | // once all cbs are returned, asyncMap should invoke cb on results array. 7 | // example: 8 | // asyncMap([ 9 | // function(cb){ 10 | // setTimeout(function(){ 11 | // cb('one') 12 | // }, 200) 13 | // }, 14 | // function(cb){ 15 | // setTimeout(function(){ 16 | // cb('two') 17 | // }, 100) 18 | // } 19 | // ], 20 | // function(results){ 21 | // // the results array will equal ['one','two'] even though 22 | // // the second function had a shorter timeout. 23 | // console.log(results); // ['one', 'two'] 24 | // }) 25 | 26 | /* 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | */ 68 | 69 | const asyncMap = (tasks, callback) => { 70 | const resultsArray = [] 71 | let resultsCount = 0 72 | 73 | for (let i = 0; i < tasks.length; i++) { 74 | ;((i) => { 75 | tasks[i]((val) => { 76 | resultsArray[i] = val 77 | resultsCount++ 78 | if (resultsCount === tasks.length) { 79 | callback(resultsArray) 80 | } 81 | }) 82 | })(i) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /intermediate/ycomb.js: -------------------------------------------------------------------------------- 1 | // write the y combinator in javascript. 2 | // then write a function that calculates the factorial of a 3 | // number using the y combinator. 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | */ 78 | 79 | function Y(X) { 80 | return (function (procedure) { 81 | return X(function (arg) { 82 | return procedure(procedure)(arg) 83 | }) 84 | })(function (procedure) { 85 | return X(function (arg) { 86 | return procedure(procedure)(arg) 87 | }) 88 | }) 89 | } 90 | 91 | // or 92 | const Y = (f) => ((p) => f((a) => p(p)(a)))((p) => f((a) => p(p)(a))) 93 | 94 | // or 95 | const Y = function (f) { 96 | return (function (g) { 97 | return g(g) 98 | })(function (h) { 99 | return function () { 100 | return f(h(h)).apply(null, arguments) 101 | } 102 | }) 103 | } 104 | 105 | const factorial = Y((a) => (x) => (x === 0 ? 1 : x * a(x - 1))) 106 | 107 | // 108 | const Y = (f) => ((x) => x(x))((x) => f((y) => x(x)(y))) 109 | -------------------------------------------------------------------------------- /advanced/queue-stack.js: -------------------------------------------------------------------------------- 1 | // write a stack 2 | // avoid native array methods 3 | // then implement a queue using two of your stacks 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | */ 64 | 65 | function Stack() { 66 | const storage = [] 67 | let length = 0 68 | this.push = function () { 69 | storage[length] = arguments[0] 70 | length++ 71 | } 72 | this.pop = function () { 73 | if (length) { 74 | const result = storage[length - 1] 75 | delete storage[length - 1] 76 | length-- 77 | return result 78 | } 79 | } 80 | this.size = function () { 81 | return length 82 | } 83 | } 84 | 85 | function Queue() { 86 | const inbox = new Stack() 87 | const outbox = new Stack() 88 | this.enqueue = function () { 89 | inbox.push.apply(arguments) 90 | } 91 | this.dequeue = function () { 92 | if (outbox.size() === 0) { 93 | while (inbox.size() !== 0) { 94 | outbox.push(inbox.pop()) 95 | } 96 | } 97 | return outbox.pop() 98 | } 99 | this.size = function () { 100 | return inbox.size() + outbox.size() 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /node/cp.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // node's `fs` is really swell. check out the API docs on 4 | // it's `createReadStream()` and `createWriteStream()` methods. 5 | // here we're going to rewrite `cp` (the copy utility) using `fs`. 6 | // you'll need to import `fs`, and use `process.argv` 7 | // argv = 'argument vector'. it's an array of arguments from the command line. 8 | // the first two are always `node` and the full path of the file you're running 9 | // (`/home/z/work/current/node-drills/` for example). so you'll need to start 10 | // grabbing arguments at the third index. 11 | // let's assume you're just copying one file to another. to run this you might do: 12 | // `./index.js somefile aCopyOfThatFile` 13 | 14 | /* 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | */ 63 | 64 | const fs = require('fs') 65 | const from = process.argv[2] 66 | const to = process.argv[3] 67 | const readFrom = fs.createReadStream(from) 68 | const writeTo = fs.createWriteStream(to) 69 | 70 | console.log(from, '===>', to) 71 | 72 | readFrom.on('data', (chunk) => { 73 | writeTo.write(chunk) 74 | }) 75 | readFrom.on('end', () => { 76 | writeTo.end() 77 | }) 78 | readFrom.on('error', (err) => { 79 | console.log('error!', err) 80 | }) 81 | writeTo.on('error', (err) => { 82 | console.log('error!', err) 83 | }) 84 | -------------------------------------------------------------------------------- /node/ip-server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // write a small server that just echos the user's IP address 4 | // bonus: allow JSON 5 | // don't use any third-party libs (just core node) 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | */ 61 | 62 | const http = require('http') 63 | const dns = require('dns') 64 | const port = process.env.PORT || 5000 65 | 66 | http 67 | .createServer((req, res) => { 68 | let ip 69 | if (req.method === 'GET') { 70 | ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress 71 | dns.reverse(ip, handleResponse) 72 | } else { 73 | res.writeHeader(501) 74 | res.end() 75 | } 76 | 77 | function handleResponse(error, domains) { 78 | switch (req.headers.accept) { 79 | case 'application/json': 80 | const data = { ip: ip } 81 | if (!error && domains.length > 1) { 82 | data.hostname = domains[0] 83 | } 84 | res.writeHead(200, { 'content-type': 'application/json' }) 85 | res.write(JSON.stringify(data)) 86 | res.end() 87 | break 88 | default: 89 | res.writeHead(200, { 'content-type': 'text/plain' }) 90 | res.write(ip) 91 | res.end() 92 | } 93 | } 94 | }) 95 | .listen(port) 96 | -------------------------------------------------------------------------------- /advanced/ajax-vanilla.js: -------------------------------------------------------------------------------- 1 | // rewrite $.get (ajax) in vanilla js 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | */ 35 | 36 | function get(url, responseType) { 37 | return new Promise(function (resolve, reject) { 38 | const request = new XMLHttpRequest() 39 | request.open('GET', url) 40 | request.responseType = responseType 41 | request.onload = function () { 42 | if (request.status == 200) { 43 | resolve(request.response) 44 | } else { 45 | reject(new Error(request.statusText)) 46 | } 47 | } 48 | request.onerror = function () { 49 | reject(new Error('Network Error')) 50 | } 51 | request.send() 52 | }) 53 | } 54 | 55 | // and, somewhere else: 56 | get('url/api/something', 'text').then(function (x) { 57 | console.log(x) // do stuff, i guess 58 | }) 59 | 60 | // or 61 | 62 | // post 63 | var request = new XMLHttpRequest() 64 | request.open('POST', '/some/thing', true) 65 | request.setRequestHeader( 66 | 'Content-Type', 67 | 'application/x-www-form-urlencoded; charset=UTF-8' 68 | ) 69 | request.send(data) 70 | 71 | // json 72 | var request = new XMLHttpRequest() 73 | request.open('GET', '/as/df', true) 74 | request.onload = function () { 75 | if (request.status >= 200 && request.status < 400) { 76 | const data = JSON.parse(request.responseText) 77 | } else { 78 | console.log('hmph.') 79 | } 80 | } 81 | request.onerror = function () { 82 | console.error('whoops') 83 | } 84 | request.send() 85 | -------------------------------------------------------------------------------- /node/express/2/index.js: -------------------------------------------------------------------------------- 1 | // Try writing a basic API server. 2 | // You'll need express and body-parser 3 | // Have a GET, POST, PUT, an DELETE, 4 | // and use a mock database (you can just use an array or object) 5 | 6 | /* 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | */ 66 | 67 | const express = require('express') 68 | const bodyparser = require('body-parser') 69 | const items = ['this thing', 'that thing', 'the other thing', "'sup?"] 70 | const app = express() 71 | const port = process.env.PORT || 9999 72 | 73 | app.use(bodyparser.json()) 74 | 75 | app.get('/items', (req, res) => { 76 | console.log(req.body) 77 | res.send(items) 78 | }) 79 | 80 | app.post('/items', (req, res) => { 81 | items.push(req.body.name) 82 | console.log(req.body) 83 | res.send(items) 84 | }) 85 | 86 | app.put('/items', (req, res) => { 87 | const newPosition = req.body.position 88 | items[newPosition] = req.body.newName 89 | res.send(items) 90 | }) 91 | 92 | app.delete('/items/:id', (req, res) => { 93 | console.log(req.params) 94 | items.splice(req.params.id, 1) 95 | res.send(items) 96 | }) 97 | 98 | app.listen(port, () => { 99 | console.log('listening on', port) 100 | }) 101 | -------------------------------------------------------------------------------- /basic/funcArray.js: -------------------------------------------------------------------------------- 1 | // make this work 2 | funcArray[0]() // 0 3 | funcArray[1]() // 1 4 | funcArray[2]() // 2 5 | funcArray[3]() // 3 6 | funcArray[4]() // 4 7 | funcArray[5]() // 5 8 | // 9 | 10 | /* 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | */ 72 | 73 | function funcArray(nums) { 74 | let newArr = [] 75 | for (let i = 0; i < nums; i++) { 76 | let num = i 77 | newArr.push(() => num) 78 | } 79 | return newArr 80 | } 81 | 82 | function funcArray(nums) { 83 | var newArr = [] 84 | for (var i = 0; i < nums; i++) { 85 | newArr.push( 86 | function (num) { 87 | return num 88 | }.bind(null, i) 89 | ) 90 | } 91 | return newArr 92 | } 93 | 94 | function funcArray(nums) { 95 | var newArr = [] 96 | for (var i = 0; i < nums; i++) { 97 | newArr.push( 98 | (function (num) { 99 | return function () { 100 | return num 101 | } 102 | })(i) 103 | ) 104 | } 105 | return newArr 106 | } 107 | 108 | function funcArray(nums) { 109 | return Array.from(Array(nums)) 110 | .map((el, ind) => ind) 111 | .map((el) => { 112 | let x = el 113 | return () => x 114 | }) 115 | } 116 | -------------------------------------------------------------------------------- /intermediate/insert-at-index.js: -------------------------------------------------------------------------------- 1 | // write a function that will allow you to insert 2 | // a given word into phrase at index 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | */ 70 | 71 | function insertAtIndexes(phrase, word, indexes) { 72 | let insertionOffset = 0 73 | for (const element of indexes) { 74 | // slices first param for 0 characters, at the index specified. 75 | // inserts second param at that index, then concats the rest of the first param onto the end of that. 76 | // repeats for each element in indices array. 77 | phrase = 78 | phrase.slice(0, element + insertionOffset) + 79 | word + 80 | phrase.slice(element + insertionOffset) 81 | // advances offset by the second param's length so as not to get things all out of order 82 | insertionOffset += word.length 83 | } 84 | return phrase 85 | } 86 | 87 | const insertAtIndices = (phrase, word, indices) => { 88 | // takes indices array, reverses. 89 | // map just performs the passed in function for each element in that array. 90 | indices.reverse().map((val) => { 91 | // does the same sort of slicing and inserting as above. 92 | phrase = phrase.slice(0, val) + word + phrase.slice(val) 93 | }) 94 | return phrase 95 | } 96 | -------------------------------------------------------------------------------- /advanced/memoize.js: -------------------------------------------------------------------------------- 1 | // write a memoizing function 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | */ 52 | 53 | export const memoizeSimple = (fn) => { 54 | let cachedArg 55 | let cachedRes 56 | return (arg) => { 57 | if (cachedArg === arg) { 58 | return cachedRes 59 | } 60 | cachedArg = arg 61 | cachedRes = fn(arg) 62 | return cachedRes 63 | } 64 | } 65 | 66 | export const memoizeWithCache = (fn) => (arg, memoCache) => { 67 | if (memoCache.arg === arg) { 68 | return memoCache.res 69 | } 70 | const res = fn(arg) 71 | memoCache.arg = arg 72 | memoCache.res = res 73 | return res 74 | } 75 | 76 | export function memoize(fn) { 77 | const cache = {} 78 | const fnVal = function (val) { 79 | return val 80 | } 81 | return function () { 82 | const key = fnVal.apply(this, arguments) 83 | if (key in cache) { 84 | return cache[key] 85 | } else { 86 | const v = fn.apply(this, arguments) 87 | cache[key] = v 88 | return v 89 | } 90 | } 91 | } 92 | 93 | function memoize(fn) { 94 | var cache = {} 95 | return function (n) { 96 | var key = JSON.stringify([].slice.call(arguments)) 97 | if (!(key in cache)) { 98 | cache[key] = fn.apply(null, arguments) 99 | } 100 | 101 | return cache[key] 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /basic/factorial.js: -------------------------------------------------------------------------------- 1 | // write a function that that takes a number and returns 2 | // its factorial. example: 3 | // `factorial(4)` // => 24 (4 * 3 * 2 * 1 = 24) 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | */ 67 | 68 | function factorial(num) { 69 | if (num < 0) { 70 | return -1 71 | } else if (num === 0) { 72 | return 1 73 | } else { 74 | console.log(num) 75 | return num * factorial(num - 1) 76 | } 77 | } 78 | 79 | var factorial = function (n) { 80 | if (result < 2) { 81 | return 1 82 | } 83 | var result = 1 84 | for (var i = 2; i <= n; i++) { 85 | result *= i 86 | } 87 | return result 88 | } 89 | 90 | function factorial(num) { 91 | if (num === 1) { 92 | return 1 93 | } else if (num === 0 || num < 0) { 94 | return 0 95 | } 96 | return num * factorial(num - 1) 97 | } 98 | 99 | // using a generator 100 | function* factorial(n) { 101 | let result = 1 102 | for (let i = 1; i <= n; i++) { 103 | result *= i 104 | yield result 105 | } 106 | } 107 | // and then 108 | for (let f of factorial(number)) { 109 | console.log(f) // or whatever 110 | } 111 | 112 | // pure lambda expression 113 | ;((f) => f(f))((f) => (n) => (n === 0 ? 1 : n * f(f)(n - 1))) 114 | -------------------------------------------------------------------------------- /node/rock-paper-scissors.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // write a rock-paper-scissors game in node! 4 | // we'll want to run it like `./rock-paper-scissors.js rock` 5 | // (or paper, or scissors, obviously). 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | */ 60 | 61 | const rpc = (arg) => { 62 | const choices = ['Rock', 'Paper', 'Scissors'] 63 | const title = arg 64 | arg = arg.toLowerCase() 65 | const random = () => Math.floor(Math.random() * 3) 66 | const ans = choices[random()] 67 | 68 | if (arg === ans.toLowerCase()) { 69 | return `Tie! ${title} vs. ${ans}.` 70 | } 71 | if (ans === 'Paper') { 72 | if (arg === 'rock') { 73 | return `${title} lost to ${ans}.` 74 | } 75 | 76 | if (arg === 'scissors') { 77 | return `${title} beat ${ans}.` 78 | } 79 | } 80 | 81 | if (ans === 'Rock') { 82 | if (arg === 'paper') { 83 | return `${title} beat ${ans}.` 84 | } 85 | 86 | if (arg === 'scissors') { 87 | return `${title} lost to ${ans}.` 88 | } 89 | } 90 | 91 | if (ans === 'Scissors') { 92 | if (arg === 'rock') { 93 | return `${title} beat ${ans}.` 94 | } 95 | 96 | if (arg === 'paper') { 97 | return `${title} lost to ${ans}.` 98 | } 99 | } 100 | } 101 | 102 | console.log(rpc(process.argv[2])) 103 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *$py.class 2 | *.7z 3 | *.aux 4 | *.bz2 5 | *.chi 6 | *.chs.h 7 | *.class 8 | *.dat 9 | *.dyn_hi 10 | *.dyn_o 11 | *.egg 12 | *.elf 13 | *.eventlog 14 | *.gz 15 | *.hi 16 | *.hp 17 | *.jar 18 | *.key 19 | *.ko 20 | *.lock 21 | *.log 22 | *.o 23 | *.obj 24 | *.out 25 | *.pid 26 | *.prof 27 | *.py[cod] 28 | *.seed 29 | *.so 30 | *.so.* 31 | *.swp 32 | *.tar 33 | *.tmp 34 | *~ 35 | .AppleDB 36 | .AppleDesktop 37 | .AppleDouble 38 | .DS_Store 39 | .DocumentRevisions-V100 40 | .HTF/ 41 | .LSOverride 42 | .Spotlight-V100 43 | .TemporaryItems 44 | .Trashes 45 | .VolumeIcon.icns 46 | ._* 47 | ._.DS_Store 48 | .apdisk 49 | .bower-cache 50 | .bower-registry 51 | .bower-tmp 52 | .cabal-sandbox/ 53 | .completer.hist 54 | .fseventsd 55 | .grunt 56 | .hpc 57 | .hsenv 58 | .idea 59 | .lein-deps-sum 60 | .lein-failures 61 | .lein-plugins/ 62 | .lein-repl-history 63 | .lock-wscript 64 | .merlin 65 | .netrwhist 66 | .nrepl-port 67 | .psci* 68 | .pulp-cache 69 | .sass-cache 70 | .stack-work/ 71 | .vimsession~ 72 | .virtualenv 73 | .vscode 74 | /.build/ 75 | /checkouts/ 76 | /classes/ 77 | Icon 78 | Network Trash Folder 79 | Temporary Items 80 | __pycache__/ 81 | _build/ 82 | _references.js 83 | bower_components 84 | build.js 85 | build/Release 86 | bundle 87 | bundle.js 88 | cabal-dev 89 | cabal.project.local 90 | cabal.sandbox.config 91 | coverage 92 | data 93 | db 94 | dist 95 | dist-* 96 | lib-cov 97 | logs 98 | node_modules 99 | npm-debug.log* 100 | output 101 | pids 102 | pom.xml 103 | pom.xml.asc 104 | public/lib 105 | src/.webpack.js 106 | x/ 107 | .nyc_output 108 | /tags 109 | target/ 110 | **/*.rs.bak 111 | !Cargo.lock 112 | core 113 | .terraform/ 114 | *.tfstate* 115 | *.tfvars 116 | -------------------------------------------------------------------------------- /node/express/3/index.js: -------------------------------------------------------------------------------- 1 | // write a server that will run a game of rock-paper-scissors 2 | // be able to send a post request (to, for example, '/play') with a choice 3 | // of rock, paper, or scissors, and have the server respond with whether 4 | // you've won or lost against the computer. 5 | // you'll need express and body-parser for this. 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | */ 47 | 48 | const express = require('express') 49 | const bodyParser = require('body-parser') 50 | const app = express() 51 | const port = process.env.PORT || 3000 52 | const options = ['rock', 'paper', 'scissors'] 53 | 54 | const determineWinner = (human, computer) => { 55 | if (human === 'rock' && computer === 'scissors') { 56 | return 'human' 57 | } else if (human === 'scissors' && computer === 'paper') { 58 | return 'human' 59 | } else if (human === 'paper' && computer === 'rock') { 60 | return 'human' 61 | } else { 62 | return 'computer' 63 | } 64 | } 65 | 66 | app.use(bodyParser.json()) 67 | 68 | app.post('/play', (req, res) => { 69 | if (!req.body.choice) { 70 | return res.status(500).json('make a choice!') 71 | } 72 | 73 | const humanChoice = req.body.choice 74 | const index = Math.floor(Math.random() * options.length) 75 | const computerChoice = options[index] 76 | let result 77 | 78 | result = 79 | req.body.choice === computerChoice 80 | ? 'tie' 81 | : determineWinner(humanChoice, computerChoice) 82 | console.log(computerChoice) 83 | res.json(result) 84 | }) 85 | 86 | app.listen(port, () => { 87 | console.log('listening on port:', port) 88 | }) 89 | -------------------------------------------------------------------------------- /basic/functions-only-once.js: -------------------------------------------------------------------------------- 1 | // run a function only once 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | */ 64 | 65 | var something = (function () { 66 | var executed = false 67 | return function () { 68 | if (!executed) { 69 | executed = true 70 | // do something 71 | } 72 | } 73 | })() 74 | 75 | var a = (function () { 76 | var randomValue 77 | return function (flagForceNewValue) { 78 | if (randomValue === undefined || flagForceNewValue) { 79 | randomValue = Math.floor(Math.random() * (10 - 1) + 1) 80 | } 81 | return randomValue 82 | } 83 | })() 84 | 85 | function once(func) { 86 | return function () { 87 | var f = func 88 | func = null 89 | return f.apply(this, arguments) 90 | } 91 | } 92 | 93 | function once(fn, context) { 94 | var result 95 | return function () { 96 | if (fn) { 97 | result = fn.apply(context || this, arguments) 98 | fn = null 99 | } 100 | return result 101 | } 102 | } 103 | 104 | export default function once(fn) { 105 | var f = function () { 106 | if (f.called) { 107 | return f.value 108 | } 109 | f.called = true 110 | return (f.value = fn.apply(this, arguments)) 111 | } 112 | f.called = false 113 | return f 114 | } 115 | // and 116 | import once from 'once' 117 | function foo(cb) { 118 | cb = once(cb) 119 | if (!cb.called) { 120 | // do things 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /basic/list.js: -------------------------------------------------------------------------------- 1 | // implement a list, using a class 2 | // this is just a representation of 3 | // an ordered sequence of values 4 | // where the same value can appear multiple times 5 | // it should have `get`, `push`, `pop`, `shift`, and 6 | // `unshift` methods 7 | 8 | /* 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | */ 65 | 66 | export default class List { 67 | constructor() { 68 | this.memory = [] 69 | this.length = 0 70 | } 71 | 72 | get(addr) { 73 | return this.memory[addr] 74 | } 75 | 76 | push(val) { 77 | this.memory[this.length] = val 78 | this.length++ 79 | } 80 | 81 | pop() { 82 | if (this.length === 0) { 83 | return 84 | } 85 | const last = this.length - 1 86 | const val = this.memory[last] 87 | delete this.memory[last] 88 | this.length-- 89 | return val 90 | } 91 | 92 | unshift(val) { 93 | let prev = val 94 | for (let addr = 0; addr < this.length; addr++) { 95 | const curr = this.memory[addr] 96 | this.memory[addr] = prev 97 | prev = curr 98 | } 99 | this.memory[this.length] = prev 100 | this.length++ 101 | } 102 | 103 | shift() { 104 | if (this.length === 0) { 105 | return 106 | } 107 | const val = this.memory[0] 108 | for (let addr = 0; addr < this.length; addr++) { 109 | this.memory[addr] = this.memory[addr + 1] 110 | } 111 | delete this.memory[this.length - 1] 112 | this.length-- 113 | return val 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /intermediate/minimum-stack.js: -------------------------------------------------------------------------------- 1 | // Implement a stack which keeps track of its minimum value. 2 | // Challenge: can you keep the operation time complexity to `O(1)`? 3 | // Hint: Try using some extra space. What data structure might work for keeping track of minimums? 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | */ 82 | 83 | function Stack() { 84 | this.valueStack = [] 85 | this.minimumStack = [] 86 | } 87 | 88 | Stack.prototype.getMinimum = function () { 89 | return this.minimumStack.length === 0 90 | ? null 91 | : this.minimumStack[this.minimumStack.length - 1] 92 | } 93 | 94 | Stack.prototype.peek = function () { 95 | return this.valueStack[this.valueStack.length - 1] 96 | } 97 | 98 | Stack.prototype.push = function (item) { 99 | this.valueStack.push(item) 100 | 101 | const currentMin = 102 | this.minimumStack.length > 0 103 | ? this.minimumStack[this.minimumStack.length - 1] 104 | : item 105 | 106 | if (item < currentMin) { 107 | this.minimumStack.push(item) 108 | } else { 109 | this.minimumStack.push(currentMin) 110 | } 111 | } 112 | 113 | Stack.prototype.pushAll = function (items) { 114 | items.forEach(function (item) { 115 | this.push(item) 116 | }, this) 117 | } 118 | 119 | const stack = new Stack() 120 | stack.pushAll([1, 2, 3, 5, 0]) 121 | console.log(stack.getMinimum()) 122 | -------------------------------------------------------------------------------- /advanced/triangle-counter.js: -------------------------------------------------------------------------------- 1 | /* We have a triabgle made of blocks. The topmost row has 1 block, 2 | * the next row has 2 blocks, the next row has 3 blocks, and so on. 3 | * Compute the total number of blocks in such a triangle with the 4 | * given number of rows. 5 | 6 | triangle(2) ---> 3 7 | * 8 | * * 9 | 10 | triangle(3) ---> 6 11 | * 12 | * * 13 | * * * 14 | 15 | triangle(4) ---> 16 | * 17 | * * 18 | * * * 19 | * * * * 20 | 21 | triangle(5) 22 | * 23 | * * 24 | * * * 25 | * * * * 26 | * * * * * 27 | 28 | */ 29 | 30 | /* 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | * 82 | * 83 | * 84 | * 85 | * 86 | * 87 | * 88 | * 89 | * 90 | * 91 | * 92 | * 93 | * 94 | */ 95 | 96 | function triangle(n) { 97 | if (n === 1 || n === 0) { 98 | return n 99 | } 100 | return n + triangle(n - 1) 101 | } 102 | 103 | function triangleBuilder(n) { 104 | let arr = [] 105 | for (let i = n; i >= 0; i--) { 106 | let lineArr = [] 107 | const spaces = i 108 | const stars = n - i 109 | let spaceArr = [] 110 | for (let j = 0; j < spaces; j++) { 111 | spaceArr.push(' ') 112 | } 113 | spaceArr = spaceArr.join('') 114 | let stArr = [] 115 | for (let k = 0; k < stars; k++) { 116 | stArr.push('* ') 117 | } 118 | stArr = stArr.join('') 119 | lineArr.push(spaceArr) 120 | lineArr.push(stArr) 121 | lineArr.push(' \n') 122 | lineArr = lineArr.join('') 123 | arr.push(lineArr) 124 | } 125 | arr = arr.join('') 126 | return arr 127 | } 128 | 129 | console.log(triangleBuilder(5)) 130 | -------------------------------------------------------------------------------- /node/cat.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // rewrite `cat(1)` in node! 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | */ 64 | 65 | const fs = require('fs') 66 | const args = process.argv.slice(2) 67 | 68 | if (!args[0]) { 69 | console.error('please specify file(s) to catenate') 70 | } else { 71 | for (let i = 0; i < args.length; i++) { 72 | fs.createReadStream(args[i]).pipe(process.stdout) 73 | } 74 | } 75 | 76 | // 77 | // below is a much more exhaustive, windows-friendly `cat(1)`. 78 | // 79 | 80 | const fs = require('fs') 81 | 82 | function cat(result, file) { 83 | let stdout = '' 84 | const stderr = '' 85 | 86 | try { 87 | stdout = result.stdout + fs.readFileSync(file, 'utf8') 88 | stderr = result.stderr 89 | } catch (e) { 90 | stdout = result.stdout 91 | stderr = 92 | result.stderr + 93 | ['cat: ', file, ': ', 'No such file or directory.'].join('') 94 | } 95 | return { stdout: stdout, stderr: stderr } 96 | } 97 | const nl = (str) => 98 | str.length > 0 && str[str.length - 1] !== '\n' ? str + '\n' : str 99 | const doCat = (files) => { 100 | let results = files.reduce(cat, { stdout: '', stderr: '' }) 101 | return { stdout: nl(results.stdout), stderr: nl(results.stderr) } 102 | } 103 | 104 | let results = doCat(process.argv.slice(2)) 105 | 106 | if (results.stderr.length) { 107 | process.stderr.write(results.stderr) 108 | } 109 | if (results.stdout.length) { 110 | process.stdout.write(results.stdout) 111 | } 112 | 113 | process.exit(results.stderr.length ? 1 : 0) 114 | -------------------------------------------------------------------------------- /basic/longest-word-in-string.js: -------------------------------------------------------------------------------- 1 | // Write a function that returns the longest word(s) 2 | // from a sentence. The function should not return 3 | // any duplicate words (case-insensitive). 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | */ 56 | 57 | const longest = function (str) { 58 | str = str.toLowerCase().split(' ') 59 | let longestLength = 0 60 | const longestWord = [] 61 | for (let i = 0; i < str.length; i++) { 62 | str[i] = str[i].trim() 63 | if (str[i].length > longestLength) { 64 | longestWord.splice(0, longestLength - 1, str[i]) 65 | longestLength = str[i].length 66 | } else if ( 67 | str[i].length === longestLength && 68 | !longestWord.includes(str[i]) && 69 | str[i] !== '' 70 | ) { 71 | longestWord.push(str[i]) 72 | } 73 | } 74 | return longestWord 75 | } 76 | 77 | console.log(longest('I gave a present to my parents')) 78 | 79 | function findLongestWord(str) { 80 | str = str.split(' ') 81 | const longest = str.reduce(function (a, b) { 82 | return a.length >= b.length ? a : b 83 | }) 84 | return longest.length 85 | } 86 | 87 | // Every sentence contain spaces, I'll consider a space to break words 88 | // TimeComplexity O(N), Space Complexity: O(1) 89 | function findLongestWord(input) { 90 | let currentCount = 0 91 | let result = 0 92 | for (let i = 0; i < input.length; i++) { 93 | // Until I find space incrementing count 94 | if (input[i] !== ' ') { 95 | currentCount++ 96 | } else { 97 | result = Math.max(result, currentCount) 98 | currentCount = 0 99 | } 100 | } 101 | return result 102 | } 103 | -------------------------------------------------------------------------------- /basic/palindrome-check.js: -------------------------------------------------------------------------------- 1 | // check if something's a palindrome 2 | // bonus: try using a regex 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | * 82 | * 83 | * 84 | * 85 | * 86 | * 87 | * 88 | * 89 | * 90 | */ 91 | 92 | const pal = (str) => str === str.split('').reverse.join('') 93 | 94 | // same as above, verbosely 95 | function palindrome(str) { 96 | return str === str.split('').reverse().join('') 97 | } 98 | 99 | function palindrome(str) { 100 | var result = true 101 | for (var i = 0; i < Math.floor(str.length / 2); i++) { 102 | if (str[i] != str[str.length - 1 - i]) { 103 | return false 104 | } 105 | } 106 | return result 107 | } 108 | 109 | function palindrome(str) { 110 | if (str.slice(0, 1) != str.slice(-1)) { 111 | return false 112 | } 113 | if (str.length == 0 || str.length == 1) { 114 | return true 115 | } 116 | return palindrome(str.slice(1, -1)) 117 | } 118 | 119 | function palindrome(str) { 120 | str = str.toLowerCase() 121 | str = str.replace(/[^a-z]/g, '') 122 | for (var i = 0; i <= Math.floor(str.length / 2); i++) { 123 | if (str[i] !== str[str.length - i - 1]) { 124 | return false 125 | } 126 | } 127 | return true 128 | } 129 | 130 | function palindrome(str) { 131 | const re = /[\W_]/g 132 | const low = str.toLowerCase().replace(re, '') 133 | const rev = lowRegSgtr.split('').reverse().join('') 134 | return low === rev 135 | } 136 | -------------------------------------------------------------------------------- /intermediate/queue.js: -------------------------------------------------------------------------------- 1 | // Implement a basic queue 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | */ 64 | 65 | const Queue = function () { 66 | this.storage = {} 67 | this.everAdded = 0 68 | this.frontIndex = 0 69 | this.currentSize = 0 70 | } 71 | 72 | Queue.prototype.enqueue = function (val) { 73 | this.storage[this.everAdded] = val 74 | this.everAdded++ 75 | this.currentSize++ 76 | } 77 | 78 | Queue.prototype.dequeue = function () { 79 | if (this.currentSize > 0) { 80 | this.currentSize-- 81 | } 82 | const res = this.storage[this.frontIndex] 83 | delete this.storage[this.frontIndex] 84 | this.frontIndex++ 85 | return res 86 | } 87 | 88 | Queue.prototype.size = function () { 89 | return this.currentSize 90 | } 91 | 92 | // 93 | const Q = () => { 94 | const instance = {} 95 | const storage = {} 96 | let front = 0 97 | let back = 0 98 | 99 | instance.size = () => back - front 100 | 101 | instance.enqueue = (val) => { 102 | storage[back++] = val 103 | } 104 | 105 | instance.dequeue = () => { 106 | instance.size() && front++ 107 | const res = storage[front] 108 | delete storage[front] 109 | return res 110 | } 111 | 112 | return instance 113 | } 114 | 115 | // with a class 116 | class Queue { 117 | constructor() { 118 | this.list = [] 119 | this.length = 0 120 | } 121 | 122 | enqueue(v) { 123 | this.length++ 124 | this.list.push(v) 125 | } 126 | 127 | dequeue() { 128 | if (this.length === 0) return 129 | this.length-- 130 | return this.list.shift() 131 | } 132 | 133 | peek() { 134 | return this.list[0] 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /intermediate/stack.js: -------------------------------------------------------------------------------- 1 | // Implement a basic stack 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | */ 78 | 79 | const Stack = function () { 80 | this.storage = {} 81 | this.currentSize = 0 82 | } 83 | 84 | Stack.prototype.push = function (val) { 85 | this.storage[this.currentSize] = val 86 | this.currentSize++ 87 | } 88 | 89 | Stack.prototype.pop = function () { 90 | if (this.currentSize > 0) { 91 | this.currentSize-- 92 | } 93 | const res = this.storage[this.currentSize] 94 | delete this.storage[this.currentSize] 95 | return res 96 | } 97 | 98 | Stack.prototype.size = function () { 99 | return this.currentSize 100 | } 101 | 102 | // 103 | const Stack = () => { 104 | const instance = {} 105 | const storage = {} 106 | let length = 0 107 | 108 | instance.push = (val) => { 109 | storage[length] = val 110 | length++ 111 | } 112 | 113 | instance.push = () => { 114 | length && length-- 115 | const res = storage[length] 116 | delete storage[length] 117 | return res 118 | } 119 | 120 | instance.size = () => length 121 | 122 | return instance 123 | } 124 | 125 | // using a class 126 | class Stack { 127 | constructor() { 128 | this.list = [] 129 | this.length = 0 130 | } 131 | 132 | push(val) { 133 | this.length++ 134 | this.list.push(val) 135 | } 136 | 137 | pop() { 138 | if (this.length === 0) return 139 | this.length-- 140 | return this.list.pop() 141 | } 142 | 143 | peek() { 144 | return this.list[this.length - 1] 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /intermediate/max-profit.js: -------------------------------------------------------------------------------- 1 | // Write a function that takes in an array of stock prices, as numbers, and 2 | // determine what the maximum possible profit from that day. Remember that you 3 | // cannot sell before you buy. The function should return an object containing the 4 | // maximum profit, and the buy and sell indices 5 | 6 | // usage : maxProfit([10, 7, 5, 8, 11, 9]) // {buyIndex : 2, sellIndex : 4, profit : 6} 7 | 8 | /* 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | */ 56 | 57 | const maxProf = (arr) => { 58 | let buy = 0 59 | let sell = 0 60 | let maxDiff = 0 61 | let min = 0 62 | let diff 63 | 64 | for (let i = 1; i < arr.length; i++) { 65 | // if current value is less than current minimum, update minimum 66 | if (arr[i] < arr[min]) { 67 | min = i 68 | } 69 | // find difference between current value and min value 70 | diff = arr[i] - arr[min] 71 | // if current difference is higher than max, we've found a better combination than the current one 72 | // update our choices accordingly 73 | if (diff > maxDiff) { 74 | buy = min 75 | sell = i 76 | maxDiff = diff 77 | } 78 | } 79 | return { buy, sell, maxDiff } 80 | } 81 | console.log(maxProf([10, 7, 5, 8, 11, 9])) 82 | 83 | // 84 | function maxProfit(arg) { 85 | const maxProfit = { 86 | buyIndex: null, 87 | sellIndex: null, 88 | profit: 0, 89 | } 90 | 91 | for (let i = 0; i < arg.length; i++) { 92 | for (let j = i + 1; j < arg.length; j++) { 93 | if (arg[j] - arg[i] > maxProfit.profit) { 94 | maxProfit.buyIndex = i 95 | maxProfit.sellIndex = j 96 | maxProfit.profit = arg[j] - arg[i] 97 | } 98 | } 99 | } 100 | return maxProfit 101 | } 102 | console.log(maxProf([10, 7, 5, 8, 11, 9])) 103 | -------------------------------------------------------------------------------- /intermediate/throttle-debounce.js: -------------------------------------------------------------------------------- 1 | // write functions for debounce and throttle 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | */ 65 | 66 | function debounce(fn, delay) { 67 | var timer = null 68 | return function () { 69 | var context = this, 70 | args = arguments 71 | clearTimeout(timer) 72 | timer = setTimeout(function () { 73 | fn.apply(context, args) 74 | }, delay) 75 | } 76 | } 77 | 78 | function throttle(fn, threshhold) { 79 | threshhold || (threshhold = 250) 80 | var last, deferTimer 81 | 82 | return function () { 83 | var context = this, 84 | now = +new Date(), 85 | args = arguments 86 | 87 | if (last && now < last + threshhold) { 88 | // within threshold, set to threshold 89 | // hold on to it 90 | clearTimeout(deferTimer) 91 | deferTimer = setTimeout(function () { 92 | last = now 93 | fn.apply(context, args) 94 | }, threshhold) 95 | } else { 96 | // outside threshold, execute it 97 | last = now 98 | fn.apply(context, args) 99 | } 100 | } 101 | } 102 | 103 | function throttle(fn, ms) { 104 | let lastCalled, timeout, ctx, args 105 | 106 | return function () { 107 | if (!lastCalled || (new Date() - lastCalled > ms && !timeout)) { 108 | lastCalled = new Date() 109 | return fn.apply(this, arguments) 110 | } else { 111 | ctx = this 112 | args = [].slice.call(arguments) 113 | if (!timeout) { 114 | timeout = setTimeout(() => { 115 | lastCalled = new Date() 116 | fn.apply(ctx, args) 117 | timeout = null 118 | }, ms) 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /basic/abcheck.js: -------------------------------------------------------------------------------- 1 | // Write a function called ABCheck that takes a string parameter and return true 2 | // if the characters a and b are separated by exactly 3 places anywhere 3 | // in the string at least once (ie. "lane borrowed" would result in true 4 | // because there is exactly three characters between a and b). 5 | // Otherwise return false. 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | */ 64 | 65 | var ABCheck = function (str) { 66 | for (var i = 0; i < str.length; i++) { 67 | if ( 68 | (str[i] === 'a' && str[i + 4] === 'b') || 69 | (str[i] === 'b' && str[i + 4] === 'a') 70 | ) { 71 | return true 72 | } 73 | } 74 | return false 75 | } 76 | 77 | var ABCheck = function (str) { 78 | return str.match(/a...b/g) !== null 79 | } 80 | 81 | var ABCheck = function (str) { 82 | if (/a...b/.test(str) || /b...a/.test(str)) { 83 | return true 84 | } else { 85 | return false 86 | } 87 | } 88 | 89 | function ABCheck(str) { 90 | var newStr = str.toLowerCase() 91 | for (var i = 0; i < newStr.length; i++) { 92 | if ( 93 | (newStr[i] === 'a' && newStr[i + 4] === 'b') || 94 | (newStr[i] === 'a' && newStr[i - 4] === 'b') || 95 | (newStr[i] === 'b' && newStr[i + 4] === 'a') || 96 | (newStr[i] === 'b' && newStr[i - 4] === 'a') 97 | ) { 98 | return true 99 | } 100 | } 101 | return false 102 | } 103 | 104 | // test your code 105 | var test1 = 'lane borrowed' // should return true 106 | var test2 = 'laneborrowed' // should return false 107 | var test3 = 'any big string' // should return true 108 | var test4 = 'boy are these toy problems neat' // should return true 109 | var test5 = 'boyare these toy problems neat' // should return false 110 | -------------------------------------------------------------------------------- /advanced/clock-angles.js: -------------------------------------------------------------------------------- 1 | // given a standard clock face, write a function that returns the 2 | // inner angle between the hour and the minute hands. so: 3 | // 12:00 - returns 0 4 | // 3:00 - returns 90 5 | // 2:30 - returns 165 6 | 7 | // hour: 30 degrees / hour 8 | // .5 degrees / minute 9 | // minute: 6 degrees / minute 10 | 11 | /* 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | */ 60 | 61 | const timeAngle = function (time) { 62 | time = time.split(':') 63 | const hour = Number(time[0]) 64 | const minute = Number(time[1]) 65 | let hourAngle = hour * 30 + minute * 0.5 66 | let minuteAngle = minute * 6 67 | if (hourAngle >= 360) { 68 | hourAngle -= 360 69 | } 70 | if (minuteAngle >= 360) { 71 | minuteAngle -= 360 72 | } 73 | if (hourAngle - minuteAngle > 180 || minuteAngle - hourAngle > 180) { 74 | if (hourAngle >= minuteAngle) { 75 | return 180 - (hourAngle - minuteAngle - 180) 76 | } 77 | if (minuteAngle > hourAngle) { 78 | return 180 - (minuteAngle - hourAngle - 180) 79 | } 80 | } 81 | if (hourAngle >= minuteAngle) { 82 | return hourAngle - minuteAngle 83 | } 84 | if (minuteAngle > hourAngle) { 85 | return minuteAngle - hourAngle 86 | } 87 | } 88 | 89 | function clockFace(time) { 90 | time = time.split(':') 91 | const hour = Number(time[0]) 92 | const min = Number(time[1]) 93 | let hrAng = hour * 30 + min * 0.5 94 | let minAng = min * 6 95 | if (hrAng >= 360) { 96 | hrAng -= 360 97 | } 98 | if (minAng >= 360) { 99 | minAng -= 360 100 | } 101 | if (hrAng - minAng > 180 || minAng - hrAng > 180) { 102 | if (hrAng >= minAng) { 103 | return 180 - (hrAng - minAng - 180) 104 | } 105 | if (minAng > hrAng) { 106 | return 180 - (minAng - hrAng - 180) 107 | } 108 | } 109 | if (hrAng >= minAng) { 110 | return hrAng - minAng 111 | } 112 | if (minANg > hrAng) { 113 | return minAng - hrAng 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /node/morsecode.js: -------------------------------------------------------------------------------- 1 | // write a translator that takes in a file 2 | // and outputs that file in morse code 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | */ 72 | 73 | const fs = require('fs') 74 | 75 | function show_props(obj, moresC, objName) { 76 | let result = '' 77 | 78 | for (const prop in obj) { 79 | if (moresC == obj[prop]) { 80 | result = prop 81 | } 82 | } 83 | return result 84 | } 85 | 86 | fs.readFileSync(process.argv[2]) 87 | .toString() 88 | .split('\n') 89 | .forEach((line) => { 90 | if (line !== '') { 91 | const code = { 92 | A: '.-', 93 | B: '-...', 94 | C: '-.-.', 95 | D: '-..', 96 | E: '.', 97 | F: '..-.', 98 | G: '--.', 99 | H: '....', 100 | I: '..', 101 | J: '.---', 102 | K: '-.-', 103 | L: '.-..', 104 | M: '--', 105 | N: '-.', 106 | O: '---', 107 | P: '.--.', 108 | Q: '--.-', 109 | R: '.-.', 110 | S: '...', 111 | T: '-', 112 | U: '..-', 113 | V: '...-', 114 | W: '.--', 115 | X: '-..-', 116 | Y: '-.--', 117 | Z: '--..', 118 | 0: '-----', 119 | 1: '.----', 120 | 2: '..---', 121 | 3: '...--', 122 | 4: '....-', 123 | 5: '.....', 124 | 6: '-....', 125 | 7: '--...', 126 | 8: '---..', 127 | 9: '----.', 128 | } 129 | 130 | line = line.split(' ') 131 | 132 | let output = '' 133 | 134 | for (let i = 0; i <= line.length; i++) { 135 | if (line[i] !== '') { 136 | show_props(code, line[i], 'o') 137 | output += result 138 | } else { 139 | output += ' ' 140 | } 141 | } 142 | 143 | process.stdout.write(output) 144 | } 145 | }) 146 | -------------------------------------------------------------------------------- /intermediate/debounce.js: -------------------------------------------------------------------------------- 1 | // Write a function that accepts a function and timeout, x, 2 | // in number of milliseconds. It will return a new function 3 | // that can only be executed on per timeout period - and if 4 | // the function is invoked during the timeout period, the timeout 5 | // period restarts. This is useful for functions that can be 6 | // need to be blocked on subsequent attempts over short period 7 | // of times. Once such is example, is clicks on a button. 8 | 9 | // Once written, add a third parameter that will allow the 10 | // function to be executed immediately if set to true. Otherwise 11 | // the function will run at the end of the timeout period. 12 | 13 | // test your code 14 | const text = () => 'good' 15 | const inner = debounce(text, 4000) 16 | const inner2 = debounce(text, 2000, true) 17 | const inner3 = debounce(text, 3000, false) 18 | 19 | /* 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | * 82 | * 83 | * 84 | * 85 | * 86 | * 87 | * 88 | * 89 | * 90 | * 91 | * 92 | * 93 | */ 94 | 95 | function debounce(cb, x, execute) { 96 | let flag = true 97 | let timeId 98 | function resetFlag() { 99 | timeId = setTimeout(function () { 100 | flag = true 101 | }, x) 102 | } 103 | 104 | return function () { 105 | if (execute) { 106 | return cb() 107 | } 108 | 109 | if (flag) { 110 | flag = false 111 | resetFlag() 112 | return cb() 113 | } else { 114 | flag = false 115 | clearTimeout(timeId) 116 | resetFlag() 117 | return 'too soon' 118 | } 119 | } 120 | } 121 | 122 | module.exports = (func, wait, immediate) => { 123 | let timeout 124 | return () => { 125 | const context = this 126 | const args = arguments 127 | const later = () => { 128 | func.apply(this, args) 129 | } 130 | 131 | if (immediate) { 132 | func.apply(context, args) 133 | } else { 134 | clearTimeout(timeout) 135 | timeout = setTimeout(later, wait) 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /basic/missingnumber.js: -------------------------------------------------------------------------------- 1 | // Write a function that accepts an array of integers in 2 | // random order of unknown length, but with one number 3 | // missing. Return the missing number. 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | */ 73 | 74 | const oneMissingNumber = (arr) => { 75 | const sorted = arr.slice(0).sort((a, b) => a - b) 76 | return sorted.filter((num, i) => sorted[i + 1] - num > 1).map((a) => a + 1) 77 | } 78 | 79 | // More complex, handles multiple missing numbers. 80 | function missingNumber(arr) { 81 | let counter 82 | const hash = {} 83 | for (var i = 0; i < arr.length; i++) { 84 | if (!counter) { 85 | counter = arr[i] 86 | } 87 | if (counter > arr[i]) { 88 | counter = arr[i] 89 | } 90 | hash[arr[i]] = true 91 | } 92 | 93 | for (var i = 0; i < arr.length; i++) { 94 | if (!hash[counter]) { 95 | return counter 96 | } 97 | counter++ 98 | } 99 | 100 | return ( 101 | 'The missing number is either ' + 102 | (counter - arr.length - 1) + 103 | ' or ' + 104 | counter 105 | ) 106 | } 107 | 108 | // to test your function: 109 | const set1 = [20, 18] 110 | const set2 = [1115, 1119, 1114, 1112, 1121, 1113, 1118, 1116, 1120] 111 | const set3 = [ 112 | 93, 113 | 95, 114 | 101, 115 | 96, 116 | 102, 117 | 100, 118 | 97, 119 | 90, 120 | 92, 121 | 105, 122 | 106, 123 | 103, 124 | 88, 125 | 91, 126 | 94, 127 | 104, 128 | 89, 129 | 98, 130 | ] 131 | const set4 = [8, 4, 5, 9, 2, 6, 1, 10, 7] 132 | const set5 = [ 133 | 93, 134 | 95, 135 | 101, 136 | 96, 137 | 102, 138 | 100, 139 | 97, 140 | 90, 141 | 92, 142 | 105, 143 | 106, 144 | 103, 145 | 88, 146 | 91, 147 | 94, 148 | 104, 149 | 89, 150 | 98, 151 | 99, 152 | ] 153 | 154 | missingNumber(set1) // returns 19 155 | missingNumber(set2) // returns 1117 156 | missingNumber(set3) // returns 99 157 | missingNumber(set4) // returns 3 158 | missingNumber(set5) // returns '87 or 107' 159 | -------------------------------------------------------------------------------- /node/tic-tac-toe.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // write an interactive tic-tac-toe game that runs in the terminal! 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | */ 74 | 75 | const proc = process 76 | const input = proc.stdin 77 | const output = proc.stdout 78 | const block = [1, 2, 3, 4, 5, 6, 7, 8, 9] 79 | 80 | let count = 0 81 | let player = 'X' 82 | let aPlayer = 'O' 83 | 84 | input.setRawMode(1) 85 | input.resume() 86 | input.setEncoding('utf8') 87 | 88 | function draw() { 89 | output.write( 90 | '\033c' + 91 | block[0] + 92 | '|' + 93 | block[1] + 94 | '|' + 95 | block[2] + 96 | '\n' + 97 | block[3] + 98 | '|' + 99 | block[4] + 100 | '|' + 101 | block[5] + 102 | '\n' + 103 | block[6] + 104 | '|' + 105 | block[7] + 106 | '|' + 107 | block[8] + 108 | '\n' 109 | ) 110 | } 111 | 112 | function tic(first) { 113 | if (typeof block[first - 1] == 'number') { 114 | block[first - 1] = player 115 | if (player == 'X') { 116 | player = 'O' 117 | aPlayer = 'X' 118 | } else { 119 | player = 'X' 120 | aPlayer = 'O' 121 | } 122 | count++ 123 | } 124 | } 125 | 126 | function win() { 127 | if ( 128 | (block[0] == block[4] && block[4] == block[8]) || 129 | (block[2] == block[4] && block[4] == block[6]) || 130 | (block[0] == block[1] && block[1] == block[2]) || 131 | (block[3] == block[4] && block[4] == block[5]) || 132 | (block[6] == block[7] && block[7] == block[8]) || 133 | (block[0] == block[3] && block[3] == block[6]) || 134 | (block[1] == block[4] && block[4] == block[7]) || 135 | (block[2] == block[5] && block[5] == block[8]) 136 | ) { 137 | return 1 138 | } 139 | } 140 | 141 | input.on('data', (key) => { 142 | if (key == 'q') { 143 | proc.exit() 144 | } 145 | if (key > 0 && key <= 9) { 146 | tic(key) 147 | } 148 | draw() 149 | if (win()) { 150 | output.write(aPlayer + ' wins!' + '\n') 151 | proc.exit() 152 | } 153 | if (count > 8) { 154 | output.write("it's a draw!\n") 155 | proc.exit() 156 | } 157 | }) 158 | 159 | draw() 160 | -------------------------------------------------------------------------------- /basic/first-non-repeated-character-in-a-string.js: -------------------------------------------------------------------------------- 1 | // Given an arbitrary input string, return the first 2 | // non-repeated character in the string. 3 | // For example: 4 | // firstNonRepeatedCharacter(‘ABA’); // => ‘B’ 5 | // firstNonRepeatedCharacter(‘AABCABD’); // => ‘C’ 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | */ 57 | 58 | function firstNonRepeatedCharacter(str) { 59 | for (var i = 0; i < str.length; i++) { 60 | if (str.indexOf(str[i]) === str.lastIndexOf(str[i])) { 61 | return str[i] 62 | } 63 | } 64 | return 'no unique characters' 65 | } 66 | 67 | var firstNon = function (str) { 68 | for (var i = 0; i < str.length; i++) { 69 | if (str.indexOf(str[i]) === str.lastIndexOf(str[i])) { 70 | return str[i] 71 | } 72 | } 73 | return 'nothing, ya big dumb' 74 | } 75 | 76 | var firstNon2 = function (str) { 77 | for (var i = 0; i < str.length; i++) { 78 | var c = str.charAt(i) 79 | if (str.indexOf(c) === i && str.indexOf(c, i + 1) === -1) { 80 | return c 81 | } 82 | } 83 | return 'no unique characters' 84 | } 85 | 86 | // This function uses a hash. 87 | // It's a little more code, but it avoids using a nested for loop. 88 | function firstNonRepeatedCharacter(str) { 89 | var hash = {} 90 | for (var i = 0; i < str.length; i++) { 91 | if (!hash[str[i]]) { 92 | hash[str[i]] = 1 93 | } else { 94 | hash[str[i]]++ 95 | } 96 | } 97 | // console.log(hash) 98 | for (var i = 0; i < str.length; i++) { 99 | if (hash[str[i]] === 1) { 100 | return str[i] 101 | } 102 | } 103 | return 'no unique characters' 104 | } 105 | 106 | var firstNonRepeatedCharacter = function (string) { 107 | if (string === undefined || string.length === 0) { 108 | return false 109 | } 110 | var charCounts = {} 111 | for (var i = 0; i < string.length; i++) { 112 | charCounts[string[i]] = charCounts[string[i]] 113 | ? charCounts[string[i]] + 1 114 | : 1 115 | } 116 | for (var j = 0; j < string.length; j++) { 117 | if (charCounts[string[j]] === 1) { 118 | return string[j] 119 | } 120 | } 121 | return false 122 | } 123 | 124 | // tests 125 | var test1 = 'AABBCDEDCF' // should return 'C'. 126 | var test2 = 'ABAACDFF' // should return 'B' 127 | var test3 = 'AABBCCDD' // should return no letters. No unique letters. 128 | -------------------------------------------------------------------------------- /intermediate/set.js: -------------------------------------------------------------------------------- 1 | // implement Set 2 | // it should have add, contains, and remove methods 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | */ 73 | 74 | const setPrototype = {} 75 | 76 | const Set = function () { 77 | const set = Object.create(setPrototype) 78 | set._storage = [] 79 | return set 80 | } 81 | 82 | setPrototype.add = function (a) { 83 | if (!this._storage.includes(a)) { 84 | this._storage.push(a) 85 | } 86 | } 87 | 88 | setPrototype.contains = function (a) { 89 | return this._storage.indexOf(a) > -1 90 | } 91 | 92 | setPrototype.remove = function (a) { 93 | const i = this._storage.indexOf(a) 94 | this._storage.splice(i, 1) 95 | } 96 | 97 | // 98 | class Set { 99 | constructor() { 100 | this.storage = [] 101 | } 102 | 103 | add(a) { 104 | if (!this.storage.includes(a)) { 105 | this.storage.push(a) 106 | } 107 | } 108 | 109 | contains(a) { 110 | return this.storage.includes(a) 111 | } 112 | 113 | remove(a) { 114 | this.storage.splice(this.storage.indexOf(a), 1) 115 | } 116 | } 117 | 118 | // how imperative can you get? 119 | function findIndex(items, size, item) { 120 | for (let i = 0; i <= size; i++) { 121 | if (items[i] === item) { 122 | return i + 1 123 | } 124 | } 125 | return null 126 | } 127 | 128 | function Set() { 129 | this.size = 0 130 | this.items = [] 131 | } 132 | 133 | Set.prototype.add = function (item) { 134 | this.items[this.size] = item 135 | this.size++ 136 | } 137 | 138 | Set.prototype.isEmpty = function () { 139 | return this.size <= 0 140 | } 141 | 142 | Set.prototype.contains = function (item) { 143 | if (findIndex(this.items, this.size, item)) { 144 | return true 145 | } 146 | return false 147 | } 148 | 149 | Set.prototype.remove = function (item) { 150 | let index = findIndex(this.items, this.size, item) 151 | let tempSet = [] 152 | 153 | if (index) { 154 | let i = 0 155 | index-- 156 | while (i < index) { 157 | tempSet[i] = this.items[i] 158 | i++ 159 | } 160 | 161 | for (let j = index + 1; j < this.size; j++) { 162 | tempSet[i] = this.items[j] 163 | i++ 164 | } 165 | 166 | this.items = tempSet 167 | this.size-- 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /advanced/stock-ticker.js: -------------------------------------------------------------------------------- 1 | // I have an array of 24 stock prices for each out tomorrow, e.g. 2 | // [20, 15, 1, 10, 15, 8, 16, 17, 8, 13, 10, 11, 19, 7, 6, 12, 6, 6, 6, 2, 11, 5, 1, 5] 3 | // I start with no stock and can only buy and sell once, otherwise the time police will get me. 4 | // Write a function that lets me know which hour to buy and which hour to sell to maximize my profit. 5 | 6 | // For the above array, your function should return [2, 12]. 7 | 8 | /* 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | */ 73 | 74 | // easy solution 75 | const ticker = (arr) => { 76 | let buy = 0 77 | let sell = 1 78 | let diff = arr[sell] - arr[buy] 79 | 80 | for (let i = 0; i < arr.length; i++) { 81 | for (let j = i + 1; j < arr.length; j++) { 82 | const check = arr[j] - arr[i] 83 | if (check > diff) { 84 | buy = i 85 | sell = j 86 | diff = check 87 | } 88 | } 89 | } 90 | return [buy, sell] 91 | } 92 | 93 | console.log( 94 | ticker([ 95 | 16, 96 | 7, 97 | 13, 98 | 8, 99 | 3, 100 | 9, 101 | 12, 102 | 3, 103 | 14, 104 | 3, 105 | 16, 106 | 13, 107 | 2, 108 | 3, 109 | 14, 110 | 2, 111 | 5, 112 | 4, 113 | 17, 114 | 13, 115 | 11, 116 | 2, 117 | 20, 118 | 1, 119 | ]) 120 | ) 121 | 122 | // harder solution 123 | const ticker2 = (arr) => { 124 | let buy = 0 125 | let sell = 0 126 | let maxDiff = 0 127 | let min = 0 128 | let diff 129 | 130 | for (let i = 1; i < arr.length; i++) { 131 | // if current value is less than current minimum, update minimum 132 | if (arr[i] < arr[min]) { 133 | min = i 134 | } 135 | // find difference between current value and min value 136 | diff = arr[i] - arr[min] 137 | // if current difference is higher than max, we've found a better combination than the current one 138 | // update our choices accordingly 139 | if (diff > maxDiff) { 140 | buy = min 141 | sell = i 142 | maxDiff = diff 143 | } 144 | } 145 | return [buy, sell] 146 | } 147 | 148 | console.log( 149 | ticker2([ 150 | 20, 151 | 15, 152 | 1, 153 | 10, 154 | 15, 155 | 8, 156 | 16, 157 | 17, 158 | 8, 159 | 13, 160 | 10, 161 | 11, 162 | 19, 163 | 7, 164 | 6, 165 | 12, 166 | 6, 167 | 6, 168 | 6, 169 | 2, 170 | 11, 171 | 5, 172 | 1, 173 | 5, 174 | ]) 175 | ) 176 | -------------------------------------------------------------------------------- /node/chat-server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // this is super advanced, but... 4 | // see if you can write a server for a chat 5 | // something you could connect to using 6 | // `nc localhost 5678` (or whatever port) 7 | 8 | /* 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | */ 78 | 79 | // 80 | // complex one 81 | // 82 | 83 | const net = require('net') 84 | const sockets = [] // connected people 85 | const port = process.argv[2] || process.env.PORT || 5678 86 | const server = net.Server((socket) => { 87 | sockets.push(socket) // connecting, announcing number of connections 88 | socket.write(`there are ${sockets.length} people chatting`) 89 | 90 | for (let i = 0; i < sockets.length; i++) { 91 | // announcing newbie 92 | console.log('new user; total of ' + sockets.length) 93 | if (sockets[i] == socket) { 94 | // except to newbie 95 | continue 96 | } 97 | sockets[i].write('one user joined\n') 98 | } 99 | 100 | socket.on('data', (d) => { 101 | // the chat 102 | for (let i = 0; i < sockets.length; i++) { 103 | if (sockets[i] == socket) { 104 | continue // don't send message to sender 105 | } 106 | sockets[i].write(d) // send message 107 | console.log('message sent') 108 | } 109 | }) 110 | 111 | socket.on('end', () => { 112 | // remove disconnected peeps 113 | let i = sockets.indexOf(socket) 114 | sockets.splice(i, 1) 115 | 116 | for (let i = 0; i < sockets.length; i++) { 117 | // tell people when people leave 118 | sockets[i].write('one user left\n') 119 | console.log(`user left; total of ${sockets.length}`) 120 | } 121 | }) 122 | }) 123 | server.listen(port) 124 | console.log(`chat server running on ${port}`) 125 | 126 | // 127 | // simpler version 128 | // 129 | const net = require('net') 130 | const sockets = [] 131 | const port = 5678 132 | 133 | const server = net.createServer((socket) => { 134 | socket.write('welcome to the chat\n') 135 | sockets.push(socket) 136 | 137 | socket.on('data', (data) => { 138 | sockets.forEach((s) => { 139 | if (s != socket) { 140 | s.write(data) 141 | } 142 | }) 143 | }) 144 | 145 | socket.on('end', () => { 146 | sockets.forEach((s, i) => { 147 | if (s == socket) { 148 | sockets.slice(i, 1) 149 | } 150 | }) 151 | }) 152 | }) 153 | 154 | server.listen(port) 155 | console.log(`server listening on ${port}`) 156 | -------------------------------------------------------------------------------- /advanced/lotto.js: -------------------------------------------------------------------------------- 1 | // Part one: 2 | // Create a function that will return an array of six randomly generated 3 | // numbers that are between 1 and 60. 4 | 5 | // Part two: 6 | // Create a function that will use setTimeout to console.log each number in 7 | // the generated array in a dramatic fashion. For example, have the function 8 | // console.log each number in the array every two seconds. Maybe the last 9 | // number, or powerball, after an extra few seconds to make it extra dramatic. 10 | 11 | // Part three (black diamond): 12 | // Use clearTimeout in some way. Maybe build some functionality that will allow 13 | // you to stop all the setTimeouts, like if there was an urgent news bulletin 14 | // that interrupted the powerball drawing. Or, have an option to that will allow 15 | // you to be able to console.log each item in the lotto array without waiting 16 | // for the setTimeout. 17 | 18 | /* 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | */ 72 | 73 | function lottoGenerator() { 74 | const arr = [] 75 | function rando(lot) { 76 | const ran = Math.floor(Math.random() * (60 - 1 + 1)) + 1 77 | return lot.includes(ran) ? rando(lot) : ran 78 | } 79 | for (let i = 0; i < 6; i++) { 80 | const ran = rando(arr) 81 | arr.push(ran) 82 | } 83 | return arr 84 | } 85 | 86 | function revealLotto(lottoArr, optOut) { 87 | if (optOut) { 88 | return lottoArr 89 | } 90 | const timeoutArr = [] 91 | lottoArr.forEach(function (val, i) { 92 | const timeId = setTimeout( 93 | function (num) { 94 | console.log(num) 95 | }, 96 | (i + 1) * 3000, 97 | val 98 | ) 99 | timeoutArr.push(timeId) 100 | }) 101 | return timeoutArr 102 | } 103 | 104 | function cancelReveal(arr) { 105 | for (const element of arr) { 106 | clearTimeout(element) 107 | } 108 | } 109 | 110 | const currentLotto = lottoGenerator 111 | const timeoutIds = revealLotto(currentLotto) 112 | 113 | // Pass true as the second argument to bypass the setTimout, and just 114 | // return the currentLotto. 115 | revealLotto(currentLotto, true) 116 | 117 | // use cancelReveal to stop all the setTimeouts 118 | cancelReveal(timeoutIds) 119 | 120 | // Using this to make sure my lottoGenerator is producing arrays populated 121 | // with unique values 122 | function test() { 123 | for (let i = 0; i < 50_000; i++) { 124 | const newArr = lottoGenerator() 125 | for (let j = 0; j < newArr.length; j++) { 126 | if (newArr.indexOf(newArr[j]) !== j) { 127 | return 'error' 128 | } 129 | } 130 | } 131 | return true 132 | } 133 | -------------------------------------------------------------------------------- /advanced/quicksort.js: -------------------------------------------------------------------------------- 1 | // takes an array, sorts it using quicksort algorithm 2 | // outputs to console 3 | // running time O(nlog(n)) 4 | 5 | /* 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | */ 75 | 76 | function quicksort(arr) { 77 | sort(arr, 0, arr.length - 1) 78 | function swap(arr, a, b) { 79 | var temp = arr[a] 80 | arr[a] = arr[b] 81 | arr[b] = temp 82 | } 83 | function partition(arr, l, r) { 84 | var p = arr[r], 85 | i = l - 1, 86 | j = l 87 | while (j < r) { 88 | if (arr[j] <= p) { 89 | swap(arr, ++i, j) 90 | } 91 | j++ 92 | } 93 | swap(arr, i + 1, r) 94 | return i + 1 95 | } 96 | function sort(arr, l, r) { 97 | var p 98 | if (l < r) { 99 | p = partition(arr, l, r) 100 | sort(arr, l, p - 1) 101 | sort(arr, p + 1, r) 102 | } else if (l === arr.length) { 103 | console.log(arr) 104 | } 105 | } 106 | } 107 | 108 | // or, much more concisely, from le wikipedia: 109 | function quickersort(a) { 110 | var left = [], 111 | right = [], 112 | pivot = a[0] 113 | if (a.length == 0) { 114 | return [] 115 | } 116 | for (var i = 1; i < a.length; i++) { 117 | a[i] < pivot ? left.push(a[i]) : right.push(a[i]) 118 | } 119 | return quickersort(left).concat(pivot, quickersort(right)) 120 | } 121 | 122 | // basically the s ame, just different syntax 123 | function quicksort(arr) { 124 | if (arr.length === 0) { 125 | return [] 126 | } 127 | let left = [], 128 | right = [], 129 | pivot = arr[0] 130 | for (let i = 1; i < arr.length; i++) { 131 | if (arr[i] < pivot) { 132 | left.push(arr[i]) 133 | } else { 134 | right.push(arr[i]) 135 | } 136 | } 137 | return quicksort(left).concat(pivot, quicksort(right)) 138 | } 139 | 140 | // similarly 141 | const quickSort = (nums) => { 142 | if (nums.length <= 1) { 143 | return nums 144 | } 145 | const pivot = nums[nums.length - 1], 146 | left = [], 147 | right = [] 148 | 149 | for (let i = 0; i < nums.length - 1; i++) { 150 | if (nums[i] < pivot) { 151 | left.push(nums[i]) 152 | } else { 153 | right.push(nums[i]) 154 | } 155 | } 156 | return [...quickSort(left), pivot, ...quickSort(right)] 157 | } 158 | 159 | // 160 | function quikSrt(a) { 161 | if (a.length < 2) return a 162 | const l = [] 163 | const r = [] 164 | const b = [a[0]] 165 | for (let i = 1; i < a.length; i++) { 166 | if (a[i] > a[0]) { 167 | r.push(a[i]) 168 | } else if (a[i] < a[0]) { 169 | l.push(a[i]) 170 | } else { 171 | b.push(a[0]) 172 | } 173 | } 174 | return quikSrt(l).concat(b).concat(quikSrt(r)) 175 | } 176 | 177 | const qs = (arr) => { 178 | const lte = (a) => (b) => a <= b 179 | const gt = (a) => (b) => a > b 180 | const filter = [].filter 181 | if (arr.length === 0) { 182 | return [] 183 | } 184 | const [x, ...xs] = arr 185 | const smallerOrEqual = filter.call(xs, lte(x)) 186 | const larger = filter.call(xs, gt(x)) 187 | return [...qs(smallerOrEqual), x, ...qs(larger)] 188 | } 189 | -------------------------------------------------------------------------------- /intermediate/bubble-sort.js: -------------------------------------------------------------------------------- 1 | // implement a bubble sort 2 | // example usage: `bubbleSort([2, 1, 3])` // => [1, 2, 3] 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | */ 55 | 56 | var randomArray = function (size) { 57 | var array = [] 58 | for (var i = 0; i < size; i++) { 59 | array.push(parseInt(Math.random() * 100)) 60 | } 61 | return array 62 | } 63 | var bubbleSort = function (array) { 64 | var swapped = true 65 | while (swapped) { 66 | swapped = false 67 | for (var i = 0; i < array.length - 1; i++) { 68 | if (array[i] > array[i + 1]) { 69 | swap(i, i + 1) 70 | swapped = true 71 | } 72 | } 73 | } 74 | function swap(a, b) { 75 | var tmp = array[a] 76 | array[a] = array[b] 77 | array[b] = tmp 78 | } 79 | } 80 | var array = randomArray(5000) 81 | console.log(array) 82 | console.time('bubbleSort') 83 | console.log('\n#########################################\n') 84 | bubbleSort(array) 85 | console.timeEnd('bubbleSort') 86 | console.log('\n#########################################\n') 87 | 88 | // 89 | // 90 | // 91 | var i 92 | var bubbleSort = function (array) { 93 | var len = array.length 94 | if (len <= 1) { 95 | return array 96 | } 97 | for (var i = 0; i < len; i += 1) { 98 | var hasSwapped = false 99 | for (var j = 0; j < len - i - 1; j += 1) { 100 | if (array[j] > array[j + 1]) { 101 | swap(array, j, j + 1) 102 | hasSwapped = true 103 | } 104 | } 105 | if (!hasSwapped) break 106 | } 107 | return array 108 | } 109 | var swap = function (array, i, j) { 110 | var temp = array[i] 111 | array[i] = array[j] 112 | array[j] = temp 113 | } 114 | 115 | // 116 | // 117 | // 118 | // swap adjacent elements if not in correct order 119 | // one pass without swaps then stop the algorithm 120 | var bubbleSort = function (array) { 121 | var temp, 122 | isSwapped = true 123 | while (isSwapped) { 124 | isSwapped = false 125 | for (var j = 0; j < array.length - 1; j++) { 126 | if (array[j] > array[j + 1]) { 127 | temp = array[j + 1] 128 | array[j + 1] = array[j] 129 | array[j] = temp 130 | isSwapped = true 131 | } 132 | } 133 | } 134 | return array 135 | } 136 | 137 | const bubbleSort = (nums) => { 138 | do { 139 | let swapped = false 140 | for (let i = 0; i < nums.length; i++) { 141 | snapshot(nums) 142 | if (nums[i] > nums[i + 1]) { 143 | let temp = nums[i] 144 | nums[i] = nums[i + 1] 145 | nums[i + 1] = temp 146 | swapped = true 147 | } 148 | } 149 | } while (swapped) 150 | snapshot(nums) 151 | } 152 | 153 | // 154 | function bubbleSort(arr) { 155 | for (let j = 0; j < arr.length; j++) { 156 | for (let i = 0; i < arr.length - j; i++) { 157 | if (arr[i] > arr[i + 1]) { 158 | let a = arr[i] 159 | let b = arr[i + 1] 160 | arr[i] = b 161 | arr[i + 1] = a 162 | } 163 | } 164 | } 165 | return arr 166 | } 167 | 168 | // 169 | const bubbleSort = (array) => { 170 | if (arguments.length === 0 || !Array.isArray(array)) { 171 | throw new Error() 172 | } 173 | let hasSwapped = true 174 | while (hasSwapped) { 175 | hasSwapped = false 176 | for (let i = 0; i < array.length - 1; i++) { 177 | let temp = array[i] 178 | if (array[i] > array[i + 1]) { 179 | array[i] = array[i + 1] 180 | array[i + 1] = temp 181 | hasSwapped = true 182 | } 183 | } 184 | if (!hasSwapped) { 185 | return array 186 | } 187 | } 188 | return array 189 | } 190 | -------------------------------------------------------------------------------- /advanced/mergesort.js: -------------------------------------------------------------------------------- 1 | // implement a merge sort 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | */ 71 | 72 | // a has large enough buffer at end to hold b 73 | // a and b are sorted 74 | // alast is the index of the last item 75 | var mergebuffer = function (a, b, alast) { 76 | var bindex = b.length - 1, 77 | aindex = alast 78 | endindex = a.length - 1 79 | while (bindex >= 0 && aindex >= 0) { 80 | if (b[bindex] >= a[aindex]) { 81 | a[endindex--] = b[bindex--] 82 | } else { 83 | a[endindex--] = a[aindex--] 84 | } 85 | } 86 | for (var i = 0; i <= bindex; i++) { 87 | a[i] = b[i] 88 | } 89 | return a 90 | } 91 | 92 | var mergesort = function (array, lo, hi) { 93 | if (lo === undefined) { 94 | lo = 0 95 | hi = array.length - 1 96 | } 97 | if (lo < hi) { 98 | var mid = ~~((lo + hi) / 2) 99 | mergesort(array, lo, mid) // mergesort left 100 | mergesort(array, mid + 1, hi) // mergesort right 101 | merge(array, lo, mid, hi) // merge two pieces 102 | } 103 | } 104 | 105 | var merge = function (array, lo, mid, hi) { 106 | var helper = [], 107 | hLeft = lo 108 | hRight = mid + 1 109 | current = lo 110 | 111 | for (var i = lo; i <= hi; i++) { 112 | helper[i] = array[i] 113 | } 114 | 115 | while (hLeft <= mid && hRight <= hi) { 116 | if (helper[hLeft] < helper[hRight]) { 117 | array[current++] = helper[hLeft++] 118 | } else { 119 | array[current++] = helper[hRight++] 120 | } 121 | } 122 | for (var i = hLeft; i <= mid; i++) { 123 | array[current++] = helper[i] 124 | } 125 | } 126 | 127 | // 128 | // 129 | var mergeSort = function (array) { 130 | var lists = [] 131 | // Split array into sublists 132 | // Natural variant: split array into pre-sorted sublists 133 | var currentList = [] 134 | for (var i = 0; i < array.length; i++) { 135 | if (currentList.length && array[i] < currentList[currentList.length - 1]) { 136 | lists.push(currentList) 137 | currentList = [] 138 | } 139 | currentList.push(array[i]) 140 | } 141 | lists.push(currentList) 142 | // Until the entire array is sorted 143 | while (lists.length > 1) { 144 | var newLists = [] 145 | // Merge all adjacent lists 146 | for (var i = 0; i < Math.floor(lists.length / 2); i++) { 147 | newLists.push(merge(lists[i * 2], lists[i * 2 + 1])) 148 | } 149 | // Include the leftover list if the number is odd 150 | if (lists.length % 2) { 151 | newLists.push(lists[lists.length - 1]) 152 | } 153 | lists = newLists 154 | } 155 | // We have a single, fully sorted list 156 | return lists[0] 157 | } 158 | 159 | var merge = function (left, right) { 160 | var merged = [] 161 | var iL = 0 162 | var iR = 0 163 | while (merged.length < left.length + right.length) { 164 | // Default to the left element for stability 165 | if (iR >= right.length || left[iL] <= right[iR]) { 166 | merged.push(left[iL]) 167 | iL += 1 168 | } else { 169 | merged.push(right[iR]) 170 | iR += 1 171 | } 172 | } 173 | return merged 174 | } 175 | 176 | // 177 | const merge = (left, right) => { 178 | const results = [] 179 | while (left.length && right.length) { 180 | if (left[0] <= right[0]) { 181 | results.push(left.shift()) 182 | } else { 183 | results.push(right.shift()) 184 | } 185 | } 186 | while (left.length) { 187 | results.push(left.shift()) 188 | } 189 | while (right.length) { 190 | results.push(right.shift()) 191 | } 192 | return results 193 | } 194 | const mergeSort = (nums) => { 195 | if (nums.length < 2) { 196 | return nums 197 | } 198 | const length = nums.length 199 | const middle = Math.floor(length / 2) 200 | const left = nums.slice(0, middle) 201 | const right = nums.slice(middle, length) 202 | return merge(mergeSort(left), mergeSort(right)) 203 | } 204 | 205 | // 206 | function mergeSort(arr) { 207 | function merge(a, b) { 208 | let r = [] 209 | while (a.length && b.length) { 210 | if (a[0] < b[0]) { 211 | r.push(a.shift()) 212 | } else { 213 | ret.push(b.shift()) 214 | } 215 | } 216 | r = r.concat(a).concat(b) 217 | return r 218 | } 219 | if (arr.length < 2) return arr 220 | return merge( 221 | mergeSort(arr.slice(0, arr.length / 2)), 222 | mergeSort(arr.slice(arr.length / 2)) 223 | ) 224 | } 225 | -------------------------------------------------------------------------------- /intermediate/array-flatten.js: -------------------------------------------------------------------------------- 1 | // take array with possible nested arrays; flatten it 2 | // (without using .flat()) 3 | 4 | /* 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | */ 62 | 63 | // Using type coercion; 64 | // works as long as elements are all numbers and no arrays are empty 65 | function flatten(arr) { 66 | if (!Array.isArray(arr)) return Error('please input an array') 67 | return (arr + '').split(',').map(Number) 68 | } 69 | 70 | // this is gross don't ever do this 71 | const iteratively = (array) => { 72 | for (let i = 0, l = array.length; i < l; i += 1) { 73 | if (Array.isArray(array[i])) { 74 | // if the item at ith index is an array 75 | array = [ 76 | ...array.slice(0, i), // portion of the before the ith index 77 | ...array[i], // the item of ith index, which is an array 78 | ...array.slice(i + 1, l), // portion of the after the ith index 79 | ] 80 | l = array.length // update the value of l as length of the array has increased 81 | i -= 1 // the item at current ith idex could be an array 82 | } 83 | } 84 | 85 | return array 86 | } 87 | 88 | // this is better 89 | const recursively = (array) => { 90 | return array.reduce((previous, current) => { 91 | return previous.concat( 92 | // if current item is an array flatten it 93 | Array.isArray(current) ? recursively(current) : current 94 | ) 95 | }, []) 96 | } 97 | 98 | // do it like this 99 | const inOneLine = (a) => (Array.isArray(a) ? [].concat(...a.map(inOneLine)) : a) 100 | 101 | // this is the old js version of the above one-liner 102 | function moreLines(a) { 103 | var newArr 104 | if (Array.isArray(a)) { 105 | return (newArr = []).concat.apply(newArr, a.map(moreLines)) 106 | } 107 | return a 108 | } 109 | 110 | // don't do this even more than you shouldn't do that one up there 111 | function grossWay(input) { 112 | var flattened = [] 113 | for (var i = 0; i < input.length; ++i) { 114 | var current = input[i] 115 | for (var j = 0; j < current.length; ++j) { 116 | flattened.push(current[j]) 117 | } 118 | } 119 | } 120 | 121 | // this won't work all the way down 122 | function nah(input) { 123 | var flattened = input.reduce(function (a, b) { 124 | return a.concat(b) 125 | }, []) 126 | } 127 | 128 | // neither will this 129 | function nope(input) { 130 | var res = Array.prototype.concat.apply([], input) 131 | return res 132 | } 133 | 134 | // 135 | function flatten(arr) { 136 | const flat = [].concat(...arr) 137 | return flat.some(Array.isArray) ? flatten(flat) : flat 138 | } 139 | 140 | // 141 | function flatten(array) { 142 | return array.reduce( 143 | (previous, current) => 144 | Array.isArray(current) 145 | ? [...previous, ...flatten(current)] 146 | : [...previous, current], 147 | [] 148 | ) 149 | } 150 | 151 | // 152 | const flattened = arg.reduce((a, b) => a.concat(b)) 153 | 154 | // 155 | function flatten(arr) { 156 | var flatArr = [], 157 | i 158 | function nestedCheck(arr1) { 159 | for (var j = 0; j < arr1.length; j++) { 160 | if (!Array.isArray(arr1[j])) flatArr.push(arr1[j]) 161 | else nestedCheck(arr1[j]) 162 | } 163 | } 164 | for (i = 0; i < arr.length; i++) { 165 | if (!Array.isArray(arr[i])) flatArr.push(arr[i]) 166 | else nestedCheck(arr[i]) 167 | } 168 | return flatArr 169 | } 170 | 171 | // 172 | function flatten(array) { 173 | var flatArray = [] 174 | for (var i = 0; i < array.length; i++) { 175 | if (Array.isArray(array[i])) { 176 | var newArray = flatten(array[i]) 177 | for (var j = 0; j < newArray.length; j++) { 178 | flatArray.push(newArray[j]) 179 | } 180 | } else { 181 | flatArray.push(array[i]) 182 | } 183 | } 184 | return flatArray 185 | } 186 | 187 | // this way is ugly-looking but actually very fast 188 | module.exports = function flatten(arr) { 189 | return flat(arr, []) 190 | } 191 | function flat(arr, res) { 192 | var len = arr.length, 193 | i = -1 194 | while (len--) { 195 | var cur = arr[++i] 196 | if (Array.isArray(cur)) { 197 | flat(cur, res) 198 | } else { 199 | res.push(cur) 200 | } 201 | } 202 | return res 203 | } 204 | 205 | // using a generator 206 | function* flatten(arr) { 207 | if (Array.isArray(arr)) { 208 | for (let i = 0; i < arr.length; i++) { 209 | yield* flatten(arr[i]) 210 | } 211 | } else { 212 | yield arr 213 | } 214 | } 215 | // and then 216 | for (let f of flatten(arr)) { 217 | console.log(f) // or whatever 218 | } 219 | -------------------------------------------------------------------------------- /node/repl.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // you've all seen a REPL, now. pretty cool stuff, right? 4 | // it's really useful. why bother running chrome, opening up a new tab, 5 | // opening devtools, and opening the console, when you can just run 6 | // js in your terminal? 7 | // let's write a REPL using nothing but node built-ins. 8 | // you'll want to require `repl`, here. 9 | // don't forget to `chmod +x index.js` and throw in the shebang 10 | // if you want to execute this. 11 | // bonus: check the API docs for `net`, and figure out how you could 12 | // connect to this REPL remotely. 13 | // bonus bonus: figure out how to start the repl and load in source files 14 | 15 | /* 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | */ 67 | 68 | const net = require('net') 69 | const repl = require('repl') 70 | const port = 5100 71 | 72 | net 73 | .createServer((socket) => { 74 | let remote = repl.start(' |> ', socket) 75 | }) 76 | .listen(port) 77 | 78 | console.log(`remote repl available on ${port}`) 79 | 80 | let local = repl.start(' |> ') 81 | 82 | // or 83 | const net = require('net') 84 | const repl = require('repl') 85 | const port = process.env.PORT || 5000 86 | 87 | let connections = 0 88 | 89 | repl.start({ 90 | prompt: 'stdrepl|> ', 91 | input: process.stdin, 92 | output: process.stdout, 93 | }) 94 | 95 | net 96 | .createServer((socket) => { 97 | connections += 1 98 | repl 99 | .start({ 100 | prompt: 'nixsockrepl|> ', 101 | input: socket, 102 | output: socket, 103 | }) 104 | .on('exit', () => { 105 | socket.end() 106 | }) 107 | }) 108 | .listen('/tmp/node-repl-sock') 109 | 110 | net 111 | .createServer((socket) => { 112 | connections += 1 113 | repl 114 | .start({ 115 | prompt: 'tcpsockrepl|> ', 116 | input: socket, 117 | output: socket, 118 | }) 119 | .on('exit', () => { 120 | socket.end() 121 | }) 122 | }) 123 | .listen(port) 124 | 125 | // this one lets you load in files 126 | const fs = require('fs'), 127 | vm = require('vm'), 128 | path = require('path'), 129 | repl = require('repl') 130 | 131 | // let repl source files 132 | repl.REPLServer.prototype.source = function (file) { 133 | if (!~file.indexOf('.')) { 134 | file += '.js' 135 | } 136 | if (path.existsSync(file)) { 137 | vm.runInContext(fs.readFileSync(file).toString(), this.context) 138 | } else { 139 | this.outputStream.write('ERROR: file ' + file + ' not found!\n') 140 | } 141 | this.displayPrompt() 142 | } 143 | 144 | const server = repl.start() 145 | 146 | // `./ filename` will source `./filename.js` 147 | server.defineCommand('/', { 148 | help: 'source file', 149 | action: function (file) { 150 | this.source(file) 151 | }, 152 | }) 153 | 154 | // from command args 155 | for (let i = 2; i < process.argv.length; i++) { 156 | server.source(process.argv[i]) 157 | } 158 | 159 | // so does this one 160 | // npm i -S temp 161 | // chmod +x thisFile.js 162 | // ./thisFile.js someOtherFile.js 163 | 164 | const temp = require('temp') 165 | const fs = require('fs') 166 | const repl = require('repl').start('> ') 167 | const lastContents = {} 168 | const inputFile = process.argv[2] 169 | 170 | const hasChanged = (file, newData) => { 171 | let oldData = lastContents[file] 172 | if (!oldData) { 173 | return true 174 | } 175 | if (oldData.length != newData.length) { 176 | return true 177 | } 178 | for (let i = 0, l = oldData.length; i < l; i++) { 179 | if (oldData[i] != newData[i]) { 180 | return true 181 | } 182 | } 183 | return false 184 | } 185 | 186 | const reload = (file) => { 187 | fs.readFile(file, (err, data) => { 188 | if (err) { 189 | throw err 190 | } 191 | if (!hasChanged(file, data)) { 192 | return 193 | } 194 | if (file in lastContents) { 195 | console.log(`\nreloading ${file}\n`) 196 | } 197 | lastContents[file] = data 198 | temp.open('filerrepl-temp-source', (err, info) => { 199 | if (err) { 200 | throw err 201 | } 202 | fs.write(info.fd, data, 0, data.length, 0, (err, written) => { 203 | if (err) { 204 | throw err 205 | } 206 | try { 207 | let module = require(info.path) 208 | for (let each in module) { 209 | repl.context[each] = module[each] 210 | } 211 | } catch (e) { 212 | console.log(e.stack) 213 | } 214 | }) 215 | }) 216 | }) 217 | } 218 | 219 | const start = (file) => { 220 | reload(file) 221 | fs.watchFile(file, reload.bind(null, file)) 222 | } 223 | 224 | start(inputFile) 225 | -------------------------------------------------------------------------------- /advanced/singly-linked-list.js: -------------------------------------------------------------------------------- 1 | // implement a singly-linked list 2 | 3 | /* 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | */ 64 | 65 | const createNode = (val) => { 66 | const node = {} 67 | node.value = val 68 | node.next = null 69 | return node 70 | } 71 | 72 | const SinglyLinkedList = function () { 73 | this.head = null 74 | this.tail = null 75 | this.currentSize = 0 76 | } 77 | 78 | SinglyLinkedList.prototype.addToTail = function (val) { 79 | const node = createNode(val) 80 | if (!this.head) { 81 | this.head = node 82 | this.tail = node 83 | } else { 84 | this.tail.next = node 85 | this.tail = node 86 | this.currentSize++ 87 | } 88 | } 89 | 90 | SinglyLinkedList.prototype.removeHead = function () { 91 | if (!this.head) { 92 | return null 93 | } 94 | if (this.currentSize > 0) { 95 | this.currentSize-- 96 | } 97 | const removedHead = this.head 98 | if (this.head === this.tail) { 99 | this.tail = null 100 | } 101 | delete this.head 102 | this.head = removedHead.next 103 | return removedHead.next 104 | } 105 | 106 | SinglyLinkedList.prototype.contains = function (tar) { 107 | let node = this.head 108 | if (node.value === tar) { 109 | return node 110 | } 111 | while (node.next) { 112 | node = node.next 113 | if (node.value === tar) { 114 | return node 115 | } 116 | } 117 | return false 118 | } 119 | 120 | SinglyLinkedList.prototype.size = function () { 121 | return this.currentSize 122 | } 123 | 124 | // 125 | const Node = (val) => { 126 | const n = {} 127 | n.value = val 128 | n.next = null 129 | return n 130 | } 131 | const LL = () => { 132 | const list = {} 133 | list.head = null 134 | list.tail = null 135 | 136 | list.addToTail = (val) => { 137 | if (list.head === null) { 138 | list.head = Node(val) 139 | list.tail = list.head 140 | } else { 141 | list.tail.next = Node(val) 142 | list.tail = list.tail.next 143 | } 144 | } 145 | 146 | list.removeHead = () => { 147 | const tmp = list.head.value 148 | list.head = list.head.next 149 | return tmp 150 | } 151 | 152 | list.contains = (tgt) => { 153 | let cur = list.head 154 | 155 | while (cur) { 156 | if (cur.value === tgt) { 157 | return true 158 | } 159 | cur = cur.next 160 | } 161 | return false 162 | } 163 | return list 164 | } 165 | 166 | // 167 | class LinkedList { 168 | constructor() { 169 | this.head = null 170 | this.length = 0 171 | } 172 | 173 | get(pos) { 174 | if (pos >= this.length) { 175 | throw new Error('Position outside range.') 176 | } 177 | let curr = this.head 178 | for (let i = 0; i < pos; i++) { 179 | curr = curr.next 180 | } 181 | return curr 182 | } 183 | 184 | add(val, pos) { 185 | const node = { 186 | value: val, 187 | next: null, 188 | } 189 | if (pos === 0) { 190 | node.next = this.head 191 | this.head = node 192 | } else { 193 | const prev = this.get(pos - 1) 194 | const curr = prev.next 195 | node.next = curr 196 | prev.next = node 197 | } 198 | this.length++ 199 | } 200 | 201 | remove(pos) { 202 | if (!this.head) { 203 | throw new Error('Empty.') 204 | } 205 | if (pos === 0) { 206 | this.head = this.head.next 207 | } else { 208 | const prev = this.get(pos - 1) 209 | prev.next = prev.next.next 210 | } 211 | this.length-- 212 | } 213 | } 214 | 215 | // 216 | class List { 217 | constructor() { 218 | this.memory = [] 219 | this.length = 0 220 | } 221 | 222 | get(addr) { 223 | return this.memory[addr] 224 | } 225 | 226 | push(val) { 227 | this.memory[this.length] = val 228 | this.length++ 229 | } 230 | 231 | pop() { 232 | if (this.length === 0) { 233 | return 234 | } 235 | const last = this.length - 1 236 | const val = this.memory[last] 237 | delete this.memory[last] 238 | this.length-- 239 | return val 240 | } 241 | 242 | unshift(val) { 243 | let prev = val 244 | for (let addr = 0; addr < this.length; addr++) { 245 | const curr = this.memory[addr] 246 | this.memory[addr] = prev 247 | prev = curr 248 | } 249 | this.memory[this.length] = prev 250 | this.length++ 251 | } 252 | 253 | shift() { 254 | if (this.length === 0) { 255 | return 256 | } 257 | const val = this.memory[0] 258 | for (let addr = 0; addr < this.length; addr++) { 259 | this.memory[addr] = this.memory[addr + 1] 260 | } 261 | delete this.memory[this.length - 1] 262 | this.length-- 263 | return val 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /intermediate/curry.js: -------------------------------------------------------------------------------- 1 | // curry 2 | // usage: 3 | // const add = (a, b) => a + b 4 | // const curried = curry(add) 5 | // console.log(curried((2)(2))) // => 4 6 | 7 | /* 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | * 42 | * 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 54 | * 55 | * 56 | * 57 | * 58 | * 59 | * 60 | * 61 | * 62 | * 63 | * 64 | * 65 | * 66 | * 67 | * 68 | * 69 | * 70 | * 71 | * 72 | * 73 | * 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | */ 82 | 83 | // NOTE: I've seen sooo many cool solutions to this one! 84 | // Several of them are included here. 85 | 86 | const curry = (fn) => { 87 | const getFunctionArguments = (fn) => { 88 | if (typeof fn !== 'function') { 89 | throw new TypeError( 90 | `Expected argument to be a function! Received a ${typeof fn}.` 91 | ) 92 | } 93 | const functionAsString = fn.toString() 94 | if (functionAsString) { 95 | const m = functionAsString.match(/\(.*?\)/) 96 | if (m && m[0]) { 97 | const args = m[0] // match everything between brackets 98 | .replace(/[()]/gi, '') // remove brackets 99 | .replace(/\s/gi, '') // remove all whitespace 100 | .split(',') // split on the commas 101 | return args.filter((a) => a) // remove possible empty string from the result 102 | } 103 | } 104 | } 105 | const originalArguments = getFunctionArguments(fn) || [] 106 | const makeCurriedFunc = (...args) => { 107 | const givenArguments = args || [] 108 | return givenArguments.length < originalArguments.length 109 | ? (...rest) => makeCurriedFunc(...givenArguments, ...rest) 110 | : fn(...givenArguments) 111 | } 112 | return (...args) => makeCurriedFunc(...args) 113 | } 114 | 115 | function curry(fn) { 116 | return innerCurry([]) 117 | function innerCurry(args) { 118 | if (args.length >= fn.length) { 119 | return fn.apply(null, args) 120 | } else { 121 | return function () { 122 | return innerCurry(args.concat([].slice.call(arguments))) 123 | } 124 | } 125 | } 126 | } 127 | 128 | // Prototype's version? 129 | Function.prototype.curry = function () { 130 | var fn = this, 131 | args = Array.prototype.slice.call(arguments) 132 | return function () { 133 | return fn.apply(this, args.concat(Array.prototype.slice.call(arguments))) 134 | } 135 | } 136 | 137 | // Functional's version? 138 | Function.prototype.partial = function () { 139 | var fn = this, 140 | args = Array.prototype.slice.call(arguments) 141 | return function () { 142 | var arg = 0 143 | for (var i = 0; i < args.length && arg < arguments.length; i++) { 144 | if (args[i] === undefined) { 145 | args[i] = arguments[arg++] 146 | } 147 | return fn.apply(this, args) 148 | } 149 | } 150 | } 151 | 152 | // 153 | Function.prototype.curry = function () { 154 | if (arguments.length < 1) { 155 | return this 156 | } 157 | var __method = this, 158 | args = toArray(arguments) 159 | return function () { 160 | return __method.apply(this, args.concat(toArray(arguments))) 161 | } 162 | } 163 | 164 | Function.prototype.curry = function () { 165 | var method = this, 166 | i = 0, 167 | len = this.length, 168 | args = [] 169 | 170 | function f() { 171 | args.push(arguments[0]) 172 | if (++i < len) { 173 | return f 174 | } else { 175 | method.apply(this, args) 176 | } 177 | } 178 | return f 179 | } 180 | 181 | // 182 | const argsArr = (args) => Array.from(args) 183 | 184 | const curry = (fn, n) => { 185 | const args = argsArr(arguments) 186 | if (n === args.length - 2) { 187 | return fn.apply(undefined, args.slice(2)) 188 | } else { 189 | return () => { 190 | return curry.apply(undefined, args.concat(arguments)) 191 | } 192 | } 193 | } 194 | // modified to use Function.length 195 | const newCurry = (fn, n) => { 196 | let args = argsArr(arguments) 197 | if (typeof n == 'undefined') { 198 | args[1] = fn.length 199 | } 200 | if (n === args.length - 2) { 201 | return fn.apply(undefined, args.slice(2)) 202 | } 203 | return function () { 204 | return newCurry.apply(undefined, args.concat(argsArr(arguments))) 205 | } 206 | } 207 | 208 | // okay, that's cute because it just lets you specify however many you want, but... 209 | const cur = (fn, ...argsOne) => (...argsTwo) => fn(...argsOne, ...argsTwo) 210 | // or, allowing placeholders, as in underscore: 211 | const curMore = (fn, ...argsOne) => { 212 | let i = argsOne.indexOf(_) 213 | let argsOne = i === -1 ? [] : argsOne.splice(i).slice(1) 214 | return (...argsTwo) => fn(...argsOne, ...argsTwo, ...argsThree) 215 | } 216 | 217 | // 218 | function curry(fx) { 219 | var arity = fx.length 220 | function f1() { 221 | var args = Array.prototype.slice.call(arguments, 0) 222 | if (args.length >= arity) { 223 | return fx.apply(null, args) 224 | } 225 | function f2() { 226 | return f1.apply( 227 | null, 228 | args.concat(Array.prototype.slice.call(arguments, 0)) 229 | ) 230 | } 231 | f2.toString = function () { 232 | return fToString(fx) + '(' + args.join(', ') + ')' 233 | } 234 | return f2 235 | } 236 | f1.toString = function () { 237 | return fToString(fx) 238 | } 239 | return f1 240 | } 241 | 242 | // this is approximately the same as wu.js's .autoCurry() (which has been removed??) 243 | var autoCurry = (function () { 244 | var toArray = function toArray(arr, from) { 245 | return Array.prototype.slice.call(arr, from || 0) 246 | }, 247 | curry = function curry(fn) { 248 | var args = toArray(arguments, 1) 249 | return function curried() { 250 | return fn.apply(this, args.concat(toArray(arguments))) 251 | } 252 | } 253 | 254 | return function autoCurry(fn, numArgs) { 255 | numArgs = numArgs || fn.length 256 | return function autoCurried() { 257 | if (arguments.length < numArgs) { 258 | return numArgs - arguments.length > 0 259 | ? autoCurry( 260 | curry.apply(this, [fn].concat(toArray(arguments))), 261 | numArgs - arguments.length 262 | ) 263 | : curry.apply(this, [fn].concat(toArray(arguments))) 264 | } else { 265 | return fn.apply(this, arguments) 266 | } 267 | } 268 | } 269 | })() 270 | 271 | // 272 | const curry = (fn) => { 273 | const originalArguments = fn 274 | .toString() 275 | .match(/\(.*?\)/)[0] 276 | .replace(/[()]/gi, '') 277 | .replace(/\s/gi, '') 278 | .split(',') 279 | .filter((x) => x) 280 | 281 | const makeCurriedFunc = (...args) => { 282 | const givenArguments = [...args] || [] 283 | return givenArguments.length < originalArguments.length 284 | ? (...rest) => makeCurriedFunc(...givenArguments, ...rest) 285 | : fn(...givenArguments) 286 | } 287 | 288 | return (...args) => makeCurriedFunc(...args) 289 | } 290 | --------------------------------------------------------------------------------