diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 77b1cea..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Code 4 Tomorrow - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/Project_Based_Course/Calculator/Filler.html b/Project_Based_Course/Calculator/Filler.html deleted file mode 100644 index e107dd2..0000000 --- a/Project_Based_Course/Calculator/Filler.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Project_Based_Course/Calculator/Problem_1_Solution/style.css b/Project_Based_Course/Calculator/Problem_1_Solution/style.css deleted file mode 100644 index 644d1bf..0000000 --- a/Project_Based_Course/Calculator/Problem_1_Solution/style.css +++ /dev/null @@ -1,112 +0,0 @@ -/* -*, *::before, *::after { - box-sizing: border-box; - font-family: Gotham Rounded, sans-serif; - font-weight: normal; -} -*/ - - - - body { - padding: 0; - margin: 0; - background: #0F2027; /* fallback for old browsers */ - background: -webkit-linear-gradient(to right, #2C5364, #203A43, #0F2027); /* Chrome 10-25, Safari 5.1-6 */ - background: linear-gradient(to right, #2C5364, #203A43, #0F2027); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ - - font-family: 'ReactiveAnchor-L3L0n', sans-serif; - - } - - .calculator-grid { - display: grid; - justify-content: center; - align-content: center; - min-height: 100vh; - grid-template-columns: repeat(4, 100px); - grid-template-rows: minmax(120px, auto) repeat(5, 100px); - grid-gap: 20px 20px; - } - - - .calculator-grid > button { - cursor: pointer; - font-size: 2rem; - font-family: 'ReactiveAnchor-L3L0n', sans-serif; - outline: none; - background-color: rgba(0, 0, 0, .75); - color: #2ca8fd; - border-radius: 20px; - padding: 0px; - /* Adding Transitions; different transitions properties due to compatibility issues in different browsers */ - -webkit-transition: background-color 2s ease-out; - -moz-transition: background-color 2s ease-out; - -o-transition: background-color 2s ease-out; - transition: background-color 2s ease-out; - - } - - .calculator-grid > button:hover { - background-color: rgba(255, 255, 255, .9); - font-family: 'ReactiveAnchor-L3L0n', sans-serif; - } - - .span-two { - grid-column: span 2; - } - - .output { - grid-column: 1 / -1; - background: #0F2027; /* fallback for old browsers */ - background: -webkit-linear-gradient(to right, #2C5364, #203A43, #0F2027); /* Chrome 10-25, Safari 5.1-6 */ - background: linear-gradient(to right, #2C5364, #203A43, #0F2027); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ - display: flex; - align-items: flex-end; - justify-content: space-around; - flex-direction: column; - padding: 10px; - word-wrap: break-word; - word-break: break-all; - border-radius: 5px; - } - - .output .previous-operand { - color: rgba(255, 255, 255, .75); - font-size: 1.5rem; - } - - .output .current-operand { - color: white; - font-size: 2.5rem; - } - -#op { - background-color: #065caf; - color: #28a5fd; - font-family: 'ReactiveAnchor-L3L0n', sans-serif; - /* Adding Transitions for operator backgrounds*/ - -webkit-transition: background-color 2s ease-out; - -moz-transition: background-color 2s ease-out; - -o-transition: background-color 2s ease-out; - transition: background-color 2s ease-out; -} - -#op:hover { - background-color: #0f9; -} - -#misc { - background-color: #5f5f60; - color: #9d9fa0; - font-family: 'ReactiveAnchor-L3L0n', sans-serif; - /* Adding Transitions for AC / DEL button backgrounds*/ - -webkit-transition: background-color 2s ease-out; - -moz-transition: background-color 2s ease-out; - -o-transition: background-color 2s ease-out; - transition: background-color 2s ease-out; -} - -#misc:hover { - background-color: #0F2027; -} \ No newline at end of file diff --git a/Project_Based_Course/Calculator/Problem_2_Solution/filler.html b/Project_Based_Course/Calculator/Problem_2_Solution/filler.html deleted file mode 100644 index 861f0a2..0000000 --- a/Project_Based_Course/Calculator/Problem_2_Solution/filler.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Project_Based_Course/Calculator/Problem_2_Solution/index2.html b/Project_Based_Course/Calculator/Problem_2_Solution/index2.html deleted file mode 100644 index 3ed5aaa..0000000 --- a/Project_Based_Course/Calculator/Problem_2_Solution/index2.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - Calculator - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Project_Based_Course/Calculator/Problem_2_Solution/script2.js b/Project_Based_Course/Calculator/Problem_2_Solution/script2.js deleted file mode 100644 index f7f2422..0000000 --- a/Project_Based_Course/Calculator/Problem_2_Solution/script2.js +++ /dev/null @@ -1,158 +0,0 @@ -class Calculator { - constructor(previousOperandTextElement, currentOperandTextElement) { - this.previousOperandTextElement = previousOperandTextElement - this.currentOperandTextElement = currentOperandTextElement - this.clear() - } - - clear() { - this.currentOperand = '' - this.previousOperand = '' - this.operation = undefined - } - - delete() { - this.currentOperand = this.currentOperand.toString().slice(0, -1) - } - - appendNumber(number) { - if (number === '.' && this.currentOperand.includes('.')) return - this.currentOperand = this.currentOperand.toString() + number.toString() - } - - chooseOperation(operation) { - - if (this.currentOperand === '') return - - this.operation = operation - this.previousOperand = this.currentOperand - this.currentOperand = '' - - //console.log("prev" + this.previousOperand) - //console.log("cur" + this.currentOperand) - } - - compute() { - let computation - - //console.log(this.previousOperand + ", " + this.currentOperand) - //console.log(typeof(this.previousOperand) + ", " + typeof(this.currentOperand)) - - const prev = typeof(this.previousOperand) === "string" || typeof(this.previousOperand) === "number" ? parseFloat(this.previousOperand) : "" - const current = typeof(this.currentOperand) === "string" || typeof(this.currentOperand) === "number" ? parseFloat(this.currentOperand) : "" - - //console.log(prev + "\n" + current + "\n") - - if (isNaN(prev) && isNaN(current)) return - - if (!isNaN(prev) && !isNaN(current)) - switch (this.operation) { - case '+': - computation = prev + current - break - case '-': - computation = prev - current - break - case '*': - computation = prev * current - break - case '÷': - computation = prev / current - break - // New feature 1 - case '^': - computation = prev**current - break - // New feature 1 - default: - return - } - else if (!isNaN(prev)) - switch (this.operation) { - // New feature 2 - case '√': - computation = Math.sqrt(prev) - break - case '^2': - computation = prev * prev; - break - case '^3': - computation = prev * prev * prev; - break - // New feature 2 - default: - return - } - - this.currentOperand = computation - this.operation = undefined - this.previousOperand = '' - } - - getDisplayNumber(number) { - const stringNumber = number.toString() - const integerDigits = parseFloat(stringNumber.split('.')[0]) - const decimalDigits = stringNumber.split('.')[1] - let integerDisplay - if (isNaN(integerDigits)) { - integerDisplay = '' - } else { - integerDisplay = integerDigits.toLocaleString('en', { maximumFractionDigits: 0 }) - } - if (decimalDigits != null) { - return `${integerDisplay}.${decimalDigits}` - } else { - return integerDisplay - } - } - - updateDisplay() { - this.currentOperandTextElement.innerText = - this.getDisplayNumber(this.currentOperand) - if (this.operation != null) { - this.previousOperandTextElement.innerText = - `${this.getDisplayNumber(this.previousOperand)} ${this.operation}` - } else { - this.previousOperandTextElement.innerText = '' - } - } -} - -const numberButtons = document.querySelectorAll('[data-number]') -const operationButtons = document.querySelectorAll('[data-operation]') -const equalsButton = document.querySelector('[data-equals]') -const deleteButton = document.querySelector('[data-delete]') -const allClearButton = document.querySelector('[data-all-clear]') -const previousOperandTextElement = document.querySelector('[data-previous-operand]') -const currentOperandTextElement = document.querySelector('[data-current-operand]') - -const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement) - -numberButtons.forEach(button => { -button.addEventListener('click', () => { - calculator.appendNumber(button.innerText) - calculator.updateDisplay() -}) -}) - -operationButtons.forEach(button => { -button.addEventListener('click', () => { - calculator.chooseOperation(button.innerText) - calculator.updateDisplay() -}) -}) - -equalsButton.addEventListener('click', button => { -calculator.compute() -calculator.updateDisplay() -}) - -allClearButton.addEventListener('click', button => { -calculator.clear() -calculator.updateDisplay() -}) - -deleteButton.addEventListener('click', button => { -calculator.delete() -calculator.updateDisplay() -}) \ No newline at end of file diff --git a/Project_Based_Course/Calculator/Problem_2_Solution/style2.css b/Project_Based_Course/Calculator/Problem_2_Solution/style2.css deleted file mode 100644 index c17866c..0000000 --- a/Project_Based_Course/Calculator/Problem_2_Solution/style2.css +++ /dev/null @@ -1,66 +0,0 @@ - -*, *::before, *::after { - box-sizing: border-box; - font-family: Gotham Rounded, sans-serif; - font-weight: normal; -} - -body { - padding: 0; - margin: 0; - background: linear-gradient(to right, #13547a, #80d0c7); -} - -.calculator-grid { - display: grid; - justify-content: center; - align-content: center; - min-height: 100vh; - grid-template-columns: repeat(5, 100px); /* We need 5 columns with the new calculator */ - grid-template-rows: minmax(120px, auto) repeat(6, 100px); /* We need 6 rows */ -} - - -.calculator-grid > button { - cursor: pointer; - font-size: 2rem; - border: 1px solid white; - outline: none; - background-color: rgba(255, 255, 255, .75); -} - -.calculator-grid > button:hover { - background-color: rgba(255, 255, 255, .9); -} - -.span-two { - grid-column: span 2; -} - -/* New */ -.equal { - grid-column-start: 3; - grid-column-end: -1; -} - -.output { - grid-column: 1 / -1; - background-color: rgba(0, 0, 0, .75); - display: flex; - align-items: flex-end; - justify-content: space-around; - flex-direction: column; - padding: 10px; - word-wrap: break-word; - word-break: break-all; -} - -.output .previous-operand { - color: rgba(255, 255, 255, .75); - font-size: 1.5rem; -} - -.output .current-operand { - color: white; - font-size: 2.5rem; -} \ No newline at end of file diff --git a/Project_Based_Course/Calculator/index.html b/Project_Based_Course/Calculator/index.html deleted file mode 100644 index f7e1cec..0000000 --- a/Project_Based_Course/Calculator/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - Calculator - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - - - - -
- - diff --git a/Project_Based_Course/Calculator/script.js b/Project_Based_Course/Calculator/script.js deleted file mode 100644 index 1abbde7..0000000 --- a/Project_Based_Course/Calculator/script.js +++ /dev/null @@ -1,126 +0,0 @@ -class Calculator { - constructor(previousOperandTextElement, currentOperandTextElement) { - this.previousOperandTextElement = previousOperandTextElement - this.currentOperandTextElement = currentOperandTextElement - this.clear() - } - - clear() { - this.currentOperand = '' - this.previousOperand = '' - this.operation = undefined - } - - delete() { - this.currentOperand = this.currentOperand.toString().slice(0, -1) - } - - appendNumber(number) { - if (number === '.' && this.currentOperand.includes('.')) return - this.currentOperand = this.currentOperand.toString() + number.toString() - } - - chooseOperation(operation) { - if (this.currentOperand === '') return - if (this.previousOperand !== '') { - this.compute() - } - this.operation = operation - this.previousOperand = this.currentOperand - this.currentOperand = '' - } - - compute() { - let computation - const prev = parseFloat(this.previousOperand) - const current = parseFloat(this.currentOperand) - if (isNaN(prev) || isNaN(current)) return - switch (this.operation) { - case '+': - computation = prev + current - break - case '-': - computation = prev - current - break - case '*': - computation = prev * current - break - case '÷': - computation = prev / current - break - default: - return - } - this.currentOperand = computation - this.operation = undefined - this.previousOperand = '' - } - - getDisplayNumber(number) { - const stringNumber = number.toString() - const integerDigits = parseFloat(stringNumber.split('.')[0]) - const decimalDigits = stringNumber.split('.')[1] - let integerDisplay - if (isNaN(integerDigits)) { - integerDisplay = '' - } else { - integerDisplay = integerDigits.toLocaleString('en', { maximumFractionDigits: 0 }) - } - if (decimalDigits != null) { - return `${integerDisplay}.${decimalDigits}` - } else { - return integerDisplay - } - } - - updateDisplay() { - this.currentOperandTextElement.innerText = - this.getDisplayNumber(this.currentOperand) - if (this.operation != null) { - this.previousOperandTextElement.innerText = - `${this.getDisplayNumber(this.previousOperand)} ${this.operation}` - } else { - this.previousOperandTextElement.innerText = '' - } - } -} - - -const numberButtons = document.querySelectorAll('[data-number]') -const operationButtons = document.querySelectorAll('[data-operation]') -const equalsButton = document.querySelector('[data-equals]') -const deleteButton = document.querySelector('[data-delete]') -const allClearButton = document.querySelector('[data-all-clear]') -const previousOperandTextElement = document.querySelector('[data-previous-operand]') -const currentOperandTextElement = document.querySelector('[data-current-operand]') - -const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement) - -numberButtons.forEach(button => { - button.addEventListener('click', () => { - calculator.appendNumber(button.innerText) - calculator.updateDisplay() - }) -}) - -operationButtons.forEach(button => { - button.addEventListener('click', () => { - calculator.chooseOperation(button.innerText) - calculator.updateDisplay() - }) -}) - -equalsButton.addEventListener('click', button => { - calculator.compute() - calculator.updateDisplay() -}) - -allClearButton.addEventListener('click', button => { - calculator.clear() - calculator.updateDisplay() -}) - -deleteButton.addEventListener('click', button => { - calculator.delete() - calculator.updateDisplay() -}) diff --git a/Project_Based_Course/Calculator/style.css b/Project_Based_Course/Calculator/style.css deleted file mode 100644 index 1565e12..0000000 --- a/Project_Based_Course/Calculator/style.css +++ /dev/null @@ -1,61 +0,0 @@ -/* -*, *::before, *::after { - box-sizing: border-box; - font-family: Gotham Rounded, sans-serif; - font-weight: normal; -} -*/ - -body { - padding: 0; - margin: 0; - background: linear-gradient(to right, #13547a, #80d0c7); -} - -.calculator-grid { - display: grid; - justify-content: center; - align-content: center; - min-height: 100vh; - grid-template-columns: repeat(4, 100px); - grid-template-rows: minmax(120px, auto) repeat(4, 100px); -} - - -.calculator-grid > button { - cursor: pointer; - font-size: 2rem; - border: 1px solid white; - outline: none; - background-color: rgba(255, 255, 255, .75); -} - -.calculator-grid > button:hover { - background-color: rgba(255, 255, 255, .9); -} - -.span-two { - grid-column: span 2; -} - -.output { - grid-column: 1 / -1; - background-color: rgba(0, 0, 0, .75); - display: flex; - align-items: flex-end; - justify-content: space-around; - flex-direction: column; - padding: 10px; - word-wrap: break-word; - word-break: break-all; -} - -.output .previous-operand { - color: rgba(255, 255, 255, .75); - font-size: 1.5rem; -} - -.output .current-operand { - color: white; - font-size: 2.5rem; -} diff --git a/Project_Based_Course/Tank_Game/Filler.html b/Project_Based_Course/Tank_Game/Filler.html deleted file mode 100644 index 2f01528..0000000 --- a/Project_Based_Course/Tank_Game/Filler.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Project_Based_Course/Tank_Game/index.html b/Project_Based_Course/Tank_Game/index.html deleted file mode 100644 index b2307e9..0000000 --- a/Project_Based_Course/Tank_Game/index.html +++ /dev/null @@ -1,5 +0,0 @@ - -Tank game -

- - diff --git a/Project_Based_Course/Tank_Game/tank_game.js b/Project_Based_Course/Tank_Game/tank_game.js deleted file mode 100644 index 058fef1..0000000 --- a/Project_Based_Course/Tank_Game/tank_game.js +++ /dev/null @@ -1,1244 +0,0 @@ -var TankGame = (function() { - var TARGET_WIDTH = 801; // Desired width - var TARGET_HEIGHT = 601; - var WIDTH; // Actual width of game, scaled to fit screen - var HEIGHT; - var GUI_HEIGHT = 150; - var DEBUG = false; - // WASD - var P1_UP = 87; - var P1_DOWN = 83; - var P1_LEFT = 65; - var P1_RIGHT = 68; - var P1_FIRE = 49; // Character 1 - - // Arrow keys - var P2_UP = 38; - var P2_DOWN = 40; - var P2_LEFT = 37; - var P2_RIGHT = 39; - var P2_FIRE = 189; // Character - - - // Other settings - var TANK_SIZE = 15; - var TANK_SPEED = 1; - var TANK_TURN_SPEED = 5; - var WALL_WIDTH = 2; - var CELL_SIZE = 50; - var RESET_COUNTER_MAX = 200; // Time to start next round (frames) - var EPSILON = 0.001; // Used for comparing floats - - // Optimization: skip collision checks between distant objects - // NOTE: This only works if there are no large objects in the scene - var MAX_DIST_FOR_COLLISIONS = 2; // (this is multiplied by CELL_SIZE) - - // Global variables (Do not attempt to configure) - var TANK_P1, TANK_P2; - var CELLS_X, CELLS_Y; - var CANVAS, CTX, KEYSTATE, GAME_OBJECTS; - var PRERENDERED_CANVAS, PRERENDERED_CTX, PRERENDERED_REDRAW_NEEDED; - var GUI_REDRAW_NEEDED; - var END_ROUND = false; - var RESET_COUNTER; - - var P1 = 1; - var P2 = 2; - var P1_SCORE = 0; - var P2_SCORE = 0; - - - - - /* - =============================================================================== - -------------------------------------CLASSES----------------------------------- - =============================================================================== - */ - - function deg2rad(degrees) { - return degrees * (Math.PI/180); - } - - class Vector2d { - constructor(x, y) { - if (typeof x == 'undefined' || typeof y == 'undefined') { - throw "Invalid arguments"; - } - this.x = x; - this.y = y; - } - - rotate(radians) { - // Rotates coordinates counterclockwise - //radians=-radians - if (radians != 0) { - var x = this.x; - var y = this.y; - this.x = x * Math.cos(radians) - y * Math.sin(radians); - this.y = x * Math.sin(radians) + y * Math.cos(radians); - } - return this; - } - - add(vector) { - if (vector instanceof Vector2d) { - this.x += vector.x; - this.y += vector.y; - } - else throw "Invalid argument"; - return this; - } - - subtract(vector) { - if (vector instanceof Vector2d) { - this.x -= vector.x; - this.y -= vector.y; - } - else throw "Invalid argument"; - return this; - } - - multiply(value) { - if (isNaN(value) === false) { - this.x *= value; - this.y *= value; - } - else throw "Invalid argument"; - return this; - } - - get_dot_product(other) { - // Calculates the dot product between given vector - if (other instanceof Vector2d) return this.x*other.x + this.y*other.y; - else throw "Invalid argument"; - } - - get_unit_vector() { - var c = this.get_magnitude(); - var unit_vec = new Vector2d(this.x/c, this.y/c); - return unit_vec; - } - - get_right_normal() { - return new Vector2d(this.y, -this.x); - } - - get_magnitude() { - return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); - } - - get_magnitude_squared() { - return Math.pow(this.x, 2) + Math.pow(this.y, 2); - } - - get_inverted() { - return new Vector2d(-this.x, -this.y); - } - - clone() { - return new Vector2d(this.x, this.y); - } - - reflect(vector) { - /* - Reflects this vector around given unit vector. - vec1 - (2*vec2*(vec2.vec1)) - */ - if (vector instanceof Vector2d) { - var vec2 = vector.clone(); // Avoid modifying given vector - vec2.multiply(vec2.get_dot_product(this)); - vec2.multiply(2); - this.subtract(vec2); - return this; - } - else throw "Invalid argument"; - } - }; - - class GameObject { - constructor(x, y, width, height, movable = false) { - this.destructible = true; // Can this object be destroyed? - this.max_hp = 1000; - this.hp = this.max_hp; - this.pos = new Vector2d(x, y); - this.width = width; - this.height = height; - this.rotation = 0; // In degrees - this.velocity = new Vector2d(0, 0); - this.movable = movable; // Can be moved by collisions - this.color = {}; - this.color.r = 0; - this.color.g = 0; - this.color.b = 0; - this.verts = []; - this.rotated_verts = []; - this.ignored_collision_objs = [this]; - this.circle = false; - this.radius = 0; - this.unstoppable = false; // Lets object move through destructible objects - - var w = this.width / 2; - var h = this.height / 2; - this.verts.push(new Vector2d(-w, -h)); - this.verts.push(new Vector2d(-w, h)); - this.verts.push(new Vector2d(w, h)); - this.verts.push(new Vector2d(w, -h)); - - GAME_OBJECTS.push(this); - if (this.movable == false) { - PRERENDERED_REDRAW_NEEDED = true; - } - - } - - damage(amount) { - if (this.destructible && this.hp > 0) { - if (amount > 0) { - this.hp -= amount; - this.color_by_damage(); - } - else console.log("WARNING: Attempted to damage by negative amount!!!"); - } - } - - set_unstoppable(value) { - this.unstoppable = value; - } - - set_destructible(value) { - this.destructible = value; - } - - color_by_damage() { - var red = Math.round(255 - (255 * (this.hp/this.max_hp))); - this.color.r = red; - } - - rotate(degrees) { - if (degrees != 0) { - this.rotation += degrees; - while (this.rotation < 0) this.rotation += 360; - while (this.rotation > 360) this.rotation -= 360; - this.calculate_rotated_verts(); - } - } - - move(vector) { - if (vector instanceof Vector2d) { - this.pos.add(vector); - } - else throw "Invalid argument"; - } - - get_rect(local_coordinates) { - var x = this.pos.x; - var y = this.pos.y; - var w = this.width / 2; - var h = this.height / 2; - if (local_coordinates) return [-w, -h, w*2, h*2]; - else return [x-w, y-h, w*2, h*2]; - } - - calculate_rotated_verts() { - var radians = deg2rad(this.rotation) - this.rotated_verts = []; - for (var vert of this.verts) { - this.rotated_verts.push(vert.clone().rotate(radians)); - } - this.rotated_verts; - } - - get_verts() { - if (this.rotated_verts.length === 0) this.calculate_rotated_verts(); - return this.rotated_verts; - } - - on_collision(obj) { - /* - Default GameObjects do nothing on collision. Child classes can use this - for example to damage or give powerups to tanks on collision. - */ - //console.log(typeof(obj)); - } - - destroy() { - var i = GAME_OBJECTS.indexOf(this); - delete GAME_OBJECTS[i]; - if (this.movable == false) { - PRERENDERED_REDRAW_NEEDED = true; - } - } - - update() { - /* - Moves GameObject by its velocity and checks for collisions. - If collisions are found, attempts to solve them by moving itself. - */ - if (this.hp <= 0) { - this.destroy(); - return; - } - if (this.movable) { - // Move by velocity, if it has any - this.move(this.velocity); - - // Get all colliding objects - var collisions = GetCollisions(this); - - var attempts = 0; // Track attempts to prevent infinite loops - var done = false; - var max_attempts = 5; - while(done === false && attempts < max_attempts) { - var prev_pos = this.pos.clone(); - var prev_velo = this.velocity.clone(); - done = true; - if (collisions.length > 0) { - //console.log(collisions); - } - for (var i = 0; i < collisions.length; i++) { - // Loop over all collisions one at a time - var collision = collisions[i]; - var obj1 = collision.obj1; // This object (redundant) - var obj2 = collision.obj2; // The colliding object - var dir = collision.direction.clone(); - if (this.unstoppable && obj2.destructible == true) { - // Don't attempt to solve collisions for unstoppable objects - // unstoppable objects can go through almost anything. - obj1.on_collision(obj2); - obj2.on_collision(obj1); - break; - } - this.move(dir.clone().multiply(collision.magnitude)); - this.velocity.reflect(dir); - - - // Get all new collisions after moving - var new_collisions = GetCollisions(this); - if (new_collisions.length === 0) { - // Success! No new collisions found - obj1.on_collision(obj2); - obj2.on_collision(obj1); - break; // Don't check any other collisions - } - else if (i < collisions.length-1) { - // Fail! Move back to original position and attempt to solve the next collision - this.pos = prev_pos; - this.velocity = prev_velo; - } - else { - // Fail! No collisions remaining. Try to resolve collisions from the new position - obj1.on_collision(obj2); - obj2.on_collision(obj1); - collisions = new_collisions; - done = false; - attempts++; - } - } - - } - if(attempts > 1) { - console.log("Attempted to resolve collisions " + attempts + " times"); - } - } - } - - draw(context) { - context.save(); - let color = "rgb(" + this.color.r + "," + this.color.g + "," + this.color.b + ")"; - context.fillStyle = color; - context.translate(this.pos.x, this.pos.y); - context.beginPath(); - if (this.circle === true) { - context.arc(0, 0, this.radius, 0, 2 * Math.PI); - } - else { - var verts = this.get_verts(); - context.moveTo(verts[0].x, verts[0].y); - for (var vert of verts) { - context.lineTo(vert.x, vert.y); - } - context.lineTo(vert.x, vert.y); - } - context.fill(); - context.restore(); - } - }; - - var GunTypes = { - // Enumeration for different types of guns - 'normal' : 1, - 'machinegun' : 2, - 'heavy' : 3, - } - - class Gun { - /* - Handles the firing of tank guns. - */ - constructor(tank) { - this.bullet_size = 5; - this.bullet_speed = 1.5; - this.ammo = 1000; // Max shots for current gun - this.clip = 5; // Max simultaenous shots - this.fire_delay = 0.5; - this.last_shot = Date.now(); - this.tank = tank; // Used for ignoring collisions when firing - this.type = GunTypes.normal; - this.damage_amount = 4; - this.randomize_direction = false; - } - - fire(x, y, direction) { - var bullet; - if (this.randomize_direction) { - direction += Math.random() * 10 - 5; // Add a random offset of +-5 degrees - } - if (this.clip > 0 && this.ammo > 0) { - if (Date.now() - this.last_shot > this.fire_delay * 1000) { - GUI_REDRAW_NEEDED = true; // GUI has info about remaining ammo - this.clip--; - this.ammo--; - this.last_shot = Date.now(); - bullet = new Bullet(x, y, direction, this.damage_amount, this, this.bullet_size, this.bullet_speed); - } - } - return bullet; - } - - reload() { - // Adds one bullet to clip. - this.clip++; - } - - get_name() { - return "40mm gun"; - } - - get_ammo_str() { - switch (this.type) { - case GunTypes.normal: - return "infinite"; - break; - default: - return this.ammo; - } - } - }; - - class Machinegun extends Gun { - constructor(tank) { - super(tank); - this.bullet_size = 2; - this.bullet_speed = 2; - this.ammo = 75; - this.clip = 25; - this.fire_delay = 0.1; - this.damage_amount = 1; - this.randomize_direction = true; - this.type = GunTypes.machinegun; - } - - get_name() { - return ".50 caliber machine gun"; - } - }; - - class Heavygun extends Gun { - constructor(tank) { - super(tank); - this.bullet_size = 20; - this.bullet_speed = 1.5; - this.ammo = 3; - this.clip = 3; - this.fire_delay = 1; - this.damage_amount = 1000; - this.randomize_direction = false; - this.type = GunTypes.heavy; - } - - fire(x, y, direction) { - // Override firing to make the bullet unstoppable - var bullet = super.fire(x, y, direction); - if (bullet) - bullet.set_unstoppable(true); - } - - get_name() { - return "155mm heavy gun"; - } - }; - - class Tank extends GameObject { - constructor(x, y, player) { - super(x, y, TANK_SIZE, TANK_SIZE, true); // Movable=true - this.player = player; - this.speed = 1; - this.turn_speed = 5; - this.fire_delay = 0; - this.max_fire_delay = 30; - this.max_ammo = 5; - this.ammo = this.max_ammo; - this.max_hp = 10; - this.hp = this.max_hp; - this.color_by_damage(); - - // Add a gun - this.set_gun(GunTypes.normal); - var w = this.width / 2; - var h = this.height / 2; - var last_vert = this.verts.pop(); - this.verts.push(new Vector2d(w, h/2)); - this.verts.push(new Vector2d(w*2, h/2)); - this.verts.push(new Vector2d(w*2, -h/2)); - this.verts.push(new Vector2d(w, -h/2)); - this.verts.push(last_vert); - } - - set_gun(type) { - GUI_REDRAW_NEEDED = true; // GUI has info about player weapons - switch (type) { - case GunTypes.normal : - this.gun = new Gun(this); - break; - case GunTypes.machinegun : - this.gun = new Machinegun(this); - break; - case GunTypes.heavy : - this.gun = new Heavygun(this); - break; - default : - console.log("Invalid gun type given " + type); - this.gun = new Gun(this); - break; - } - } - - destroy() { - END_ROUND = true; - this.player === P1 ? P2_SCORE++ : P1_SCORE++; - for (var i = 0; i < 360; i += 60) { - // Spawn a ring of bullets on death - var radians = deg2rad(i); - var damage = 4; - var off_x = this.width * Math.cos(radians); - var off_y = this.width * Math.sin(radians); - new Bullet(this.pos.x + off_x, this.pos.y + off_y, i, damage); - } - super.destroy(); - } - - update() { - /* - Checks for user input and checks collisions. - */ - if (this.fire_delay > 0) this.fire_delay--; - var p = this.player; - var radians = deg2rad(this.rotation); - - if ((p == P1 && KEYSTATE[P1_UP]) || (p == P2 && KEYSTATE[P2_UP])) { - this.velocity.x = this.speed * Math.cos(radians); - this.velocity.y = this.speed * Math.sin(radians); - } - else if ((p == P1 && KEYSTATE[P1_DOWN]) || (p == P2 && KEYSTATE[P2_DOWN])) { - this.velocity.x = -this.speed * Math.cos(radians); - this.velocity.y = -this.speed * Math.sin(radians); - } - else { - this.velocity = new Vector2d(0, 0); - } - if ((p == P1 && KEYSTATE[P1_LEFT]) || (p == P2 && KEYSTATE[P2_LEFT])) { - this.rotate(-this.turn_speed); - - } - else if ((p == P1 && KEYSTATE[P1_RIGHT]) || (p == P2 && KEYSTATE[P2_RIGHT])) { - this.rotate(this.turn_speed); - } - - super.update(); // Move and check collisions before firing - - if ((p == P1 && KEYSTATE[P1_FIRE]) || (p == P2 && KEYSTATE[P2_FIRE])) { - if (this.gun.ammo > 0) { - var off_x = this.width * 0.9 * Math.cos(radians); - var off_y = this.width * 0.9 * Math.sin(radians); - this.gun.fire(this.pos.x + off_x, this.pos.y + off_y, this.rotation); - } - else { - this.set_gun(GunTypes.normal); // Replace all special guns with a regular gun - } - - } - } - }; - - var PowerupType = { - 'machinegun' : 1, - 'heavy' : 2, - 'speed' : 3, - 'get_random_type' : - function get_random_type() { - return Math.ceil(Math.random() * 3); - } - }; - - class Powerup extends GameObject { - constructor(x, y, type) { - super(x, y, 10, 10, true); - this.type = type; - this.max_hp = 20; - this.hp = this.max_hp; - this.last_damage_tick = Date.now(); // Cause damage to self every second - this.turn_speed = 5; - this.re_color(); - } - - re_color() { - switch(this.type) { - case PowerupType.machinegun: - this.color = {"r":0, "g": 200, "b": 200}; - break; - case PowerupType.heavy: - this.color = {"r":0, "g": 50, "b": 120}; - break; - case PowerupType.speed: - this.color = {"r":0, "g": 255, "b": 255}; - break; - default: - console.log("Powerup has invalid type!"); - this.color = {"r":0, "g": 10, "b": 10}; - } - } - - update() { - this.rotate(this.turn_speed); - if (Date.now() - this.last_damage_tick > 1000) { - this.last_damage_tick = Date.now(); - this.damage(1); // Max time to live is 20 seconds; - } - super.update(); - } - - on_collision(obj) { - if (obj instanceof Tank) { - switch (this.type) { - case PowerupType.machinegun: - obj.set_gun(GunTypes.machinegun); - break; - case PowerupType.heavy: - obj.set_gun(GunTypes.heavy); - break; - case PowerupType.speed: - obj.speed++; - break; - default: - console.log("Powerup has invalid type!"); - } - this.destroy(); - } - } - }; - - class Bullet extends GameObject { - constructor(x, y, direction, damage, gun, size, speed) { - if (typeof speed == 'undefined') speed = 1.5; - if (typeof size == 'undefined') size = 5; - super(x, y, size, size, true); - this.max_time_to_live = 15000; // After this time the bullet disappears (milliseconds) - this.remaining_bounces = 10; - this.first_bounce = true; - this.spawn_time = Date.now(); - this.ignore_owner_for = 3 * size / speed; // HACK: this value is just randomly guessed (milliseconds) - this.speed = speed; - this.gun = gun; - if (this.gun && this.gun.tank) this.ignored_collision_objs.push(this.gun.tank); // Don't collide with tank before first bounce - this.color.r = Math.round(Math.random() * 255); - this.color.g = Math.round(Math.random() * 255); - this.color.b = Math.round(Math.random() * 255); - var radians = deg2rad(direction); - this.velocity.x = this.speed * Math.cos(radians); - this.velocity.y = this.speed * Math.sin(radians); - this.damage_amount = damage; - this.radius = this.width/2; - this.circle = true; - } - - update() { - super.update(); - if (Date.now() - this.spawn_time > this.max_time_to_live) { - // This bullet has been around long enough, destroy it - this.destroy(); - } - } - - on_collision(obj) { - this.remaining_bounces--; - if (this.first_bounce && (Date.now() - this.spawn_time > this.ignore_owner_for) && this.gun && this.gun.tank) { - // After first bounce bullet can collide with the shooting tank - this.first_bounce = false; - var ind = this.ignored_collision_objs.indexOf(this.gun.tank); - if (ind > -1) delete this.ignored_collision_objs[ind]; - } - - if (this.remaining_bounces < 1) { - this.destroy(); - } - - obj.damage(this.damage_amount); - if (obj instanceof Tank) { - this.destroy(); - } - } - - destroy() { - if (this.gun) this.gun.reload(); - super.destroy(); - } - - }; - - - - - /* - =============================================================================== - ----------------------------COLLISION DETECTION-------------------------------- - =============================================================================== - */ - - class Collision { - constructor(game_obj1, game_obj2) { - this.obj1 = game_obj1; - this.obj2 = game_obj2; - this.has_collided = false; - this.direction = new Vector2d(0, 0); // Direction of penetration - this.magnitude = Number.NEGATIVE_INFINITY; // Shortest distance of penetration - } - } - - function getSATCollision(game_obj1, game_obj2) { - /* - Uses Separating Axis Test to get the direction and magnitude of - any possible collision between given two objects. - https://en.wikipedia.org/wiki/Hyperplane_separation_theorem - - Objects can have any convex shape. Circles are a special case. - */ - var obj1 = game_obj1; - var obj2 = game_obj2; - let temp_pos1 = obj1.pos.clone(); - var d_origins = temp_pos1.subtract(obj2.pos).get_magnitude(); - var collision = new Collision(game_obj1, game_obj2); - collision.has_collided = false; - if (d_origins > MAX_DIST_FOR_COLLISIONS * CELL_SIZE) { - // Optimization: Skip further checks for distant objects - return collision; - } - var verts1 = game_obj1.get_verts(); - var verts2 = game_obj2.get_verts(); - var pos1 = game_obj1.pos.clone(); - var pos2 = game_obj2.pos.clone(); - - for (var i = 0; i < verts1.length + verts2.length; i++) { - // Calculate next axis by taking the normal of a side of one object - if (i < verts1.length) { - var vert = verts1[i]; - if (i < verts1.length-1) var next_vert = verts1[i+1]; - else var next_vert = verts1[0]; - } - else { - var vert = verts2[i - verts1.length]; - if (i < verts1.length+verts2.length-1) var next_vert = verts2[i+1 - verts1.length]; - else var next_vert = verts2[0]; - } - var side = next_vert.clone().subtract(vert).get_unit_vector(); - var axis = side.get_right_normal(); - - // Get minimum and maximum projections on axis from center of obj1 - var min_dist1 = verts1[0].get_dot_product(axis); - var max_dist1 = min_dist1; - for (var j = 1; j < verts1.length; j++) { - var distance = verts1[j].get_dot_product(axis); - if (distance < min_dist1) min_dist1 = distance; - else if (distance > max_dist1) max_dist1 = distance; - } - - // Get minimum and maximum projections on axis from center of obj2 - var min_dist2 = verts2[0].get_dot_product(axis); - var max_dist2 = min_dist2; - for (var j = 1; j < verts2.length; j++) { - var distance = verts2[j].get_dot_product(axis); - if (distance < min_dist2) min_dist2 = distance; - else if (distance > max_dist2) max_dist2 = distance; - } - - // Calculate the distance between objects and flip axis if necessary - var d = new Vector2d(pos2.x - pos1.x, pos2.y - pos1.y).get_dot_product(axis); - - // Calculate the gaps between objects projected along axis - // Negative gap means that there is a collision on this axis - var gap1 = d - max_dist1 + min_dist2; - var gap2 = - d - max_dist2 + min_dist1; - if (gap1 >= -EPSILON || gap2 >= -EPSILON) { - // No collision on this axis - these objects cannot be colliding! - collision.has_collided = false; - return collision; - } - if (gap1 > gap2 && gap1 > collision.magnitude) { - collision.magnitude = gap1; - collision.direction = axis; - } - if (gap2 > gap1 && gap2 > collision.magnitude) { - collision.magnitude = gap2; - collision.direction = axis.get_inverted(); - } - } - collision.has_collided = true; - return collision; - } - - function GetCollisions(obj) { - /* - Checks collisions given gameobject and all other gameobjects. - */ - var ign1 = obj.ignored_collision_objs; - var collisions = []; - for (obj_ind in GAME_OBJECTS) { - var other_obj = GAME_OBJECTS[obj_ind]; - var ign2 = other_obj.ignored_collision_objs; - if (ign1.indexOf(other_obj) === -1 && ign2.indexOf(obj) === -1) { - var collision = getSATCollision(obj, other_obj); - if (collision.has_collided === true) { - collisions.push(collision); - } - } - } - return collisions; - } - - - - - - - /* - =============================================================================== - ---------------------------------MAIN FUNCTIONS-------------------------------- - =============================================================================== - */ - - function fitToWindow() { - /* - Scales the game if the browser window is too small. - */ - let screen_margin = 10; - WIDTH = Math.min(TARGET_WIDTH, window.innerWidth - screen_margin); - HEIGHT = Math.min(TARGET_HEIGHT, window.innerHeight - screen_margin - 300); - WIDTH = Math.max(WIDTH, 100); - HEIGHT = Math.max(HEIGHT, 100); - - CANVAS.width = WIDTH; - CANVAS.height = HEIGHT + GUI_HEIGHT; - - PRERENDERED_CANVAS.width = WIDTH; - PRERENDERED_CANVAS.height = HEIGHT + GUI_HEIGHT; - } - - function main() { - /* - Creates a new HTML5 canvas element, adds listeners for input and - contains the main loop. - */ - CANVAS = document.createElement("canvas"); - CTX = CANVAS.getContext("2d"); - - // Initialize another canvas for quickly drawing static objects - PRERENDERED_CANVAS = document.createElement("canvas"); - PRERENDERED_CTX = PRERENDERED_CANVAS.getContext("2d"); - - fitToWindow(); // Set the size of both canvas - - // Attempt to find a document element with specific id, otherwise attach the - // canvas to document body. - attach_to = document.getElementById('game_window'); - if (attach_to == null) attach_to = document.body; - attach_to.appendChild(CANVAS); - - // Add listeners for keydown and keyup - KEYSTATE = {}; - document.addEventListener("keydown", function(evt) { - if([32, 37, 38, 39, 40].indexOf(evt.keyCode) > -1) { - evt.preventDefault(); // Prevent scrolling with arrowkeys and spacebar - } - KEYSTATE[evt.keyCode] = true; - }); - - document.addEventListener("keyup", function(evt) { - delete KEYSTATE[evt.keyCode]; - }); - - init(); - RESET_COUNTER = 0; - - var previous_time = Date.now(); // Time in milliseconds - var frames = 0; - var iteration_time = 0; - - var loop = function() { - /* - The main loop where all the magic happens. - */ - var start_time = Date.now(); - // Step the game forwards and draw everything - spawn_powerup(); - update(); - draw(); - iteration_time += Date.now() - start_time; - - // FPS-counter for performance analysis - if (DEBUG) { - frames++; - if (Date.now() - previous_time > 1000) { - console.log(frames + " : " + (iteration_time/frames)); - previous_time = Date.now(); - iteration_time = 0; - frames = 0; - } - } - - - // Start a new round if necessary - if (END_ROUND === true) RESET_COUNTER++; - if (RESET_COUNTER > RESET_COUNTER_MAX) { - init(); - END_ROUND = false; - RESET_COUNTER = 0; - } - - // Wait for the browser to finish drawing before looping again - window.requestAnimationFrame(loop, CANVAS); - }; - window.requestAnimationFrame(loop, CANVAS); - } - - function spawn_powerup() { - // Randomly spawns a random powerup to the level - this.max_spawn_time = 50000; // Max time between spawns (Milliseconds) - if (typeof this.last_spawn == 'undefined') { - this.last_spawn = Date.now(); - this.next_spawn_in = Math.random() * this.max_spawn_time; - } - if (Date.now() - this.last_spawn > this.next_spawn_in) { - this.last_spawn = Date.now(); - this.next_spawn_in = Math.random() * this.max_spawn_time; - let pos = get_random_location(); - new Powerup(pos.x, pos.y, PowerupType.get_random_type()); - } - } - - function get_random_location() { - // Gets a location, which is in the middle of a random cell. - var x = (Math.floor(Math.random() * CELLS_X) + 0.5) * (CELL_SIZE); - var y = (Math.floor(Math.random() * CELLS_Y) + 0.5) * (CELL_SIZE); - return new Vector2d(x, y); - } - - function init() { - /* - Initialize global variables. - */ - GAME_OBJECTS = []; - KEYSTATE = {}; // Reset the keystate to avoid stuck buttons - PRERENDERED_REDRAW_NEEDED = true; - GUI_REDRAW_NEEDED = true; - - fitToWindow(); // Rescale the game window, if necessary - - // Generate map - maze_generator_kruskal(); - - // Create tanks at random locations - - let pos = get_random_location(); - TANK_P1 = new Tank(pos.x, pos.y, P1); - let pos2 = pos; - while (pos.x == pos2.x && pos.y == pos2.y) { - pos2 = get_random_location(); - } - TANK_P2 = new Tank(pos2.x, pos2.y, P2); - } - - function update() { - /* - Handles game logic by moving all objects and checking collisions. - */ - for (obj_ind in GAME_OBJECTS) { - obj = GAME_OBJECTS[obj_ind]; - obj.update(); - } - } - - function draw() { - /* - Handles all drawing on the HTML5 canvas. - */ - - // Game - CTX.fillStyle = "#fff"; - CTX.clearRect(0, 0, WIDTH, HEIGHT); - - // Redraw static objects only if they have been changed - if (PRERENDERED_REDRAW_NEEDED) { - PRERENDERED_CTX.fillStyle = "#fff"; - PRERENDERED_CTX.clearRect(0, 0, WIDTH, HEIGHT); - PRERENDERED_REDRAW_NEEDED = false; - for (obj_ind in GAME_OBJECTS) { - obj = GAME_OBJECTS[obj_ind]; - if (obj.movable === false) { - obj.draw(PRERENDERED_CTX); - } - } - } - - // Draw prerendered static objects - CTX.drawImage(PRERENDERED_CANVAS, 0, 0); - - // Draw other objects - for (obj_ind in GAME_OBJECTS) { - obj = GAME_OBJECTS[obj_ind]; - if (obj.movable === true) { - obj.draw(CTX); - } - } - - // GUI - if (GUI_REDRAW_NEEDED || END_ROUND) { - GUI_REDRAW_NEEDED = false; - var P2_offset_x = WIDTH - 270; - CTX.save(); - CTX.translate(0, HEIGHT); // Move to GUI space - CTX.fillStyle = "#fff"; - CTX.clearRect(0, 0, WIDTH, GUI_HEIGHT); - CTX.font = "30px Arial"; - CTX.fillStyle = (P1_SCORE >= P2_SCORE) ? "green" : "red"; - CTX.fillText("Player One: " + P1_SCORE, 30, 50); - CTX.fillStyle = (P2_SCORE >= P1_SCORE) ? "green" : "red"; - CTX.fillText("Player Two: " + P2_SCORE, P2_offset_x, 50); - if (END_ROUND === true) { - CTX.fillStyle = "blue"; - CTX.fillText("Next round in: " + (RESET_COUNTER_MAX - RESET_COUNTER), P2_offset_x/2, 50); - } - CTX.fillStyle = "#000"; - CTX.font = "16px Arial"; - CTX.fillText("Move: WASD", 30, 80); - CTX.fillText("Fire: 1", 30, 100); - CTX.fillText("Move: Arrow keys", P2_offset_x, 80); - CTX.fillText("Fire: -", P2_offset_x, 100); - CTX.font = "bold " + CTX.font; - CTX.fillText("Weapon: " + TANK_P1.gun.get_name(), 30, 120); - CTX.fillText("Ammo remaining: " + TANK_P1.gun.get_ammo_str(), 30, 140); - CTX.fillText("Weapon: " + TANK_P2.gun.get_name(), P2_offset_x, 120); - CTX.fillText("Ammo remaining: " + TANK_P2.gun.get_ammo_str(), P2_offset_x, 140); - CTX.restore(); - } - } - - - - - - /* - =============================================================================== - ---------------------------------MAP GENERATION-------------------------------- - =============================================================================== - */ - - function maze_generator_kruskal() { - /* - Uses randomized Kruskal's algorithm to generate a maze. - https://en.wikipedia.org/wiki/Maze_generation_algorithm#Randomized_Kruskal.27s_algorithm - - Normally this algorithm generates 'perfect' mazes, with only one route - from end to beginning. For gameplay reasons multiple routes through the - maze is preferred. This is achieved by randomly deleting additional walls. - */ - - class Cell { - constructor(x, y, i, j) { - this.ind_x = i; - this.ind_y = j; - this.x = x; - this.y = y; - this.right_wall = true; - this.bottom_wall = true; - } - }; - - function shuffle(a) { - /* - Shuffles array in place. - Taken from http://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array-in-javascript - because I'm lazy and it is a perfectly fine function. - */ - var j, x, i; - for (var i = a.length; i; i--) { - j = Math.floor(Math.random() * i); - x = a[i - 1]; - a[i - 1] = a[j]; - a[j] = x; - } - } - - function find_cell_set(cell, sets) { - // Finds the set where the given cell is found. - for (set in sets) { - if (sets[set].has(cell)) return set; - } - } - - function join_cell_sets(cell_1, cell_2, sets) { - /* - Checks if given cells are in different sets, joins the sets and returns - true. Otherwise returns false. - */ - set_ind1 = find_cell_set(cell_1, sets); - set_ind2 = find_cell_set(cell_2, sets); - if (!(set_ind1 === set_ind2)) { - var joined_set = new Set(function*() { - yield* sets[set_ind1]; yield* sets[set_ind2]; }() - ); - delete sets[set_ind1]; - delete sets[set_ind2]; - sets.push(joined_set); - return true; - } - return false; - } - cell_size_min = 30; - cell_size_max = 100; - rand = Math.random(); - CELL_SIZE = 30 + (rand * (100-30)); // A random number between min and max - CELL_SIZE = Math.floor(CELL_SIZE); - console.log(CELL_SIZE); - console.log(CELL_SIZE % 5); - CELL_SIZE -= CELL_SIZE % 5; - console.log(CELL_SIZE); - - // Create cells to assist with maze generation - var cells = []; - CELLS_X = Math.floor(WIDTH / CELL_SIZE); - CELLS_Y = Math.floor(HEIGHT / CELL_SIZE); - for (var i = 0; i < CELLS_X; i++) { - var x = i * CELL_SIZE + CELL_SIZE / 2; - var column = [] - - for (var j = 0; j < CELLS_Y; j++) { - var y = j * CELL_SIZE + CELL_SIZE / 2; - new_cell = new Cell(x, y, i, j); - column[j] = new_cell; - } - cells[i] = column; - } - - // Add all walls to arrays and create a set for each cell - var right_walls = []; - var bottom_walls = []; - var cell_sets = []; - for (var i = 0; i < CELLS_X; i++) { - for (var j = 0; j < CELLS_Y; j++) { - cell = cells[i][j]; - cell_sets.push(new Set([cell])); - right_walls.push(cell); - bottom_walls.push(cell); - } - } - - // Shuffle walls to randomize the maze - shuffle(right_walls); - shuffle(bottom_walls); - - // These variables adjust the proportion of removed horizontal and vertical - // walls. - var horiz_prob = 0.6; // value must be 0 < x <= 1 - var vert_prob = 0.7; // value must be 0 < x <= 1 - var remove_anyway_prob = 0.2; // Probability for removing extra walls - - // Remove all walls between disconnected cells - while (right_walls.length > 0 && bottom_walls.length > 0) { - // Right walls - if (right_walls.length > 0 && Math.random() < vert_prob) { - var cell = right_walls.pop(); - if (cell.ind_x + 1 < CELLS_X) { - next_cell = cells[cell.ind_x+1][cell.ind_y]; - // Check if the cell on right belongs to the same set (already connected) - if (join_cell_sets(cell, next_cell, cell_sets)) { - cell.right_wall = false; - } - // Randomly delete the wall anyway - else if (Math.random() < remove_anyway_prob) cell.right_wall = false; - } - } - - // Bottom walls - if (bottom_walls.length > 0 && Math.random() < horiz_prob) { - var cell = bottom_walls.pop(); - if (cell.ind_y + 1 < CELLS_Y) { - next_cell = cells[cell.ind_x][cell.ind_y+1]; - // Check if the cell below belongs to the same set (already connected) - if (join_cell_sets(cell, next_cell, cell_sets)) { - cell.bottom_wall = false; - } - // Randomly delete the wall anyway - else if (Math.random() < remove_anyway_prob) cell.bottom_wall = false; - } - } - } - - // Create a GameObject for every wall - for (column_ind in cells) { - column = cells[column_ind]; - for (cell_ind in column) { - cell = column[cell_ind]; - var x = cell.x; - var y = cell.y; - var s = CELL_SIZE/2; - var w = WALL_WIDTH/2; - if (cell.bottom_wall) { - let wall = new GameObject(x, y+s, s*2, w*2); - if (cell_ind == column.length-1) { - // Make the border walls indestructible - wall.set_destructible(false); - } - } - if (cell.right_wall) { - let wall = new GameObject(x+s, y, w*2, s*2); - if (column_ind == cells.length-1) { - // Make the border walls indestructible - wall.set_destructible(false); - } - } - - // Add left border wall - if (column_ind == 0) { - let wall = new GameObject(x-s+1, y, w*2, s*2); // Offset by one to improve visibility - // Make the border walls indestructible - wall.set_destructible(false); - } - // Add top border wall - if (cell_ind == 0) { - let wall = new GameObject(x, y-s+1, s*2, w*2); // Offset by one to improve visibility - // Make the border walls indestructible - wall.set_destructible(false); - } - } - } - } - - main(); - - return { - // Return some objects/methods for debugging purposes - GAME_OBJECTS : GAME_OBJECTS, - SET_DEBUG : function set_debug(value) { DEBUG = value; }, - SET_COLLISION_DISTANCE : function set_collision_distance(value) { MAX_DIST_FOR_COLLISIONS = value; }, - }; - -})(); diff --git a/README.md b/README.md deleted file mode 100644 index 5c2ad21..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# javascript -Code from C4T's JavaScript course diff --git a/ch1/solutions/solution_4.js b/ch1/solutions/solution_4.js deleted file mode 100644 index 850cc04..0000000 --- a/ch1/solutions/solution_4.js +++ /dev/null @@ -1,5 +0,0 @@ -// Code here - -console.log("My Favorite Fruits"); - -console.table(["Apple", "Orange", "Dragonfruit"]); diff --git a/ch1/solutions/solution_6.js b/ch1/solutions/solution_6.js deleted file mode 100644 index 1c883f2..0000000 --- a/ch1/solutions/solution_6.js +++ /dev/null @@ -1,7 +0,0 @@ -// Code here - -let person = {name: "Matthew", age: 16, bankAccount: 0}; - -console.log(typeof person.name); -console.log(typeof person.age); -console.log(typeof person.bankAccount); diff --git a/ch1/templates/template_4.js b/ch1/templates/template_4.js deleted file mode 100644 index 0cbe41c..0000000 --- a/ch1/templates/template_4.js +++ /dev/null @@ -1,7 +0,0 @@ -/** TASK(S) - * 1. Log into console: "My Favorite Fruits" - * 2. Log into console 3 different fruits organized in a table. - */ - -// Code here - diff --git a/ch1/templates/template_6.js b/ch1/templates/template_6.js deleted file mode 100644 index c4d15e4..0000000 --- a/ch1/templates/template_6.js +++ /dev/null @@ -1,7 +0,0 @@ -/** TASK(S) - * 1. Create an object and store it in a variable (The object should have at least 3 properties). - * 2. Log to console the different types of the properties - */ - -// Code here - diff --git a/ch10_JSON/JSONP1/JSON_P1_Solution.html b/ch10_JSON/JSONP1/JSON_P1_Solution.html deleted file mode 100644 index c9e0928..0000000 --- a/ch10_JSON/JSONP1/JSON_P1_Solution.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - LOL - - - - - - - - diff --git a/ch10_JSON/JSONP2/index.html b/ch10_JSON/JSONP2/index.html deleted file mode 100644 index 4109064..0000000 --- a/ch10_JSON/JSONP2/index.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - LOL - - - -
-
-

-

-

-

-

-

-

-

-

-
- - - - - diff --git a/ch10_JSON/JSONP2/index.js b/ch10_JSON/JSONP2/index.js deleted file mode 100644 index b346c32..0000000 --- a/ch10_JSON/JSONP2/index.js +++ /dev/null @@ -1,18 +0,0 @@ -document.getElementById("Submit").onclick = function() { - let form = { - companyName: document.getElementById("companyName").value, - NumOfEmployees: document.getElementById("NumOfEmployees").value, - Revenue: document.getElementById("Revenue").value, - Rating: document.getElementById("Rating").value, - usCorp: document.getElementById("usCorp").value - } - console.log(JSON.stringify(form)) - - -} - - - - - - diff --git a/ch10_JSON/JSON_Problems_Template.html b/ch10_JSON/JSON_Problems_Template.html deleted file mode 100644 index b461122..0000000 --- a/ch10_JSON/JSON_Problems_Template.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - LOL - - - - - diff --git a/ch10_JSON/Readme.txt b/ch10_JSON/Readme.txt deleted file mode 100644 index d8f7e90..0000000 --- a/ch10_JSON/Readme.txt +++ /dev/null @@ -1 +0,0 @@ -This folder holds the solution code for the JSON chapter of Javascript intermediate diff --git a/ch2/solutions/solution_2.js b/ch2/solutions/solution_2.js deleted file mode 100644 index 551eed1..0000000 --- a/ch2/solutions/solution_2.js +++ /dev/null @@ -1,5 +0,0 @@ -// Code here - -let ans = ((200 * 10 + 126) / 2) % 6; - -console.log(ans); // 1 diff --git a/ch2/solutions/solution_3.js b/ch2/solutions/solution_3.js deleted file mode 100644 index 88032e9..0000000 --- a/ch2/solutions/solution_3.js +++ /dev/null @@ -1,9 +0,0 @@ -// Code here - -let ans = 300; - -ans += 6; -ans -= 200; -ans %= 6; - -console.log(ans); diff --git a/ch2/templates/template_2.js b/ch2/templates/template_2.js deleted file mode 100644 index 53342d9..0000000 --- a/ch2/templates/template_2.js +++ /dev/null @@ -1,8 +0,0 @@ -/** TASK(S) - * 1. Determine the value of this mathematical word problem: - * 200 times 10 plus 126. Divide it by two. Find remainder if divided by 6. - * 2. Log to console the value. - */ - -// Code here - diff --git a/ch2/templates/template_3.js b/ch2/templates/template_3.js deleted file mode 100644 index f19a3ae..0000000 --- a/ch2/templates/template_3.js +++ /dev/null @@ -1,11 +0,0 @@ -/** TASK(S) - * 1. Create a variable call "ans" (type number). Set it equal to 300. - * 2. Change the value of "ans" with the following instructions: - * * Add 6 to "ans" - * * Remove 200 from "ans" - * * Set "ans" to the remainder when "ans" is divided by 6. - * 3. Log to console "ans". - */ - -// Code here - diff --git a/ch3/solutions/solution_3.js b/ch3/solutions/solution_3.js deleted file mode 100644 index 63235c2..0000000 --- a/ch3/solutions/solution_3.js +++ /dev/null @@ -1,18 +0,0 @@ -let givenNumber = 4; - -if (givenNumber % 2 == 0) { - if (givenNumber == 2) { - console.log("My given number is either 2 or 4."); - } else if (givenNumber == 4) { - console.log("My given number is either 2 or 4."); - } - - // another solution - /* - if (givenNumber == 2 || givenNumber == 4) { - console.log("My given number is either 2 or 4."); - } - */ -} else { - console.log("My given number is bad."); -} \ No newline at end of file diff --git a/ch3/solutions/solution_5.js b/ch3/solutions/solution_5.js deleted file mode 100644 index c64c7bf..0000000 --- a/ch3/solutions/solution_5.js +++ /dev/null @@ -1,19 +0,0 @@ -let character = "Warrior"; -let stats = null; - -switch (character) { - case "Warrior": - stats = {attack: 80, defence: 60, speed: 30}; - break; - case "Scout": - stats = {attack: 50, defence: 20, speed: 80}; - break; - case "Archer": - stats = {attack: 60, defence: 30, speed: 40}; - break; - default: - console.log("Unable to assigned character."); - break; -} - -console.log(stats); \ No newline at end of file diff --git a/ch3/templates/template_3.js b/ch3/templates/template_3.js deleted file mode 100644 index afd2f85..0000000 --- a/ch3/templates/template_3.js +++ /dev/null @@ -1,10 +0,0 @@ -/** TASK(S) - * 1. Create a variable called "givenNumber". Set it to any number. - * 2. Check whether the number is divisble by 2. Hint: Use "%" operator. - * 3. If it is divisble by 2, check whether than number is equal to either 2 or 4. If it is, - * then log to console: "My given number is either 2 or 4". - * 4. If it is not divisble by 2, log to console: "My given number is bad". - */ - -// Code here - diff --git a/ch3/templates/template_5.js b/ch3/templates/template_5.js deleted file mode 100644 index 679da1b..0000000 --- a/ch3/templates/template_5.js +++ /dev/null @@ -1,17 +0,0 @@ -/** TASK(S) - * 1. Create a variable called "character". Set it to a string that is one of the characters in step (2). - * Create another variable called "stats". Set it to null. - * 2. Check whether the character is one of the following: - * * Warrior - * * Scout - * * Archer - * 3. Using a switch statement, set the "stats" variable to the stats of the character: - * * Warrior: {attack: 80, defence: 60, speed: 30} - * * Scout: {attack: 50, defence: 20, speed: 80} - * * Archer: {attack: 60, defence: 30, speed: 40} - * 4. If the "character" variable does not match any character, log to console: "Unable to assigned character". - * 5. Log to console the stats. - */ - -// Code here - diff --git a/ch4/solutions/solution_2.js b/ch4/solutions/solution_2.js deleted file mode 100644 index e48ee3c..0000000 --- a/ch4/solutions/solution_2.js +++ /dev/null @@ -1,7 +0,0 @@ -let sum = 0; - -for (let i = 1; i <= 10; i++) { - sum += i; -} - -console.log(sum); diff --git a/ch4/solutions/solution_5.js b/ch4/solutions/solution_5.js deleted file mode 100644 index 036ee91..0000000 --- a/ch4/solutions/solution_5.js +++ /dev/null @@ -1,8 +0,0 @@ -let i = 1; -while (i <= 1000) { - if (i % 2 == 0 && i % 3 == 0) { - console.log(i); - } - - i++ -} diff --git a/ch4/templates/template_2.js b/ch4/templates/template_2.js deleted file mode 100644 index 2415109..0000000 --- a/ch4/templates/template_2.js +++ /dev/null @@ -1,9 +0,0 @@ -/** TASK(S) - * 1. Create a variable called "sum". - * 2. Create a for loop that adds up all the number, including, 1 to 10. - * 3. "sum" should be equal to the number in step (2). - * 3. Log to console the variable "sum". - */ - -// Code here - diff --git a/ch4/templates/template_5.js b/ch4/templates/template_5.js deleted file mode 100644 index f85e0f4..0000000 --- a/ch4/templates/template_5.js +++ /dev/null @@ -1,7 +0,0 @@ -/** TASK(S) - * 1. Using a while loop, find all numbers divisble by 2 and 3 between 0 to 1000 (inclusive). - * 2. Log to console the numbers. - */ - -// Code here - diff --git a/ch5/solutions/solution_3.js b/ch5/solutions/solution_3.js deleted file mode 100644 index 1f2927a..0000000 --- a/ch5/solutions/solution_3.js +++ /dev/null @@ -1,9 +0,0 @@ -const myFavoriteNumbers = [2, 7, 69, 10, 21]; - -let sum = 0; - -for (let num of myFavoriteNumbers) { - sum += num; -} - -console.log(sum); diff --git a/ch5/solutions/solution_7.js b/ch5/solutions/solution_7.js deleted file mode 100644 index a250e6f..0000000 --- a/ch5/solutions/solution_7.js +++ /dev/null @@ -1,29 +0,0 @@ -const field = [ - [0, 0, 1], - [0, 1, 0], - [1, 0, 0] -]; - -let cowLocations = [ - [-1, -1], - [-1, -1], - [-1, -1] -]; - -let count = 0; - -for (let i = 0; i < 3; i++) { - - for (let j = 0; j < 3; j++) { - - if (field[i][j] == 1) { - cowLocations[count][0] = i; - cowLocations[count][1] = j; - count++; - } - - } - -} - -console.log(cowLocations); diff --git a/ch5/templates/template_3.js b/ch5/templates/template_3.js deleted file mode 100644 index 51f8233..0000000 --- a/ch5/templates/template_3.js +++ /dev/null @@ -1,9 +0,0 @@ -/** TASK(S) - * 1. Create an array called "myFavoriteNumbers". - * 2. Add your favorite numbers (or some random numbers) - * 3. Add up all of these favorite numbers. - * 4. Log to console the sum of these favorite numbers. - */ - -// Code here - diff --git a/ch5/templates/template_7.js b/ch5/templates/template_7.js deleted file mode 100644 index aafca5a..0000000 --- a/ch5/templates/template_7.js +++ /dev/null @@ -1,13 +0,0 @@ -/** TASK(S) - * 1. Given a 2D array called "field", find me the where the cows are in respect to the 2D array. - * ("1" represents a cow, "0" represents no cow) - * 2. Add all these locations into a 2D array that has 3 rows and 2 columns (there will only be 3 cows). - * 3. Log to console this 2D array. - */ - -// Code here -const field = [ - [0, 0, 1], - [0, 1, 0], - [1, 0, 0] -]; diff --git a/ch6/solutions/solution_2.js b/ch6/solutions/solution_2.js deleted file mode 100644 index 7cf1406..0000000 --- a/ch6/solutions/solution_2.js +++ /dev/null @@ -1,3 +0,0 @@ -const distance = (x, y) => Math.sqrt((x * x) + (y * y)); - -console.log(distance(4, 4)); diff --git a/ch6/solutions/solution_5.js b/ch6/solutions/solution_5.js deleted file mode 100644 index 6238988..0000000 --- a/ch6/solutions/solution_5.js +++ /dev/null @@ -1,9 +0,0 @@ -let words = ['people', 'us', 'iPhone', 'history', 'sandals', 'sevens', 'legends']; - -for (let word of words) { - if (word.indexOf('s') != -1) { - words = words.filter((str) => word != str); - } -} - -console.log(words); diff --git a/ch6/templates/template_2.js b/ch6/templates/template_2.js deleted file mode 100644 index da6ae16..0000000 --- a/ch6/templates/template_2.js +++ /dev/null @@ -1,13 +0,0 @@ -/** TASK(S) - * 1. Create an arrow function/method that has 2 parameters: "x" and "y". - * 2. Have the arrow function return the distance from the origin to the x-coordinate, "x", and - * y-coordinate, "y". - * 3. Log to console the distance from the origin to (4,4) - * - * * Distance Formula: https://www.shorturl.at/krzN4 - * * Origin = (0, 0) - * * Hint: Use "Math.sqrt()" to take the square root of whatever is in the parameter. - */ - -// Code here - diff --git a/ch6/templates/template_5.js b/ch6/templates/template_5.js deleted file mode 100644 index f561c3d..0000000 --- a/ch6/templates/template_5.js +++ /dev/null @@ -1,9 +0,0 @@ -/** TASK(S) - * 1. Given an array of words, remove all words in the array that have "s" in them. - * 2. Log to console this new array of words. - * - * * Hint: "filter" method will prove useful. - */ - -// Code here -let words = ['people', 'us', 'iPhone', 'history', 'sandals', 'sevens', 'legends']; diff --git a/ch8/FetchAPI/index.html b/index.html similarity index 100% rename from ch8/FetchAPI/index.html rename to index.html diff --git a/ch8/FetchAPI/index.js b/index.js similarity index 100% rename from ch8/FetchAPI/index.js rename to index.js diff --git a/ch8/FetchAPI/template.js b/template.js similarity index 100% rename from ch8/FetchAPI/template.js rename to template.js