├── Unit_1 ├── Lesson_4 │ ├── items.html │ └── let.js ├── Lesson_5 │ └── const.js ├── Lesson_6 │ ├── binary_ip.js │ ├── includes.js │ └── pad.js ├── Lesson_7 │ └── templates.js └── Lesson_8_Capstone │ └── dsl.js ├── Unit_2 ├── Lesson_10 │ └── spaceship.js ├── Lesson_11 │ └── destructuring.js ├── Lesson_12 │ └── state_manager.js ├── Lesson_13 │ ├── spaceship.js │ └── symbol_primitive.js ├── Lesson_14_Capstone │ └── index.js └── Lesson_9 │ └── avg.js ├── Unit_3 ├── Lesson_15 │ └── rest.js ├── Lesson_16 │ └── car.js ├── Lesson_17 │ └── arrow_function.js ├── Lesson_18 │ ├── generators.js │ └── infinite_lists.js └── Lesson_19_Capstone │ └── prisoners_delimma.js ├── Unit_4 └── Lesson_22_Capstone │ ├── final │ ├── .babelrc │ ├── .gitignore │ ├── dest │ │ └── build.js │ ├── index.html │ ├── package.json │ └── src │ │ ├── index.js │ │ ├── keyboard.js │ │ ├── letter_slots.js │ │ ├── status.js │ │ ├── status_display.js │ │ └── words.js │ └── start │ ├── .babelrc │ ├── .gitignore │ ├── dest │ └── build.js │ ├── index.html │ ├── package.json │ └── src │ └── index.js ├── Unit_5 ├── Lesson_23 │ ├── comparing_of_in.js │ ├── html_safe.js │ ├── list_friends.js │ ├── primes.js │ ├── reverse.js │ ├── spread.js │ ├── words.js │ └── yield_all.js ├── Lesson_24 │ └── set_utils.js ├── Lesson_25 │ ├── obj_to_map.js │ └── singleton.js └── Lesson_26_Capstone │ ├── final │ ├── .babelrc │ ├── .gitignore │ ├── dest │ │ └── build.js │ ├── index.html │ ├── package.json │ └── src │ │ ├── cards.js │ │ ├── elements.js │ │ ├── index.js │ │ ├── templates.js │ │ └── utils.js │ └── start │ ├── .babelrc │ ├── .gitignore │ ├── dest │ └── build.js │ ├── index.html │ ├── package.json │ └── src │ ├── elements.js │ └── templates.js ├── Unit_6 ├── Lesson_27 │ └── fish.js ├── Lesson_28 │ └── car.js └── Lesson_29_Capstone │ ├── final │ ├── .babelrc │ ├── .gitignore │ ├── dest │ │ └── build.js │ ├── index.html │ ├── package.json │ └── src │ │ ├── comet.js │ │ ├── explosion.js │ │ ├── framework │ │ ├── canvas.js │ │ ├── controllable_sprite.js │ │ ├── drifting_sprite.js │ │ ├── game.js │ │ ├── hit_test.js │ │ ├── interactions.js │ │ ├── sprite.js │ │ └── utils.js │ │ ├── index.js │ │ ├── rocket.js │ │ ├── shapes.js │ │ └── ship.js │ └── start │ ├── .babelrc │ ├── .gitignore │ ├── dest │ └── build.js │ ├── index.html │ ├── package.json │ └── src │ ├── framework │ ├── canvas.js │ ├── controllable_sprite.js │ ├── drifting_sprite.js │ ├── game.js │ ├── hit_test.js │ ├── interactions.js │ ├── sprite.js │ └── utils.js │ └── shapes.js ├── Unit_7 ├── Lesson_30 │ └── user_view.js ├── Lesson_31 │ ├── alligator.js │ ├── catching_errors.js │ ├── fetch_image.js │ ├── fetch_orgs.js │ ├── then_chaining.js │ └── wait.js ├── Lesson_32 │ ├── all_resolved.js │ ├── fail.js │ ├── fetch_image.js │ └── runner.js ├── Lesson_33 │ ├── current_time.js │ ├── filter.js │ └── from_set.js └── Lesson_34_Capstone │ ├── final │ ├── .babelrc │ ├── dest │ │ └── build.js │ ├── index.html │ ├── package.json │ └── src │ │ └── index.js │ └── start │ ├── .babelrc │ ├── dest │ └── build.js │ ├── index.html │ ├── package.json │ └── src │ └── index.js └── readme.md /Unit_1/Lesson_4/items.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Unit_1/Lesson_4/let.js: -------------------------------------------------------------------------------- 1 | //------------ 2 | 3 | let read, write; 4 | { 5 | let data = {}; 6 | 7 | write = function (key, val) { 8 | data[key] = val; 9 | } 10 | 11 | read = function (key) { 12 | return data[key]; 13 | } 14 | } 15 | 16 | write('message', 'Welcome to ES6!'); 17 | read('message'); 18 | // console.log(data); This line commented out because it errors 19 | 20 | //------------ 21 | 22 | let num = 0; 23 | function getNum() { 24 | if (!num) { 25 | num = 1; 26 | } 27 | return num; 28 | } 29 | console.log( getNum() ); 30 | 31 | //------------ 32 | -------------------------------------------------------------------------------- /Unit_1/Lesson_5/const.js: -------------------------------------------------------------------------------- 1 | const ADD_ITEM = 'ADD_ITEM'; 2 | const DEL_ITEM = 'DEL_ITEM'; 3 | const CLEAR_ALL_ITEMS = 'CLEAR_ALL_ITEMS'; 4 | const items = []; 5 | 6 | function actionHandler(action) { 7 | switch (action.type) { 8 | case ADD_ITEM: 9 | items.push(action.item); 10 | break; 11 | case DEL_ITEM: 12 | items.splice(items.indexOf(action.item), 1); 13 | break; 14 | case CLEAR_ALL_ITEMS: 15 | items.splice(0, items.length); 16 | break; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /Unit_1/Lesson_6/binary_ip.js: -------------------------------------------------------------------------------- 1 | function binaryIP(decimalIPStr) { 2 | return decimalIPStr.split('.').map(function(octet) { 3 | return Number(octet).toString(2).padStart(8, '0') 4 | }).join('.'); 5 | } 6 | 7 | binaryIP('192.168.2.1'); 8 | -------------------------------------------------------------------------------- /Unit_1/Lesson_6/includes.js: -------------------------------------------------------------------------------- 1 | let locationA = 'Atlanta, Ga'; 2 | let locationB = 'Galveston, Tx'; 3 | 4 | locationA.includes('Ga'); 5 | locationB.includes('Ga'); 6 | 7 | locationA.includes('Ga', locationA.indexOf(' ')); 8 | locationB.includes('Ga', locationB.indexOf(' ')); 9 | -------------------------------------------------------------------------------- /Unit_1/Lesson_6/pad.js: -------------------------------------------------------------------------------- 1 | 'abc'.padStart(6); 2 | 'abc'.padEnd(6); 3 | 4 | 'abc'.padStart(6, 'x'); 5 | 'abc'.padEnd(6, 'x'); 6 | 7 | 'abc'.padStart(6, 'xyz'); 8 | 'abc'.padEnd(6, 'xyz'); 9 | 10 | 'abc'.padStart(8, '123'); 11 | 'abc'.padEnd(5, '123'); 12 | 13 | 'abcdef'.padStart(4, '123'); 14 | -------------------------------------------------------------------------------- /Unit_1/Lesson_7/templates.js: -------------------------------------------------------------------------------- 1 | function fa(icon) { 2 | return `fa-${icon} fa`; 3 | } 4 | 5 | fa('check-square'); 6 | 7 | //--- 8 | 9 | function logParts() { 10 | let stringParts = arguments[0]; 11 | let values = [].slice.call(arguments, 1); <1> 12 | console.log( 'Strings:', stringParts ); 13 | console.log( 'Values:', values ); 14 | } 15 | 16 | logParts`1${2}3${4}${5}`; 17 | 18 | //--- 19 | 20 | function noop() { 21 | let stringParts = arguments[0]; 22 | let values = [].slice.call(arguments, 1); 23 | return stringParts.reduce(function(memo, nextPart) { 24 | return memo + String(values.shift()) + nextPart; 25 | }); 26 | } 27 | 28 | noop`1${2}3${4}${5}`; 29 | 30 | //--- 31 | 32 | function stripWS() { 33 | let stringParts = arguments[0]; 34 | let values = [].slice.call(arguments, 1); 35 | let str = stringParts.reduce(function(memo, nextPart) { 36 | return memo + String(values.shift()) + nextPart; 37 | }); 38 | return str.replace(/\n\s*/g, ''); 39 | } 40 | 41 | function getProductHTML(product) { 42 | return stripWS` 43 |
44 |
45 | ${product.name} 46 |
47 |
${product.desc}
48 |
49 | `; 50 | } 51 | -------------------------------------------------------------------------------- /Unit_1/Lesson_8_Capstone/dsl.js: -------------------------------------------------------------------------------- 1 | function createTag(func) { 2 | return function() { 3 | const strs = arguments[0]; 4 | const vals = [].slice.call(arguments, 1); 5 | return func(strs, vals); 6 | } 7 | } 8 | 9 | function interlace(strs, vals) { 10 | vals = vals.slice(0); 11 | return strs.reduce(function(all, str) { 12 | return all + String(vals.shift()) + str; 13 | }); 14 | } 15 | 16 | function htmlEscape (str) { 17 | str = str.replace(//g, '>'); 19 | return str; 20 | } 21 | 22 | const htmlSafe = createTag(function(strs, vals){ 23 | return interlace(strs, vals.map(htmlEscape)); 24 | }); 25 | 26 | 27 | const expand = function(parts, items){ 28 | const start = parts[0]; 29 | const end = parts[1]; 30 | const mapped = items.map(function(item){ 31 | return start + item + end; 32 | }); 33 | 34 | return mapped.join(''); 35 | }; 36 | 37 | 38 | const lessons = [ 39 | 'Declaring Variables with let', 40 | 'Declaring constants with const', 41 | 'New String Methods', 42 | 'Template Literals', 43 | ] 44 | 45 | const html = `` 48 | -------------------------------------------------------------------------------- /Unit_2/Lesson_10/spaceship.js: -------------------------------------------------------------------------------- 1 | const baseSpaceShip = { 2 | fly: function() { 3 | // ... fly function implementation 4 | }, 5 | shoot: function() { 6 | // ... shoot function implementation 7 | }, 8 | destroy: function() { 9 | // ... function for when the ship is destroyed 10 | } 11 | } 12 | 13 | function enhancedSpaceShip(enhancements) { 14 | return Object.assign({}, baseSpaceShip, enhancements); 15 | } 16 | 17 | function createBomberSpaceShip() { 18 | return enhancedSpaceShip({ 19 | bomb: function() { 20 | // ... make the ship drop a bomb 21 | } 22 | }); 23 | } 24 | 25 | function createStealthSpaceShip() { 26 | return enhancedSpaceShip({ 27 | stealth: function() { 28 | // ... make the ship invisible 29 | } 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /Unit_2/Lesson_11/destructuring.js: -------------------------------------------------------------------------------- 1 | let geolocation = { 2 | "location": { 3 | "lat": 51.0, 4 | "lng": -0.1 5 | }, 6 | "accuracy": 1200.4 7 | } 8 | 9 | let { location: {lat, lng}, accuracy } = geolocation; 10 | 11 | console.log(lat); // 51.0 12 | console.log(lng); // -0.1 13 | console.log(accuracy); // 1200.4 14 | console.log(location); // undefined 15 | 16 | //---- 17 | 18 | let coords = [51.0, -0.1]; 19 | 20 | let [lat, lng] = coords; 21 | 22 | console.log(lat); 23 | console.log(lng); 24 | 25 | //---- 26 | 27 | let location = ['Atlanta', [33.7490, 84.3880]]; 28 | 29 | let [ place, [lat, lng] ] = location; 30 | 31 | console.log(place); // "Atlanta" 32 | console.log(lat); // 33.7490 33 | console.log(lng); // 84.3880 34 | 35 | //---- 36 | 37 | let product = { 38 | name: 'Whiskey Glass', 39 | details: { 40 | price: 18.99, 41 | description: 'Enjoy your whiskey in this glass' 42 | }, 43 | images: { 44 | primary: '/images/main.jpg', 45 | others: [ 46 | '/images/1.jpg', 47 | '/images/2.jpg' 48 | ] 49 | } 50 | } 51 | 52 | let { 53 | name, 54 | details: { price, description}, 55 | images: { 56 | primary, 57 | others: [secondary, tertiary] 58 | } 59 | } = product; 60 | 61 | console.log(name); 62 | console.log(price); 63 | console.log(description); 64 | console.log(primary); 65 | console.log(secondary); 66 | console.log(tertiary); 67 | 68 | console.log(details); 69 | console.log(images); 70 | console.log(others); 71 | 72 | //---- 73 | 74 | const { 0:a, 1:b, length } = ['foo', 'bar'] 75 | 76 | console.log(a) 77 | console.log(b) 78 | console.log(length) 79 | 80 | //---- 81 | 82 | const [first, second, last] = 'abc' 83 | 84 | console.log(first) 85 | console.log(second) 86 | console.log(last) 87 | -------------------------------------------------------------------------------- /Unit_2/Lesson_12/state_manager.js: -------------------------------------------------------------------------------- 1 | function createStateManager() { 2 | const state = {}; 3 | return { 4 | update(changes) { 5 | Object.assign(state, changes); 6 | }, 7 | getState() { 8 | return Object.assign({}, state); 9 | } 10 | } 11 | } 12 | 13 | function setValue(name, value) { 14 | stateManager.update({ 15 | [name]: value 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /Unit_2/Lesson_13/spaceship.js: -------------------------------------------------------------------------------- 1 | const baseSpaceShip = { 2 | [Symbol.for('Spaceship.weapon')]: { 3 | fire() { 4 | // the default shooting implementation 5 | } 6 | }, 7 | fire: function() { 8 | if (this.hasAmmo()) { 9 | const weapon = this[Symbol.for('Spaceship.weapon')]; 10 | weapon.fire(); 11 | this.decrementAmmo(); 12 | } 13 | }, 14 | 15 | // other methods omitted 16 | } 17 | 18 | const bomberSpaceShip = Object.assign({}, baseSpaceShip, { 19 | [Symbol.for('Spaceship.weapon')]: { 20 | fire() { 21 | // drop a bomb 22 | } 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /Unit_2/Lesson_13/symbol_primitive.js: -------------------------------------------------------------------------------- 1 | const age = { 2 | number: 32, 3 | string: 'thirty-two', 4 | [Symbol.toPrimitive](hint) { 5 | switch(hint) { 6 | case 'string': 7 | return this.string; 8 | break; 9 | case 'number': 10 | return this.number; 11 | break; 12 | default: 13 | return `${this.string}(${this.number})`; 14 | break; 15 | } 16 | } 17 | }; 18 | 19 | console.log(` 20 | I am ${age} years old, but by the time you 21 | read this I will be at least ${+age + 1} 22 | `); 23 | console.log( age + '' ); 24 | console.log( age.toString() ); 25 | -------------------------------------------------------------------------------- /Unit_2/Lesson_14_Capstone/index.js: -------------------------------------------------------------------------------- 1 | function lock(secret) { 2 | const key = Symbol('key') 3 | 4 | return { 5 | key, unlock(keyUsed) { 6 | if (keyUsed === key) { 7 | return secret 8 | } else { 9 | return '*'.repeat( secret.length || secret.toString().length ) 10 | } 11 | } 12 | } 13 | } 14 | 15 | function choose(message, options, secondAttempt) { 16 | const opts = options.map(function(option, index) { <1> 17 | return `Type ${index+1} for: ${option}` 18 | }) 19 | 20 | const resp = Number( prompt(`${message}\n\n${opts.join('\n')}`) ) - 1 <2> 21 | 22 | if ( options[resp] ) { 23 | return resp <3> 24 | } else if (!secondAttempt) { 25 | return choose(`Last try!\n${message}`, options, true) <4> 26 | } else { 27 | throw Error('No selection') <5> 28 | } 29 | } 30 | 31 | function init() { 32 | const { key:key1, unlock:door1 } = lock('A new car') 33 | const { key:key2, unlock:door2 } = lock('A trip to Hawaii') 34 | const { key:key3, unlock:door3 } = lock('$100 Dollars') 35 | 36 | const keys = [key1, key2, key3] 37 | const doors = [door1, door2, door3] 38 | 39 | const key = keys[Math.floor(Math.random() * 3)] 40 | 41 | const message = 'You have been given a \u{1F511} please choose a door.' 42 | 43 | const options = doors.map(function(door, index) { 44 | return `Door #${index+1}: ${door()}` 45 | }) 46 | 47 | const door = doors[ choose(message, options) ] 48 | 49 | alert( door(key) ) 50 | } 51 | -------------------------------------------------------------------------------- /Unit_2/Lesson_9/avg.js: -------------------------------------------------------------------------------- 1 | function avg() { 2 | const args = Array.from(arguments); 3 | const sum = args.reduce(function(a, b) { 4 | return a + b; 5 | }); 6 | return sum / args.length; 7 | } 8 | -------------------------------------------------------------------------------- /Unit_3/Lesson_15/rest.js: -------------------------------------------------------------------------------- 1 | function countKids(...allMyChildren) { 2 | return `You have ${allMyChildren.length} children!`; 3 | } 4 | 5 | countKids('Talan', 'Jonathan'); 6 | 7 | function family(spouse, ...kids) { 8 | return `You are married to ${spouse} with ${kids.length} kids`; 9 | } 10 | 11 | family('Christina', 'Talan', 'Jonathan'); 12 | 13 | //---- 14 | 15 | function pluck(object, ...props) { 16 | return props.map(function(property) { 17 | return object[property]; 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /Unit_3/Lesson_16/car.js: -------------------------------------------------------------------------------- 1 | function car({ make = 'Ford', model = 'Mustang', year = 2017 } = {}) { 2 | console.log(`${make}:${model}:${year}`) 3 | } 4 | 5 | let modern = car(); <1> 6 | let classic = car({ year: 1965 }); 7 | -------------------------------------------------------------------------------- /Unit_3/Lesson_17/arrow_function.js: -------------------------------------------------------------------------------- 1 | const add = (a, b) => a + b; 2 | const rand = () => Math.random(); 3 | 4 | const exponent = exp => base => base ** exp 5 | 6 | const square = exponent(2) 7 | const cube = exponent(3) 8 | const powerOf4 = exponent(4) 9 | 10 | square(5) 11 | cube(5) 12 | powerOf4(5) 13 | 14 | function pluck(object, ...props) { 15 | return props.map( prop => object[prop] ); 16 | } 17 | -------------------------------------------------------------------------------- /Unit_3/Lesson_18/generators.js: -------------------------------------------------------------------------------- 1 | function* myGeneratorFunction() { 2 | console.log('Started') 3 | let recievedA = yield 'a'; 4 | console.log('recievedA:', recievedA); 5 | let recievedB = yield 'b'; 6 | console.log('recievedB:', recievedB); 7 | } 8 | 9 | const myGenerator = myGeneratorFunction(); 10 | 11 | let gotA = myGenerator.next(0); 12 | console.log('gotA:', gotA); 13 | let gotB = myGenerator.next(1); 14 | console.log('gotB:', gotB); 15 | let gotC = myGenerator.next(2); 16 | console.log('gotC:', gotC); 17 | -------------------------------------------------------------------------------- /Unit_3/Lesson_18/infinite_lists.js: -------------------------------------------------------------------------------- 1 | function* infinite() { 2 | let i = 0; 3 | while (true) { 4 | yield i++; 5 | } 6 | } 7 | 8 | function* fibonacci() { 9 | let prev = 0, next = 1; 10 | 11 | for (;;) { 12 | yield next; 13 | [next, prev] = [next + prev, next]; 14 | } 15 | } 16 | 17 | function take(gen, count) { 18 | return Array(count).fill(1).map( 19 | () => gen.next().value 20 | ); 21 | } 22 | 23 | take(infinite(), 7); 24 | take(fibonacci(), 7); 25 | -------------------------------------------------------------------------------- /Unit_3/Lesson_19_Capstone/prisoners_delimma.js: -------------------------------------------------------------------------------- 1 | // --- Prisoners 2 | 3 | const retaliate = { 4 | name: 'retaliate', 5 | *generator() { 6 | let stats = [] 7 | for(;;) { 8 | stats = yield { 9 | snitch() { 10 | return stats.pop() > 0 11 | } 12 | } 13 | } 14 | } 15 | } 16 | 17 | const never = { 18 | name: 'never', 19 | * generator() { 20 | for(;;) { 21 | yield { 22 | snitch() { 23 | return false 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | const always = { 31 | name: 'always', 32 | * generator() { 33 | for(;;) { 34 | yield { 35 | snitch() { 36 | return true 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | const rand = { 44 | name: 'random', 45 | * generator() { 46 | for(;;) { 47 | yield { 48 | snitch() { 49 | return Math.random() > 0.5 50 | } 51 | } 52 | } 53 | } 54 | } 55 | 56 | // --- Simulation 57 | 58 | function* getPrisoners({ name, generator }) { 59 | const stats = [], prisoners = generator() 60 | 61 | for(;;) { 62 | const prisoner = prisoners.next(stats.slice()).value 63 | 64 | const finished = yield Object.assign({}, prisoner, { 65 | sentencedTo(years) { 66 | stats.push(years) 67 | } 68 | }) 69 | 70 | if (finished) { 71 | break 72 | } 73 | } 74 | 75 | return { name, stats } 76 | } 77 | 78 | function getScore({ value }) { 79 | const { name, stats } = value 80 | const score = stats.reduce( (total, years) => total + years) 81 | return { 82 | [name]: score 83 | } 84 | } 85 | 86 | function interrogate(criminal, accomplice) { 87 | 88 | const criminalsnitched = criminal.snitch() 89 | const accomplicesnitched = accomplice.snitch() 90 | 91 | if (criminalsnitched && accomplicesnitched) { 92 | criminal.sentencedTo(1) 93 | accomplice.sentencedTo(1) 94 | } else if (criminalsnitched) { 95 | criminal.sentencedTo(0) 96 | accomplice.sentencedTo(2) 97 | } else if (accomplicesnitched) { 98 | criminal.sentencedTo(2) 99 | accomplice.sentencedTo(0) 100 | } else { 101 | criminal.sentencedTo(0) 102 | accomplice.sentencedTo(0) 103 | } 104 | } 105 | 106 | function do50times(cb) { 107 | for (let i = 0; i < 50; i++) { 108 | cb() 109 | } 110 | } 111 | 112 | function test(...candidates) { 113 | 114 | const factories = candidates.map(getPrisoners) 115 | const tested = [] 116 | 117 | for(;;) { 118 | const criminal = factories.pop() 119 | tested.push(criminal) 120 | 121 | do50times(() => interrogate(criminal.next().value, criminal.next().value)) 122 | 123 | if (!factories.length) { 124 | break 125 | } 126 | 127 | for (let i = 0; i < factories.length; i++) { 128 | const accomplice = factories[i] 129 | do50times(() => interrogate(criminal.next().value, accomplice.next().value)) 130 | } 131 | } 132 | 133 | return Object.assign.apply({}, tested.map(criminal => ( 134 | getScore(criminal.next(true) 135 | )))) 136 | } 137 | 138 | test(retaliate , never, always, rand); 139 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-es2015-modules-commonjs"], 3 | "sourceMaps": "inline" 4 | } 5 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/dest/build.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o${ letter }`; 16 | } else { 17 | return ``; 18 | } 19 | } 20 | 21 | function keyboard(guesses) { 22 | return ` 23 |
24 |
${ firstRow.map(char => key(char, guesses)).join('') }
25 |
${ secondRow.map(char => key(char, guesses)).join('') }
26 |
27 | `; 28 | } 29 | 30 | },{}],2:[function(require,module,exports){ 31 | 'use strict'; 32 | 33 | Object.defineProperty(exports, "__esModule", { 34 | value: true 35 | }); 36 | exports.default = letterSlots; 37 | function letterSlot(letter, guesses) { 38 | if (guesses.includes(letter)) { 39 | return `${ letter }`; 40 | } else { 41 | return ' '; 42 | } 43 | } 44 | 45 | function letterSlots(word, guesses) { 46 | const slots = word.split('').map(letter => letterSlot(letter, guesses)); 47 | 48 | return `
${ slots.join('') }
`; 49 | } 50 | 51 | },{}],3:[function(require,module,exports){ 52 | 'use strict'; 53 | 54 | Object.defineProperty(exports, "__esModule", { 55 | value: true 56 | }); 57 | exports.guessesRemaining = guessesRemaining; 58 | exports.isGameWon = isGameWon; 59 | exports.isGameOver = isGameOver; 60 | exports.isStillPlaying = isStillPlaying; 61 | const MAX_INCORRECT_GUESSES = 5; 62 | 63 | function guessesRemaining(word, guesses) { 64 | const incorrectGuesses = guesses.filter(char => !word.includes(char)); 65 | return MAX_INCORRECT_GUESSES - incorrectGuesses.length; 66 | } 67 | 68 | function isGameWon(word, guesses) { 69 | return !word.split('').find(letter => !guesses.includes(letter)); 70 | } 71 | 72 | function isGameOver(word, guesses) { 73 | return !guessesRemaining(word, guesses) && !isGameWon(word, guesses); 74 | } 75 | 76 | function isStillPlaying(word, guesses) { 77 | return guessesRemaining(word, guesses) && !isGameOver(word, guesses) && !isGameWon(word, guesses); 78 | } 79 | 80 | },{}],4:[function(require,module,exports){ 81 | 'use strict'; 82 | 83 | Object.defineProperty(exports, "__esModule", { 84 | value: true 85 | }); 86 | exports.default = statusDisplay; 87 | 88 | var _status = require('./status'); 89 | 90 | var status = _interopRequireWildcard(_status); 91 | 92 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } 93 | 94 | function getMessage(word, guesses) { 95 | if (status.isGameWon(word, guesses)) { 96 | return 'YOU WIN!'; 97 | } else if (status.isGameOver(word, guesses)) { 98 | return 'GAME OVER'; 99 | } else { 100 | return `Guesses Remaining: ${ status.guessesRemaining(word, guesses) }`; 101 | } 102 | } 103 | 104 | function statusDisplay(word, guesses) { 105 | return `
${ getMessage(word, guesses) }
`; 106 | } 107 | 108 | },{"./status":3}],5:[function(require,module,exports){ 109 | 'use strict'; 110 | 111 | Object.defineProperty(exports, "__esModule", { 112 | value: true 113 | }); 114 | exports.default = getRandomWord; 115 | function getWords(cb) { 116 | cb(['bacon', 'teacher', 'automobile']); 117 | } 118 | 119 | function getRandomWord(cb) { 120 | getWords(words => { 121 | const randomWord = words[Math.floor(Math.random() * words.length)]; 122 | cb(randomWord.toUpperCase()); 123 | }); 124 | } 125 | 126 | },{}],6:[function(require,module,exports){ 127 | 'use strict'; 128 | 129 | var _words = require('./words'); 130 | 131 | var _words2 = _interopRequireDefault(_words); 132 | 133 | var _status = require('./status'); 134 | 135 | var _letter_slots = require('./letter_slots'); 136 | 137 | var _letter_slots2 = _interopRequireDefault(_letter_slots); 138 | 139 | var _keyboard = require('./keyboard'); 140 | 141 | var _keyboard2 = _interopRequireDefault(_keyboard); 142 | 143 | var _status_display = require('./status_display'); 144 | 145 | var _status_display2 = _interopRequireDefault(_status_display); 146 | 147 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 148 | 149 | function drawGame(word, guesses) { 150 | document.querySelector('#status-display').innerHTML = (0, _status_display2.default)(word, guesses); 151 | document.querySelector('#letter-slots').innerHTML = (0, _letter_slots2.default)(word, guesses); 152 | document.querySelector('#keyboard').innerHTML = (0, _keyboard2.default)(guesses); 153 | } 154 | 155 | (0, _words2.default)(word => { 156 | const guesses = []; 157 | 158 | document.addEventListener('click', event => { 159 | if ((0, _status.isStillPlaying)(word, guesses) && event.target.tagName === 'BUTTON') { 160 | guesses.push(event.target.dataset.char); 161 | drawGame(word, guesses); 162 | } 163 | }); 164 | 165 | drawGame(word, guesses); 166 | }); 167 | 168 | },{"./keyboard":1,"./letter_slots":2,"./status":3,"./status_display":4,"./words":5}]},{},[6]); 169 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hangman 6 | 52 | 53 | 54 |
55 |
56 |
57 |
58 |
59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "modules-hangman", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", 15 | "babelify": "^7.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/src/index.js: -------------------------------------------------------------------------------- 1 | import getRandomWord from './words' 2 | import { isStillPlaying } from './status' 3 | import letterSlots from './letter_slots' 4 | import keyboard from './keyboard' 5 | import statusDisplay from './status_display' 6 | 7 | function drawGame(word, guesses) { 8 | document.querySelector('#status-display').innerHTML = statusDisplay(word, guesses) 9 | document.querySelector('#letter-slots').innerHTML = letterSlots(word, guesses) 10 | document.querySelector('#keyboard').innerHTML = keyboard(guesses) 11 | } 12 | 13 | getRandomWord(word => { 14 | const guesses = [] 15 | 16 | document.addEventListener('click', event => { 17 | if (isStillPlaying(word, guesses) && event.target.tagName === 'BUTTON') { 18 | guesses.push(event.target.dataset.char) 19 | drawGame(word, guesses) 20 | } 21 | }) 22 | 23 | drawGame(word, guesses) 24 | }) 25 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/src/keyboard.js: -------------------------------------------------------------------------------- 1 | const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('') 2 | 3 | const firstRow = alphabet.slice(0, 13) 4 | const secondRow = alphabet.slice(13) 5 | 6 | function key(letter, guesses) { 7 | if (guesses.includes(letter)) { 8 | return `${letter}` 9 | } else { 10 | return `` 11 | } 12 | } 13 | 14 | export default function keyboard(guesses) { 15 | return ` 16 |
17 |
${ firstRow.map(char => key(char, guesses)).join('') }
18 |
${ secondRow.map(char => key(char, guesses)).join('') }
19 |
20 | ` 21 | } 22 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/src/letter_slots.js: -------------------------------------------------------------------------------- 1 | function letterSlot(letter, guesses) { 2 | if (guesses.includes(letter)) { 3 | return `${letter}` 4 | } else { 5 | return ' ' 6 | } 7 | } 8 | 9 | export default function letterSlots(word, guesses) { 10 | const slots = word.split('').map(letter => letterSlot(letter, guesses)) 11 | 12 | return `
${ slots.join('') }
` 13 | } 14 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/src/status.js: -------------------------------------------------------------------------------- 1 | const MAX_INCORRECT_GUESSES = 5 2 | 3 | export function guessesRemaining(word, guesses) { 4 | const incorrectGuesses = guesses.filter(char => !word.includes(char)) 5 | return MAX_INCORRECT_GUESSES - incorrectGuesses.length 6 | } 7 | 8 | export function isGameWon(word, guesses) { 9 | return !word.split('').find(letter => !guesses.includes(letter)) 10 | } 11 | 12 | export function isGameOver(word, guesses) { 13 | return !guessesRemaining(word, guesses) && !isGameWon(word, guesses) 14 | } 15 | 16 | export function isStillPlaying(word, guesses) { 17 | return guessesRemaining(word, guesses) && 18 | !isGameOver(word, guesses) && 19 | !isGameWon(word, guesses) 20 | } 21 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/src/status_display.js: -------------------------------------------------------------------------------- 1 | import * as status from './status' 2 | 3 | function getMessage(word, guesses) { 4 | if (status.isGameWon(word, guesses)) { 5 | return 'YOU WIN!' 6 | } else if (status.isGameOver(word, guesses)) { 7 | return 'GAME OVER' 8 | } else { 9 | return `Guesses Remaining: ${status.guessesRemaining(word, guesses)}` 10 | } 11 | } 12 | 13 | export default function statusDisplay(word, guesses) { 14 | return `
${getMessage(word, guesses)}
` 15 | } 16 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/final/src/words.js: -------------------------------------------------------------------------------- 1 | function getWords(cb) { 2 | cb(['bacon', 'teacher', 'automobile']) 3 | } 4 | 5 | export default function getRandomWord(cb) { 6 | getWords(words => { 7 | const randomWord = words[Math.floor(Math.random() * words.length)] 8 | cb(randomWord.toUpperCase()) 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/start/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-es2015-modules-commonjs"], 3 | "sourceMaps": "inline" 4 | } 5 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/start/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/start/dest/build.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_4/Lesson_22_Capstone/start/dest/build.js -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/start/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hangman 6 | 52 | 53 | 54 |
55 |
56 |
57 |
58 |
59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "modules-hangman", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", 15 | "babelify": "^7.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Unit_4/Lesson_22_Capstone/start/src/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_4/Lesson_22_Capstone/start/src/index.js -------------------------------------------------------------------------------- /Unit_5/Lesson_23/comparing_of_in.js: -------------------------------------------------------------------------------- 1 | const obj = { series: "Get Programming", publisher: "Manning" }; 2 | const arr = [ "Get Programming", "Manning" ]; 3 | 4 | for (const name in obj) { 5 | console.log(name); 6 | } 7 | 8 | for (const name of arr) { 9 | console.log(name); 10 | } 11 | -------------------------------------------------------------------------------- /Unit_5/Lesson_23/html_safe.js: -------------------------------------------------------------------------------- 1 | function interlace(strs, vals, processer=String) { 2 | vals = [ ...vals ]; 3 | return strs.reduce((all, str) => { 4 | return all + processer(vals.shift()) + str; 5 | }); 6 | } 7 | 8 | const htmlSafe = (strs, ...vals) => interlace(strs, vals, htmlEscape); 9 | -------------------------------------------------------------------------------- /Unit_5/Lesson_23/list_friends.js: -------------------------------------------------------------------------------- 1 | function* listFriends(friends) { 2 | const [first, second, ...others] = friends 3 | if (first) yield first 4 | if (second) yield second 5 | if (others.length === 1) yield others[0] 6 | if (others.length > 1) yield `${others.length} others` 7 | } 8 | 9 | const friends = ['JD', 'Christina', 'Talan', 'Jonathan'] 10 | 11 | const friendsList = [ ...listFriends(friends) ] 12 | 13 | const liked = `${sentenceJoin(friendsList)} liked this.` 14 | -------------------------------------------------------------------------------- /Unit_5/Lesson_23/primes.js: -------------------------------------------------------------------------------- 1 | // function primesIterator () { 2 | // const primes = [2, 3, 5] 3 | // return { 4 | // next() { 5 | // const value = primes.shift() 6 | // const done = !value 7 | // return { 8 | // value, 9 | // done 10 | // } 11 | // } 12 | // } 13 | // } 14 | 15 | function* primesIterator () { 16 | yield 2 17 | yield 3 18 | yield 5 19 | } 20 | 21 | const primesIterable = { 22 | [Symbol.iterator]: primesIterator 23 | } 24 | 25 | const myPrimes = [ ...primesIterable ] 26 | 27 | [ ...primesIterator() ] 28 | -------------------------------------------------------------------------------- /Unit_5/Lesson_23/reverse.js: -------------------------------------------------------------------------------- 1 | myArray[Symbol.iterator] = function* () { 2 | const copy = [ ...this ]; <1> 3 | copy.reverse(); 4 | for (const item of copy) yield item; 5 | } 6 | const backwards = [ ...myArray ] 7 | -------------------------------------------------------------------------------- /Unit_5/Lesson_23/spread.js: -------------------------------------------------------------------------------- 1 | const surname = "Isaacks"; 2 | const letters = [ ...surname ]; 3 | console.log(letters); 4 | 5 | const easyAs = [ ...'123', 'ABC' ]; 6 | console.log(easyAs); 7 | 8 | 9 | const vowels = ['A', 'E', 'I', 'O', 'U']; 10 | const consonants = 'BCDFGHJKLMNPQRSTVWXYZ'; 11 | 12 | const alphabet = [ ...vowels, ...consonants ].sort(); 13 | 14 | console.log(alphabet.length); 15 | -------------------------------------------------------------------------------- /Unit_5/Lesson_23/words.js: -------------------------------------------------------------------------------- 1 | const myString = Object("Iterables are quite something"); 2 | myString[Symbol.iterator] = function* () { 3 | for (const word of this.split(' ')) yield word; 4 | } 5 | const words = [ ...myString ] 6 | -------------------------------------------------------------------------------- /Unit_5/Lesson_23/yield_all.js: -------------------------------------------------------------------------------- 1 | function* yieldAll(...values) { 2 | for (const val of values) { 3 | yield val 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Unit_5/Lesson_24/set_utils.js: -------------------------------------------------------------------------------- 1 | function pop(set) { 2 | const last = [ ...set ].pop(); 3 | set.delete(last); 4 | return last; 5 | } 6 | 7 | function shift(set) { 8 | const first = [ ...set ].shift(); 9 | set.delete(first); 10 | return first; 11 | } 12 | 13 | function sendFirstToBack(set) { 14 | const arr = [ ...set ]; 15 | arr.push( arr.shift() ); 16 | return new Set(arr); 17 | } 18 | -------------------------------------------------------------------------------- /Unit_5/Lesson_25/obj_to_map.js: -------------------------------------------------------------------------------- 1 | const myObj = { foo: 'bar' } 2 | const myMap = new Map(Object.keys(myObj).map(key => [ key, myObj[key] ])) 3 | -------------------------------------------------------------------------------- /Unit_5/Lesson_25/singleton.js: -------------------------------------------------------------------------------- 1 | const instances = new Map(); 2 | export default function Singleton(constructor) { 3 | if (!instances.has(constructor)) { 4 | instances.set(constructor, new constructor()); 5 | } 6 | return instances.get(constructor); 7 | } 8 | 9 | console.log(Singleton(Array)) 10 | console.log(Singleton(Array).length) 11 | console.log(Singleton(Array).push("new value")) 12 | console.log(Singleton(Array).push("another value")) 13 | console.log(Singleton(Array).length) 14 | const now = Singleton(Date) 15 | setTimeout(() => { 16 | const later = Singleton(Date) 17 | console.log(now === later) 18 | }, 10000) 19 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-es2015-modules-commonjs"], 3 | "presets": ["stage-3"], 4 | "sourceMaps": "inline" 5 | } 6 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/dest/build.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { 32 | idx--; 33 | const swap = Math.floor(Math.random() * cards.length); 34 | const card = cards[swap]; 35 | cards[swap] = cards[idx]; 36 | cards[idx] = card; 37 | } 38 | deck.clear(); 39 | cards.forEach(card => deck.add(card)); 40 | } 41 | 42 | function pop(deck) { 43 | const card = [...deck].pop(); 44 | isCardFlipped.set(card, true); 45 | deck.delete(card); 46 | return card; 47 | } 48 | 49 | function createDeck() { 50 | const deck = new Set(); 51 | for (const suit of suits) { 52 | for (const face of faces) { 53 | deck.add({ face, suit }); 54 | } 55 | } 56 | shuffle(deck); 57 | return deck; 58 | } 59 | 60 | function dealInitialHand(hand, deck) { 61 | hand.add(pop(deck)); 62 | hand.add(pop(deck)); 63 | } 64 | 65 | function countHand(hand) { 66 | let count = 0; 67 | const aces = new Set(); 68 | for (const card of hand) { 69 | const { face } = card; 70 | if (face === 'A') { 71 | count += 1; 72 | aces.add(card); 73 | } else { 74 | count += faceValues.get(face); 75 | } 76 | } 77 | for (const card of aces) { 78 | if (count <= 11) { 79 | count += 10; 80 | } 81 | } 82 | return count; 83 | } 84 | 85 | },{}],2:[function(require,module,exports){ 86 | 'use strict'; 87 | 88 | Object.defineProperty(exports, "__esModule", { 89 | value: true 90 | }); 91 | exports.buttonsEl = exports.playerEl = exports.dealerEl = undefined; 92 | exports.render = render; 93 | exports.addCard = addCard; 94 | exports.updateLabel = updateLabel; 95 | exports.status = status; 96 | 97 | var _templates = require('./templates'); 98 | 99 | var _cards = require('./cards'); 100 | 101 | const app = document.querySelector('#blackjack'); 102 | const statusEl = app.querySelector('.status'); 103 | 104 | const dealerEl = exports.dealerEl = app.querySelector('.dealer'); 105 | const playerEl = exports.playerEl = app.querySelector('.player'); 106 | const buttonsEl = exports.buttonsEl = app.querySelector('.buttons'); 107 | 108 | function domNode(str) { 109 | var template = document.createElement('template'); 110 | template.innerHTML = str; 111 | return template.content.firstChild; 112 | } 113 | 114 | function render(element, hand) { 115 | element.querySelector('.hand').innerHTML = [...hand].map(_templates.cardTemplate).join(''); 116 | element.querySelector('.score').innerHTML = (0, _cards.countHand)(hand); 117 | updateLabel(element, hand); 118 | } 119 | 120 | function addCard(element, hand, card) { 121 | hand.add(card); 122 | const cardNode = domNode((0, _templates.cardTemplate)(card)); 123 | element.querySelector('.hand').classList.add("adding"); 124 | element.querySelector('.hand').appendChild(cardNode); 125 | element.querySelector('.score').innerHTML = (0, _cards.countHand)(hand); 126 | setTimeout(() => element.querySelector('.hand').classList.remove("adding"), 10); 127 | } 128 | 129 | function updateLabel(element, hand) { 130 | const scoreEl = element.querySelector('.score'); 131 | const score = (0, _cards.countHand)(hand); 132 | if (score > 21) { 133 | scoreEl.classList.add('bust'); 134 | } else if (score === 21) { 135 | scoreEl.classList.add('blackjack'); 136 | } 137 | } 138 | 139 | function status(msg) { 140 | statusEl.classList.remove('hidden'); 141 | statusEl.innerHTML = msg; 142 | } 143 | 144 | },{"./cards":1,"./templates":3}],3:[function(require,module,exports){ 145 | 'use strict'; 146 | 147 | Object.defineProperty(exports, "__esModule", { 148 | value: true 149 | }); 150 | exports.cardTemplate = undefined; 151 | 152 | var _cards = require('./cards'); 153 | 154 | function suitIcon(card) { 155 | const Spades = '\u2660'; 156 | const Clubs = '\u2663'; 157 | const Diamonds = '\u2666'; 158 | const Hearts = '\u2665'; 159 | return { Spades, Clubs, Diamonds, Hearts }[card.suit]; 160 | } 161 | 162 | function getCssClass(card) { 163 | return ` 164 | card 165 | ${ card.suit.toLowerCase() } 166 | ${ _cards.isCardFlipped.get(card) && 'flipped' } 167 | `; 168 | } 169 | 170 | const cardTemplate = exports.cardTemplate = card => `
172 |
\uD83D\uDC09
173 |
174 | ${ card.face } 175 |
176 |
`; 177 | 178 | },{"./cards":1}],4:[function(require,module,exports){ 179 | "use strict"; 180 | 181 | Object.defineProperty(exports, "__esModule", { 182 | value: true 183 | }); 184 | exports.wait = wait; 185 | function wait(iterator, milliseconds, callback) { 186 | const int = setInterval(() => { 187 | const { done } = iterator.next(); 188 | if (done) { 189 | clearInterval(int); 190 | callback(); 191 | } 192 | }, milliseconds); 193 | } 194 | 195 | },{}],5:[function(require,module,exports){ 196 | 'use strict'; 197 | 198 | var _templates = require('./templates'); 199 | 200 | var _utils = require('./utils'); 201 | 202 | var _elements = require('./elements'); 203 | 204 | var _cards = require('./cards'); 205 | 206 | const deck = (0, _cards.createDeck)(); 207 | 208 | const dealerHand = new Set(); 209 | (0, _cards.dealInitialHand)(dealerHand, deck); 210 | (0, _cards.flipCardDown)([...dealerHand][0]); 211 | 212 | const playerHand = new Set(); 213 | (0, _cards.dealInitialHand)(playerHand, deck); 214 | 215 | (0, _elements.render)(_elements.dealerEl, dealerHand); 216 | (0, _elements.render)(_elements.playerEl, playerHand); 217 | 218 | function* dealerPlay() { 219 | _elements.dealerEl.querySelector('.card').classList.add("flipped"); 220 | // keep hitting until you at least tie 221 | while ((0, _cards.countHand)(dealerHand) < (0, _cards.countHand)(playerHand)) { 222 | (0, _elements.addCard)(_elements.dealerEl, dealerHand, (0, _cards.pop)(deck)); 223 | yield; 224 | } 225 | // if tied but less than 17, hit again for the win 226 | if ((0, _cards.countHand)(dealerHand) === (0, _cards.countHand)(playerHand)) { 227 | if ((0, _cards.countHand)(dealerHand) < 17) { 228 | (0, _elements.addCard)(_elements.dealerEl, dealerHand, (0, _cards.pop)(deck)); 229 | yield; 230 | } 231 | } 232 | } 233 | 234 | function dealerTurn(callback) { 235 | (0, _utils.wait)(dealerPlay(), 1000, callback); 236 | } 237 | 238 | function hit() { 239 | (0, _elements.addCard)(_elements.playerEl, playerHand, (0, _cards.pop)(deck)); 240 | (0, _elements.updateLabel)(_elements.playerEl, playerHand); 241 | const score = (0, _cards.countHand)(playerHand); 242 | if (score > 21) { 243 | _elements.buttonsEl.classList.add('hidden'); 244 | (0, _elements.status)('Bust!'); 245 | } else if (score === 21) { 246 | stay(); 247 | } 248 | } 249 | 250 | function stay() { 251 | _elements.buttonsEl.classList.add('hidden'); 252 | _elements.dealerEl.querySelector('.score').classList.remove('hidden'); 253 | dealerTurn(() => { 254 | (0, _elements.updateLabel)(_elements.dealerEl, dealerHand); 255 | const dealerScore = (0, _cards.countHand)(dealerHand); 256 | const playerScore = (0, _cards.countHand)(playerHand); 257 | if (dealerScore > 21 || dealerScore < playerScore) { 258 | (0, _elements.status)('You win!'); 259 | } else if (dealerScore === playerScore) { 260 | (0, _elements.status)('Push.'); 261 | } else { 262 | (0, _elements.status)('Dealer wins!'); 263 | } 264 | }); 265 | } 266 | 267 | document.querySelector('.hit-me').addEventListener('click', hit); 268 | document.querySelector('.stay').addEventListener('click', stay); 269 | 270 | },{"./cards":1,"./elements":2,"./templates":3,"./utils":4}]},{},[5]); 271 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 157 | 158 | 159 |
160 | 161 |
162 |
163 | 164 |
165 |
166 |
167 |
168 |
169 |
170 | 171 | 172 |
173 |
174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blackjack", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", 14 | "babel-preset-stage-3": "^6.17.0", 15 | "babelify": "^7.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/src/cards.js: -------------------------------------------------------------------------------- 1 | const suits = new Set(['Spades', 'Clubs', 'Diamonds', 'Hearts']); 2 | const faces = new Set([ 3 | '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A' 4 | ]); 5 | const faceValues = new Map([ 6 | ['2', 2], ['3', 3], ['4', 4], ['5', 5], ['6', 6], ['7', 7], ['8', 8], 7 | ['9', 9], ['10', 10], ['J', 10], ['Q', 10], ['K', 10] 8 | ]); 9 | 10 | export const isCardFlipped = new Map(); 11 | 12 | export function flipCardUp(card) { 13 | isCardFlipped.set(card, true); 14 | } 15 | 16 | export function flipCardDown(card) { 17 | isCardFlipped.set(card, false); 18 | } 19 | 20 | export function shuffle(deck) { 21 | const cards = [ ...deck ]; 22 | let idx = cards.length; 23 | while (idx > 0) { 24 | idx-- 25 | const swap = Math.floor(Math.random() * cards.length); 26 | const card = cards[swap]; 27 | cards[swap] = cards[idx]; 28 | cards[idx] = card; 29 | } 30 | deck.clear(); 31 | cards.forEach(card => deck.add(card)); 32 | } 33 | 34 | export function pop(deck) { 35 | const card = [ ...deck ].pop() 36 | isCardFlipped.set(card, true) 37 | deck.delete(card) 38 | return card 39 | } 40 | 41 | export function createDeck() { 42 | const deck = new Set(); 43 | for (const suit of suits) { 44 | for (const face of faces) { 45 | deck.add({ face, suit }); 46 | } 47 | } 48 | shuffle(deck); 49 | return deck; 50 | } 51 | 52 | export function dealInitialHand(hand, deck) { 53 | hand.add(pop(deck)); 54 | hand.add(pop(deck)); 55 | } 56 | 57 | export function countHand(hand) { 58 | let count = 0; 59 | const aces = new Set(); 60 | for (const card of hand) { 61 | const { face } = card; 62 | if (face === 'A') { 63 | count += 1; 64 | aces.add(card); 65 | } else { 66 | count += faceValues.get(face); 67 | } 68 | } 69 | for (const card of aces) { 70 | if (count <= 11) { 71 | count += 10; 72 | } 73 | } 74 | return count; 75 | } 76 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/src/elements.js: -------------------------------------------------------------------------------- 1 | import { cardTemplate } from './templates'; 2 | import { countHand } from './cards'; 3 | 4 | const app = document.querySelector('#blackjack'); 5 | const statusEl = app.querySelector('.status'); 6 | 7 | export const dealerEl = app.querySelector('.dealer'); 8 | export const playerEl = app.querySelector('.player'); 9 | export const buttonsEl = app.querySelector('.buttons'); 10 | 11 | function domNode(str) { 12 | var template = document.createElement('template'); 13 | template.innerHTML = str; 14 | return template.content.firstChild; 15 | } 16 | 17 | export function render(element, hand) { 18 | element.querySelector('.hand').innerHTML = [...hand].map(cardTemplate).join(''); 19 | element.querySelector('.score').innerHTML = countHand(hand); 20 | updateLabel(element, hand); 21 | } 22 | 23 | export function addCard(element, hand, card) { 24 | hand.add(card); 25 | const cardNode = domNode(cardTemplate(card)); 26 | element.querySelector('.hand').classList.add("adding"); 27 | element.querySelector('.hand').appendChild(cardNode); 28 | element.querySelector('.score').innerHTML = countHand(hand); 29 | setTimeout(() => element.querySelector('.hand').classList.remove("adding"), 10); 30 | } 31 | 32 | export function updateLabel(element, hand) { 33 | const scoreEl = element.querySelector('.score'); 34 | const score = countHand(hand); 35 | if (score > 21) { 36 | scoreEl.classList.add('bust'); 37 | } else if (score === 21) { 38 | scoreEl.classList.add('blackjack'); 39 | } 40 | } 41 | 42 | export function status(msg) { 43 | statusEl.classList.remove('hidden'); 44 | statusEl.innerHTML = msg; 45 | } 46 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/src/index.js: -------------------------------------------------------------------------------- 1 | import { cardTemplate } from './templates'; 2 | import { wait } from './utils'; 3 | 4 | import { 5 | dealerEl, playerEl, buttonsEl, updateLabel, status, render, addCard 6 | } from './elements'; 7 | 8 | import { 9 | createDeck, pop, countHand, dealInitialHand, flipCardDown, flipCardUp 10 | } from './cards'; 11 | 12 | const deck = createDeck(); 13 | 14 | const dealerHand = new Set(); 15 | dealInitialHand(dealerHand, deck); 16 | flipCardDown([ ...dealerHand ][0]); 17 | 18 | const playerHand = new Set(); 19 | dealInitialHand(playerHand, deck); 20 | 21 | render(dealerEl, dealerHand); 22 | render(playerEl, playerHand); 23 | 24 | function* dealerPlay() { 25 | dealerEl.querySelector('.card').classList.add("flipped"); 26 | // keep hitting until you at least tie 27 | while( countHand(dealerHand) < countHand(playerHand) ) { 28 | addCard(dealerEl, dealerHand, pop(deck)); 29 | yield; 30 | } 31 | // if tied but less than 17, hit again for the win 32 | if ( countHand(dealerHand) === countHand(playerHand) ) { 33 | if (countHand(dealerHand) < 17) { 34 | addCard(dealerEl, dealerHand, pop(deck)); 35 | yield; 36 | } 37 | } 38 | } 39 | 40 | function dealerTurn(callback) { 41 | wait(dealerPlay(), 1000, callback); 42 | } 43 | 44 | function hit() { 45 | addCard(playerEl, playerHand, pop(deck)); 46 | updateLabel(playerEl, playerHand); 47 | const score = countHand(playerHand); 48 | if (score > 21) { 49 | buttonsEl.classList.add('hidden'); 50 | status('Bust!'); 51 | } else if (score === 21) { 52 | stay(); 53 | } 54 | } 55 | 56 | function stay() { 57 | buttonsEl.classList.add('hidden'); 58 | dealerEl.querySelector('.score').classList.remove('hidden'); 59 | dealerTurn(() => { 60 | updateLabel(dealerEl, dealerHand); 61 | const dealerScore = countHand(dealerHand); 62 | const playerScore = countHand(playerHand); 63 | if (dealerScore > 21 || dealerScore < playerScore) { 64 | status('You win!'); 65 | } else if (dealerScore === playerScore) { 66 | status('Push.'); 67 | } else { 68 | status('Dealer wins!'); 69 | } 70 | }); 71 | } 72 | 73 | document.querySelector('.hit-me').addEventListener('click', hit); 74 | document.querySelector('.stay').addEventListener('click', stay); 75 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/src/templates.js: -------------------------------------------------------------------------------- 1 | import { isCardFlipped } from './cards'; 2 | 3 | function suitIcon(card) { 4 | const Spades = '\u2660'; 5 | const Clubs = '\u2663'; 6 | const Diamonds = '\u2666'; 7 | const Hearts = '\u2665'; 8 | return { Spades, Clubs, Diamonds, Hearts }[card.suit]; 9 | } 10 | 11 | function getCssClass(card) { 12 | return ` 13 | card 14 | ${card.suit.toLowerCase()} 15 | ${isCardFlipped.get(card) && 'flipped'} 16 | ` 17 | } 18 | 19 | export const cardTemplate = card => ( 20 | `
22 |
\uD83D\uDC09
23 |
24 | ${card.face} 25 |
26 |
` 27 | ); 28 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/final/src/utils.js: -------------------------------------------------------------------------------- 1 | export function wait(iterator, milliseconds, callback) { 2 | const int = setInterval(() => { 3 | const { done } = iterator.next(); 4 | if (done) { 5 | clearInterval(int); 6 | callback(); 7 | } 8 | }, milliseconds); 9 | } 10 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/start/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-es2015-modules-commonjs"], 3 | "presets": ["stage-3"], 4 | "sourceMaps": "inline" 5 | } 6 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/start/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/start/dest/build.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_5/Lesson_26_Capstone/start/dest/build.js -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/start/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 155 | 156 | 157 |
158 | 159 |
160 |
161 | 162 |
163 |
164 |
165 |
166 |
167 |
168 | 169 | 170 |
171 |
172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blackjack", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", 14 | "babel-preset-stage-3": "^6.17.0", 15 | "babelify": "^7.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/start/src/elements.js: -------------------------------------------------------------------------------- 1 | import { cardTemplate } from './templates'; 2 | import { countHand } from './cards'; 3 | 4 | const app = document.querySelector('#blackjack'); 5 | const statusEl = app.querySelector('.status'); 6 | 7 | export const dealerEl = app.querySelector('.dealer'); 8 | export const playerEl = app.querySelector('.player'); 9 | export const buttonsEl = app.querySelector('.buttons'); 10 | 11 | function domNode(str) { 12 | var template = document.createElement('template'); 13 | template.innerHTML = str; 14 | return template.content.firstChild; 15 | } 16 | 17 | export function render(element, hand) { 18 | element.querySelector('.hand').innerHTML = [...hand].map(cardTemplate).join(''); 19 | element.querySelector('.score').innerHTML = countHand(hand); 20 | updateLabel(element, hand); 21 | } 22 | 23 | export function addCard(element, hand, card) { 24 | hand.add(card); 25 | const cardNode = domNode(cardTemplate(card)); 26 | element.querySelector('.hand').classList.add("adding"); 27 | element.querySelector('.hand').appendChild(cardNode); 28 | element.querySelector('.score').innerHTML = countHand(hand); 29 | setTimeout(() => element.querySelector('.hand').classList.remove("adding"), 10); 30 | } 31 | 32 | export function updateLabel(element, hand) { 33 | const scoreEl = element.querySelector('.score'); 34 | const score = countHand(hand); 35 | if (score > 21) { 36 | scoreEl.classList.add('bust'); 37 | } else if (score === 21) { 38 | scoreEl.classList.add('blackjack'); 39 | } 40 | } 41 | 42 | export function status(msg) { 43 | statusEl.classList.remove('hidden'); 44 | statusEl.innerHTML = msg; 45 | } 46 | -------------------------------------------------------------------------------- /Unit_5/Lesson_26_Capstone/start/src/templates.js: -------------------------------------------------------------------------------- 1 | import { isCardFlipped } from './cards'; 2 | 3 | function suitIcon(card) { 4 | const Spades = '\u2660'; 5 | const Clubs = '\u2663'; 6 | const Diamonds = '\u2666'; 7 | const Hearts = '\u2665'; 8 | return { Spades, Clubs, Diamonds, Hearts }[card.suit]; 9 | } 10 | 11 | function getCssClass(card) { 12 | return ` 13 | card 14 | ${card.suit.toLowerCase()} 15 | ${isCardFlipped.get(card) && 'flipped'} 16 | ` 17 | } 18 | 19 | export const cardTemplate = card => ( 20 | `
22 |
\uD83D\uDC09
23 |
24 | ${card.face} 25 |
26 |
` 27 | ); 28 | -------------------------------------------------------------------------------- /Unit_6/Lesson_27/fish.js: -------------------------------------------------------------------------------- 1 | function Fish(name) { 2 | this.name = name; 3 | this.hunger = 1; 4 | this.dead = false; 5 | this.born = new Date(); 6 | } 7 | Fish.prototype = { 8 | eat(amount=1) { 9 | if (this.dead) { 10 | console.log(`${this.name} is dead and can no longer eat.`); 11 | return; 12 | } 13 | this.hunger -= amount; 14 | if (this.hunger < 0) { 15 | this.dead = true; 16 | console.log(`${this.name} has died from over eating.`) 17 | return 18 | } 19 | }, 20 | sleep() { 21 | this.hunger++; 22 | if (this.hunger >= 5) { 23 | this.dead = true; 24 | console.log(`${this.name} has starved.`) 25 | } 26 | }, 27 | isHungry: function() { 28 | return this.hunger > 0; 29 | } 30 | } 31 | 32 | const oscar = new Fish('oscar'); 33 | console.assert(oscar instanceof Fish); 34 | console.assert(oscar.isHungry()); 35 | while(oscar.isHungry()) { 36 | oscar.eat(); 37 | } 38 | console.assert(!oscar.isHungry()); 39 | console.assert(!oscar.dead); 40 | oscar.eat(); 41 | console.assert(oscar.dead); 42 | -------------------------------------------------------------------------------- /Unit_6/Lesson_28/car.js: -------------------------------------------------------------------------------- 1 | class Car { 2 | constructor() { 3 | this.gas = 50; 4 | this.milage = 0; 5 | } 6 | 7 | hasGas() { 8 | return this.gas > 0; 9 | } 10 | 11 | drive() { 12 | if (this.hasGas()) { 13 | this.milage++; 14 | this.gas--; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-es2015-modules-commonjs"], 3 | "presets": ["stage-2"], 4 | "sourceMaps": "inline" 5 | } 6 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/dest/build.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o new Comet({ 56 | x, y, size, speed, removeOnExit, 57 | rotation: r + ninetyDeg * i 58 | })); 59 | this.remove(); 60 | } 61 | } 62 | exports.default = Comet; 63 | Comet.stroke = '#73C990'; 64 | 65 | },{"./framework/canvas":3,"./framework/drifting_sprite":5,"./framework/game":6,"./framework/utils":10,"./shapes":12}],2:[function(require,module,exports){ 66 | 'use strict'; 67 | 68 | Object.defineProperty(exports, "__esModule", { 69 | value: true 70 | }); 71 | 72 | var _sprite = require('./framework/sprite'); 73 | 74 | var _sprite2 = _interopRequireDefault(_sprite); 75 | 76 | var _shapes = require('./shapes'); 77 | 78 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 79 | 80 | const START_SIZE = 10; 81 | const END_SIZE = 50; 82 | const SIDES = 8; 83 | 84 | const defaultOptions = { 85 | size: START_SIZE 86 | }; 87 | 88 | class Explosion extends _sprite2.default { 89 | constructor(options) { 90 | super(Object.assign({}, defaultOptions, options)); 91 | this.shape = (0, _shapes.explosionShape)(this.size, SIDES); 92 | } 93 | 94 | next() { 95 | this.size = this.size * 1.1; 96 | this.shape = (0, _shapes.explosionShape)(this.size, SIDES); 97 | this.fill = `rgba(255, 100, 0, ${ (END_SIZE - this.size) * .005 })`; 98 | this.stroke = `rgba(255, 0, 0, ${ (END_SIZE - this.size) * .1 })`; 99 | if (this.size > END_SIZE) { 100 | this.remove(); 101 | } 102 | return this; 103 | } 104 | } 105 | exports.default = Explosion; 106 | 107 | },{"./framework/sprite":9,"./shapes":12}],3:[function(require,module,exports){ 108 | 'use strict'; 109 | 110 | Object.defineProperty(exports, "__esModule", { 111 | value: true 112 | }); 113 | exports.clear = clear; 114 | exports.next = next; 115 | exports.draw = draw; 116 | const canvas = document.querySelector("#canvas"); 117 | const ctx = canvas.getContext('2d'); 118 | 119 | const CANVAS_WIDTH = exports.CANVAS_WIDTH = canvas.width; 120 | const CANVAS_HEIGHT = exports.CANVAS_HEIGHT = canvas.height; 121 | 122 | function clear() { 123 | ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); 124 | } 125 | 126 | function next() { 127 | ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; 128 | ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); 129 | } 130 | 131 | function draw({ x, y, rotation, shape, fill, stroke }) { 132 | ctx.save(); 133 | ctx.translate(x, y); 134 | ctx.rotate(rotation); 135 | ctx.moveTo(shape[0][0], shape[0][1]); 136 | ctx.beginPath(); 137 | shape.forEach(([x, y]) => ctx.lineTo(x, y)); 138 | ctx.closePath(); 139 | if (fill) { 140 | ctx.fillStyle = fill; 141 | ctx.fill(); 142 | } 143 | if (stroke) { 144 | ctx.strokeStyle = stroke; 145 | ctx.stroke(); 146 | } 147 | ctx.restore(); 148 | } 149 | 150 | },{}],4:[function(require,module,exports){ 151 | 'use strict'; 152 | 153 | Object.defineProperty(exports, "__esModule", { 154 | value: true 155 | }); 156 | 157 | var _sprite = require('./sprite'); 158 | 159 | var _sprite2 = _interopRequireDefault(_sprite); 160 | 161 | var _canvas = require('./canvas'); 162 | 163 | var _interactions = require('./interactions'); 164 | 165 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 166 | 167 | const defaultOptions = { 168 | x: _canvas.CANVAS_WIDTH / 2, 169 | y: _canvas.CANVAS_HEIGHT / 2, 170 | rotation: 0, 171 | vr: 0, 172 | vx: 0, 173 | vy: 0 174 | }; 175 | 176 | class ControllableSprite extends _sprite2.default { 177 | 178 | constructor(options) { 179 | super(Object.assign({}, defaultOptions, options)); 180 | (0, _interactions.registerControllableSprite)(this); 181 | } 182 | 183 | next() { 184 | this.rotation += this.vr; 185 | this.vr *= .95; 186 | 187 | this.x += this.vx; 188 | this.y += this.vy; 189 | this.vx *= .99; 190 | this.vy *= .99; 191 | 192 | return this; 193 | } 194 | 195 | accelerate() { 196 | const dx = Math.cos(this.rotation); 197 | const dy = Math.sin(this.rotation); 198 | 199 | this.vx += dx * .2; 200 | this.vy += dy * .2; 201 | } 202 | 203 | turnCCW() { 204 | if (this.vr > 0) { 205 | this.vr = 0; 206 | } 207 | this.vr = Math.max(this.vr - .03, -.09); 208 | } 209 | 210 | turnCW() { 211 | if (this.vr < 0) { 212 | this.vr = 0; 213 | } 214 | this.vr = Math.min(this.vr + .03, .09); 215 | } 216 | 217 | } 218 | exports.default = ControllableSprite; 219 | 220 | },{"./canvas":3,"./interactions":8,"./sprite":9}],5:[function(require,module,exports){ 221 | 'use strict'; 222 | 223 | Object.defineProperty(exports, "__esModule", { 224 | value: true 225 | }); 226 | 227 | var _sprite = require('./sprite'); 228 | 229 | var _sprite2 = _interopRequireDefault(_sprite); 230 | 231 | var _game = require('./game'); 232 | 233 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 234 | 235 | class DriftingSprite extends _sprite2.default { 236 | 237 | next() { 238 | const speed = (0, _game.getSpriteProperty)(this, 'speed') || 1; 239 | const rotation = (0, _game.getSpriteProperty)(this, 'rotation') || 0; 240 | 241 | this.x += Math.cos(rotation) * speed; 242 | this.y += Math.sin(rotation) * speed; 243 | 244 | return this; 245 | } 246 | 247 | } 248 | exports.default = DriftingSprite; 249 | 250 | },{"./game":6,"./sprite":9}],6:[function(require,module,exports){ 251 | 'use strict'; 252 | 253 | Object.defineProperty(exports, "__esModule", { 254 | value: true 255 | }); 256 | exports.registerSprite = registerSprite; 257 | exports.unregisterSprite = unregisterSprite; 258 | exports.getSpriteProperty = getSpriteProperty; 259 | exports.getSpriteProperties = getSpriteProperties; 260 | exports.start = start; 261 | exports.stop = stop; 262 | 263 | var _sprite = require('./sprite'); 264 | 265 | var _sprite2 = _interopRequireDefault(_sprite); 266 | 267 | var _canvas = require('./canvas'); 268 | 269 | var canvas = _interopRequireWildcard(_canvas); 270 | 271 | var _interactions = require('./interactions'); 272 | 273 | var interactions = _interopRequireWildcard(_interactions); 274 | 275 | var _hit_test = require('./hit_test'); 276 | 277 | var _hit_test2 = _interopRequireDefault(_hit_test); 278 | 279 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } 280 | 281 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 282 | 283 | const allSprites = new Set(); 284 | const spritesByType = new Map(); 285 | let raf; 286 | let gameOver = false; 287 | 288 | function registerSprite(sprite) { 289 | const type = sprite.constructor; 290 | 291 | allSprites.add(sprite); 292 | 293 | let proto = Object.getPrototypeOf(sprite); 294 | while (proto instanceof _sprite2.default) { 295 | 296 | const type = proto.constructor; 297 | 298 | if (!spritesByType.has(type)) { 299 | spritesByType.set(type, new Set()); 300 | } 301 | 302 | spritesByType.get(type).add(sprite); 303 | 304 | proto = Object.getPrototypeOf(proto); 305 | } 306 | } 307 | 308 | function unregisterSprite(sprite) { 309 | allSprites.delete(sprite); 310 | for (const set of spritesByType.values()) { 311 | set.delete(sprite); 312 | } 313 | } 314 | 315 | function loopCanvas(sprite) { 316 | if (sprite.x < 0) sprite.x = canvas.CANVAS_WIDTH; 317 | if (sprite.y < 0) sprite.y = canvas.CANVAS_HEIGHT; 318 | if (sprite.x > canvas.CANVAS_WIDTH) sprite.x = 0; 319 | if (sprite.y > canvas.CANVAS_HEIGHT) sprite.y = 0; 320 | } 321 | 322 | function isOutsideCanvas(sprite) { 323 | if (sprite.x < 0) return true; 324 | if (sprite.y < 0) return true; 325 | if (sprite.x > canvas.CANVAS_WIDTH) return true; 326 | if (sprite.y > canvas.CANVAS_HEIGHT) return true; 327 | return false; 328 | } 329 | 330 | function getObjectProperty(obj, name) { 331 | const prop = obj[name]; 332 | if (typeof prop === 'function') { 333 | return obj[name](); 334 | } else { 335 | return prop; 336 | } 337 | } 338 | 339 | function getSpriteProperty(sprite, name) { 340 | const obj = sprite[name] ? sprite : sprite.constructor; 341 | return getObjectProperty(obj, name); 342 | } 343 | 344 | function getSpriteProperties(sprite, names) { 345 | return names.map(name => getSpriteProperty(sprite, name)); 346 | } 347 | 348 | function colliding(spriteA, spriteB) { 349 | if (spriteA === spriteB) return false; 350 | return (0, _hit_test2.default)({ 351 | x: getSpriteProperty(spriteA, 'x'), 352 | y: getSpriteProperty(spriteA, 'y'), 353 | shape: getSpriteProperty(spriteA, 'shape') 354 | }, { 355 | x: getSpriteProperty(spriteB, 'x'), 356 | y: getSpriteProperty(spriteB, 'y'), 357 | shape: getSpriteProperty(spriteB, 'shape') 358 | }); 359 | } 360 | 361 | function draw(sprite) { 362 | 363 | const collidesWith = getSpriteProperty(sprite, 'collidesWith'); 364 | if (collidesWith) { 365 | searching: for (const type of collidesWith) { 366 | const set = type === _sprite2.default ? allSprites : spritesByType.get(type); 367 | for (const instance of set || new Set()) { 368 | if (colliding(sprite, instance)) { 369 | sprite.collision(instance); 370 | break searching; 371 | } 372 | } 373 | } 374 | } 375 | 376 | if (isOutsideCanvas(sprite)) { 377 | if (getSpriteProperty(sprite, 'removeOnExit')) { 378 | unregisterSprite(sprite); 379 | return; 380 | } else { 381 | loopCanvas(sprite); 382 | } 383 | } 384 | 385 | const props = 'x y rotation shape fill stroke'.split(' '); 386 | const [x, y, rotation, shape, fill, stroke] = getSpriteProperties(sprite, props); 387 | 388 | canvas.draw({ x, y, rotation, shape, fill, stroke }); 389 | } 390 | 391 | function frame() { 392 | if (gameOver) return; 393 | 394 | canvas.next(); 395 | 396 | interactions.next(); 397 | 398 | allSprites.forEach(sprite => draw(sprite.next())); 399 | 400 | raf = window.requestAnimationFrame(frame); 401 | } 402 | 403 | function start() { 404 | canvas.clear(); 405 | interactions.start(); 406 | 407 | raf = window.requestAnimationFrame(frame); 408 | } 409 | 410 | function stop() { 411 | console.log('Game Over'); 412 | gameOver = true; 413 | interactions.stop(); 414 | window.cancelAnimationFrame(raf); 415 | } 416 | 417 | },{"./canvas":3,"./hit_test":7,"./interactions":8,"./sprite":9}],7:[function(require,module,exports){ 418 | "use strict"; 419 | 420 | Object.defineProperty(exports, "__esModule", { 421 | value: true 422 | }); 423 | exports.default = hitTest; 424 | function squareBounds(shape) { 425 | const xPoints = shape.shape.map(([x, y]) => x); 426 | const yPoints = shape.shape.map(([x, y]) => y); 427 | return { 428 | top: shape.y + Math.min(...yPoints), 429 | bottom: shape.y + Math.max(...yPoints), 430 | left: shape.x + Math.min(...xPoints), 431 | right: shape.x + Math.max(...xPoints) 432 | }; 433 | } 434 | 435 | function intersects(a, b) { 436 | if (a.left > b.right || b.left > a.right) return false; 437 | 438 | if (a.bottom < b.top || b.bottom < a.top) return false; 439 | 440 | return true; 441 | } 442 | 443 | function hitTest(a, b) { 444 | return intersects(squareBounds(a), squareBounds(b)); 445 | } 446 | 447 | },{}],8:[function(require,module,exports){ 448 | 'use strict'; 449 | 450 | Object.defineProperty(exports, "__esModule", { 451 | value: true 452 | }); 453 | exports.registerControllableSprite = registerControllableSprite; 454 | exports.next = next; 455 | exports.isPressingSpace = isPressingSpace; 456 | exports.start = start; 457 | exports.stop = stop; 458 | 459 | var _utils = require('./utils'); 460 | 461 | const SPACE = 32; 462 | const UP = 38; 463 | const LEFT = 37; 464 | const RIGHT = 39; 465 | 466 | const actions = { 467 | [SPACE]: false, 468 | [UP]: false, 469 | [LEFT]: false, 470 | [RIGHT]: false 471 | }; 472 | 473 | const constrolledSprites = new Set(); 474 | 475 | function registerControllableSprite(sprite) { 476 | constrolledSprites.add(sprite); 477 | } 478 | 479 | function handleKeyDown(event) { 480 | actions[event.keyCode] = true; 481 | } 482 | 483 | function handleKeyUp(event) { 484 | actions[event.keyCode] = false; 485 | } 486 | 487 | const delay = method => (0, _utils.throttle)(() => { 488 | for (const sprite of constrolledSprites) { 489 | sprite[method](); 490 | } 491 | }); 492 | 493 | const accelerate = delay('accelerate'); 494 | const turnCCW = delay('turnCCW'); 495 | const turnCW = delay('turnCW'); 496 | 497 | function next() { 498 | if (actions[UP]) accelerate(); 499 | if (actions[RIGHT]) turnCW(); 500 | if (actions[LEFT]) turnCCW(); 501 | } 502 | 503 | function isPressingSpace() { 504 | return actions[SPACE]; 505 | } 506 | 507 | function start() { 508 | document.addEventListener('keydown', handleKeyDown); 509 | document.addEventListener('keyup', handleKeyUp); 510 | } 511 | 512 | function stop() { 513 | document.removeEventListener('keydown', handleKeyDown); 514 | document.removeEventListener('keyup', handleKeyUp); 515 | } 516 | 517 | },{"./utils":10}],9:[function(require,module,exports){ 518 | 'use strict'; 519 | 520 | Object.defineProperty(exports, "__esModule", { 521 | value: true 522 | }); 523 | 524 | var _canvas = require('./canvas'); 525 | 526 | var _game = require('./game'); 527 | 528 | function defaultOptions() { 529 | const x = Math.random() * _canvas.CANVAS_WIDTH; 530 | const y = Math.random() * _canvas.CANVAS_HEIGHT; 531 | const rotation = Math.random() * (Math.PI * 2); 532 | } 533 | 534 | class Sprite { 535 | 536 | constructor(options) { 537 | Object.assign(this, defaultOptions(), options); 538 | (0, _game.registerSprite)(this); 539 | } 540 | 541 | remove() { 542 | (0, _game.unregisterSprite)(this); 543 | } 544 | 545 | next() { 546 | return this; 547 | } 548 | collision() {} 549 | 550 | } 551 | exports.default = Sprite; 552 | 553 | },{"./canvas":3,"./game":6}],10:[function(require,module,exports){ 554 | "use strict"; 555 | 556 | Object.defineProperty(exports, "__esModule", { 557 | value: true 558 | }); 559 | exports.range = range; 560 | exports.throttle = throttle; 561 | function range(length) { 562 | return Array.from({ length }, (x, i) => i); 563 | } 564 | 565 | function throttle(fn) { 566 | let count = 0; 567 | return (...args) => { 568 | count++; 569 | if (count >= 5) { 570 | count = 0; 571 | fn(...args); 572 | } 573 | }; 574 | } 575 | 576 | },{}],11:[function(require,module,exports){ 577 | 'use strict'; 578 | 579 | Object.defineProperty(exports, "__esModule", { 580 | value: true 581 | }); 582 | 583 | var _drifting_sprite = require('./framework/drifting_sprite'); 584 | 585 | var _drifting_sprite2 = _interopRequireDefault(_drifting_sprite); 586 | 587 | var _game = require('./framework/game'); 588 | 589 | var _explosion = require('./explosion'); 590 | 591 | var _explosion2 = _interopRequireDefault(_explosion); 592 | 593 | var _shapes = require('./shapes'); 594 | 595 | var _comet = require('./comet'); 596 | 597 | var _comet2 = _interopRequireDefault(_comet); 598 | 599 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 600 | 601 | class Rocket extends _drifting_sprite2.default { 602 | 603 | collision(target) { 604 | new _explosion2.default({ 605 | x: (0, _game.getSpriteProperty)(this, 'x'), 606 | y: (0, _game.getSpriteProperty)(this, 'y') 607 | }); 608 | target.multiply(); 609 | this.remove(); 610 | } 611 | } 612 | exports.default = Rocket; 613 | Rocket.shape = _shapes.rocket; 614 | Rocket.fill = '#1AC2FB'; 615 | Rocket.removeOnExit = true; 616 | Rocket.speed = 5; 617 | Rocket.collidesWith = [_comet2.default]; 618 | 619 | },{"./comet":1,"./explosion":2,"./framework/drifting_sprite":5,"./framework/game":6,"./shapes":12}],12:[function(require,module,exports){ 620 | "use strict"; 621 | 622 | Object.defineProperty(exports, "__esModule", { 623 | value: true 624 | }); 625 | exports.cometShape = cometShape; 626 | exports.explosionShape = explosionShape; 627 | const ship = exports.ship = [[10, 0], [-10, -5], [-7, 0], [-10, 5], [10, 0]]; 628 | 629 | const rocket = exports.rocket = [[10, 0], [0, -5], [0, 5], [10, 0]]; 630 | 631 | const ufo = exports.ufo = [[-20, 0], [-5, -5], [-5, -10], [5, -10], [5, -5], [20, 0], [5, 10], [-5, 10], [-20, 0]]; 632 | 633 | function cometShape(size, sides) { 634 | const points = []; 635 | for (let i = 0; i < 2; i += 2 / sides) { 636 | const distance = size + Math.random() * 6 - 3; 637 | points.push([Math.cos(Math.PI * i) * distance, Math.sin(Math.PI * i) * distance]); 638 | } 639 | 640 | return points; 641 | } 642 | 643 | function explosionShape(size, sides) { 644 | const points = []; 645 | let point = 0; 646 | for (let i = 0; i < 2; i += 1 / sides) { 647 | const distance = point % 2 ? size : size / 2; 648 | points.push([Math.cos(Math.PI * i) * distance, Math.sin(Math.PI * i) * distance]); 649 | point++; 650 | } 651 | 652 | return points; 653 | } 654 | 655 | },{}],13:[function(require,module,exports){ 656 | 'use strict'; 657 | 658 | Object.defineProperty(exports, "__esModule", { 659 | value: true 660 | }); 661 | 662 | var _controllable_sprite = require('./framework/controllable_sprite'); 663 | 664 | var _controllable_sprite2 = _interopRequireDefault(_controllable_sprite); 665 | 666 | var _game = require('./framework/game'); 667 | 668 | var _interactions = require('./framework/interactions'); 669 | 670 | var _utils = require('./framework/utils'); 671 | 672 | var _shapes = require('./shapes'); 673 | 674 | var _comet = require('./comet'); 675 | 676 | var _comet2 = _interopRequireDefault(_comet); 677 | 678 | var _rocket = require('./rocket'); 679 | 680 | var _rocket2 = _interopRequireDefault(_rocket); 681 | 682 | var _explosion = require('./explosion'); 683 | 684 | var _explosion2 = _interopRequireDefault(_explosion); 685 | 686 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 687 | 688 | class Ship extends _controllable_sprite2.default { 689 | constructor(...args) { 690 | var _temp; 691 | 692 | return _temp = super(...args), this.fire = (0, _utils.throttle)(() => { 693 | const x = (0, _game.getSpriteProperty)(this, 'x'); 694 | const y = (0, _game.getSpriteProperty)(this, 'y'); 695 | const rotation = (0, _game.getSpriteProperty)(this, 'rotation'); 696 | 697 | new _rocket2.default({ x, y, rotation }); 698 | }), _temp; 699 | } 700 | 701 | collision() { 702 | new _explosion2.default({ 703 | x: (0, _game.getSpriteProperty)(this, 'x'), 704 | y: (0, _game.getSpriteProperty)(this, 'y') 705 | }); 706 | 707 | this.remove(); 708 | 709 | setTimeout(_game.stop, 500); 710 | } 711 | 712 | next() { 713 | super.next(); 714 | 715 | if ((0, _interactions.isPressingSpace)()) { 716 | this.fire(); 717 | } 718 | 719 | return this; 720 | } 721 | } 722 | exports.default = Ship; 723 | Ship.shape = _shapes.ship; 724 | Ship.stroke = '#fff'; 725 | Ship.collidesWith = [_comet2.default]; 726 | 727 | },{"./comet":1,"./explosion":2,"./framework/controllable_sprite":4,"./framework/game":6,"./framework/interactions":8,"./framework/utils":10,"./rocket":11,"./shapes":12}],14:[function(require,module,exports){ 728 | 'use strict'; 729 | 730 | var _game = require('./framework/game'); 731 | 732 | var _ship = require('./ship'); 733 | 734 | var _ship2 = _interopRequireDefault(_ship); 735 | 736 | var _comet = require('./comet'); 737 | 738 | var _comet2 = _interopRequireDefault(_comet); 739 | 740 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 741 | 742 | new _ship2.default(); 743 | 744 | new _comet2.default(); 745 | new _comet2.default(); 746 | new _comet2.default(); 747 | 748 | (0, _game.start)(); 749 | 750 | },{"./comet":1,"./framework/game":6,"./ship":13}]},{},[14]); 751 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "canvas-ship", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", 14 | "babel-preset-stage-2": "^6.17.0", 15 | "babelify": "^7.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/comet.js: -------------------------------------------------------------------------------- 1 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './framework/canvas'; 2 | import DriftingSprite from './framework/drifting_sprite'; 3 | import { cometShape } from './shapes' 4 | import { getSpriteProperty } from './framework/game'; 5 | import { range } from './framework/utils'; 6 | 7 | function defaultOptions() { 8 | return { 9 | size: 20, 10 | sides: 20, 11 | speed: 1, 12 | x: Math.random() * CANVAS_WIDTH, 13 | y: Math.random() * CANVAS_HEIGHT, 14 | rotation: Math.random() * (Math.PI * 2) 15 | } 16 | } 17 | 18 | export default class Comet extends DriftingSprite { 19 | static stroke = '#73C990'; 20 | 21 | constructor(options) { 22 | super(Object.assign({}, defaultOptions(), options)); 23 | this.shape = cometShape(this.size, this.sides); 24 | } 25 | 26 | multiply() { 27 | const x = getSpriteProperty(this, 'x'); 28 | const y = getSpriteProperty(this, 'y'); 29 | let size = getSpriteProperty(this, 'size'); 30 | let speed = getSpriteProperty(this, 'speed'); 31 | 32 | if (size < 5) { 33 | this.remove(); 34 | return; 35 | } 36 | size /= 2; 37 | speed *= 1.5; 38 | const removeOnExit = size < 5; 39 | const r = Math.random() * Math.PI; 40 | const ninetyDeg = Math.PI/2; 41 | range(4).forEach(i => new Comet({ 42 | x, y, size, speed, removeOnExit, 43 | rotation: r + ninetyDeg * i, 44 | })) 45 | this.remove(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/explosion.js: -------------------------------------------------------------------------------- 1 | import Sprite from './framework/sprite'; 2 | import { explosionShape } from './shapes'; 3 | 4 | const START_SIZE = 10; 5 | const END_SIZE = 50; 6 | const SIDES = 8; 7 | 8 | const defaultOptions = { 9 | size: START_SIZE 10 | } 11 | 12 | export default class Explosion extends Sprite { 13 | constructor(options) { 14 | super(Object.assign({}, defaultOptions, options)); 15 | this.shape = explosionShape(this.size, SIDES); 16 | } 17 | 18 | next() { 19 | this.size = this.size * 1.1; 20 | this.shape = explosionShape(this.size, SIDES); 21 | this.fill = `rgba(255, 100, 0, ${(END_SIZE-this.size)*.005})` 22 | this.stroke = `rgba(255, 0, 0, ${(END_SIZE-this.size)*.1})` 23 | if (this.size > END_SIZE) { 24 | this.remove(); 25 | } 26 | return this; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/framework/canvas.js: -------------------------------------------------------------------------------- 1 | const canvas = document.querySelector("#canvas"); 2 | const ctx = canvas.getContext('2d'); 3 | 4 | export const CANVAS_WIDTH = canvas.width; 5 | export const CANVAS_HEIGHT = canvas.height; 6 | 7 | export function clear() { 8 | ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); 9 | } 10 | 11 | export function next() { 12 | ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; 13 | ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); 14 | } 15 | 16 | export function draw({x, y, rotation, shape, fill, stroke}) { 17 | ctx.save(); 18 | ctx.translate(x, y); 19 | ctx.rotate(rotation); 20 | ctx.moveTo(shape[0][0], shape[0][1]); 21 | ctx.beginPath(); 22 | shape.forEach(([x, y]) => ctx.lineTo(x, y)); 23 | ctx.closePath(); 24 | if (fill) { 25 | ctx.fillStyle = fill; 26 | ctx.fill(); 27 | } 28 | if (stroke) { 29 | ctx.strokeStyle = stroke; 30 | ctx.stroke(); 31 | } 32 | ctx.restore(); 33 | } 34 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/framework/controllable_sprite.js: -------------------------------------------------------------------------------- 1 | import Sprite from './sprite'; 2 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './canvas'; 3 | import { registerControllableSprite } from './interactions'; 4 | 5 | const defaultOptions = { 6 | x: CANVAS_WIDTH/2, 7 | y: CANVAS_HEIGHT/2, 8 | rotation: 0, 9 | vr: 0, 10 | vx: 0, 11 | vy: 0 12 | }; 13 | 14 | export default class ControllableSprite extends Sprite { 15 | 16 | constructor(options) { 17 | super(Object.assign({}, defaultOptions, options)); 18 | registerControllableSprite(this); 19 | } 20 | 21 | next() { 22 | this.rotation += this.vr; 23 | this.vr *= .95; 24 | 25 | this.x += this.vx; 26 | this.y += this.vy; 27 | this.vx *= .99; 28 | this.vy *= .99; 29 | 30 | return this; 31 | } 32 | 33 | accelerate() { 34 | const dx = Math.cos( this.rotation ); 35 | const dy = Math.sin( this.rotation ); 36 | 37 | this.vx += dx * .2; 38 | this.vy += dy * .2; 39 | } 40 | 41 | turnCCW() { 42 | if (this.vr > 0) { 43 | this.vr = 0; 44 | } 45 | this.vr = Math.max(this.vr - .03, -.09); 46 | } 47 | 48 | turnCW() { 49 | if (this.vr < 0) { 50 | this.vr = 0; 51 | } 52 | this.vr = Math.min(this.vr + .03, .09); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/framework/drifting_sprite.js: -------------------------------------------------------------------------------- 1 | import Sprite from './sprite'; 2 | import { getSpriteProperty } from './game'; 3 | 4 | export default class DriftingSprite extends Sprite { 5 | 6 | next() { 7 | const speed = getSpriteProperty(this, 'speed') || 1; 8 | const rotation = getSpriteProperty(this, 'rotation') || 0; 9 | 10 | this.x += Math.cos(rotation) * speed; 11 | this.y += Math.sin(rotation) * speed; 12 | 13 | return this; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/framework/game.js: -------------------------------------------------------------------------------- 1 | import Sprite from './sprite'; 2 | import * as canvas from './canvas'; 3 | import * as interactions from './interactions'; 4 | import hitTest from './hit_test'; 5 | 6 | const allSprites = new Set(); 7 | const spritesByType = new Map(); 8 | let raf; 9 | let gameOver = false; 10 | 11 | export function registerSprite(sprite) { 12 | const type = sprite.constructor; 13 | 14 | allSprites.add(sprite); 15 | 16 | let proto = Object.getPrototypeOf(sprite) 17 | while(proto instanceof Sprite) { 18 | 19 | const type = proto.constructor; 20 | 21 | if (!spritesByType.has(type)) { 22 | spritesByType.set(type, new Set()); 23 | } 24 | 25 | spritesByType.get(type).add(sprite); 26 | 27 | proto = Object.getPrototypeOf(proto); 28 | } 29 | } 30 | 31 | export function unregisterSprite(sprite) { 32 | allSprites.delete(sprite); 33 | for (const set of spritesByType.values()) { 34 | set.delete(sprite); 35 | } 36 | } 37 | 38 | function loopCanvas(sprite) { 39 | if (sprite.x < 0) sprite.x = canvas.CANVAS_WIDTH; 40 | if (sprite.y < 0) sprite.y = canvas.CANVAS_HEIGHT; 41 | if (sprite.x > canvas.CANVAS_WIDTH) sprite.x = 0; 42 | if (sprite.y > canvas.CANVAS_HEIGHT) sprite.y = 0; 43 | } 44 | 45 | function isOutsideCanvas(sprite) { 46 | if (sprite.x < 0) return true; 47 | if (sprite.y < 0) return true; 48 | if (sprite.x > canvas.CANVAS_WIDTH) return true; 49 | if (sprite.y > canvas.CANVAS_HEIGHT) return true; 50 | return false; 51 | } 52 | 53 | function getObjectProperty(obj, name) { 54 | const prop = obj[name]; 55 | if (typeof prop === 'function') { 56 | return obj[name](); 57 | } else { 58 | return prop; 59 | } 60 | } 61 | 62 | export function getSpriteProperty(sprite, name) { 63 | const obj = sprite[name] ? sprite : sprite.constructor; 64 | return getObjectProperty(obj, name); 65 | } 66 | 67 | export function getSpriteProperties(sprite, names) { 68 | return names.map(name => getSpriteProperty(sprite, name)); 69 | } 70 | 71 | function colliding(spriteA, spriteB) { 72 | if (spriteA === spriteB) return false; 73 | return hitTest({ 74 | x: getSpriteProperty(spriteA, 'x'), 75 | y: getSpriteProperty(spriteA, 'y'), 76 | shape: getSpriteProperty(spriteA, 'shape') 77 | }, { 78 | x: getSpriteProperty(spriteB, 'x'), 79 | y: getSpriteProperty(spriteB, 'y'), 80 | shape: getSpriteProperty(spriteB, 'shape') 81 | }); 82 | } 83 | 84 | function draw(sprite) { 85 | 86 | const collidesWith = getSpriteProperty(sprite, 'collidesWith'); 87 | if (collidesWith) { 88 | searching: for (const type of collidesWith) { 89 | const set = type === Sprite ? allSprites : spritesByType.get(type); 90 | for (const instance of set || new Set) { 91 | if (colliding(sprite, instance)) { 92 | sprite.collision(instance); 93 | break searching; 94 | } 95 | } 96 | } 97 | } 98 | 99 | if (isOutsideCanvas(sprite)) { 100 | if (getSpriteProperty(sprite, 'removeOnExit')) { 101 | unregisterSprite(sprite); 102 | return; 103 | } else { 104 | loopCanvas(sprite); 105 | } 106 | } 107 | 108 | const props = 'x y rotation shape fill stroke'.split(' '); 109 | const [x, y, rotation, shape, fill, stroke] = getSpriteProperties(sprite, props); 110 | 111 | canvas.draw({ x, y, rotation, shape, fill, stroke }); 112 | } 113 | 114 | function frame() { 115 | if (gameOver) return; 116 | 117 | canvas.next(); 118 | 119 | interactions.next(); 120 | 121 | allSprites.forEach(sprite => draw( sprite.next() )); 122 | 123 | raf = window.requestAnimationFrame(frame); 124 | } 125 | 126 | export function start() { 127 | canvas.clear(); 128 | interactions.start(); 129 | 130 | raf = window.requestAnimationFrame(frame); 131 | } 132 | 133 | export function stop() { 134 | console.log('Game Over'); 135 | gameOver = true; 136 | interactions.stop(); 137 | window.cancelAnimationFrame(raf); 138 | } 139 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/framework/hit_test.js: -------------------------------------------------------------------------------- 1 | function squareBounds(shape) { 2 | const xPoints = shape.shape.map(([x, y]) => x) 3 | const yPoints = shape.shape.map(([x, y]) => y) 4 | return { 5 | top: shape.y + Math.min(...yPoints), 6 | bottom: shape.y + Math.max(...yPoints), 7 | left: shape.x + Math.min(...xPoints), 8 | right: shape.x + Math.max(...xPoints) 9 | } 10 | } 11 | 12 | function intersects(a, b) { 13 | if (a.left > b.right || b.left > a.right) 14 | return false 15 | 16 | if (a.bottom < b.top || b.bottom < a.top) 17 | return false 18 | 19 | return true 20 | } 21 | 22 | export default function hitTest(a, b) { 23 | if (Number.isNaN(a.x + a.y + b.x + b.y)) return false; 24 | return intersects( 25 | squareBounds(a), 26 | squareBounds(b) 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/framework/interactions.js: -------------------------------------------------------------------------------- 1 | import { throttle } from './utils'; 2 | 3 | const SPACE = 32 4 | const UP = 38 5 | const LEFT = 37 6 | const RIGHT = 39 7 | 8 | const actions = { 9 | [SPACE]: false, 10 | [UP]: false, 11 | [LEFT]: false, 12 | [RIGHT]: false 13 | } 14 | 15 | const constrolledSprites = new Set(); 16 | 17 | export function registerControllableSprite(sprite) { 18 | constrolledSprites.add(sprite); 19 | } 20 | 21 | function handleKeyDown(event) { 22 | actions[event.keyCode] = true 23 | } 24 | 25 | function handleKeyUp(event) { 26 | actions[event.keyCode] = false 27 | } 28 | 29 | const delay = method => throttle( 30 | () => { 31 | for (const sprite of constrolledSprites) { 32 | sprite[method](); 33 | } 34 | } 35 | ); 36 | 37 | const accelerate = delay('accelerate'); 38 | const turnCCW = delay('turnCCW'); 39 | const turnCW = delay('turnCW'); 40 | 41 | export function next() { 42 | if (actions[UP]) accelerate(); 43 | if (actions[RIGHT]) turnCW(); 44 | if (actions[LEFT]) turnCCW(); 45 | } 46 | 47 | export function isPressingSpace() { 48 | return actions[SPACE]; 49 | } 50 | 51 | export function start() { 52 | document.addEventListener('keydown', handleKeyDown) 53 | document.addEventListener('keyup', handleKeyUp) 54 | } 55 | 56 | export function stop() { 57 | document.removeEventListener('keydown', handleKeyDown) 58 | document.removeEventListener('keyup', handleKeyUp) 59 | } 60 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/framework/sprite.js: -------------------------------------------------------------------------------- 1 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './canvas'; 2 | import { registerSprite, unregisterSprite } from './game'; 3 | 4 | function defaultOptions() { 5 | const x = Math.random() * CANVAS_WIDTH; 6 | const y = Math.random() * CANVAS_HEIGHT; 7 | const rotation = Math.random() * (Math.PI * 2); 8 | } 9 | 10 | export default class Sprite { 11 | 12 | constructor(options) { 13 | Object.assign(this, defaultOptions(), options); 14 | registerSprite(this); 15 | } 16 | 17 | remove() { 18 | unregisterSprite(this); 19 | } 20 | 21 | next() { 22 | return this; 23 | } 24 | collision() { 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/framework/utils.js: -------------------------------------------------------------------------------- 1 | export function range(length) { 2 | return Array.from({ length }, (x, i) => i) 3 | } 4 | 5 | export function throttle(fn) { 6 | let count = 0 7 | return (...args) => { 8 | count++ 9 | if (count >= 5) { 10 | count = 0 11 | fn(...args) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/index.js: -------------------------------------------------------------------------------- 1 | import { start } from './framework/game'; 2 | 3 | import Ship from './ship'; 4 | import Comet from './comet'; 5 | 6 | new Ship(); 7 | 8 | new Comet(); 9 | new Comet(); 10 | new Comet(); 11 | 12 | start(); 13 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/rocket.js: -------------------------------------------------------------------------------- 1 | import DriftingSprite from './framework/drifting_sprite'; 2 | import { getSpriteProperty } from './framework/game'; 3 | import Explosion from './explosion'; 4 | import { rocket } from './shapes'; 5 | import Comet from './comet'; 6 | 7 | 8 | export default class Rocket extends DriftingSprite { 9 | static shape = rocket; 10 | static fill = '#1AC2FB'; 11 | static removeOnExit = true; 12 | static speed = 5; 13 | static collidesWith = [Comet]; 14 | 15 | collision(target) { 16 | new Explosion({ 17 | x: getSpriteProperty(this, 'x'), 18 | y: getSpriteProperty(this, 'y'), 19 | }); 20 | target.multiply(); 21 | this.remove(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/shapes.js: -------------------------------------------------------------------------------- 1 | export const ship = [ 2 | [10, 0], [-10, -5], [-7, 0], [-10, 5], [10, 0] 3 | ] 4 | 5 | export const rocket = [ 6 | [10, 0], [0, -5], [0, 5], [10, 0] 7 | ] 8 | 9 | export const ufo = [ 10 | [-20, 0], [-5, -5], [-5, -10], [5, -10], [5, -5], 11 | [20, 0], [5, 10], [-5, 10], [-20, 0] 12 | ] 13 | 14 | export function cometShape(size, sides) { 15 | const points = [] 16 | for (let i = 0; i < 2; i += 2/sides) { 17 | const distance = size + (Math.random() * 6) - 3 18 | points.push([ 19 | Math.cos(Math.PI*i)*distance, 20 | Math.sin(Math.PI*i)*distance 21 | ]) 22 | } 23 | 24 | return points 25 | } 26 | 27 | export function explosionShape(size, sides) { 28 | const points = [] 29 | let point = 0 30 | for (let i = 0; i < 2; i += 1/sides) { 31 | const distance = point % 2 ? size : size / 2 32 | points.push([ 33 | Math.cos(Math.PI*i)*distance, 34 | Math.sin(Math.PI*i)*distance 35 | ]) 36 | point++ 37 | } 38 | 39 | return points 40 | } 41 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/final/src/ship.js: -------------------------------------------------------------------------------- 1 | import ControllableSprite from './framework/controllable_sprite'; 2 | import { getSpriteProperty, stop } from './framework/game'; 3 | import { isPressingSpace } from './framework/interactions'; 4 | import { throttle } from './framework/utils'; 5 | import { ship as shape } from './shapes'; 6 | import Comet from './comet'; 7 | import Rocket from './rocket'; 8 | import Explosion from './explosion'; 9 | 10 | export default class Ship extends ControllableSprite { 11 | static shape = shape; 12 | static stroke = '#fff'; 13 | static collidesWith = [Comet]; 14 | 15 | fire = throttle(() => { 16 | const x = getSpriteProperty(this, 'x'); 17 | const y = getSpriteProperty(this, 'y'); 18 | const rotation = getSpriteProperty(this, 'rotation'); 19 | 20 | new Rocket({ x, y, rotation }); 21 | }) 22 | 23 | collision() { 24 | new Explosion({ 25 | x: getSpriteProperty(this, 'x'), 26 | y: getSpriteProperty(this, 'y'), 27 | }); 28 | 29 | this.remove(); 30 | 31 | setTimeout(stop, 500); 32 | } 33 | 34 | next() { 35 | super.next(); 36 | 37 | if (isPressingSpace()) { 38 | this.fire(); 39 | } 40 | 41 | return this; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-es2015-modules-commonjs"], 3 | "presets": ["stage-2"], 4 | "sourceMaps": "inline" 5 | } 6 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/dest/build.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_6/Lesson_29_Capstone/start/dest/build.js -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "canvas-ship", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", 14 | "babel-preset-stage-2": "^6.17.0", 15 | "babelify": "^7.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/src/framework/canvas.js: -------------------------------------------------------------------------------- 1 | const canvas = document.querySelector("#canvas"); 2 | const ctx = canvas.getContext('2d'); 3 | 4 | export const CANVAS_WIDTH = canvas.width; 5 | export const CANVAS_HEIGHT = canvas.height; 6 | 7 | export function clear() { 8 | ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); 9 | } 10 | 11 | export function next() { 12 | ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; 13 | ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); 14 | } 15 | 16 | export function draw({x, y, rotation, shape, fill, stroke}) { 17 | ctx.save(); 18 | ctx.translate(x, y); 19 | ctx.rotate(rotation); 20 | ctx.moveTo(shape[0][0], shape[0][1]); 21 | ctx.beginPath(); 22 | shape.forEach(([x, y]) => ctx.lineTo(x, y)); 23 | ctx.closePath(); 24 | if (fill) { 25 | ctx.fillStyle = fill; 26 | ctx.fill(); 27 | } 28 | if (stroke) { 29 | ctx.strokeStyle = stroke; 30 | ctx.stroke(); 31 | } 32 | ctx.restore(); 33 | } 34 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/src/framework/controllable_sprite.js: -------------------------------------------------------------------------------- 1 | import Sprite from './sprite'; 2 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './canvas'; 3 | import { registerControllableSprite } from './interactions'; 4 | 5 | const defaultOptions = { 6 | x: CANVAS_WIDTH/2, 7 | y: CANVAS_HEIGHT/2, 8 | rotation: 0, 9 | vr: 0, 10 | vx: 0, 11 | vy: 0 12 | }; 13 | 14 | export default class ControllableSprite extends Sprite { 15 | 16 | constructor(options) { 17 | super(Object.assign({}, defaultOptions, options)); 18 | registerControllableSprite(this); 19 | } 20 | 21 | next() { 22 | this.rotation += this.vr; 23 | this.vr *= .95; 24 | 25 | this.x += this.vx; 26 | this.y += this.vy; 27 | this.vx *= .99; 28 | this.vy *= .99; 29 | 30 | return this; 31 | } 32 | 33 | accelerate() { 34 | const dx = Math.cos( this.rotation ); 35 | const dy = Math.sin( this.rotation ); 36 | 37 | this.vx += dx * .2; 38 | this.vy += dy * .2; 39 | } 40 | 41 | turnCCW() { 42 | if (this.vr > 0) { 43 | this.vr = 0; 44 | } 45 | this.vr = Math.max(this.vr - .03, -.09); 46 | } 47 | 48 | turnCW() { 49 | if (this.vr < 0) { 50 | this.vr = 0; 51 | } 52 | this.vr = Math.min(this.vr + .03, .09); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/src/framework/drifting_sprite.js: -------------------------------------------------------------------------------- 1 | import Sprite from './sprite'; 2 | import { getSpriteProperty } from './game'; 3 | 4 | export default class DriftingSprite extends Sprite { 5 | 6 | next() { 7 | const speed = getSpriteProperty(this, 'speed') || 1; 8 | const rotation = getSpriteProperty(this, 'rotation') || 0; 9 | 10 | this.x += Math.cos(rotation) * speed; 11 | this.y += Math.sin(rotation) * speed; 12 | 13 | return this; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/src/framework/game.js: -------------------------------------------------------------------------------- 1 | import Sprite from './sprite'; 2 | import * as canvas from './canvas'; 3 | import * as interactions from './interactions'; 4 | import hitTest from './hit_test'; 5 | 6 | const allSprites = new Set(); 7 | const spritesByType = new Map(); 8 | let raf; 9 | let gameOver = false; 10 | 11 | export function registerSprite(sprite) { 12 | const type = sprite.constructor; 13 | 14 | allSprites.add(sprite); 15 | 16 | let proto = Object.getPrototypeOf(sprite) 17 | while(proto instanceof Sprite) { 18 | 19 | const type = proto.constructor; 20 | 21 | if (!spritesByType.has(type)) { 22 | spritesByType.set(type, new Set()); 23 | } 24 | 25 | spritesByType.get(type).add(sprite); 26 | 27 | proto = Object.getPrototypeOf(proto); 28 | } 29 | } 30 | 31 | export function unregisterSprite(sprite) { 32 | allSprites.delete(sprite); 33 | for (const set of spritesByType.values()) { 34 | set.delete(sprite); 35 | } 36 | } 37 | 38 | function loopCanvas(sprite) { 39 | if (sprite.x < 0) sprite.x = canvas.CANVAS_WIDTH; 40 | if (sprite.y < 0) sprite.y = canvas.CANVAS_HEIGHT; 41 | if (sprite.x > canvas.CANVAS_WIDTH) sprite.x = 0; 42 | if (sprite.y > canvas.CANVAS_HEIGHT) sprite.y = 0; 43 | } 44 | 45 | function isOutsideCanvas(sprite) { 46 | if (sprite.x < 0) return true; 47 | if (sprite.y < 0) return true; 48 | if (sprite.x > canvas.CANVAS_WIDTH) return true; 49 | if (sprite.y > canvas.CANVAS_HEIGHT) return true; 50 | return false; 51 | } 52 | 53 | function getObjectProperty(obj, name) { 54 | const prop = obj[name]; 55 | if (typeof prop === 'function') { 56 | return obj[name](); 57 | } else { 58 | return prop; 59 | } 60 | } 61 | 62 | export function getSpriteProperty(sprite, name) { 63 | const obj = sprite[name] ? sprite : sprite.constructor; 64 | return getObjectProperty(obj, name); 65 | } 66 | 67 | export function getSpriteProperties(sprite, names) { 68 | return names.map(name => getSpriteProperty(sprite, name)); 69 | } 70 | 71 | function colliding(spriteA, spriteB) { 72 | if (spriteA === spriteB) return false; 73 | return hitTest({ 74 | x: getSpriteProperty(spriteA, 'x'), 75 | y: getSpriteProperty(spriteA, 'y'), 76 | shape: getSpriteProperty(spriteA, 'shape') 77 | }, { 78 | x: getSpriteProperty(spriteB, 'x'), 79 | y: getSpriteProperty(spriteB, 'y'), 80 | shape: getSpriteProperty(spriteB, 'shape') 81 | }); 82 | } 83 | 84 | function draw(sprite) { 85 | 86 | const collidesWith = getSpriteProperty(sprite, 'collidesWith'); 87 | if (collidesWith) { 88 | searching: for (const type of collidesWith) { 89 | const set = type === Sprite ? allSprites : spritesByType.get(type); 90 | for (const instance of set || new Set) { 91 | if (colliding(sprite, instance)) { 92 | sprite.collision(instance); 93 | break searching; 94 | } 95 | } 96 | } 97 | } 98 | 99 | if (isOutsideCanvas(sprite)) { 100 | if (getSpriteProperty(sprite, 'removeOnExit')) { 101 | unregisterSprite(sprite); 102 | return; 103 | } else { 104 | loopCanvas(sprite); 105 | } 106 | } 107 | 108 | const props = 'x y rotation shape fill stroke'.split(' '); 109 | const [x, y, rotation, shape, fill, stroke] = getSpriteProperties(sprite, props); 110 | 111 | canvas.draw({ x, y, rotation, shape, fill, stroke }); 112 | } 113 | 114 | function frame() { 115 | if (gameOver) return; 116 | 117 | canvas.next(); 118 | 119 | interactions.next(); 120 | 121 | allSprites.forEach(sprite => draw( sprite.next() )); 122 | 123 | raf = window.requestAnimationFrame(frame); 124 | } 125 | 126 | export function start() { 127 | canvas.clear(); 128 | interactions.start(); 129 | 130 | raf = window.requestAnimationFrame(frame); 131 | } 132 | 133 | export function stop() { 134 | console.log('Game Over'); 135 | gameOver = true; 136 | interactions.stop(); 137 | window.cancelAnimationFrame(raf); 138 | } 139 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/src/framework/hit_test.js: -------------------------------------------------------------------------------- 1 | function squareBounds(shape) { 2 | const xPoints = shape.shape.map(([x, y]) => x) 3 | const yPoints = shape.shape.map(([x, y]) => y) 4 | return { 5 | top: shape.y + Math.min(...yPoints), 6 | bottom: shape.y + Math.max(...yPoints), 7 | left: shape.x + Math.min(...xPoints), 8 | right: shape.x + Math.max(...xPoints) 9 | } 10 | } 11 | 12 | function intersects(a, b) { 13 | if (a.left > b.right || b.left > a.right) 14 | return false 15 | 16 | if (a.bottom < b.top || b.bottom < a.top) 17 | return false 18 | 19 | return true 20 | } 21 | 22 | export default function hitTest(a, b) { 23 | if (Number.isNaN(a.x + a.y + b.x + b.y)) return false; 24 | return intersects( 25 | squareBounds(a), 26 | squareBounds(b) 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/src/framework/interactions.js: -------------------------------------------------------------------------------- 1 | import { throttle } from './utils'; 2 | 3 | const SPACE = 32 4 | const UP = 38 5 | const LEFT = 37 6 | const RIGHT = 39 7 | 8 | const actions = { 9 | [SPACE]: false, 10 | [UP]: false, 11 | [LEFT]: false, 12 | [RIGHT]: false 13 | } 14 | 15 | const constrolledSprites = new Set(); 16 | 17 | export function registerControllableSprite(sprite) { 18 | constrolledSprites.add(sprite); 19 | } 20 | 21 | function handleKeyDown(event) { 22 | actions[event.keyCode] = true 23 | } 24 | 25 | function handleKeyUp(event) { 26 | actions[event.keyCode] = false 27 | } 28 | 29 | const delay = method => throttle( 30 | () => { 31 | for (const sprite of constrolledSprites) { 32 | sprite[method](); 33 | } 34 | } 35 | ); 36 | 37 | const accelerate = delay('accelerate'); 38 | const turnCCW = delay('turnCCW'); 39 | const turnCW = delay('turnCW'); 40 | 41 | export function next() { 42 | if (actions[UP]) accelerate(); 43 | if (actions[RIGHT]) turnCW(); 44 | if (actions[LEFT]) turnCCW(); 45 | } 46 | 47 | export function isPressingSpace() { 48 | return actions[SPACE]; 49 | } 50 | 51 | export function start() { 52 | document.addEventListener('keydown', handleKeyDown) 53 | document.addEventListener('keyup', handleKeyUp) 54 | } 55 | 56 | export function stop() { 57 | document.removeEventListener('keydown', handleKeyDown) 58 | document.removeEventListener('keyup', handleKeyUp) 59 | } 60 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/src/framework/sprite.js: -------------------------------------------------------------------------------- 1 | import { CANVAS_WIDTH, CANVAS_HEIGHT } from './canvas'; 2 | import { registerSprite, unregisterSprite } from './game'; 3 | 4 | function defaultOptions() { 5 | const x = Math.random() * CANVAS_WIDTH; 6 | const y = Math.random() * CANVAS_HEIGHT; 7 | const rotation = Math.random() * (Math.PI * 2); 8 | } 9 | 10 | export default class Sprite { 11 | 12 | constructor(options) { 13 | Object.assign(this, defaultOptions(), options); 14 | registerSprite(this); 15 | } 16 | 17 | remove() { 18 | unregisterSprite(this); 19 | } 20 | 21 | next() { 22 | return this; 23 | } 24 | collision() { 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/src/framework/utils.js: -------------------------------------------------------------------------------- 1 | export function range(length) { 2 | return Array.from({ length }, (x, i) => i) 3 | } 4 | 5 | export function throttle(fn) { 6 | let count = 0 7 | return (...args) => { 8 | count++ 9 | if (count >= 5) { 10 | count = 0 11 | fn(...args) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Unit_6/Lesson_29_Capstone/start/src/shapes.js: -------------------------------------------------------------------------------- 1 | export const ship = [ 2 | [10, 0], [-10, -5], [-7, 0], [-10, 5], [10, 0] 3 | ] 4 | 5 | export const rocket = [ 6 | [10, 0], [0, -5], [0, 5], [10, 0] 7 | ] 8 | 9 | export const ufo = [ 10 | [-20, 0], [-5, -5], [-5, -10], [5, -10], [5, -5], 11 | [20, 0], [5, 10], [-5, 10], [-20, 0] 12 | ] 13 | 14 | export function cometShape(size, sides) { 15 | const points = [] 16 | for (let i = 0; i < 2; i += 2/sides) { 17 | const distance = size + (Math.random() * 6) - 3 18 | points.push([ 19 | Math.cos(Math.PI*i)*distance, 20 | Math.sin(Math.PI*i)*distance 21 | ]) 22 | } 23 | 24 | return points 25 | } 26 | 27 | export function explosionShape(size, sides) { 28 | const points = [] 29 | let point = 0 30 | for (let i = 0; i < 2; i += 1/sides) { 31 | const distance = point % 2 ? size : size / 2 32 | points.push([ 33 | Math.cos(Math.PI*i)*distance, 34 | Math.sin(Math.PI*i)*distance 35 | ]) 36 | point++ 37 | } 38 | 39 | return points 40 | } 41 | -------------------------------------------------------------------------------- /Unit_7/Lesson_30/user_view.js: -------------------------------------------------------------------------------- 1 | // You will need axios 2 | import axios from 'axios'; 3 | 4 | function getOrgs(username) { 5 | return axios.get(`https://api.github.com/users/${username}/orgs`); 6 | } 7 | 8 | class UserView { 9 | constructor(user) { 10 | this.user = user; 11 | this.orgs = getOrgs(user.username); <1> 12 | } 13 | 14 | defaultView() { 15 | // show the default view 16 | } 17 | 18 | orgView() { 19 | // show loading screen 20 | this.orgs.then(resp => { <2> 21 | const orgs = resp.orgs; 22 | // show the orgs 23 | }) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Unit_7/Lesson_31/alligator.js: -------------------------------------------------------------------------------- 1 | const later = new Promise((resolve, reject) => { 2 | // Do something asynchronously 3 | resolve('alligator'); 4 | }); 5 | 6 | later.then(response => { 7 | console.log(response); 8 | }); 9 | -------------------------------------------------------------------------------- /Unit_7/Lesson_31/catching_errors.js: -------------------------------------------------------------------------------- 1 | Promise.resolve() 2 | .then(() => console.log('A')) 3 | .then(() => Promise.reject('X')) 4 | .then(() => console.log('B')) 5 | .catch(err => console.log('caught:', err)) 6 | .then(() => console.log('C')); 7 | -------------------------------------------------------------------------------- /Unit_7/Lesson_31/fetch_image.js: -------------------------------------------------------------------------------- 1 | function fetchImage(src) { 2 | return new Promise((res, rej) => { 3 | const img = new Image(); 4 | img.onload = res; 5 | img.onerror = rej; 6 | img.src = src; 7 | }); 8 | } 9 | 10 | fetchImage('https://www.fillmurray.com/200/300').then( 11 | () => console.log('image loaded'), 12 | () => console.log('image failed') 13 | ); 14 | -------------------------------------------------------------------------------- /Unit_7/Lesson_31/fetch_orgs.js: -------------------------------------------------------------------------------- 1 | fetch("https://api.github.com/users/jisaacks/orgs") 2 | .then(resp => resp.json()) 3 | .then(results => { 4 | // do something with results 5 | }); 6 | -------------------------------------------------------------------------------- /Unit_7/Lesson_31/then_chaining.js: -------------------------------------------------------------------------------- 1 | Promise.resolve(1) 2 | .then(number => number + 1) <1> 3 | .then(number => number + 1) <2> 4 | .then(number => number + 1) <3> 5 | .then(number => { 6 | console.log(number) <4> 7 | }); 8 | -------------------------------------------------------------------------------- /Unit_7/Lesson_31/wait.js: -------------------------------------------------------------------------------- 1 | function wait(milliseconds) { 2 | return new Promise((resolve) => { 3 | setTimeout(resolve, milliseconds); 4 | }); 5 | } 6 | 7 | wait(5000).then(() => { 8 | // 5 seconds later... 9 | }); 10 | -------------------------------------------------------------------------------- /Unit_7/Lesson_32/all_resolved.js: -------------------------------------------------------------------------------- 1 | async function allResolved(promises) { 2 | const resolved = []; 3 | const handlers = promises.map(promise => ( 4 | promise 5 | .then(resp => resolved.push(resp)) 6 | .catch(() => { /* skip rejects */ }) 7 | )); 8 | await Promise.all(handlers); 9 | return resolved; 10 | } 11 | -------------------------------------------------------------------------------- /Unit_7/Lesson_32/fail.js: -------------------------------------------------------------------------------- 1 | async function fail() { 2 | const msg = await Promise.reject('I failed.'); 3 | return 'I Succeeded.'; 4 | }; 5 | 6 | fail().then(msg => console.log(msg), msg => console.log(msg)) 7 | 8 | async function tryTest() { 9 | try { 10 | return Promise.reject('err err'); 11 | } catch(err) { 12 | return Promise.resolve(`caught: ${err}`); 13 | } 14 | } 15 | 16 | tryTest().then(response => { 17 | console.log('response:', response); 18 | }); 19 | -------------------------------------------------------------------------------- /Unit_7/Lesson_32/fetch_image.js: -------------------------------------------------------------------------------- 1 | async function fetchImage(url) { 2 | const resp = await fetch(url); 3 | const blob = await resp.blob(); 4 | return createImageBitmap(blob); 5 | }; 6 | 7 | fetchImage('my-image.png').then(image => { 8 | // do something with image 9 | }); 10 | -------------------------------------------------------------------------------- /Unit_7/Lesson_32/runner.js: -------------------------------------------------------------------------------- 1 | const runner = gen => (...args) => { 2 | const generator = gen(...args); 3 | return new Promise((resolve, reject) => { 4 | const run = prev => { 5 | const { value, done } = generator.next(prev); 6 | if (done) { 7 | resolve(value); 8 | } else if (value instanceof Promise) { 9 | value.then(run, reject); 10 | } else { 11 | run(value); 12 | } 13 | } 14 | run(); 15 | }); 16 | } 17 | 18 | const fetchImageAsync = runner(function* fetchImage(url) { 19 | const resp = yield fetch(url); 20 | const blob = yield resp.blob(); 21 | const image = yield createImageBitmap(blob); 22 | 23 | return image; 24 | }); 25 | 26 | fetchImageAsync('my-image.png').then(image => { 27 | // do something with image 28 | }); 29 | -------------------------------------------------------------------------------- /Unit_7/Lesson_33/current_time.js: -------------------------------------------------------------------------------- 1 | // You can use zen-observable as a polyfil 2 | 3 | const currentTime$ = new Observable(observer => { 4 | const interval = setInterval(() => { 5 | const currentTime = new Date(); 6 | observer.next(currentTime); 7 | }, 1000); 8 | 9 | return () => clearInterval(interval); 10 | }); 11 | 12 | const currentTimeSubscription = currentTime$.subscribe({ 13 | next(currentTime) { 14 | // show current time 15 | } 16 | }); 17 | 18 | currentTime$.map(data => `${date.getHours()}:${date.getMinutes()}`).distinct(); 19 | 20 | // currentTimeSubscription.unsubscribe(); 21 | -------------------------------------------------------------------------------- /Unit_7/Lesson_33/filter.js: -------------------------------------------------------------------------------- 1 | function filter (obs$, fn) { 2 | return new Observable(observer => obs$.subscribe({ 3 | next(val) { 4 | if (fn(val)) observer.next(val); 5 | } 6 | })); 7 | } 8 | 9 | filter(Observable.of(1, 2, 3, 4, 5), n => n % 2).subscribe({ 10 | next(val) { 11 | console.log('filtered: ', val); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /Unit_7/Lesson_33/from_set.js: -------------------------------------------------------------------------------- 1 | Observable.from(new Set([1, 2, 3])).subscribe({ 2 | start() { 3 | console.log('--- started getting values ---'); 4 | }, 5 | next(value) { 6 | console.log('==> next value', value); 7 | }, 8 | complete(a) { 9 | console.log('--- done getting values ---'); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/final/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-es2015-modules-commonjs"], 3 | "presets": ["stage-2"], 4 | "sourceMaps": "inline" 5 | } 6 | -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/final/dest/build.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o { 5 | var _ref = _asyncToGenerator(function* (url) { 6 | const resp = yield fetch(url); 7 | const blob = yield resp.blob(); 8 | return createImageBitmap(blob); 9 | }); 10 | 11 | return function fetchImage(_x) { 12 | return _ref.apply(this, arguments); 13 | }; 14 | })(); 15 | 16 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } 17 | 18 | function getRandomImage() { 19 | return fetchImage('https://source.unsplash.com/random'); 20 | } 21 | 22 | function draw(img, alpha = 1) { 23 | const gal = document.getElementById('gallery'); 24 | const ctx = gal.getContext('2d'); 25 | ctx.globalAlpha = alpha; 26 | ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, gal.width, gal.height); 27 | } 28 | 29 | function fade(image) { 30 | return new Promise(resolve => { 31 | function fadeIn(alpha) { 32 | draw(image, alpha); 33 | if (alpha >= .99) { 34 | resolve(); 35 | } else { 36 | alpha += (1 - alpha) / 24; 37 | window.requestAnimationFrame(() => fadeIn(alpha)); 38 | } 39 | } 40 | fadeIn(0.1); 41 | }); 42 | } 43 | 44 | function wait(ms) { 45 | return new Promise(resolve => { 46 | setTimeout(resolve, ms); 47 | }); 48 | } 49 | 50 | const pause = () => wait(1500); 51 | 52 | function repeat(fn) { 53 | return new Promise((resolve, reject) => { 54 | const go = () => fn().then(() => { 55 | setTimeout(go, 0); 56 | }, reject); 57 | go(); 58 | }); 59 | } 60 | 61 | function nextImage() { 62 | return getRandomImage().then(fade).then(pause); 63 | } 64 | 65 | function start() { 66 | return repeat(nextImage).catch(start); 67 | } 68 | 69 | start(); 70 | 71 | },{}]},{},[1]); 72 | -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/final/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/final/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gallery", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", 14 | "babel-preset-stage-2": "^6.17.0", 15 | "babelify": "^7.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/final/src/index.js: -------------------------------------------------------------------------------- 1 | async function fetchImage(url) { 2 | const resp = await fetch(url); 3 | const blob = await resp.blob(); 4 | return createImageBitmap(blob); 5 | } 6 | 7 | function getRandomImage() { 8 | return fetchImage('https://source.unsplash.com/random'); 9 | } 10 | 11 | function draw(img, alpha=1) { 12 | const gal = document.getElementById('gallery'); 13 | const ctx = gal.getContext('2d'); 14 | ctx.globalAlpha = alpha; 15 | ctx.drawImage(img, 16 | 0, 0, img.width, img.height, 17 | 0, 0, gal.width, gal.height 18 | ); 19 | } 20 | 21 | function fade(image) { 22 | return new Promise(resolve => { 23 | function fadeIn(alpha) { 24 | draw(image, alpha); 25 | if (alpha >= .99) { 26 | resolve(); 27 | } else { 28 | alpha += (1-alpha)/24; 29 | window.requestAnimationFrame(() => fadeIn(alpha)); 30 | } 31 | } 32 | fadeIn(0.1); 33 | }); 34 | } 35 | 36 | function wait(ms) { 37 | return new Promise(resolve => { 38 | setTimeout(resolve, ms); 39 | }) 40 | } 41 | 42 | const pause = () => wait(1500); 43 | 44 | function repeat(fn) { 45 | return new Promise((resolve, reject) => { 46 | const go = () => fn().then(() => { 47 | setTimeout(go, 0); 48 | }, reject); 49 | go(); 50 | }); 51 | } 52 | 53 | function nextImage() { 54 | return getRandomImage().then(fade).then(pause); 55 | } 56 | 57 | function start() { 58 | return repeat(nextImage).catch(start); 59 | } 60 | 61 | start(); 62 | -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/start/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["transform-es2015-modules-commonjs"], 3 | "presets": ["stage-2"], 4 | "sourceMaps": "inline" 5 | } 6 | -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/start/dest/build.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_7/Lesson_34_Capstone/start/dest/build.js -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/start/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gallery", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "browserify -t [ babelify ] ./src -o ./dest/build.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0", 14 | "babel-preset-stage-2": "^6.17.0", 15 | "babelify": "^7.3.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Unit_7/Lesson_34_Capstone/start/src/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jisaacks/get-programming-jsnext/d80df37207a6bc4df74b9e81413cd9ee45df0bb7/Unit_7/Lesson_34_Capstone/start/src/index.js -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Get Programming With JavaScript Next 2 | 3 | This is the code for the book [Get Programming with JavaScript Next](https://www.manning.com/books/get-programming-with-javascript-next) 4 | --------------------------------------------------------------------------------