diff --git a/.gitignore b/.gitignore index 7893b49..9b9f152 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ build/gcov builld/logs build/temp build/test -.vscode \ No newline at end of file +.vscode +#encounter_test.sh \ No newline at end of file diff --git a/encounter_test.sh b/encounter_test.sh new file mode 100644 index 0000000..1a2253d --- /dev/null +++ b/encounter_test.sh @@ -0,0 +1,8 @@ +#Small scirpt to run the tests and generate the coverage report +#cleans artifacts before building +date +ceedling clean +ceedling gcov:encounter +ceedling utils:gcov +cd build/artifacts/gcov +xdg-open GcovCoverageResults.html & diff --git a/project.yml b/project.yml index b3f24b9..90eaf3c 100644 --- a/project.yml +++ b/project.yml @@ -101,4 +101,4 @@ - xml_tests_report - gcov -... +... diff --git a/src/c/encounter.c b/src/c/encounter.c new file mode 100644 index 0000000..5ea3027 --- /dev/null +++ b/src/c/encounter.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include + +#include "encounter.h" +#include "playerinput.h" +#include "helper.h" + +/*Gegner mit AC, damagedealt = damage-AC, kann nicht kleiner 1 sein +evtl. lair bonus der dem gegner ein wenig mehr/weniger damage erlaubt +gegner erhalten eine zufällige menge Gold, die beim tod an den spieler gegeben werden +humanoide gegner haben heiltränke mit denen sie sich ggf heilen. +heilung erfolgt dann, wenn bestimmte hp (50%) unterschritten wird. wird allerdings gewürfelt, +je niedriger die hp%, desto höher die chance. */ + +bool playerAlive(int health) +{ + if (health > 0) + { + return true; + } + else + { + return false; + } +} + +int playerHealth(int health, int damage, int armor) +{ + const int maxhealth = 100; + health = health - damage; + if (health > maxhealth) + { + health = maxhealth; + } + return health; +} + +void enemyHeal(enemy *enemy, int healAmount) +{ + int currentHealth = getEnemyHealth(enemy); + int maxHealth = getEnemyMaxHealth(enemy); + if (currentHealth + healAmount > maxHealth) + { + healAmount = maxHealth - currentHealth; + } + setEnemyHealth(enemy, currentHealth + healAmount); +} + +void enemyDamaged(enemy *enemy, int damage) +{ + int armor = getEnemyArmor(enemy); + int currentHealth = getEnemyHealth(enemy); + int damagedealt = damage - armor; + if (damagedealt < 1) + { + damagedealt = 1; + } + setEnemyHealth(enemy, currentHealth - damagedealt); +} + + + +int switchTurns(int currentTurn) +{ + currentTurn = currentTurn % 2 + 1; + return currentTurn; +} + +int fight(int playerH, int playerDamage, int playerArmor, int playerAttack, enemy* enemy) +{ + int currentTurn = 2; + char decision; + while (playerAlive(playerH) && getEnemyHealth(enemy) > 0) + { + if (currentTurn != 1) + { + decision = playerInputChar(); + switch(decision){ + case 'a': + enemyDamaged(enemy, playerDamage); + break; + case 'h': + playerH = playerHealth(playerH, -10, playerArmor); + break; + case 'f': + return 2; + } + + } + else + { + if(enemyChoosesHeal(enemy)) + { + enemyHeal(enemy, 10); + } + else + { + playerH = playerHealth(playerH, getEnemyDamage(enemy), playerArmor); + } + } + currentTurn = switchTurns(currentTurn); + } + if (playerAlive(playerH)) + { + return 1; + } + else + { + return 0; + } +} + +int randomIntRange(int min, int max) +{ + int value = randomInt(); + return (value % (max - min + 1)) + min; +} + + +int map(int x, int in_min, int in_max, int out_min, int out_max) +{ + //vgl Arduino map() https://www.arduino.cc/reference/en/language/functions/math/map/ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +bool enemyChoosesHeal(enemy* enemy) +{ + int currentHealth = getEnemyHealth(enemy); + int maxHealth = getEnemyMaxHealth(enemy); + int healthd20 = 20 - map(currentHealth, 0, maxHealth, 0, 20); + int rolld20 = randomIntRange(1, 20); + return (healthd20 + rolld20) >= 30; +} + +// Getter/Setter Funktionen +void setEnemyHealth(enemy* enemy, int newhealth) +{ + enemy->health = newhealth; +} + +void setEnemyDamage(enemy* enemy, int newdamage) +{ + enemy->damage = newdamage; +} + +void setEnemyArmor(enemy* enemy, int newarmor) +{ + enemy->armor = newarmor; +} + +int getEnemyHealth(enemy* enemy) +{ + return enemy->health; +} + +int getEnemyArmor(enemy* enemy) +{ + return enemy->armor; +} + +int getEnemyDamage(enemy* enemy) +{ + return enemy->damage; +} + +int getEnemyMaxHealth(enemy* enemy) +{ + return enemy->maxHealth; +} \ No newline at end of file diff --git a/src/c/encounter.h b/src/c/encounter.h new file mode 100644 index 0000000..312f35a --- /dev/null +++ b/src/c/encounter.h @@ -0,0 +1,40 @@ +#ifndef ENCOUNTER_H +#define ENCOUNTER_H + +#include + +typedef struct enemy{ + int health; + int damage; + int armor; + int maxHealth; +} enemy; + + +bool playerAlive(int health); +int playerHealth(int health, int damage, int armor); +void enemyHeal(enemy *enemy, int healAmount); +void enemyDamaged(enemy* enemy, int damage); +bool enemyChoosesHeal(enemy* enemy); +int switchTurns(int currentTurn); +int fight(int playerH, int playerDamage, int playerArmor, int playerAttack, enemy* enemy); + +//Funktionen die Mathematische Berechnungen durchführen +int map(int x, int in_min, int in_max, int out_min, int out_max); +int randomIntRange(int min, int max); +//Getter/Setter Funktionen + +//setEnemyHealth(&enemy, health); +void setEnemyHealth(enemy* enemy, int newhealth); + +//setEnemyDamage(&enemy.damage, damage); +void setEnemyDamage(enemy* enemy, int newdamage); +//setEnemyArmor(&enemy.armor, armor); +void setEnemyArmor(enemy* enemy, int newarmor); +//Function to get the value of Data in a struct, needs a pointer to the struct +int getEnemyMaxHealth(enemy* enemy); +int getEnemyHealth(enemy* enemy); +int getEnemyArmor(enemy* enemy); +int getEnemyDamage(enemy* enemy); + +#endif \ No newline at end of file diff --git a/src/c/helper.c b/src/c/helper.c new file mode 100644 index 0000000..7b3381d --- /dev/null +++ b/src/c/helper.c @@ -0,0 +1,6 @@ +#include "helper.h" + +int randomInt() +{ + return rand(); +} \ No newline at end of file diff --git a/src/c/helper.h b/src/c/helper.h new file mode 100644 index 0000000..c1a5799 --- /dev/null +++ b/src/c/helper.h @@ -0,0 +1,8 @@ +#ifndef HELPER_H +#define HELPER_H +//erlaubt es z.b. rand() zu mocken + +int randomInt(); + + +#endif \ No newline at end of file diff --git a/src/c/playerinput.c b/src/c/playerinput.c new file mode 100644 index 0000000..478d563 --- /dev/null +++ b/src/c/playerinput.c @@ -0,0 +1,6 @@ +#include "playerinput.h" + +char playerInputChar(){ + char c; + return c; +} \ No newline at end of file diff --git a/src/c/playerinput.h b/src/c/playerinput.h new file mode 100644 index 0000000..d6d6ffa --- /dev/null +++ b/src/c/playerinput.h @@ -0,0 +1,6 @@ +#ifndef PLAYERINPUT_H +#define PLAYERINPUT_H + +char playerInputChar(); + +#endif \ No newline at end of file diff --git a/test/c/test_encounter.c b/test/c/test_encounter.c new file mode 100644 index 0000000..0f07a36 --- /dev/null +++ b/test/c/test_encounter.c @@ -0,0 +1,375 @@ +#ifdef TEST +#include "unity.h" + +#include "encounter.h" +#include "playerinput.h" +#include "mock_playerinput.h" +#include "helper.h" +#include "mock_helper.h" + +void setUp(void) +{ +} + +void teardown(void) +{ +} + +void test_isPlayerAlive_healthGreaterZero(void) +{ + // arrange + int health = 100; + bool result; + // act + result = playerAlive(health); + // assert + TEST_ASSERT_TRUE(result); +} + +void test_isPlayerAlive_healthLowerZero(void) +{ + // arrange + int health = -1; + bool result; + // act + result = playerAlive(health); + + // assert + TEST_ASSERT_FALSE(result); +} + +void test_playerIsDamaged(void) +{ + // arrange + int health = 100; + int damage = 10; + int armor = 0; + int expectedHealth = 90; + // act + health = playerHealth(health, damage, armor); + // assert + TEST_ASSERT_EQUAL(expectedHealth, health); +} + +void test_playerIsNotOverhealed(void) +{ + // arrange + int health = 100; + int armor = 0; + int heal = -10; + int expectedHealth = 100; + // act + health = playerHealth(health, heal, armor); + // assert + TEST_ASSERT_EQUAL(expectedHealth, health); +} + +void test_setEnemyHealth(void) +{ + // arrange + int health = 50, result; + // act + enemy test = {health * 2}; + setEnemyHealth(&test, health); + result = test.health; + // assert + TEST_ASSERT_EQUAL(health, result); +} + +void test_getEnemyHealth(void) +{ + // arrange + int health = 50, result; + // act + enemy test = {health}; + result = getEnemyHealth(&test); + // assert + TEST_ASSERT_EQUAL(health, result); +} + +void test_setEnemyDamage(void) +{ + // arrange + int damage = 4, result; + enemy test = {50, damage * 2}; + // act + setEnemyDamage(&test, damage); + result = test.damage; + // assert + TEST_ASSERT_EQUAL(damage, result); +} + +void test_getEnemyDamage(void) +{ + // arrange + int damage = 4, result; + // act + enemy test = {50, damage}; + result = getEnemyDamage(&test); + // assert + TEST_ASSERT_EQUAL(damage, result); +} + +void test_get_setEnemyArmor(void) +{ + // arrange + int armor = 4, result; + enemy test = {50, 4, armor * 2}; + // act + setEnemyArmor(&test, armor); + result = getEnemyArmor(&test); + // assert + TEST_ASSERT_EQUAL(armor, result); +} + +void test_PlayerAttacksEnemy_DoesDamage(void) +{ + // arrange + int playerDamage = 10; + int enemyHealth = 50; + int enemyArmor = 4; + // health - (damage - armor) + int expectedEnemyHealth = 44; + // act + enemy test = {enemyHealth, 4, enemyArmor}; + enemyDamaged(&test, playerDamage); + // assert + TEST_ASSERT_EQUAL(expectedEnemyHealth, test.health); +} + +void test_PlayerAttacksEnemy_DoesMinDamage(void) +{ + // arrange + int playerDamage = 10; + int enemyHealth = 50; + int enemyArmor = 10; + // health - (damage - armor) + int expectedEnemyHealth = 49; + // act + enemy test = {enemyHealth, 4, enemyArmor}; + enemyDamaged(&test, playerDamage); + // assert + TEST_ASSERT_EQUAL(expectedEnemyHealth, test.health); +} + +// A better way to get the value of a struct, REFACTORING if it works +void test_getterWithParams(void) +{ + // arrange + int health = 50, armor = 4, damage = 4, maxHealth = 5; + int healthResult, armorResult, damageResult, maxHealthResult; + enemy test = {health, damage, armor, maxHealth}; + // act + healthResult = getEnemyHealth(&test); + armorResult = getEnemyArmor(&test); + damageResult = getEnemyDamage(&test); + maxHealthResult = getEnemyMaxHealth(&test); + // assert + TEST_ASSERT_EQUAL(health, healthResult); + TEST_ASSERT_EQUAL(armor, armorResult); + TEST_ASSERT_EQUAL(damage, damageResult); + TEST_ASSERT_EQUAL(maxHealth, maxHealthResult); +} +void test_switchingTurns(void) +{ + // arrange + int currentTurn = 0, result; + // act + result = switchTurns(currentTurn); + // assert + TEST_ASSERT_EQUAL(1, result); +} + +void test_FightPlayerWins(void) +{ + // arange + int playerHealth = 100, playerDamage = 10, playerArmor = 4, playerAttack = 5; + int enemyHealth = 1, enemyDamage = 4, enemyArmor = 4, enemyMaxHealth = 5; + int result; + // aCt + playerInputChar_ExpectAndReturn('a'); + enemy test = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + result = fight(playerHealth, playerDamage, playerArmor, playerAttack, &test); + // assert + TEST_ASSERT_EQUAL(1, result); +} + +void test_FightEnemyWins(void) +{ + // arange + int playerHealth = 1, playerDamage = 10, playerArmor = 4, playerAttack = 5; + int enemyHealth = 100, enemyDamage = 4, enemyArmor = 4, enemyMaxHealth = 100; + int result; + // act + playerInputChar_ExpectAndReturn('a'); + randomInt_ExpectAndReturn(1); + enemy test = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + result = fight(playerHealth, playerDamage, playerArmor, playerAttack, &test); + // assert + TEST_ASSERT_EQUAL(0, result); +} + +void test_FightPlayerChoosesAttack(void) +{ + // arrange + int playerHealth = 100, playerDamage = 10, playerArmor = 4, playerAttack = 5; + int enemyHealth = 6, enemyDamage = 4, enemyArmor = 4, enemyMaxHealth = 100; + int result; + // act + playerInputChar_ExpectAndReturn('a'); + enemy test = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + fight(playerHealth, playerDamage, playerArmor, playerAttack, &test); + result = getEnemyHealth(&test); + // assert + TEST_ASSERT_EQUAL(0, result); +} + +void test_FightPlayerHeals_thenAttacks_Wins(void) +{ + // arrange + int playerHealth = 2, playerDamage = 10, playerArmor = 4, playerAttack = 10; + int enemyHealth = 11, enemyDamage = 4, enemyArmor = 4, enemyMaxHealth = 100; + int result; + // act + enemy test = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + playerInputChar_ExpectAndReturn('h'); + randomInt_ExpectAndReturn(1); + playerInputChar_ExpectAndReturn('a'); + randomInt_ExpectAndReturn(1); + playerInputChar_ExpectAndReturn('a'); + result = fight(playerHealth, playerDamage, playerArmor, playerAttack, &test); + // assert + TEST_ASSERT_EQUAL(1, result); +} + +void test_FightPlayerFlees(void) +{ + // arrange + int playerHealth = 10, playerDamage = 10, playerArmor = 4, playerAttack = 10; + int enemyHealth = 11, enemyDamage = 4, enemyArmor = 4, enemyMaxHealth = 100; + int result; + // act + enemy test = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + playerInputChar_ExpectAndReturn('f'); + result = fight(playerHealth, playerDamage, playerArmor, playerAttack, &test); + // assert + TEST_ASSERT_EQUAL(2, result); +} + +void test_randomIntRange(void) +{ + int expected = 4; + randomInt_ExpectAndReturn(15); + int result = randomIntRange(1, 6); + TEST_ASSERT_EQUAL_INT(expected, result); +} + +void test_enemyCanHeal(void) +{ + // arrange + int enemyHealth = 1, enemyDamage = 4, enemyArmor = 4, enemyMaxHealth = 20; + int healAmount = 10, expectedHealth = 11; + int result; + // act + enemy test = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + enemyHeal(&test, healAmount); + result = getEnemyHealth(&test); + // assert + TEST_ASSERT_EQUAL(expectedHealth, result); +} + +void test_enemyNoOverheal(void) +{ + // arrange + int enemyHealth = 1, enemyDamage = 4, enemyArmor = 4, enemyMaxHealth = 5; + int healAmount = 10, expectedHealth = 5; + int result; + // act + enemy test = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + enemyHeal(&test, healAmount); + result = getEnemyHealth(&test); + // assert + TEST_ASSERT_EQUAL(expectedHealth, result); +} + +void test_roll_20() +{ + int expected = 20; + int result; + + randomInt_ExpectAndReturn(39); + result = randomIntRange(1, 20); + + TEST_ASSERT_EQUAL(expected, result); +} + +void test_roll_01() +{ + int expected = 1; + int result; + + randomInt_ExpectAndReturn(40); + result = randomIntRange(1, 20); + + TEST_ASSERT_EQUAL(expected, result); +} + +void test_map10(){ + int expected1 = 10, expected2 = 0, expected3 = 20; + int result; + + result = map(50, 0, 100, 0, 20); + TEST_ASSERT_EQUAL(expected1, result); + result = map(0, 0, 100, 0, 20); + TEST_ASSERT_EQUAL(expected2, result); + result = map(100, 0, 100, 0, 20); + TEST_ASSERT_EQUAL(expected3, result); +} + +void test_enemyChoosesHeal(void) +{ + //arange + bool result; + int enemyHealth = 50, enemyDamage = 4, enemyArmor = 4, enemyMaxHealth = 100; + enemy test = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + //act + randomInt_ExpectAndReturn(39); //39%20 = 19 , 19 + 1 = 20 + result = enemyChoosesHeal(&test); + //assert + TEST_ASSERT_TRUE(result); + +} + +void test_enemyDoesNotChoosesHeal(void) +{ + //arange + bool result; + int enemyHealth = 50, enemyDamage = 4, enemyArmor = 4, enemyMaxHealth = 100; + enemy test = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + //act + randomInt_ExpectAndReturn(14); //14%20 = 14 , 14 + 1 = 15 + result = enemyChoosesHeal(&test); + //assert + TEST_ASSERT_FALSE(result); + +} + +void test_enemyChoosesHeal_ThenAttackWins(void) +{ + //arange + int result; + int enemyHealth = 6, enemyDamage = 10, enemyArmor = 5, enemyMaxHealth = 100; + int playerHealth = 10, playerDamage = 10, playerArmor = 5, playerAttack = 10; + enemy test2 = {enemyHealth, enemyDamage, enemyArmor, enemyMaxHealth}; + //act + playerInputChar_ExpectAndReturn('a'); + randomInt_ExpectAndReturn(39); //39%20 = 19 , 19 + 1 = 20 + playerInputChar_ExpectAndReturn('a'); + randomInt_ExpectAndReturn(0); //0%20 = 0 , 0 + 1 = 1 + result = fight(playerHealth, playerDamage, playerArmor, playerAttack, &test2); + //assert + TEST_ASSERT_EQUAL(0, result); + +} + +#endif // TEST diff --git a/test/c/test_helper.c b/test/c/test_helper.c new file mode 100644 index 0000000..732f30c --- /dev/null +++ b/test/c/test_helper.c @@ -0,0 +1,23 @@ +#ifdef TEST +#include "unity.h" +#include "helper.h" +#include "mock_helper.h" + +void setUp(void) +{ +} + +void teardown(void) +{ +} + +//Just to test the mock +void test_randomInt(void) +{ + int expected = 42; + randomInt_ExpectAndReturn(expected); + TEST_ASSERT_EQUAL_INT(expected, randomInt()); +} + + +#endif//Test \ No newline at end of file