This exercise allows you to practice and apply the concepts and techniques taught in class.
Upon completion of this exercise, you will be able to:
- Run predefined tests in Jasmine to verify that the program meets the technical requirements.
- Identify expected code behavior by reading and understanding test results and errors.
- Define a
class
and use it to create objects (instances). - Create a subclass that extends a parent class using
extends
andsuper()
to inherit properties and methods. - Define class methods that use the
this
keyword to access object properties. - Add or remove items from an array using the array methods (
push
,pop
,shift
,unshift
, andsplice
). - Iterate over arrays using the
for
andforEach
loops. - Pass values as arguments to functions.
- Use the
return
keyword to return a value from a function.
We have learned Object-oriented programming and how class
and inheritance work in JavaScript. Now let's work with our Viking friends, applying the concepts we have just learned.
- Fork this repo.
- Clone this repo.
- Upon completion, run the following commands:
git add .
git commit -m "Solved lab"
git push origin master
- Create a Pull Request and submit your assignment
This LAB is equipped with unit tests to provide automated feedback on your lab progress. In case you want to check the tests, they are in the tests/viking.spec.js
file.
To run the tests and your JavaScript code, open the SpecRunner.html
file using the Live Server VSCode extension.
To see the outputs of the console.log
in your JavaScript code, open the Console in the Developer Tools.
You will work on the src/viking.js
file.
Your task is to write the correct code in the src/viking.js
file to make the tests pass. In this file, you will find the following starter code:
// Soldier
class Soldier {}
// Viking
class Viking {}
// Saxon
class Saxon {}
// War
class War {}
Let's have a look at the first test case together to get you started.
The first test case says that "Soldier class >> should receive 2 arguments (health & strength)", so we have to write the correct code to pass this test. Let's make the Soldier
class receive two arguments:
// Soldier
class Soldier {
constructor(health, strength) {}
}
// Viking
class Viking {}
// Saxon
class Saxon {}
// War
class War {}
Modify the Soldier
class and add 2 methods to it: attack()
, and receiveDamage()
.
- should receive 2 arguments (health & strength)
- should receive the
health
property as its 1st argument - should receive the
strength
property as its 2nd argument
- should be a function
- should receive 0 arguments
- should return the
strength
property of theSoldier
- should be a function
- should receive 1 argument (the damage)
- should remove the received damage from the
health
property - shouldn't return anything
A Viking
is a Soldier
with an additional property, their name
. They also have a different receiveDamage()
method and a new method, battleCry()
.
Modify the Viking
class, have it inherit from Soldier
, re-implement the receiveDamage()
method for Viking
, and add a new battleCry()
method.
Viking
should extendSoldier
- should receive 3 arguments (name, health & strength)
- should receive the
name
property as its 1st argument - should receive the
health
property as its 2nd argument - should receive the
strength
property as its 3rd argument
(This method should be inherited from Soldier
, no need to re-implement it.)
- should be a function
- should receive 0 arguments
- should return the
strength
property of theViking
This method needs to be re-implemented for Viking
because the Viking
version needs to have different return values.
- should be a function
- should receive 1 argument (the damage)
- should remove the received damage from the
health
property - if the
Viking
is still alive, it should return "NAME has received DAMAGE points of damage" - if the
Viking
dies, it should return "NAME has died in act of combat"
Learn more about battle cries.
- should be a function
- should receive 0 arguments
- should return "Odin Owns You All!"
A Saxon
is a weaker kind of Soldier
. Unlike a Viking
, a Saxon
has no name. Their receiveDamage()
method will also be different than the original Soldier
version.
Modify the Saxon
, constructor function, have it inherit from Soldier
and re-implement the receiveDamage()
method for Saxon
.
Saxon
should extendSoldier
- You don't have to include a constructor method since this class will inherit perfectly from the parents class, both the health and the strength (it
extends
Soldier class 😉 )
This method should be inherited from Soldier
, no need to re-implement it.
- should be a function
- should receive 0 arguments
- should return the
strength
property of theSaxon
This method needs to be re-implemented for Saxon
because the Saxon
version needs to have different return values.
- should be a function
- should receive 1 argument (the damage)
- should remove the received damage from the
health
property - if the Saxon is still alive, it should return "A Saxon has received DAMAGE points of damage"
- if the Saxon dies, it should return "A Saxon has died in combat"
Now we get to the good stuff: WAR! Our War
class will allow us to have a Viking
army and a Saxon
army that battle each other.
Modify the War
class and add 5 methods to its class
:
addViking()
addSaxon()
vikingAttack()
saxonAttack()
showStatus()
When we first create a War
, the armies should be empty. We will add soldiers to the armies later.
- should receive 0 arguments
- should assign an empty array to the
vikingArmy
property - should assign an empty array to the
saxonArmy
property
Adds 1 Viking
to the vikingArmy
. If you want a 10 Viking
army, you need to call this 10 times.
- should be a function
- should receive 1 argument (a
Viking
object) - should add the received
Viking
to the army - shouldn't return anything
The Saxon
version of addViking()
.
- should be a function
- should receive 1 argument (a
Saxon
object) - should add the received
Saxon
to the army - shouldn't return anything
A Saxon
(chosen at random) has their receiveDamage()
method called with the damage equal to the strength
of a Viking
(also chosen at random). This should only perform a single attack and the Saxon
doesn't get to attack back.
- should be a function
- should receive 0 arguments
- should make a
Saxon
receiveDamage()
equal to thestrength
of aViking
- should remove dead Saxons from the army
- should return result of calling
receiveDamage()
of aSaxon
with thestrength
of aViking
The Saxon
version of vikingAttack()
. A Viking
receives damage equal to the strength
of a Saxon
.
- should be a function
- should receive 0 arguments
- should make a
Viking
receiveDamage()
equal to thestrength
of aSaxon
- should remove dead Vikings from the army
- should return result of calling
receiveDamage()
of aViking
with thestrength
of aSaxon
Since there is a lot of repetitive code in the previous two iterations, methods vikingAttack() and saxonAttack(), try to create one generic method and call it in the case of vikingAttack and in the case of saxonAttack instead of using almost the same code for both methods. (This iteration doesn't have the test, so ask your TAs and your instructor to give you feedback on the quality of your code after the refactor.)
Returns the current status of the War
based on the size of the armies.
- should be a function
- should receive 0 arguments
- if the
Saxon
array is empty, should return "Vikings have won the war of the century!" - if the
Viking
array is empty, should return "Saxons have fought for their lives and survived another day..." - if there are at least 1
Viking
and 1Saxon
, should return "Vikings and Saxons are still in the thick of battle."
Happy Coding! ❤️
I am stuck in the exercise and don't know how to solve the problem or where to start.
If you are stuck in your code and don't know how to solve the problem or where to start, you should take a step back and try to form a clear question about the specific issue you are facing. This will help you narrow down the problem and come up with potential solutions.
For example, is it a concept that you don't understand, or are you receiving an error message that you don't know how to fix? It is usually helpful to try to state the problem as clearly as possible, including any error messages you are receiving. This can help you communicate the issue to others and potentially get help from classmates or online resources.
Once you have a clear understanding of the problem, you will be able to start working toward the solution.
All of the Jasmine tests are failing and in red. Why did this happen?
One possible reason why all of the Jasmine tests are failing is that there is a syntax error in the code being tested. If the code contains a syntax error, it will not be loaded properly and none of the tests will be able to run. This will cause all of the tests to fail.
To troubleshoot this issue, you will need to examine the code being tested for syntax errors. Look for missing brackets, semicolons, or other syntax issues that could be causing the problem. If you find a syntax error, correct it and try running the tests again.
Another possibility is that there is an issue with the tests. It is possible that you may have modified the test file and caused an issue. If you have made changes to the test file, try copying and pasting the original test file and running the tests again to see if this resolves the issue.
How do I loop over an array using the forEach()
method?
The forEach()
method executes a provided function once for each array element. It does not return a new array but rather executes the function on each element in the array.
The syntax of the forEach()
method is as follows:
array.forEach( function(element) {
// code to be executed for each element
});
Here is an example that uses the forEach()
method to log each element and its index in an array to the console:
const fruits = ['apple', 'banana', 'cherry'];
fruits.forEach( function(element, index) {
console.log(`${index}: ${element}`);
});
You can also use an arrow function as the callback function for forEach()
:
fruits.forEach((element, index) => {
console.log(`${index}: ${element}`);
});
How do I remove an element from an array?
You should use the splice()
method to remove an array element at a specified index. The splice()
method modifies the original array and returns an array containing the removed elements.
Syntax:
array.splice(start, deleteCount, item1, item2, ... )
start
: The index of the first element to be removed.deleteCount
: The number of elements to be removed.item1, item2, ...
: (optional) The elements to add to the array, starting at thestart
index.
For example, to remove an array element at index 2
(which is "c"
):
let numbers = ["a", "b", "c", "d", "e"];
// Remove 1 element starting at index 2 (removes "c")
let removed = numbers.splice(2, 1);
console.log(numbers); // Output: ["a", "b", "d", "e"]
console.log(removed); // Output: ["c"]
For more information, check: MDN: splice()
How can I extend a class and reuse methods through inheritance?
In JavaScript, you can use the extends
keyword to create a subclass that extends a superclass (also called a base class).
The subclass inherits methods and properties from the superclass and can also have its own methods and properties.
Here is an example of extending a class and reusing its methods in JavaScript:
class Dog {
constructor (name) {
this.name = name;
}
bark() {
console.log(`${this.name} is barking.`);
}
}
class Labradoodle extends Dog {
constructor (name, color) {
super(name);
this.color = color;
}
}
const dog1 = new Labradoodle("Daisy", "white");
dog1.bark(); // Output: "Daisy is barking."
In this example, the Labradoodle
class extends the Dog
class and inherits the name
property and the bark()
method. The Labradoodle
class also defines its own property color
.
When the bark()
method is called on the dog1
object, it uses the method bark()
coming from the Dog
class, because the Labradoodle
class extends the Dog
class and inherits its methods and properties.
I am unable to push changes to the repository. What should I do?
There are a couple of possible reasons why you may be unable to push changes to a Git repository:
- You have not committed your changes: Before you can push your changes to the repository, you need to commit them using the
git commit
command. Make sure you have committed your changes and try pushing again. To do this, run the following terminal commands from the project folder:
git add .
git commit -m "Your commit message"
git push
- You do not have permission to push to the repository: If you have cloned the repository directly from the main Ironhack repository without making a Fork first, you do not have write access to the repository. To check which remote repository you have cloned, run the following terminal command from the project folder:
git remote -v
If the link shown is the same as the main Ironhack repository, you will need to fork the repository to your GitHub account first and then clone your fork to your local machine to be able to push the changes.
Note: You should make a copy of your local code to avoid losing it in the process.