├── .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 |
--------------------------------------------------------------------------------