mirror of
https://codeberg.org/andyscott/exercism.git
synced 2024-12-21 22:33:11 -05:00
C++: completed Ellen's Alien Game, Interest is Interesting, Vehicle Purchase
This commit is contained in:
parent
4ca5823d45
commit
c8ef7df34c
36 changed files with 55423 additions and 0 deletions
21
cpp/ellens-alien-game/.exercism/config.json
Normal file
21
cpp/ellens-alien-game/.exercism/config.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"authors": [
|
||||||
|
"vaeng"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"ellens_alien_game.cpp"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"ellens_alien_game_test.cpp"
|
||||||
|
],
|
||||||
|
"exemplar": [
|
||||||
|
".meta/exemplar.cpp"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"forked_from": [
|
||||||
|
"python/ellens-alien-game"
|
||||||
|
],
|
||||||
|
"icon": "character-study",
|
||||||
|
"blurb": "Learn about classes by creating an Alien for Ellen's game."
|
||||||
|
}
|
1
cpp/ellens-alien-game/.exercism/metadata.json
Normal file
1
cpp/ellens-alien-game/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"track":"cpp","exercise":"ellens-alien-game","id":"53ad73b3621b439286b870cd4047b0a8","url":"https://exercism.org/tracks/cpp/exercises/ellens-alien-game","handle":"Chomp1295","is_requester":true,"auto_approve":false}
|
66
cpp/ellens-alien-game/CMakeLists.txt
Normal file
66
cpp/ellens-alien-game/CMakeLists.txt
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
# Basic CMake project
|
||||||
|
cmake_minimum_required(VERSION 3.5.1)
|
||||||
|
|
||||||
|
# Get the exercise name from the current directory
|
||||||
|
get_filename_component(exercise ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
|
||||||
|
# Name the project after the exercise
|
||||||
|
project(${exercise} CXX)
|
||||||
|
|
||||||
|
# Get a source filename from the exercise name by replacing -'s with _'s
|
||||||
|
string(REPLACE "-" "_" file ${exercise})
|
||||||
|
|
||||||
|
# Implementation could be only a header
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.cpp)
|
||||||
|
set(exercise_cpp ${file}.cpp)
|
||||||
|
else()
|
||||||
|
set(exercise_cpp "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Use the common Catch library?
|
||||||
|
if(EXERCISM_COMMON_CATCH)
|
||||||
|
# For Exercism track development only
|
||||||
|
add_executable(${exercise} ${file}_test.cpp $<TARGET_OBJECTS:catchlib>)
|
||||||
|
elseif(EXERCISM_TEST_SUITE)
|
||||||
|
# The Exercism test suite is being run, the Docker image already
|
||||||
|
# includes a pre-built version of Catch.
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
add_executable(${exercise} ${file}_test.cpp)
|
||||||
|
target_link_libraries(${exercise} PRIVATE Catch2::Catch2WithMain)
|
||||||
|
# When Catch is installed system wide we need to include a different
|
||||||
|
# header, we need this define to use the correct one.
|
||||||
|
target_compile_definitions(${exercise} PRIVATE EXERCISM_TEST_SUITE)
|
||||||
|
else()
|
||||||
|
# Build executable from sources and headers
|
||||||
|
add_executable(${exercise} ${file}_test.cpp test/tests-main.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
CXX_STANDARD 17
|
||||||
|
CXX_STANDARD_REQUIRED OFF
|
||||||
|
CXX_EXTENSIONS OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
|
||||||
|
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(GNU|Clang)")
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
# added "-Wno-unused-parameter" to remove compiler warnings
|
||||||
|
# should make it easier for students to run their first real code
|
||||||
|
COMPILE_FLAGS "-Wall -Wextra -Wpedantic -Werror -Wno-unused-parameter"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Configure to run all the tests?
|
||||||
|
if(${EXERCISM_RUN_ALL_TESTS})
|
||||||
|
target_compile_definitions(${exercise} PRIVATE EXERCISM_RUN_ALL_TESTS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Tell MSVC not to warn us about unchecked iterators in debug builds
|
||||||
|
if(${MSVC})
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Run the tests on every build
|
||||||
|
add_custom_target(test_${exercise} ALL DEPENDS ${exercise} COMMAND ${exercise})
|
61
cpp/ellens-alien-game/HELP.md
Normal file
61
cpp/ellens-alien-game/HELP.md
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
Running the tests involves running `cmake -G` and then using the build command appropriate for your platform.
|
||||||
|
Detailed instructions on how to do this can be found on the [Running the Tests][cpp-tests-instructions] page for C++ on exercism.org.
|
||||||
|
|
||||||
|
## Passing the Tests
|
||||||
|
|
||||||
|
When you start a new exercise locally, the files are configured so that only the first test is performed.
|
||||||
|
Get that first test compiling, linking and passing by following the [three rules of test-driven development][three-laws-of-tdd].
|
||||||
|
Create just enough structure by declaring namespaces, functions, classes, etc., to satisfy any compiler errors and get the test to fail.
|
||||||
|
Then write just enough code to get the test to pass.
|
||||||
|
Once you've done that, uncomment the next test by moving the line `if defined(EXERCISM_RUN_ALL_TESTS)` past the next test.
|
||||||
|
|
||||||
|
See the example below from the Bob exercise (file `bob_test.cpp`, line 15):
|
||||||
|
|
||||||
|
```diff
|
||||||
|
-#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
TEST_CASE("shouting")
|
||||||
|
{
|
||||||
|
REQUIRE("Whoa, chill out!" == bob::hey("WATCH OUT!"));
|
||||||
|
}
|
||||||
|
+#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
```
|
||||||
|
|
||||||
|
Moving this line past the next test may result in compile errors as new constructs may be invoked that you haven't yet declared or defined.
|
||||||
|
Again, fix the compile errors minimally to get a failing test, then change the code minimally to pass the test, refactor your implementation for readability and expressiveness and then go on to the next test.
|
||||||
|
|
||||||
|
Try to use standard C++17 facilities in preference to writing your own low-level algorithms or facilities by hand.
|
||||||
|
|
||||||
|
[cpp-tests-instructions]: https://exercism.org/docs/tracks/cpp/tests
|
||||||
|
[three-laws-of-tdd]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit ellens_alien_game.cpp` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [C++ track's documentation](https://exercism.org/docs/tracks/cpp)
|
||||||
|
- The [C++ track's programming category on the forum](https://forum.exercism.org/c/programming/cpp)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
To get help if you're having trouble, you can use one of the following resources:
|
||||||
|
|
||||||
|
- [`c++-faq` tag on StackOverflow](https://stackoverflow.com/tags/c%2b%2b-faq/info)
|
||||||
|
- [C++ FAQ from isocpp.com](https://isocpp.org/faq)
|
||||||
|
- [CppReference](http://en.cppreference.com/) is a wiki reference to the C++ language and standard library
|
||||||
|
- [C traps and pitfalls](http://www.slideshare.net/LegalizeAdulthood/c-traps-and-pitfalls-for-c-programmers) is useful if you are new to C++, but have programmed in C
|
22
cpp/ellens-alien-game/HINTS.md
Normal file
22
cpp/ellens-alien-game/HINTS.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Hints
|
||||||
|
|
||||||
|
## 1. Create the `Alien` Class
|
||||||
|
|
||||||
|
- The `constructor` does not have a return type and has the same name as the `class`.
|
||||||
|
- A common convention for `classes` is using names in __PascalCase__.
|
||||||
|
|
||||||
|
## 2. The `hit` Function
|
||||||
|
|
||||||
|
- Remember the invariant: health points can't be negative.
|
||||||
|
|
||||||
|
## 3. The `is_alive` Function
|
||||||
|
|
||||||
|
- life points at `0` is the only 'dead' condition.
|
||||||
|
|
||||||
|
## 4. The `teleport` Function
|
||||||
|
|
||||||
|
- Member variables can be updated by any function of the class.
|
||||||
|
|
||||||
|
## 5. The `collision_detection` Function
|
||||||
|
|
||||||
|
- All `public` member variables can be accessed from outside the class.
|
217
cpp/ellens-alien-game/README.md
Normal file
217
cpp/ellens-alien-game/README.md
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
# Ellen's Alien Game
|
||||||
|
|
||||||
|
Welcome to Ellen's Alien Game on Exercism's C++ Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
## Classes
|
||||||
|
|
||||||
|
It is time to get to one of the core paradigms of C++: object-oriented programming (OOP).
|
||||||
|
OOP is centered around `classes` - user-defined types of data with their own set of related functions.
|
||||||
|
We will start with the basics and will cover more advanced topics further down the syllabus tree.
|
||||||
|
|
||||||
|
### Members
|
||||||
|
|
||||||
|
Classes can have **member variables** and **member functions**.
|
||||||
|
They are accessed by the **member selection** operator `.`.
|
||||||
|
Just as variables outside of `classes`, it is advisable to initialize member variables with a value upon declaration.
|
||||||
|
This value will then become the default for newly created objects of this class.
|
||||||
|
|
||||||
|
### Encapsulation and Information Hiding
|
||||||
|
|
||||||
|
Classes offer the option to restrict access to their members.
|
||||||
|
The two basic `access specifiers` are `private` and `public`.
|
||||||
|
`private` members are not accessible from outside the class.
|
||||||
|
`public` members can be accessed freely.
|
||||||
|
All members of a `class` are `private` by default.
|
||||||
|
Only members explicitly marked with `public` are freely usable outside of the class.
|
||||||
|
|
||||||
|
### Basic example
|
||||||
|
|
||||||
|
The definition of a `class` can be seen in the following example.
|
||||||
|
Notice the `;` after the definition:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Wizard {
|
||||||
|
public: // from here on all members are publicly accessible
|
||||||
|
int cast_spell() { // defines the public member function cast_spell
|
||||||
|
return damage;
|
||||||
|
}
|
||||||
|
std::string name{}; // defines the public member variable `name`
|
||||||
|
private: // from here on all members are private
|
||||||
|
int damage{5}; // defines the private member variable `damage`
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
You can access all member variables from within the class.
|
||||||
|
Take a look at `damage` inside the `cast_spell` function.
|
||||||
|
You cannot read or change `private` members outside of the class:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Wizard silverhand{};
|
||||||
|
// calling the `cast_spell` function is okay, it is public:
|
||||||
|
silverhand.cast_spell();
|
||||||
|
// => 5
|
||||||
|
|
||||||
|
// name is public and can be changed:
|
||||||
|
silverhand.name = "Laeral";
|
||||||
|
|
||||||
|
// damage is private:
|
||||||
|
silverhand.damage = 500;
|
||||||
|
// => Compilation error
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constructors
|
||||||
|
|
||||||
|
Constructors offer the possibility to assign values to member variables at object creation.
|
||||||
|
They have the same name as the `class` and do not have a return type.
|
||||||
|
A class can have several constructors.
|
||||||
|
This is useful if you do not always have a need to set all variables.
|
||||||
|
Sometimes you might want to keep everything at default but change the `name` variable.
|
||||||
|
In the case of a significant Wizard you might want to change the damage as well, so you need two `constructors`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Wizard {
|
||||||
|
public:
|
||||||
|
Wizard(std::string new_name) {
|
||||||
|
name = new_name;
|
||||||
|
}
|
||||||
|
Wizard(std::string new_name, int new_damage) {
|
||||||
|
name = new_name;
|
||||||
|
damage = new_damage;
|
||||||
|
}
|
||||||
|
int cast_spell() {
|
||||||
|
return damage;
|
||||||
|
}
|
||||||
|
std::string name{};
|
||||||
|
private:
|
||||||
|
int damage{5};
|
||||||
|
};
|
||||||
|
|
||||||
|
Wizard el{"Eleven"}; // deals 5 damage
|
||||||
|
Wizard vecna{"Vecna", 50}; // deals 50 damage
|
||||||
|
```
|
||||||
|
|
||||||
|
Constructors are a big topic and have many nuances.
|
||||||
|
If you are not explicitly defining a `constructor` for your `class`, then - and only then - the compiler will do the job for you.
|
||||||
|
This has happened in the first example above.
|
||||||
|
The _silverhand_ object is created by calling the default constructor, no arguments were passed.
|
||||||
|
All variables are set to the value that was stated in the definition of the class.
|
||||||
|
If you had not given any values in that definition, the variables might be uninitialized, which might have unintended consequences.
|
||||||
|
|
||||||
|
~~~~exercism/note
|
||||||
|
## Structs
|
||||||
|
|
||||||
|
Structs came from the language's original C roots and are as old as C++ itself.
|
||||||
|
They are effectively the same thing as `classes` with one important exception.
|
||||||
|
By default, everything in a `class` is `private`.
|
||||||
|
Structs, on the other hand, are `public` until defined otherwise.
|
||||||
|
Conventionally, the `struct` keyword is often used for **data-only structures**.
|
||||||
|
The `class` keyword is preferred for objects that need to ensure certain properties.
|
||||||
|
Such an invariant could be that the `damage` of your `Wizard` `class` cannot turn negative.
|
||||||
|
The `damage` variable is private and any function that changes the damage would ensure the invariant is preserved.
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
Ellen is making a game where the player has to fight aliens.
|
||||||
|
She has just learned about Object Oriented Programming (OOP) and is eager to take advantage of what using `classes` could offer her program.
|
||||||
|
|
||||||
|
To Ellen's delight, you have offered to help and she has given you the task of programming the aliens that the player has to fight.
|
||||||
|
|
||||||
|
|
||||||
|
## 1. Create the `Alien` Class
|
||||||
|
|
||||||
|
Define the `Alien` class with a constructor that accepts two `int` parameters `x` and `y`, putting them into `x_coordinate` and `y_coordinate` member variables.
|
||||||
|
Every alien will also start off with a health level of `3`, so the `health` member variable should be initialized as well.
|
||||||
|
|
||||||
|
`health` should be a private member variable.
|
||||||
|
To let other parts of the program read the health information, Ellen wants to have a `public` `get_health()` method which returns an `int`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Alien alien{2, 0};
|
||||||
|
alien.x_coordinate;
|
||||||
|
// => 2
|
||||||
|
alien.y_coordinate;
|
||||||
|
// => 0
|
||||||
|
alien.get_health();
|
||||||
|
// => 3
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, each alien should be able to internally track its own position and health.
|
||||||
|
|
||||||
|
## 2. The `hit` Function
|
||||||
|
|
||||||
|
Ellen would like the Alien `class` to have a `hit` method that decrements the health of an alien object by `1` when called.
|
||||||
|
This way, she can simply call `some_alien_instance.hit()` instead of having to manually change an alien's health.
|
||||||
|
Make sure that the health points do not drop below zero.
|
||||||
|
The function should return `true`.
|
||||||
|
Ellen wants to introduce shields at a later point, which would then report `false` if the shield is up.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Alien alien {0, 0};
|
||||||
|
alien.get_health();
|
||||||
|
// => 3 (Initial health value)
|
||||||
|
|
||||||
|
alien.hit(); // Decrements health by 1 point.
|
||||||
|
alien.get_health();
|
||||||
|
// => 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. The `is_alive` Function
|
||||||
|
|
||||||
|
You realize that if the health keeps decreasing, at some point it will probably hit `0`.
|
||||||
|
It would be a good idea to add an `is_alive` method that Ellen can quickly call to check if the alien is... well... alive. 😉
|
||||||
|
`some_alien_instance.is_alive()` should return a boolean.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
alien.get_health();
|
||||||
|
// => 1
|
||||||
|
alien.is_alive();
|
||||||
|
// => true
|
||||||
|
alien.hit();
|
||||||
|
alien.get_health();
|
||||||
|
// => 0
|
||||||
|
alien.is_alive();
|
||||||
|
// => false
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. The `teleport` Function
|
||||||
|
|
||||||
|
In Ellen's game, the aliens can teleport!
|
||||||
|
You will need to write a `teleport` method that takes `x_new` and `y_new` values, and changes the alien's coordinates accordingly.
|
||||||
|
For the time being, the function should return `true`.
|
||||||
|
Ellen wants to add teleport-blocking bombs in later levels, which would then report `false` for failed teleporting attempts.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
alien.teleport(5, -4);
|
||||||
|
alien.x_coordinate;
|
||||||
|
// => 5
|
||||||
|
alien.y_coordinate;
|
||||||
|
// => -4
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. The `collision_detection` Function
|
||||||
|
|
||||||
|
If the aliens can be hit by something, then they need to be able to detect when such a collision might occur.
|
||||||
|
Ellen needs to know if two aliens occupy the same coordinates.
|
||||||
|
The `collision_detection()` function takes another alien object as an argument and returns a `bool`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Alien lrrr {3, 6};
|
||||||
|
Alien ndnd {-2, 12};
|
||||||
|
lrrr.collision_detection(ndnd);
|
||||||
|
// => false
|
||||||
|
ndnd.teleport(3, 6);
|
||||||
|
ndnd.collision_detection(lrrr);
|
||||||
|
// => true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @vaeng
|
BIN
cpp/ellens-alien-game/build/ellens-alien-game
Executable file
BIN
cpp/ellens-alien-game/build/ellens-alien-game
Executable file
Binary file not shown.
44
cpp/ellens-alien-game/ellens_alien_game.cpp
Normal file
44
cpp/ellens-alien-game/ellens_alien_game.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
namespace targets {
|
||||||
|
class Alien {
|
||||||
|
public:
|
||||||
|
Alien(int x, int y) {
|
||||||
|
x_coordinate = x;
|
||||||
|
y_coordinate = y;
|
||||||
|
health = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_health() { return health; }
|
||||||
|
|
||||||
|
bool hit() {
|
||||||
|
if (health > 0) {
|
||||||
|
health -= 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_alive() { return health > 0; }
|
||||||
|
|
||||||
|
bool teleport(int x_new, int y_new) {
|
||||||
|
x_coordinate = x_new;
|
||||||
|
y_coordinate = y_new;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool collision_detection(Alien other_alien) {
|
||||||
|
if (x_coordinate == other_alien.x_coordinate &&
|
||||||
|
y_coordinate == other_alien.y_coordinate) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x_coordinate, y_coordinate;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int health;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace targets
|
71
cpp/ellens-alien-game/ellens_alien_game_test.cpp
Normal file
71
cpp/ellens-alien-game/ellens_alien_game_test.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "ellens_alien_game.cpp"
|
||||||
|
#ifdef EXERCISM_TEST_SUITE
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#else
|
||||||
|
#include "test/catch.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace targets;
|
||||||
|
|
||||||
|
TEST_CASE("Alien has correct initial coordinates", "[task_1]") {
|
||||||
|
Alien alien{2, -1};
|
||||||
|
REQUIRE(alien.x_coordinate == 2);
|
||||||
|
REQUIRE(alien.y_coordinate == -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Alien has correct initial health", "[task_1]") {
|
||||||
|
Alien alien{22, 0};
|
||||||
|
REQUIRE(alien.get_health() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("New alien does not share old aliens position", "[task_1]") {
|
||||||
|
Alien alien1{22, 0};
|
||||||
|
Alien alien2{0, 22};
|
||||||
|
REQUIRE(alien1.x_coordinate != alien2.x_coordinate);
|
||||||
|
REQUIRE(alien1.y_coordinate != alien2.y_coordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Alien is always hit", "[task_2]") {
|
||||||
|
Alien alien{6, 7};
|
||||||
|
REQUIRE(alien.hit());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE(
|
||||||
|
"Alien is alive while health is greater than 0 and stays dead afterwards",
|
||||||
|
"[task_3]") {
|
||||||
|
Alien alien{2, 54};
|
||||||
|
REQUIRE(alien.is_alive());
|
||||||
|
alien.hit();
|
||||||
|
REQUIRE(alien.is_alive());
|
||||||
|
alien.hit();
|
||||||
|
REQUIRE(alien.is_alive());
|
||||||
|
alien.hit();
|
||||||
|
REQUIRE(!alien.is_alive());
|
||||||
|
alien.hit();
|
||||||
|
REQUIRE(!alien.is_alive());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Alien Teleports reports succesful", "[task_4]") {
|
||||||
|
Alien alien{22, 1};
|
||||||
|
REQUIRE(alien.teleport(99, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Alien Teleports where it should", "[task_4]") {
|
||||||
|
Alien alien{2, -54};
|
||||||
|
REQUIRE(alien.x_coordinate == 2);
|
||||||
|
REQUIRE(alien.y_coordinate == -54);
|
||||||
|
alien.teleport(99, 8);
|
||||||
|
REQUIRE(alien.x_coordinate == 99);
|
||||||
|
REQUIRE(alien.y_coordinate == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Alien collision detection with other aliens", "[task_5]") {
|
||||||
|
Alien alien1{22, 0};
|
||||||
|
Alien alien2{0, 22};
|
||||||
|
Alien alien3{22, 0};
|
||||||
|
REQUIRE_FALSE(alien1.collision_detection(alien2));
|
||||||
|
REQUIRE(alien1.collision_detection(alien3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
#endif
|
17937
cpp/ellens-alien-game/test/catch.hpp
Normal file
17937
cpp/ellens-alien-game/test/catch.hpp
Normal file
File diff suppressed because it is too large
Load diff
2
cpp/ellens-alien-game/test/tests-main.cpp
Normal file
2
cpp/ellens-alien-game/test/tests-main.cpp
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include "catch.hpp"
|
0
cpp/freelancer-rates/freelancer-rates
Executable file → Normal file
0
cpp/freelancer-rates/freelancer-rates
Executable file → Normal file
20
cpp/interest-is-interesting/.exercism/config.json
Normal file
20
cpp/interest-is-interesting/.exercism/config.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"authors": [
|
||||||
|
"vaeng"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"interest_is_interesting.cpp"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"interest_is_interesting_test.cpp"
|
||||||
|
],
|
||||||
|
"exemplar": [
|
||||||
|
".meta/exemplar.cpp"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"forked_from": [
|
||||||
|
"go/interest-is-interesting"
|
||||||
|
],
|
||||||
|
"blurb": "Learn about loops by adding interest to savings accounts."
|
||||||
|
}
|
1
cpp/interest-is-interesting/.exercism/metadata.json
Normal file
1
cpp/interest-is-interesting/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"track":"cpp","exercise":"interest-is-interesting","id":"c756c043226a45ebb4716fa18955a809","url":"https://exercism.org/tracks/cpp/exercises/interest-is-interesting","handle":"Chomp1295","is_requester":true,"auto_approve":false}
|
66
cpp/interest-is-interesting/CMakeLists.txt
Normal file
66
cpp/interest-is-interesting/CMakeLists.txt
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
# Basic CMake project
|
||||||
|
cmake_minimum_required(VERSION 3.5.1)
|
||||||
|
|
||||||
|
# Get the exercise name from the current directory
|
||||||
|
get_filename_component(exercise ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
|
||||||
|
# Name the project after the exercise
|
||||||
|
project(${exercise} CXX)
|
||||||
|
|
||||||
|
# Get a source filename from the exercise name by replacing -'s with _'s
|
||||||
|
string(REPLACE "-" "_" file ${exercise})
|
||||||
|
|
||||||
|
# Implementation could be only a header
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.cpp)
|
||||||
|
set(exercise_cpp ${file}.cpp)
|
||||||
|
else()
|
||||||
|
set(exercise_cpp "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Use the common Catch library?
|
||||||
|
if(EXERCISM_COMMON_CATCH)
|
||||||
|
# For Exercism track development only
|
||||||
|
add_executable(${exercise} ${file}_test.cpp $<TARGET_OBJECTS:catchlib>)
|
||||||
|
elseif(EXERCISM_TEST_SUITE)
|
||||||
|
# The Exercism test suite is being run, the Docker image already
|
||||||
|
# includes a pre-built version of Catch.
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
add_executable(${exercise} ${file}_test.cpp)
|
||||||
|
target_link_libraries(${exercise} PRIVATE Catch2::Catch2WithMain)
|
||||||
|
# When Catch is installed system wide we need to include a different
|
||||||
|
# header, we need this define to use the correct one.
|
||||||
|
target_compile_definitions(${exercise} PRIVATE EXERCISM_TEST_SUITE)
|
||||||
|
else()
|
||||||
|
# Build executable from sources and headers
|
||||||
|
add_executable(${exercise} ${file}_test.cpp test/tests-main.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
CXX_STANDARD 17
|
||||||
|
CXX_STANDARD_REQUIRED OFF
|
||||||
|
CXX_EXTENSIONS OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
|
||||||
|
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(GNU|Clang)")
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
# added "-Wno-unused-parameter" to remove compiler warnings
|
||||||
|
# should make it easier for students to run their first real code
|
||||||
|
COMPILE_FLAGS "-Wall -Wextra -Wpedantic -Werror -Wno-unused-parameter"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Configure to run all the tests?
|
||||||
|
if(${EXERCISM_RUN_ALL_TESTS})
|
||||||
|
target_compile_definitions(${exercise} PRIVATE EXERCISM_RUN_ALL_TESTS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Tell MSVC not to warn us about unchecked iterators in debug builds
|
||||||
|
if(${MSVC})
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Run the tests on every build
|
||||||
|
add_custom_target(test_${exercise} ALL DEPENDS ${exercise} COMMAND ${exercise})
|
61
cpp/interest-is-interesting/HELP.md
Normal file
61
cpp/interest-is-interesting/HELP.md
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
Running the tests involves running `cmake -G` and then using the build command appropriate for your platform.
|
||||||
|
Detailed instructions on how to do this can be found on the [Running the Tests][cpp-tests-instructions] page for C++ on exercism.org.
|
||||||
|
|
||||||
|
## Passing the Tests
|
||||||
|
|
||||||
|
When you start a new exercise locally, the files are configured so that only the first test is performed.
|
||||||
|
Get that first test compiling, linking and passing by following the [three rules of test-driven development][three-laws-of-tdd].
|
||||||
|
Create just enough structure by declaring namespaces, functions, classes, etc., to satisfy any compiler errors and get the test to fail.
|
||||||
|
Then write just enough code to get the test to pass.
|
||||||
|
Once you've done that, uncomment the next test by moving the line `if defined(EXERCISM_RUN_ALL_TESTS)` past the next test.
|
||||||
|
|
||||||
|
See the example below from the Bob exercise (file `bob_test.cpp`, line 15):
|
||||||
|
|
||||||
|
```diff
|
||||||
|
-#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
TEST_CASE("shouting")
|
||||||
|
{
|
||||||
|
REQUIRE("Whoa, chill out!" == bob::hey("WATCH OUT!"));
|
||||||
|
}
|
||||||
|
+#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
```
|
||||||
|
|
||||||
|
Moving this line past the next test may result in compile errors as new constructs may be invoked that you haven't yet declared or defined.
|
||||||
|
Again, fix the compile errors minimally to get a failing test, then change the code minimally to pass the test, refactor your implementation for readability and expressiveness and then go on to the next test.
|
||||||
|
|
||||||
|
Try to use standard C++17 facilities in preference to writing your own low-level algorithms or facilities by hand.
|
||||||
|
|
||||||
|
[cpp-tests-instructions]: https://exercism.org/docs/tracks/cpp/tests
|
||||||
|
[three-laws-of-tdd]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit interest_is_interesting.cpp` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [C++ track's documentation](https://exercism.org/docs/tracks/cpp)
|
||||||
|
- The [C++ track's programming category on the forum](https://forum.exercism.org/c/programming/cpp)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
To get help if you're having trouble, you can use one of the following resources:
|
||||||
|
|
||||||
|
- [`c++-faq` tag on StackOverflow](https://stackoverflow.com/tags/c%2b%2b-faq/info)
|
||||||
|
- [C++ FAQ from isocpp.com](https://isocpp.org/faq)
|
||||||
|
- [CppReference](http://en.cppreference.com/) is a wiki reference to the C++ language and standard library
|
||||||
|
- [C traps and pitfalls](http://www.slideshare.net/LegalizeAdulthood/c-traps-and-pitfalls-for-c-programmers) is useful if you are new to C++, but have programmed in C
|
22
cpp/interest-is-interesting/HINTS.md
Normal file
22
cpp/interest-is-interesting/HINTS.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Hints
|
||||||
|
|
||||||
|
## 1. Calculate the interest rate
|
||||||
|
|
||||||
|
- You are expected to return a percentage.
|
||||||
|
|
||||||
|
## 2. Calculate the interest
|
||||||
|
|
||||||
|
- When calculating interest, it might be helpful to notice that `interest_rate` returns a percentage.
|
||||||
|
- You can use the function defined in the previous task (`interest_rate`) to calculate the interest.
|
||||||
|
|
||||||
|
## 3. Calculate the annual balance update
|
||||||
|
|
||||||
|
- When calculating the annual balance update, use the functions that have been defined in the previous steps.
|
||||||
|
|
||||||
|
## 4. Calculate the years before reaching the desired balance
|
||||||
|
|
||||||
|
- To calculate the years, one can keep looping until the desired balance is reached using a [`for`][for] loop.
|
||||||
|
- There is a special [operator][increment] to increment values by 1.
|
||||||
|
|
||||||
|
[for]: https://www.learncpp.com/cpp-tutorial/introduction-to-loops-and-while-statements/
|
||||||
|
[increment]: https://www.learncpp.com/cpp-tutorial/increment-decrement-operators-and-side-effects/
|
166
cpp/interest-is-interesting/README.md
Normal file
166
cpp/interest-is-interesting/README.md
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
# Interest is interesting
|
||||||
|
|
||||||
|
Welcome to Interest is interesting on Exercism's C++ Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
## Loops
|
||||||
|
|
||||||
|
Loops are used to repeatedly execute some logic.
|
||||||
|
The two most common types are the `while loop` (indefinite looping) and the `for loop` (definite, or counted looping).
|
||||||
|
There is also the `for each` loop, that will come up in a later concept.
|
||||||
|
|
||||||
|
### General Syntax
|
||||||
|
|
||||||
|
The `for loop` consists of a header and a code block that contains the body of the loop wrapped in curly brackets.
|
||||||
|
The header consists of 3 components separated by semicolons `;`: init-statement, condition, and another expression.
|
||||||
|
Each of these may be empty.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for (init_statement; condition; expression) {
|
||||||
|
some_statement;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- The **init_statement** component is code that runs only once before the loop starts.
|
||||||
|
- The **condition** component must be some expression that evaluates to a `boolean` and controls when the loop should stop.
|
||||||
|
The code inside the loop will run as long as this condition evaluates to `true`.
|
||||||
|
As soon as this expression evaluates to `false`, no more iterations of the loop will run.
|
||||||
|
- The **expression** component is some code that will run at the end of each iteration.
|
||||||
|
|
||||||
|
The `while loop` executes its body as long as its **condition** check is `true`.
|
||||||
|
The code snippet below shows how to transform a `for` into a `while loop`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
init_statement;
|
||||||
|
while(condition) {
|
||||||
|
some_statement;
|
||||||
|
expression;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interlude: Increments and Decrements
|
||||||
|
|
||||||
|
When working with loops it is often required to add 1 or subtract 1 from a counter variable which keeps track of the iterations.
|
||||||
|
This is so common, that the incrementing/decrementing actions have special operators: `++` and `--`.
|
||||||
|
|
||||||
|
They come in a **prefix** and a **postfix** form.
|
||||||
|
The prefix changes the variable before use in the statement and the postfix version afterward.
|
||||||
|
You probably want the prefix version most of the time.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int a{3};
|
||||||
|
int b{--a};
|
||||||
|
// b is 2, a is now 2
|
||||||
|
int c{a++};
|
||||||
|
// c is 2, a is now 3
|
||||||
|
```
|
||||||
|
|
||||||
|
### For Loops - An example
|
||||||
|
|
||||||
|
The _init component_ usually sets up a counter variable, the _condition_ checks whether the loop should be continued or stopped and the _post component_ usually increments the counter at the end of each repetition.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int sum{0};
|
||||||
|
for (int i{1}; i < 10; ++i) {
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This loop will sum the numbers from `1` to `9` (including `9`).
|
||||||
|
|
||||||
|
### Break and Continue
|
||||||
|
|
||||||
|
Inside a loop body, you can use the `break` keyword to stop the execution of the loop entirely:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int sum{2};
|
||||||
|
while(true) {
|
||||||
|
sum *= 2;
|
||||||
|
if (sum > 1000)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// sum is now 1024
|
||||||
|
```
|
||||||
|
|
||||||
|
In contrast, the keyword `continue` only stops the execution of the current iteration and continues with the next one:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int equal_sum{0};
|
||||||
|
for (int i{1}; i < 7; ++i) {
|
||||||
|
if (i%2 == 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
equal_sum += i;
|
||||||
|
}
|
||||||
|
// equal_sum is now 12
|
||||||
|
```
|
||||||
|
|
||||||
|
~~~~exercism/note
|
||||||
|
It is usually easier to understand the logic of the loop, when the use of `break` and `continue` is minimized or entirely avoided.
|
||||||
|
Both keywords skip certain sections of the code and make it often more difficult to follow along.
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
In this exercise, you'll be working with savings accounts.
|
||||||
|
Each year, the balance of your savings account is updated based on its interest rate.
|
||||||
|
The interest rate your bank gives you depends on the amount of money in your account (its balance):
|
||||||
|
|
||||||
|
- 3.213% for a balance less than `0` dollars (balance gets more negative).
|
||||||
|
- 0.5% for a balance greater than or equal to `0` dollars, and less than `1000` dollars.
|
||||||
|
- 1.621% for a balance greater than or equal to `1000` dollars, and less than `5000` dollars.
|
||||||
|
- 2.475% for a balance greater than or equal to `5000` dollars.
|
||||||
|
|
||||||
|
You have four tasks, each of which will deal with the balance and its interest rate.
|
||||||
|
|
||||||
|
## 1. Calculate the interest rate
|
||||||
|
|
||||||
|
Implement the `interest_rate` function to calculate the interest rate based on the specified balance:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
interest_rate(200.75);
|
||||||
|
// => 0.5
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Calculate the interest
|
||||||
|
|
||||||
|
Implement the `yearly_interest` function to calculate the interest based on the specified balance:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
yearly_interest(200.75):
|
||||||
|
// => 1.003750
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Calculate the annual balance update
|
||||||
|
|
||||||
|
Implement the `annual_balance_update` function to calculate the annual balance update, taking into account the interest rate:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
annual_balance_update(200.75);
|
||||||
|
// => 201.75375
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Calculate the years before reaching the desired balance
|
||||||
|
|
||||||
|
Implement the `years_until_desired_balance` function to calculate the minimum number of years required to reach the desired balance, taking into account that each year, interest is added to the balance.
|
||||||
|
This means that the balance after one year is: start balance + interest for start balance.
|
||||||
|
The balance after the second year is the balance after one year + interest for the balance after one year.
|
||||||
|
And so on, until the current year's balance is greater than or equal to the target balance.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
double balance {200.75};
|
||||||
|
double targetBalance {214.88};
|
||||||
|
years_until_desired_balance(balance, targetBalance)
|
||||||
|
// => 14
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the value returned is an `int`.
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @vaeng
|
BIN
cpp/interest-is-interesting/build/interest-is-interesting
Executable file
BIN
cpp/interest-is-interesting/build/interest-is-interesting
Executable file
Binary file not shown.
39
cpp/interest-is-interesting/interest_is_interesting.cpp
Normal file
39
cpp/interest-is-interesting/interest_is_interesting.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// interest_rate returns the interest rate for the provided balance.
|
||||||
|
double interest_rate(double balance) {
|
||||||
|
|
||||||
|
if (balance < 0) {
|
||||||
|
return 3.213;
|
||||||
|
|
||||||
|
} else if (balance >= 0 && balance < 1000) {
|
||||||
|
return 0.5;
|
||||||
|
|
||||||
|
} else if (balance >= 1000 && balance < 5000) {
|
||||||
|
return 1.621;
|
||||||
|
|
||||||
|
} else // balance >= 5000
|
||||||
|
return 2.475;
|
||||||
|
}
|
||||||
|
|
||||||
|
// yearly_interest calculates the yearly interest for the provided balance.
|
||||||
|
double yearly_interest(double balance) {
|
||||||
|
return balance * (interest_rate(balance) / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// annual_balance_update calculates the annual balance update, taking into
|
||||||
|
// account the interest rate.
|
||||||
|
double annual_balance_update(double balance) {
|
||||||
|
return yearly_interest(balance) + balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// years_until_desired_balance calculates the minimum number of years required
|
||||||
|
// to reach the desired balance.
|
||||||
|
int years_until_desired_balance(double balance, double target_balance) {
|
||||||
|
|
||||||
|
int years{0};
|
||||||
|
while (balance < target_balance) {
|
||||||
|
years++;
|
||||||
|
balance = annual_balance_update(balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return years;
|
||||||
|
}
|
224
cpp/interest-is-interesting/interest_is_interesting_test.cpp
Normal file
224
cpp/interest-is-interesting/interest_is_interesting_test.cpp
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
#include "interest_is_interesting.cpp"
|
||||||
|
#ifdef EXERCISM_TEST_SUITE
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#else
|
||||||
|
#include "test/catch.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_CASE("Minimal first interest rate", "[task_1]") {
|
||||||
|
double balance{0};
|
||||||
|
double want{0.5};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Tiny first interest rate", "[task_1]") {
|
||||||
|
double balance{0.000001};
|
||||||
|
double want{0.5};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Maximum first interest rate", "[task_1]") {
|
||||||
|
double balance{999.9999};
|
||||||
|
double want{0.5};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Minimal second interest rate", "[task_1]") {
|
||||||
|
double balance{1000.0};
|
||||||
|
double want{1.621};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Tiny second interest rate", "[task_1]") {
|
||||||
|
double balance{1000.0001};
|
||||||
|
double want{1.621};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Maximum second interest rate", "[task_1]") {
|
||||||
|
double balance{4999.9990};
|
||||||
|
double want{1.621};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Minimal third interest rate", "[task_1]") {
|
||||||
|
double balance{5000.0000};
|
||||||
|
double want{2.475};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Tiny third interest rate", "[task_1]") {
|
||||||
|
double balance{5000.0001};
|
||||||
|
double want{2.475};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Large third interest rate", "[task_1]") {
|
||||||
|
double balance{5639998.742909};
|
||||||
|
double want{2.475};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Rate on minimal negative balance", "[task_1]") {
|
||||||
|
double balance{-0.000001};
|
||||||
|
double want{3.213};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Rate on small negative balance", "[task_1]") {
|
||||||
|
double balance{-0.123};
|
||||||
|
double want{3.213};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Rate on regular negative balance", "[task_1]") {
|
||||||
|
double balance{-300.0};
|
||||||
|
double want{3.213};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Rate on large negative balance", "[task_1]") {
|
||||||
|
double balance{-152964.231};
|
||||||
|
double want{3.213};
|
||||||
|
REQUIRE_THAT(interest_rate(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Interest on negative balance", "[task_2]") {
|
||||||
|
double balance{-10000.0};
|
||||||
|
double want{-321.3};
|
||||||
|
REQUIRE_THAT(yearly_interest(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
TEST_CASE("Interest on small balance", "[task_2]") {
|
||||||
|
double balance{555.43};
|
||||||
|
double want{2.77715};
|
||||||
|
REQUIRE_THAT(yearly_interest(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
TEST_CASE("Interest on medium balance", "[task_2]") {
|
||||||
|
double balance{4999.99};
|
||||||
|
double want{81.0498379};
|
||||||
|
REQUIRE_THAT(yearly_interest(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
TEST_CASE("Interest on large balance", "[task_2]") {
|
||||||
|
double balance{34600.80};
|
||||||
|
double want{856.3698};
|
||||||
|
REQUIRE_THAT(yearly_interest(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Annual balance update for empty start balance", "[task_3]") {
|
||||||
|
double balance{0.0};
|
||||||
|
double want{0.0000};
|
||||||
|
REQUIRE_THAT(annual_balance_update(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Annual balance update for small positive start balance",
|
||||||
|
"[task_3]") {
|
||||||
|
double balance{0.000001};
|
||||||
|
double want{0.000001005};
|
||||||
|
REQUIRE_THAT(annual_balance_update(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Annual balance update for average positive start balance",
|
||||||
|
"[task_3]") {
|
||||||
|
double balance{1000.0};
|
||||||
|
double want{1016.210000};
|
||||||
|
REQUIRE_THAT(annual_balance_update(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Annual balance update for large positive start balance",
|
||||||
|
"[task_3]") {
|
||||||
|
double balance{1000.2001};
|
||||||
|
double want{1016.413343621};
|
||||||
|
REQUIRE_THAT(annual_balance_update(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Annual balance update for huge positive start balance", "[task_3]") {
|
||||||
|
double balance{898124017.826243404425};
|
||||||
|
double want{920352587.2674429417};
|
||||||
|
REQUIRE_THAT(annual_balance_update(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Annual balance update for small negative start balance",
|
||||||
|
"[task_3]") {
|
||||||
|
double balance{-0.123};
|
||||||
|
double want{-0.12695199};
|
||||||
|
REQUIRE_THAT(annual_balance_update(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Annual balance update for large negative start balance",
|
||||||
|
"[task_3]") {
|
||||||
|
double balance{-152964.231};
|
||||||
|
double want{-157878.97174203};
|
||||||
|
REQUIRE_THAT(annual_balance_update(balance),
|
||||||
|
Catch::Matchers::WithinRel(want, 0.000001));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Years before desired balance for small start balance", "[task_4]") {
|
||||||
|
double balance{100.0};
|
||||||
|
double target_balance{125.80};
|
||||||
|
int want{47};
|
||||||
|
REQUIRE(years_until_desired_balance(balance, target_balance) == want);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Years before desired balance for average start balance",
|
||||||
|
"[task_4]") {
|
||||||
|
double balance{1000.0};
|
||||||
|
double target_balance{1100.0};
|
||||||
|
int want{6};
|
||||||
|
REQUIRE(years_until_desired_balance(balance, target_balance) == want);
|
||||||
|
}
|
||||||
|
TEST_CASE("Years before desired balance for large start balance", "[task_4]") {
|
||||||
|
double balance{8080.80};
|
||||||
|
double target_balance{9090.90};
|
||||||
|
int want{5};
|
||||||
|
REQUIRE(years_until_desired_balance(balance, target_balance) == want);
|
||||||
|
}
|
||||||
|
TEST_CASE("Years before large difference between start and target balance",
|
||||||
|
"[task_4]") {
|
||||||
|
double balance{2345.67};
|
||||||
|
double target_balance{12345.6789};
|
||||||
|
int want{85};
|
||||||
|
REQUIRE(years_until_desired_balance(balance, target_balance) == want);
|
||||||
|
}
|
||||||
|
TEST_CASE("Balance is already above target", "[task_4]") {
|
||||||
|
double balance{2345.67};
|
||||||
|
double target_balance{2345.0};
|
||||||
|
int want{0};
|
||||||
|
REQUIRE(years_until_desired_balance(balance, target_balance) == want);
|
||||||
|
}
|
||||||
|
TEST_CASE("Balance is exactly same as target", "[task_4]") {
|
||||||
|
double balance{2345.0};
|
||||||
|
double target_balance{2345.0};
|
||||||
|
int want{0};
|
||||||
|
REQUIRE(years_until_desired_balance(balance, target_balance) == want);
|
||||||
|
}
|
||||||
|
TEST_CASE("Result balance would be exactly same as target", "[task_4]") {
|
||||||
|
double balance{1000.0};
|
||||||
|
double target_balance{1032.6827641};
|
||||||
|
int want{2};
|
||||||
|
REQUIRE(years_until_desired_balance(balance, target_balance) == want);
|
||||||
|
}
|
||||||
|
#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
#endif
|
17937
cpp/interest-is-interesting/test/catch.hpp
Normal file
17937
cpp/interest-is-interesting/test/catch.hpp
Normal file
File diff suppressed because it is too large
Load diff
2
cpp/interest-is-interesting/test/tests-main.cpp
Normal file
2
cpp/interest-is-interesting/test/tests-main.cpp
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include "catch.hpp"
|
0
cpp/pacman-rules/pacman-rules
Executable file → Normal file
0
cpp/pacman-rules/pacman-rules
Executable file → Normal file
25
cpp/vehicle-purchase/.exercism/config.json
Normal file
25
cpp/vehicle-purchase/.exercism/config.json
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"authors": [
|
||||||
|
"vaeng"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"vehicle_purchase.cpp"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"vehicle_purchase_test.cpp"
|
||||||
|
],
|
||||||
|
"exemplar": [
|
||||||
|
".meta/exemplar.cpp",
|
||||||
|
".meta/exemplar.h"
|
||||||
|
],
|
||||||
|
"editor": [
|
||||||
|
"vehicle_purchase.h"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"forked_from": [
|
||||||
|
"go/vehicle-purchase"
|
||||||
|
],
|
||||||
|
"icon": "vehicle-purchase",
|
||||||
|
"blurb": "Learn about comparisons and if-statements while preparing for your next vehicle purchase"
|
||||||
|
}
|
1
cpp/vehicle-purchase/.exercism/metadata.json
Normal file
1
cpp/vehicle-purchase/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"track":"cpp","exercise":"vehicle-purchase","id":"9b089e5b8358468caab02bef9d497b13","url":"https://exercism.org/tracks/cpp/exercises/vehicle-purchase","handle":"Chomp1295","is_requester":true,"auto_approve":false}
|
70
cpp/vehicle-purchase/CMakeLists.txt
Normal file
70
cpp/vehicle-purchase/CMakeLists.txt
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# Get the exercise name from the current directory
|
||||||
|
get_filename_component(exercise ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
|
||||||
|
# Basic CMake project
|
||||||
|
cmake_minimum_required(VERSION 3.5.1)
|
||||||
|
|
||||||
|
# Name the project after the exercise
|
||||||
|
project(${exercise} CXX)
|
||||||
|
|
||||||
|
# Get a source filename from the exercise name by replacing -'s with _'s
|
||||||
|
string(REPLACE "-" "_" file ${exercise})
|
||||||
|
|
||||||
|
# Implementation could be only a header
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.cpp)
|
||||||
|
set(exercise_cpp ${file}.cpp)
|
||||||
|
else()
|
||||||
|
set(exercise_cpp "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Downloads Catch library used for testing
|
||||||
|
set(CATCH_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/test/catch.hpp")
|
||||||
|
set(CATCH_DOWNLOAD_URL "https://github.com/catchorg/Catch2/releases/download/v2.11.3/catch.hpp")
|
||||||
|
if (NOT EXISTS "${CATCH_HEADER}")
|
||||||
|
file(DOWNLOAD "${CATCH_DOWNLOAD_URL}" "${CATCH_HEADER}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Use the common Catch library?
|
||||||
|
if(EXERCISM_COMMON_CATCH)
|
||||||
|
# For Exercism track development only
|
||||||
|
add_executable(${exercise} ${file}_test.cpp ${exercise_cpp} ${file}.h $<TARGET_OBJECTS:catchlib>)
|
||||||
|
elseif(EXERCISM_TEST_SUITE)
|
||||||
|
# The Exercism test suite is being run, the Docker image already
|
||||||
|
# includes a pre-built version of Catch.
|
||||||
|
find_package(Catch2 REQUIRED)
|
||||||
|
add_executable(${exercise} ${file}_test.cpp ${exercise_cpp} ${file}.h)
|
||||||
|
target_link_libraries(${exercise} PRIVATE Catch2::Catch2WithMain)
|
||||||
|
# When Catch is installed system wide we need to include a different
|
||||||
|
# header, we need this define to use the correct one.
|
||||||
|
target_compile_definitions(${exercise} PRIVATE EXERCISM_TEST_SUITE)
|
||||||
|
else()
|
||||||
|
# Build executable from sources and headers
|
||||||
|
add_executable(${exercise} ${file}_test.cpp ${exercise_cpp} ${file}.h test/tests-main.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
CXX_STANDARD 17
|
||||||
|
CXX_STANDARD_REQUIRED OFF
|
||||||
|
CXX_EXTENSIONS OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(GNU|Clang)")
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
COMPILE_FLAGS "-Wall -Wextra -Wpedantic -Werror"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Configure to run all the tests?
|
||||||
|
if(${EXERCISM_RUN_ALL_TESTS})
|
||||||
|
target_compile_definitions(${exercise} PRIVATE EXERCISM_RUN_ALL_TESTS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Tell MSVC not to warn us about unchecked iterators in debug builds
|
||||||
|
if(${MSVC})
|
||||||
|
set_target_properties(${exercise} PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Run the tests on every build
|
||||||
|
add_custom_target(test_${exercise} ALL DEPENDS ${exercise} COMMAND ${exercise})
|
||||||
|
|
61
cpp/vehicle-purchase/HELP.md
Normal file
61
cpp/vehicle-purchase/HELP.md
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
Running the tests involves running `cmake -G` and then using the build command appropriate for your platform.
|
||||||
|
Detailed instructions on how to do this can be found on the [Running the Tests][cpp-tests-instructions] page for C++ on exercism.org.
|
||||||
|
|
||||||
|
## Passing the Tests
|
||||||
|
|
||||||
|
When you start a new exercise locally, the files are configured so that only the first test is performed.
|
||||||
|
Get that first test compiling, linking and passing by following the [three rules of test-driven development][three-laws-of-tdd].
|
||||||
|
Create just enough structure by declaring namespaces, functions, classes, etc., to satisfy any compiler errors and get the test to fail.
|
||||||
|
Then write just enough code to get the test to pass.
|
||||||
|
Once you've done that, uncomment the next test by moving the line `if defined(EXERCISM_RUN_ALL_TESTS)` past the next test.
|
||||||
|
|
||||||
|
See the example below from the Bob exercise (file `bob_test.cpp`, line 15):
|
||||||
|
|
||||||
|
```diff
|
||||||
|
-#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
TEST_CASE("shouting")
|
||||||
|
{
|
||||||
|
REQUIRE("Whoa, chill out!" == bob::hey("WATCH OUT!"));
|
||||||
|
}
|
||||||
|
+#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
```
|
||||||
|
|
||||||
|
Moving this line past the next test may result in compile errors as new constructs may be invoked that you haven't yet declared or defined.
|
||||||
|
Again, fix the compile errors minimally to get a failing test, then change the code minimally to pass the test, refactor your implementation for readability and expressiveness and then go on to the next test.
|
||||||
|
|
||||||
|
Try to use standard C++17 facilities in preference to writing your own low-level algorithms or facilities by hand.
|
||||||
|
|
||||||
|
[cpp-tests-instructions]: https://exercism.org/docs/tracks/cpp/tests
|
||||||
|
[three-laws-of-tdd]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit vehicle_purchase.cpp` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [C++ track's documentation](https://exercism.org/docs/tracks/cpp)
|
||||||
|
- The [C++ track's programming category on the forum](https://forum.exercism.org/c/programming/cpp)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
To get help if you're having trouble, you can use one of the following resources:
|
||||||
|
|
||||||
|
- [`c++-faq` tag on StackOverflow](https://stackoverflow.com/tags/c%2b%2b-faq/info)
|
||||||
|
- [C++ FAQ from isocpp.com](https://isocpp.org/faq)
|
||||||
|
- [CppReference](http://en.cppreference.com/) is a wiki reference to the C++ language and standard library
|
||||||
|
- [C traps and pitfalls](http://www.slideshare.net/LegalizeAdulthood/c-traps-and-pitfalls-for-c-programmers) is useful if you are new to C++, but have programmed in C
|
25
cpp/vehicle-purchase/HINTS.md
Normal file
25
cpp/vehicle-purchase/HINTS.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Hints
|
||||||
|
|
||||||
|
## 1. Determine if you will need a driver's license
|
||||||
|
|
||||||
|
- Use the [equals comparison operator][comparison-operators] to check whether your input equals a certain string.
|
||||||
|
- Use one of the two [logical operators][logical-operators] you learned about in the boolean concept to combine the two requirements.
|
||||||
|
- You do **not** need an if-statement to solve this task. You can return the boolean expression you build directly.
|
||||||
|
|
||||||
|
## 2. Choose between two potential vehicles to buy
|
||||||
|
|
||||||
|
- Use a [comparison operator][comparison-operators] to determine which option comes first in lexicographical order.
|
||||||
|
- Then set the value of a helper variable depending of the outcome of that comparison with the help of an an [if-else statement][if-statement].
|
||||||
|
- Finally construct the recommendation sentence.
|
||||||
|
For that you can use the `+` operator to concatenate the two strings.
|
||||||
|
|
||||||
|
## 3. Calculate an estimation for the price of a used vehicle
|
||||||
|
|
||||||
|
- Start with determining the percentage of the original price based on the age of the vehicle.
|
||||||
|
Save it in a helper variable. Use an [if-else if-else statement][if-statement] as mentioned in the instructions.
|
||||||
|
- In the two if conditions use [comparison operators][comparison-operators] to compare the age of the car to the threshold values.
|
||||||
|
- To calculate the result, apply the percentage to the original price. For example `30% of x` can be calculated by dividing `30` by `100` and multiplying with `x`.
|
||||||
|
|
||||||
|
[comparison-operators]: https://golang.org/ref/spec#Comparison_operators
|
||||||
|
[logical-operators]: https://golang.org/ref/spec#Logical_operators
|
||||||
|
[if-statement]: https://golang.org/ref/spec#If_statements
|
168
cpp/vehicle-purchase/README.md
Normal file
168
cpp/vehicle-purchase/README.md
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
# Vehicle Purchase
|
||||||
|
|
||||||
|
Welcome to Vehicle Purchase on Exercism's C++ Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
## Comparisons
|
||||||
|
|
||||||
|
In C++, you can compare values using the comparison operators.
|
||||||
|
|
||||||
|
| Comparison | Operator |
|
||||||
|
| ------------------| --------- |
|
||||||
|
| equal | `==` |
|
||||||
|
| not equal | `!=` |
|
||||||
|
| less | `<` |
|
||||||
|
| less or equal | `<=` |
|
||||||
|
| greater | `>` |
|
||||||
|
| greater or equal | `>=` |
|
||||||
|
|
||||||
|
The result of these comparisons is always a boolean value:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int a{3};
|
||||||
|
|
||||||
|
bool eq1 = a != 4; // true
|
||||||
|
|
||||||
|
bool eq2 = a > 5; // false
|
||||||
|
```
|
||||||
|
|
||||||
|
The operators `==` and `!=` check whether a value is equal to another or not, respectively.
|
||||||
|
Here are some common examples:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool eq3 = 2 == 3; // false, integer comparison
|
||||||
|
|
||||||
|
bool eq4 = 2.1 != 2.2; // true, float comparison
|
||||||
|
|
||||||
|
bool eq5 = "hello" == "hello"; // true, string comparison
|
||||||
|
```
|
||||||
|
|
||||||
|
The other operators check if one value is greater than (`>`), greater or equal to (`>=`), less than (`<`), and less or equal to (`<=`) to another value.
|
||||||
|
This kind of comparison is available for numbers and strings.
|
||||||
|
When comparing strings, the dictionary order (also known as lexicographic order) is followed.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool eq6 = 2 > 3; // false, integer comparison
|
||||||
|
|
||||||
|
bool eq7 = 1.2 < 1.3; // true, float comparison
|
||||||
|
|
||||||
|
bool eq8 = "Hello" < "World"; // true, string comparison
|
||||||
|
```
|
||||||
|
|
||||||
|
## If Statements
|
||||||
|
|
||||||
|
Conditionals in C++ are similar to conditionals in other languages.
|
||||||
|
The underlying type of any conditional operation is the `bool` type, which can have the value of `true` or `false`.
|
||||||
|
Conditionals are often used as flow control mechanisms to check for various conditions.
|
||||||
|
|
||||||
|
An `if` statement can be used, which executes its code if the underlying condition is `true` like this:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::string value{"val"};
|
||||||
|
|
||||||
|
if (value == "val") {
|
||||||
|
return "was val";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In scenarios involving more than one case many `if` statements can be chained together using the `else if` and `else` statements.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int number{33};
|
||||||
|
|
||||||
|
if (number > 0) {
|
||||||
|
return "positive";
|
||||||
|
} else if (number < 0) {
|
||||||
|
return "negative";
|
||||||
|
} else {
|
||||||
|
return "zero";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Since C++17 if-statements can also include a short initialization statement that can be used to initialize one or more variables for the if statement.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int num{7};
|
||||||
|
if (int v{2 * num}; v > 10) {
|
||||||
|
return v;
|
||||||
|
} else {
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
// => 14
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: any variables created in the initialization cannot be accessed after the end of the if statement.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
In this exercise, you are going to write some code to help you prepare to buy a vehicle.
|
||||||
|
|
||||||
|
You have three tasks, one to determine if you need a license, one to help you choose between two vehicles, and one to estimate the acceptable price for a used vehicle.
|
||||||
|
|
||||||
|
## 1. Determine if you will need a driver's license
|
||||||
|
|
||||||
|
Some vehicle kinds require a driver's license to operate them.
|
||||||
|
Assume only the kinds `"car"` and `"truck"` require a license, everything else can be operated without a license.
|
||||||
|
|
||||||
|
Implement the `needs_license(kind)` function that takes the kind of vehicle as a string and returns a boolean indicating whether you need a license for that kind of vehicle.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
needs_license("car")
|
||||||
|
// => true
|
||||||
|
|
||||||
|
needs_license("bike")
|
||||||
|
// => false
|
||||||
|
|
||||||
|
needs_license("truck")
|
||||||
|
// => true
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Choose between two potential vehicles to buy
|
||||||
|
|
||||||
|
You evaluate your options of available vehicles.
|
||||||
|
You manage to narrow it down to two options but you need help making the final decision.
|
||||||
|
For that, implement the function `choose_vehicle(option1, option2)` that takes two vehicles as arguments and returns a decision that includes the option that comes first in lexicographical order.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
choose_vehicle("Wuling Hongguang", "Toyota Corolla")
|
||||||
|
// => "Toyota Corolla is clearly the better choice."
|
||||||
|
|
||||||
|
choose_vehicle("Volkswagen Beetle", "Volkswagen Golf")
|
||||||
|
// => "Volkswagen Beetle is clearly the better choice."
|
||||||
|
```
|
||||||
|
|
||||||
|
The returned string should follow the pattern of "<CHOSEN_VEHICLE> is clearly the better choice.", where `<CHOSEN_VEHICLE>` is the option of choice from the passed arguments.
|
||||||
|
|
||||||
|
## 3. Calculate an estimation for the price of a used vehicle
|
||||||
|
|
||||||
|
Now that you made a decision, you want to make sure you get a fair price at the dealership.
|
||||||
|
Since you are interested in buying a used vehicle, the price depends on how old the vehicle is.
|
||||||
|
For a rough estimate, assume if the vehicle is less than 3 years old, it costs 80% of the original price it had when it was brand new.
|
||||||
|
If it is at least 10 years old, it costs 50%.
|
||||||
|
If the vehicle is at least 3 years old but less than 10 years, it costs 70% of the original price.
|
||||||
|
|
||||||
|
Implement the `calculate_resell_price(original_price, age)` function that applies this logic using `if`, `else if` and `else` (there are other ways if you want to practice).
|
||||||
|
It takes the original price and the age of the vehicle as arguments and returns the estimated price in the dealership.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
calculate_resell_price(1000, 1)
|
||||||
|
// => 800
|
||||||
|
|
||||||
|
calculate_resell_price(1000, 5)
|
||||||
|
// => 700
|
||||||
|
|
||||||
|
calculate_resell_price(1000.0, 15)
|
||||||
|
// => 500
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: the return value is of type `double`.
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @vaeng
|
BIN
cpp/vehicle-purchase/build/vehicle-purchase
Executable file
BIN
cpp/vehicle-purchase/build/vehicle-purchase
Executable file
Binary file not shown.
17937
cpp/vehicle-purchase/test/catch.hpp
Normal file
17937
cpp/vehicle-purchase/test/catch.hpp
Normal file
File diff suppressed because it is too large
Load diff
2
cpp/vehicle-purchase/test/tests-main.cpp
Normal file
2
cpp/vehicle-purchase/test/tests-main.cpp
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include "catch.hpp"
|
35
cpp/vehicle-purchase/vehicle_purchase.cpp
Normal file
35
cpp/vehicle-purchase/vehicle_purchase.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include "vehicle_purchase.h"
|
||||||
|
#include <cctype>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace vehicle_purchase {
|
||||||
|
|
||||||
|
// needs_license determines whether a license is needed to drive a type of
|
||||||
|
// vehicle. Only "car" and "truck" require a license.
|
||||||
|
bool needs_license(std::string kind) {
|
||||||
|
return (kind == "car") || (kind == "truck");
|
||||||
|
}
|
||||||
|
|
||||||
|
// choose_vehicle recommends a vehicle for selection. It always recommends the
|
||||||
|
// vehicle that comes first in lexicographical order.
|
||||||
|
std::string choose_vehicle(std::string option1, std::string option2) {
|
||||||
|
std::string suffix{" is clearly the better choice."};
|
||||||
|
return (option1 > option2) ? option2 + suffix : option1 + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate_resell_price calculates how much a vehicle can resell for at a
|
||||||
|
// certain age.
|
||||||
|
double calculate_resell_price(double original_price, double age) {
|
||||||
|
|
||||||
|
if (age < 3) {
|
||||||
|
original_price *= 0.8;
|
||||||
|
} else if (age >= 10) {
|
||||||
|
original_price *= 0.5;
|
||||||
|
} else {
|
||||||
|
original_price *= 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
return original_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vehicle_purchase
|
11
cpp/vehicle-purchase/vehicle_purchase.h
Normal file
11
cpp/vehicle-purchase/vehicle_purchase.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace vehicle_purchase {
|
||||||
|
|
||||||
|
bool needs_license(std::string kind);
|
||||||
|
std::string choose_vehicle(std::string option1, std::string option2);
|
||||||
|
double calculate_resell_price(double original_price, double age);
|
||||||
|
|
||||||
|
} // namespace vehicle_purchase
|
108
cpp/vehicle-purchase/vehicle_purchase_test.cpp
Normal file
108
cpp/vehicle-purchase/vehicle_purchase_test.cpp
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
|
||||||
|
#include "vehicle_purchase.h"
|
||||||
|
#ifdef EXERCISM_TEST_SUITE
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#else
|
||||||
|
#include "test/catch.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_CASE("need a license for a car", "[task_1]") {
|
||||||
|
std::string kind{"car"};
|
||||||
|
REQUIRE(vehicle_purchase::needs_license(kind));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("need a license for a truck", "[task_1]") {
|
||||||
|
std::string kind{"truck"};
|
||||||
|
REQUIRE(vehicle_purchase::needs_license(kind));
|
||||||
|
}
|
||||||
|
TEST_CASE("does not need a license for a bike", "[task_1]") {
|
||||||
|
std::string kind{"bike"};
|
||||||
|
REQUIRE_FALSE(vehicle_purchase::needs_license(kind));
|
||||||
|
}
|
||||||
|
TEST_CASE("does not need a license for a stroller", "[task_1]") {
|
||||||
|
std::string kind{"stroller"};
|
||||||
|
REQUIRE_FALSE(vehicle_purchase::needs_license(kind));
|
||||||
|
}
|
||||||
|
TEST_CASE("does not need a license for a e-scooter", "[task_1]") {
|
||||||
|
std::string kind{"e-scooter"};
|
||||||
|
REQUIRE_FALSE(vehicle_purchase::needs_license(kind));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("chooses Bugatti over Ford", "[task_2]") {
|
||||||
|
std::string choice1{"Bugatti Veyron"};
|
||||||
|
std::string choice2{"Ford Pinto"};
|
||||||
|
REQUIRE(vehicle_purchase::choose_vehicle(choice1, choice2) ==
|
||||||
|
"Bugatti Veyron is clearly the better choice.");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("chooses Chery over Kia", "[task_2]") {
|
||||||
|
std::string choice1{"Kia Niro Elektro"};
|
||||||
|
std::string choice2{"Chery EQ"};
|
||||||
|
REQUIRE(vehicle_purchase::choose_vehicle(choice1, choice2) ==
|
||||||
|
"Chery EQ is clearly the better choice.");
|
||||||
|
}
|
||||||
|
TEST_CASE("chooses Ford Focus over Ford Pinto", "[task_2]") {
|
||||||
|
std::string choice1{"Ford Focus"};
|
||||||
|
std::string choice2{"Ford Pinto"};
|
||||||
|
REQUIRE(vehicle_purchase::choose_vehicle(choice1, choice2) ==
|
||||||
|
"Ford Focus is clearly the better choice.");
|
||||||
|
}
|
||||||
|
TEST_CASE("chooses 2018 over 2020", "[task_2]") {
|
||||||
|
std::string choice1{"2020 Gazelle Medeo"};
|
||||||
|
std::string choice2{"2018 Bergamont City"};
|
||||||
|
REQUIRE(vehicle_purchase::choose_vehicle(choice1, choice2) ==
|
||||||
|
"2018 Bergamont City is clearly the better choice.");
|
||||||
|
}
|
||||||
|
TEST_CASE("chooses Bugatti over ford", "[task_2]") {
|
||||||
|
std::string choice1{"Bugatti Veyron"};
|
||||||
|
std::string choice2{"ford"};
|
||||||
|
REQUIRE(vehicle_purchase::choose_vehicle(choice1, choice2) ==
|
||||||
|
"Bugatti Veyron is clearly the better choice.");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("price is reduced to 80% for age of 2", "[task_3]") {
|
||||||
|
double original_price{40000};
|
||||||
|
double age{2};
|
||||||
|
double expected{32000};
|
||||||
|
REQUIRE(vehicle_purchase::calculate_resell_price(original_price, age) ==
|
||||||
|
expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("price is reduced to 80% for age of 2.5", "[task_3]") {
|
||||||
|
double original_price{40000};
|
||||||
|
double age{2.5};
|
||||||
|
double expected{32000};
|
||||||
|
REQUIRE(vehicle_purchase::calculate_resell_price(original_price, age) ==
|
||||||
|
expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("price is reduced to 70% for age 7", "[task_3]") {
|
||||||
|
double original_price{40000};
|
||||||
|
double age{7};
|
||||||
|
double expected{28000};
|
||||||
|
REQUIRE(vehicle_purchase::calculate_resell_price(original_price, age) ==
|
||||||
|
expected);
|
||||||
|
}
|
||||||
|
TEST_CASE("price is reduced to 50% for age 10", "[task_3]") {
|
||||||
|
double original_price{25000};
|
||||||
|
double age{10};
|
||||||
|
double expected{12500};
|
||||||
|
REQUIRE(vehicle_purchase::calculate_resell_price(original_price, age) ==
|
||||||
|
expected);
|
||||||
|
}
|
||||||
|
TEST_CASE("price is reduced to 50% for age 11", "[task_3]") {
|
||||||
|
double original_price{50000};
|
||||||
|
double age{11};
|
||||||
|
double expected{25000};
|
||||||
|
REQUIRE(vehicle_purchase::calculate_resell_price(original_price, age) ==
|
||||||
|
expected);
|
||||||
|
}
|
||||||
|
TEST_CASE("float price is reduced to 70% for age 8,", "[task_3]") {
|
||||||
|
double original_price{39000.000001};
|
||||||
|
double age{8};
|
||||||
|
double expected{27300.0000007};
|
||||||
|
REQUIRE_THAT(vehicle_purchase::calculate_resell_price(original_price, age),
|
||||||
|
Catch::Matchers::WithinRel(expected, 0.001));
|
||||||
|
}
|
||||||
|
#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||||
|
#endif
|
Loading…
Reference in a new issue