C++: completed Ellen's Alien Game, Interest is Interesting, Vehicle Purchase

This commit is contained in:
Andrew Scott 2024-07-28 21:40:10 -04:00
parent 4ca5823d45
commit c8ef7df34c
Signed by: a
GPG key ID: 7CD5A5977E4931C1
36 changed files with 55423 additions and 0 deletions

View 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."
}

View 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}

View 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})

View 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

View 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.

View 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

Binary file not shown.

View 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

View 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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

0
cpp/freelancer-rates/freelancer-rates Executable file → Normal file
View file

View 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."
}

View 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}

View 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})

View 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

View 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/

View 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

Binary file not shown.

View 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;
}

View 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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

0
cpp/pacman-rules/pacman-rules Executable file → Normal file
View file

View 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"
}

View 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}

View 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})

View 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

View 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

View 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

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

View 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

View 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

View 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