mirror of
https://codeberg.org/andyscott/exercism.git
synced 2024-11-12 14:40:46 -05:00
C++: completed Pacman Rules and Freelancer Rates
This commit is contained in:
parent
1b76fd05a3
commit
4ca5823d45
22 changed files with 36666 additions and 0 deletions
21
cpp/freelancer-rates/.exercism/config.json
Normal file
21
cpp/freelancer-rates/.exercism/config.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"authors": [
|
||||
"vaeng"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"freelancer_rates.cpp"
|
||||
],
|
||||
"test": [
|
||||
"freelancer_rates_test.cpp"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.cpp"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"elixir/freelancer-rates"
|
||||
],
|
||||
"icon": "freelancer-rates",
|
||||
"blurb": "Learn about integers and floating point numbers by helping a freelancer communicate with a project manager about billing."
|
||||
}
|
1
cpp/freelancer-rates/.exercism/metadata.json
Normal file
1
cpp/freelancer-rates/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"track":"cpp","exercise":"freelancer-rates","id":"f6c4621e106f4d0c8aea55136a76694e","url":"https://exercism.org/tracks/cpp/exercises/freelancer-rates","handle":"Chomp1295","is_requester":true,"auto_approve":false}
|
66
cpp/freelancer-rates/CMakeLists.txt
Normal file
66
cpp/freelancer-rates/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/freelancer-rates/HELP.md
Normal file
61
cpp/freelancer-rates/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 freelancer_rates.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
|
24
cpp/freelancer-rates/HINTS.md
Normal file
24
cpp/freelancer-rates/HINTS.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- Browse the [`cmath` reference][cmath-reference] to learn about common mathematical operations and transformations that work with `doubles`.
|
||||
|
||||
## 1. Calculate the daily rate given an hourly rate
|
||||
|
||||
- Basic arithmetic operations where one argument is an `int`, and the other is a `double`, will return a `double`.
|
||||
|
||||
## 2. Calculate a discounted price
|
||||
|
||||
- Basic arithmetic operations where one argument is an `int`, and the other is a `double`, will return a `double`.
|
||||
|
||||
## 3. Calculate the monthly rate, given an hourly rate and a discount
|
||||
|
||||
- There is a [function in the `cmath` header][cmath-ceil] for rounding up.
|
||||
|
||||
## 4. Calculate the number of workdays given a budget, hourly rate, and discount
|
||||
|
||||
- Casting a `double` to an `int` will truncate the number at the decimal point.
|
||||
|
||||
[cmath-reference]: https://en.cppreference.com/w/cpp/header/cmath
|
||||
[cmath-ceil]: https://en.cppreference.com/w/cpp/numeric/math/ceil
|
161
cpp/freelancer-rates/README.md
Normal file
161
cpp/freelancer-rates/README.md
Normal file
|
@ -0,0 +1,161 @@
|
|||
# Freelancer Rates
|
||||
|
||||
Welcome to Freelancer Rates 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
|
||||
|
||||
The built-in number types in C++ can be divided into integers and floating points.
|
||||
Integers are whole numbers like `0`, `691`, or `-2`.
|
||||
Floating point numbers are numbers with a decimal point like `6.02214076`, `0.1`, or `-1.616`.
|
||||
|
||||
## Integers
|
||||
The following example shows the declaration and initialization of four different variables
|
||||
|
||||
```cpp
|
||||
int m_morales{9241}; // base 10: 0-9
|
||||
int a_apaec{0x24CD}; // base 16: 0-9 and A-F
|
||||
int m_gargan{0b10010000011001}; // base 2: 0-1
|
||||
int b_reilly{022031}; // base 8: 0-7
|
||||
// Leading with a 0 not the letter o.
|
||||
```
|
||||
|
||||
When you assign a value to an `int` variable, you can do so directly with a literal.
|
||||
A literal is a hard-coded number like `9241`.
|
||||
There are different integer literals for several bases of the representation.
|
||||
Decimal integer literals are the most common and use the digits `0` to `9`.
|
||||
By adding a special prefix, like `0x`, it is possible to use other bases.
|
||||
The example above shows the number `9421` in its four representations and prefixes.
|
||||
All variables are initialized to the same value.
|
||||
|
||||
For more details on the different representation systems, take a look at [a small tutorial][cpp_numerical_bases].
|
||||
|
||||
You can use an apostrophe to separate digits for easier readability.
|
||||
`9'241` is the same as `0b0100'100'0001'1001` or `92'4'1`.
|
||||
|
||||
## Floating-Point Numbers
|
||||
|
||||
The floating-point literals come in two flavors.
|
||||
In addition to the intuitive `0.0024` it is possible to use its scientific notation `2.4e-3`.
|
||||
The most common floating-point type is `double`.
|
||||
|
||||
## Arithmetic
|
||||
|
||||
C++ supports `+`, `-`, `*`, `/`, `(` and `)` and `%` to form expressions.
|
||||
The result from the operation between two integers is also an integer.
|
||||
`5 / 2` will return `2`.
|
||||
When one of the involved types is a floating-point type, the result will also be of a floating-point.
|
||||
`5.0 / 2` and `5 / 2.0` will return `2.5`.
|
||||
`%` is the remainder operator and will return the remainder of an integer division: `5%3` is `2`.
|
||||
|
||||
## Assignment operator
|
||||
|
||||
The assignment operator assigns a variable with a literal.
|
||||
Always takes place from right to left, and never the other way around.
|
||||
|
||||
```cpp
|
||||
int length = 5;
|
||||
int width = 2;
|
||||
length = width;
|
||||
```
|
||||
|
||||
Here integer value `5` is assigned to the variable `length`.
|
||||
Then integer value `2` is assigned to variable `width`.
|
||||
Finally value of `width` is copied to the variable `length` and the earlier value `5` will be lost.
|
||||
Consider also that we are only assigning the value of `width` to `length` at the moment of the assignment operation.
|
||||
Therefore, if the value of `width` changes at a later moment, it will not affect the value taken by `length`.
|
||||
|
||||
Assignment operator can be combined with the other operators(arithmetic & bitwise) known as `compound assignment` operators `+=`, `-=`, `*=`, `/=`, `%=`.
|
||||
These operators modifies the current value of a variable by performing an operation on it.
|
||||
|
||||
```cpp
|
||||
// we start with 0 people
|
||||
int people{};
|
||||
// we need 0 eggs
|
||||
int eggs{};
|
||||
// two people joined:
|
||||
people += 2;
|
||||
// people is now 2
|
||||
// let's add 3 eggs per person
|
||||
eggs += 3 * people;
|
||||
// eggs is now 6
|
||||
```
|
||||
|
||||
Variables `people` & `eggs` are initialized to `0`.
|
||||
Then, we add integer value `2` over the existing value `0` of the variable `people` and assign it back to `people`.
|
||||
`people` becomes `2` now.
|
||||
Later, we add `3` eggs for each person, which turns out to be `6` eggs in total.
|
||||
Now add this `6` to existing value `0` of the variable `eggs` and assign it back to `eggs`.
|
||||
`eggs` will be `6` now.
|
||||
The equivalent expression would be `people = people + 2` and `eggs = eggs + (3 * people)`.
|
||||
|
||||
|
||||
[cpp_numerical_bases]: https://cplusplus.com/doc/hex/
|
||||
|
||||
## Instructions
|
||||
|
||||
In this exercise, you'll be writing code to help a freelancer communicate with a project manager.
|
||||
Your task is to provide a few utilities to quickly calculate daily and monthly rates, optionally with a given discount.
|
||||
|
||||
We first establish a few rules between the freelancer and the project manager:
|
||||
|
||||
- The daily rate is 8 times the hourly rate.
|
||||
- A month has 22 billable days.
|
||||
|
||||
Sometimes, the freelancer is offering to apply a discount on their daily rate (for example for their most loyal customers or not-for-profit customers).
|
||||
|
||||
Discounts are modeled as fractional numbers representing percentages, for example, `25.0` (25%).
|
||||
|
||||
## 1. Calculate the daily rate given an hourly rate
|
||||
|
||||
Implement a function called `daily_rate` to calculate the daily rate given an hourly rate as a parameter.
|
||||
The contract defines that a day has 8 billable hours.
|
||||
|
||||
```cpp
|
||||
daily_rate(60)
|
||||
// => 480.0
|
||||
```
|
||||
|
||||
The returned daily rate should be of type `double`.
|
||||
|
||||
## 2. Calculate a discounted price
|
||||
|
||||
Implement a function `apply_discount` to calculates the price after a discount.
|
||||
It should accept two parameters: the original price and the discount rate in percent.
|
||||
|
||||
```cpp
|
||||
apply_discount(150, 10)
|
||||
// => 135.0
|
||||
```
|
||||
|
||||
The returned value should always be of type `double`, not rounded in any way.
|
||||
|
||||
## 3. Calculate the monthly rate, given an hourly rate and a discount
|
||||
|
||||
Implement a `monthly_rate` function to calculate the discounted monthly rate.
|
||||
It should have two parameters, an hourly rate and the discount in percent.
|
||||
|
||||
```cpp
|
||||
monthly_rate(77, 10.5)
|
||||
// => 12130
|
||||
```
|
||||
|
||||
The returned monthly rate should be rounded up (take the ceiling) to the nearest integer.
|
||||
|
||||
## 4. Calculate the number of complete workdays given a budget, hourly rate, and discount
|
||||
|
||||
Implement a function `days_in_budget` that takes a budget, an hourly rate, and a discount, and calculates how many complete days of work that covers.
|
||||
|
||||
```cpp
|
||||
days_in_budget(20'000, 80, 11.0)
|
||||
// => 35
|
||||
```
|
||||
|
||||
The returned number of days should be rounded down (take the floor) to the next integer.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @vaeng
|
BIN
cpp/freelancer-rates/freelancer-rates
Executable file
BIN
cpp/freelancer-rates/freelancer-rates
Executable file
Binary file not shown.
22
cpp/freelancer-rates/freelancer_rates.cpp
Normal file
22
cpp/freelancer-rates/freelancer_rates.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <cmath>
|
||||
|
||||
// daily_rate calculates the daily rate given an hourly rate
|
||||
double daily_rate(double hourly_rate) { return hourly_rate * 8; }
|
||||
|
||||
// apply_discount calculates the price after a discount
|
||||
double apply_discount(double before_discount, double discount) {
|
||||
return before_discount * ((100 - discount) / 100);
|
||||
}
|
||||
|
||||
// monthly_rate calculates the monthly rate, given an hourly rate and a discount
|
||||
// The returned monthly rate is rounded up to the nearest integer.
|
||||
int monthly_rate(double hourly_rate, double discount) {
|
||||
return ceil(apply_discount(daily_rate(hourly_rate) * 22, discount));
|
||||
}
|
||||
|
||||
// days_in_budget calculates the number of workdays given a budget, hourly rate,
|
||||
// and discount The returned number of days is rounded down (take the floor) to
|
||||
// the next integer.
|
||||
int days_in_budget(int budget, double hourly_rate, double discount) {
|
||||
return floor(budget / apply_discount(daily_rate(hourly_rate), discount));
|
||||
}
|
68
cpp/freelancer-rates/freelancer_rates_test.cpp
Normal file
68
cpp/freelancer-rates/freelancer_rates_test.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include "freelancer_rates.cpp"
|
||||
#ifdef EXERCISM_TEST_SUITE
|
||||
#include <catch2/catch.hpp>
|
||||
#else
|
||||
#include "test/catch.hpp"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
TEST_CASE("it's the hourly_rate times 8", "[task_1]") {
|
||||
REQUIRE(daily_rate(50) == 400.0);
|
||||
}
|
||||
|
||||
TEST_CASE("it always returns a float", "[task_1]") {
|
||||
REQUIRE(daily_rate(60) == 480.0);
|
||||
}
|
||||
|
||||
TEST_CASE("it does not round", "[task_1]") {
|
||||
REQUIRE(daily_rate(55.1) == 440.8);
|
||||
}
|
||||
|
||||
TEST_CASE("a discount of 10 percent leaves 90 percent of the original price",
|
||||
"[task_2]") {
|
||||
REQUIRE(apply_discount(140.0, 10) == 126.0);
|
||||
}
|
||||
|
||||
TEST_CASE("it doesn't round", "[task_2]") {
|
||||
// If unsure about the syntax of this test see:
|
||||
// https://github.com/catchorg/Catch2/blob/devel/docs/comparing-floating-point-numbers.md#withinrel
|
||||
REQUIRE_THAT(apply_discount(111.11, 13.5),
|
||||
Catch::Matchers::WithinRel(96.11015, 0.000001));
|
||||
}
|
||||
|
||||
TEST_CASE("it's the daily_rate times 22", "[task_3]") {
|
||||
REQUIRE(monthly_rate(62, 0.0) == 10'912);
|
||||
}
|
||||
|
||||
TEST_CASE("the result is rounded up", "[task_3]") {
|
||||
// 11_052.8
|
||||
REQUIRE(monthly_rate(62.8, 0.0) == 11'053);
|
||||
// 11_475.2
|
||||
REQUIRE(monthly_rate(65.2, 0.0) == 11'476);
|
||||
}
|
||||
|
||||
TEST_CASE("gives a discount", "[task_3]") {
|
||||
// 11'792 - 12% * 11_792 = 10'376.96
|
||||
REQUIRE(monthly_rate(67, 12.0) == 10'377);
|
||||
}
|
||||
|
||||
TEST_CASE("it's the budget divided by the daily rate", "[task_4]") {
|
||||
REQUIRE(days_in_budget(1'600, 50, 0.0) == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("it rounds down to next decimal place", "[task_4]") {
|
||||
// 9.97727
|
||||
REQUIRE(days_in_budget(4'390, 55, 0.0) == 9);
|
||||
// 10.18182
|
||||
REQUIRE(days_in_budget(4'480, 55, 0.0) == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("it applies the discount", "[task_4]") {
|
||||
// Without discount: 0.8
|
||||
// With discount: 1.07
|
||||
REQUIRE(days_in_budget(480, 70, 20) == 1);
|
||||
}
|
||||
|
||||
#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||
#endif
|
17937
cpp/freelancer-rates/test/catch.hpp
Normal file
17937
cpp/freelancer-rates/test/catch.hpp
Normal file
File diff suppressed because it is too large
Load diff
2
cpp/freelancer-rates/test/tests-main.cpp
Normal file
2
cpp/freelancer-rates/test/tests-main.cpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
20
cpp/pacman-rules/.exercism/config.json
Normal file
20
cpp/pacman-rules/.exercism/config.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"authors": [
|
||||
"vaeng"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"pacman_rules.cpp"
|
||||
],
|
||||
"test": [
|
||||
"pacman_rules_test.cpp"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.cpp"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"elixir/pacman-rules"
|
||||
],
|
||||
"blurb": "Learn about booleans by implementing the rules of the Pac-Man game."
|
||||
}
|
1
cpp/pacman-rules/.exercism/metadata.json
Normal file
1
cpp/pacman-rules/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"track":"cpp","exercise":"pacman-rules","id":"10de72cd2ba04a1e98b8e7e51cc18fa8","url":"https://exercism.org/tracks/cpp/exercises/pacman-rules","handle":"Chomp1295","is_requester":true,"auto_approve":false}
|
66
cpp/pacman-rules/CMakeLists.txt
Normal file
66
cpp/pacman-rules/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/pacman-rules/HELP.md
Normal file
61
cpp/pacman-rules/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 pacman_rules.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
|
27
cpp/pacman-rules/HINTS.md
Normal file
27
cpp/pacman-rules/HINTS.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- Don't worry about how the arguments are derived, just focus on combining the arguments to return the intended result.
|
||||
|
||||
## 1. Define if pac-man can eat a ghost
|
||||
|
||||
- The function must return a boolean value.
|
||||
- You can use the logical operator and ([`&&`][logical operators]) to combine the arguments for a result.
|
||||
|
||||
## 2. Define if pac-man scores
|
||||
|
||||
- The function must return a boolean value.
|
||||
- You can use the logical operator or ([`||`][logical operators]) to combine the arguments for a result.
|
||||
|
||||
## 3. Define if pac-man loses
|
||||
|
||||
- The function must return a boolean value.
|
||||
- You can use the boolean operators [`&&`][logical operators] and [`!`][logical operators] to combine the arguments for a result.
|
||||
|
||||
## 4. Define if pac-man wins
|
||||
|
||||
- The function must return a boolean value.
|
||||
- You can use the boolean operators [`&&`][logical operators] and [`!`][logical operators] to combine the arguments and results of one of the previously implemented functions.
|
||||
|
||||
[logical operators]: https://en.cppreference.com/w/cpp/language/operator_logical
|
95
cpp/pacman-rules/README.md
Normal file
95
cpp/pacman-rules/README.md
Normal file
|
@ -0,0 +1,95 @@
|
|||
# Pacman Rules
|
||||
|
||||
Welcome to Pacman Rules 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
|
||||
|
||||
Booleans in C++ are represented by the `bool` type.
|
||||
A `bool` is either `true` or `false`.
|
||||
|
||||
## Logical Operators
|
||||
|
||||
C++ supports three boolean operators: `!` (NOT), `&&` (AND), and `||` (OR).
|
||||
You can also use the alternative versions `not`, `and`, and `or`.
|
||||
|
||||
```cpp
|
||||
true || false // => true
|
||||
true && false // => false
|
||||
!true // => false
|
||||
not false // => true
|
||||
```
|
||||
|
||||
## Precedence
|
||||
|
||||
The three boolean operators each have different _operator precedence_.
|
||||
As a consequence, they are evaluated in this order: `!` first, `&&` second, and finally `||`.
|
||||
If you want to force a different ordering, you can enclose a boolean expression in parentheses (ie. `()`), as the parentheses have even higher operator precedence.
|
||||
|
||||
```cpp
|
||||
!true && false // => false
|
||||
!(true and false) // => true
|
||||
```
|
||||
|
||||
~~~~exercism/advanced
|
||||
## Conversion
|
||||
|
||||
If you use `true` or `false` in a place where a number is expected, they will be converted to `1` and `0` respectively.
|
||||
If you use a number in a Boolean operation, everything except `0` is treated as `true` - even negative values.
|
||||
|
||||
```cpp
|
||||
!true && 0.0 // => false
|
||||
true + true + false // => 2
|
||||
```
|
||||
~~~~
|
||||
|
||||
## Instructions
|
||||
|
||||
In this exercise, you need to translate some rules from the classic game Pac-Man into C++ functions.
|
||||
|
||||
You have four rules to translate, all related to the game states.
|
||||
|
||||
> Don't worry about how the arguments are derived, just focus on combining the arguments to return the intended result.
|
||||
|
||||
## 1. Define if Pac-Man eats a ghost
|
||||
|
||||
Define the `can_eat_ghost` function that takes two arguments (_if Pac-Man has a power pellet active_ and _if Pac-Man is touching a ghost_) and returns a boolean value if Pac-Man is able to eat the ghost. The function should return true only if Pac-Man has a power pellet active and is touching a ghost.
|
||||
|
||||
```cpp
|
||||
can_eat_ghost(false, true);
|
||||
// => false
|
||||
```
|
||||
|
||||
## 2. Define if Pac-Man scores
|
||||
|
||||
Define the `scored` function that takes two arguments (_if Pac-Man is touching a power pellet_ and _if Pac-Man is touching a dot_) and returns a boolean value if Pac-Man scored. The function should return true if Pac-Man is touching a power pellet or a dot.
|
||||
|
||||
```cpp
|
||||
scored(true, true);
|
||||
// => true
|
||||
```
|
||||
|
||||
## 3. Define if Pac-Man loses
|
||||
|
||||
Define the `lost` function that takes two arguments (_if Pac-Man has a power pellet active_ and _if Pac-Man is touching a ghost_) and returns a boolean value if Pac-Man loses. The function should return true if Pac-Man is touching a ghost and does not have a power pellet active.
|
||||
|
||||
```cpp
|
||||
lost(false, true);
|
||||
// => true
|
||||
```
|
||||
|
||||
## 4. Define if Pac-Man wins
|
||||
|
||||
Define the `won` function that takes three arguments (_if Pac-Man has eaten all of the dots_, _if Pac-Man has a power pellet active_, and _if Pac-Man is touching a ghost_) and returns a boolean value if Pac-Man wins. The function should return true if Pac-Man has eaten all of the dots and has not lost based on the arguments defined in part 3.
|
||||
|
||||
```cpp
|
||||
won(false, true, false);
|
||||
// => false
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @vaeng
|
BIN
cpp/pacman-rules/pacman-rules
Executable file
BIN
cpp/pacman-rules/pacman-rules
Executable file
Binary file not shown.
28
cpp/pacman-rules/pacman_rules.cpp
Normal file
28
cpp/pacman-rules/pacman_rules.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// eat_ghost returns a boolean value if Pac-Man is able to eat the ghost.
|
||||
// The function should return true only if Pac-Man has a power pellet active
|
||||
// and is touching a ghost.
|
||||
bool can_eat_ghost(bool power_pellet_active, bool touching_ghost) {
|
||||
return power_pellet_active && touching_ghost;
|
||||
}
|
||||
|
||||
// score returns a boolean value if Pac-Man scored.
|
||||
// The function should return true if Pac-Man is touching a power pellet or a
|
||||
// dot.
|
||||
bool scored(bool touching_power_pellet, bool touching_dot) {
|
||||
return touching_power_pellet || touching_dot;
|
||||
}
|
||||
|
||||
// lost returns a boolean value if Pac-Man loses.
|
||||
// The function should return true if Pac-Man is touching a ghost and
|
||||
// does not have a power pellet active.
|
||||
bool lost(bool power_pellet_active, bool touching_ghost) {
|
||||
return !power_pellet_active && touching_ghost;
|
||||
}
|
||||
|
||||
// won returns a boolean value if Pac-Man wins.
|
||||
// The function should return true if Pac-Man
|
||||
// has eaten all of the dots and has not lost
|
||||
bool won(bool has_eaten_all_dots, bool power_pellet_active,
|
||||
bool touching_ghost) {
|
||||
return has_eaten_all_dots && !lost(power_pellet_active, touching_ghost);
|
||||
}
|
66
cpp/pacman-rules/pacman_rules_test.cpp
Normal file
66
cpp/pacman-rules/pacman_rules_test.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include "pacman_rules.cpp"
|
||||
#ifdef EXERCISM_TEST_SUITE
|
||||
#include <catch2/catch.hpp>
|
||||
#else
|
||||
#include "test/catch.hpp"
|
||||
#endif
|
||||
|
||||
TEST_CASE("ghost gets eaten", "[task_1]") {
|
||||
REQUIRE(can_eat_ghost(true, true));
|
||||
}
|
||||
|
||||
TEST_CASE("ghost does not get eaten because no power pellet active",
|
||||
"[task_1]") {
|
||||
REQUIRE_FALSE(can_eat_ghost(false, true));
|
||||
}
|
||||
|
||||
TEST_CASE("ghost does not get eaten because not touching ghost", "[task_1]") {
|
||||
REQUIRE_FALSE(can_eat_ghost(true, false));
|
||||
}
|
||||
|
||||
TEST_CASE("ghost does not get eaten because no power pellet is active, even if "
|
||||
"not touching ghost",
|
||||
"[task_1]") {
|
||||
REQUIRE_FALSE(can_eat_ghost(false, false));
|
||||
}
|
||||
|
||||
TEST_CASE("score when eating dot", "[task_2]") { REQUIRE(scored(false, true)); }
|
||||
|
||||
TEST_CASE("score when eating power pellet", "[task_2]") {
|
||||
REQUIRE(scored(true, false));
|
||||
}
|
||||
|
||||
TEST_CASE("no score when nothing eaten", "[task_2]") {
|
||||
REQUIRE_FALSE(scored(false, false));
|
||||
}
|
||||
|
||||
TEST_CASE("lose if touching a ghost without a power pellet active",
|
||||
"[task_3]") {
|
||||
REQUIRE(lost(false, true));
|
||||
}
|
||||
|
||||
TEST_CASE("don't lose if touching a ghost with a power pellet active",
|
||||
"[task_3]") {
|
||||
REQUIRE_FALSE(lost(true, true));
|
||||
}
|
||||
|
||||
TEST_CASE("don't lose if not touching a ghost", "[task_3]") {
|
||||
REQUIRE_FALSE(lost(true, false));
|
||||
}
|
||||
|
||||
TEST_CASE("win if all dots eaten", "[task_4]") {
|
||||
REQUIRE(won(true, false, false));
|
||||
}
|
||||
|
||||
TEST_CASE("don't win if all dots eaten, but touching a ghost", "[task_4]") {
|
||||
REQUIRE_FALSE(won(true, false, true));
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"win if all dots eaten and touching a ghost with a power pellet active",
|
||||
"[task_4]") {
|
||||
REQUIRE(won(true, true, true));
|
||||
}
|
||||
|
||||
#if defined(EXERCISM_RUN_ALL_TESTS)
|
||||
#endif
|
17937
cpp/pacman-rules/test/catch.hpp
Normal file
17937
cpp/pacman-rules/test/catch.hpp
Normal file
File diff suppressed because it is too large
Load diff
2
cpp/pacman-rules/test/tests-main.cpp
Normal file
2
cpp/pacman-rules/test/tests-main.cpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
Loading…
Reference in a new issue