for Robot Artificial Inteligence

20. Exceptions & Namespaces

|

Exception

  • python try ~ except과 같은 원리이다
  • try ~ catch
    • try를 하고 오류가 생기면
    • Catch해서 break하겠다라는 의미이다.
    • python보다 추가된건 void 옆에 throw 를 지정해 줘서 catch에 날려버린다.

Example 1

Exception.cpp

#include <iostream>

using namespace std;

/* Exceptions - handling exceptions */
class DivisionByZeroException
{
    public:
        void getErrorMessage() { cout << "Error: Do not divide by zero"; }
};

double division(double a, double b) throw(DivisionByZeroException)
{
    if (b == 0)
        throw DivisionByZeroException();
    return a / b;
}
int main()
{
    double result;

    try
    {
        result = division(5, 0);

        cout << "the result is " << result << endl;
    }
    catch(DivisionByZeroException e)
    {
        e.getErrorMessage();
    }
    catch(...)
    {
        cout << "This is a message that will be shown, when other catch instructions wont be invoked " << endl;
    }
//    cout << "lalal" << endl;

    return 0;
}

Namespaces

  • namespace는 같은 이름을 충돌하지 않게 하는 문법입니다.
  • 많은 라이브러리를 만들어지고 있는데 서로 다른 라이브러리에 같은 이름의 형식이나 개체가 있을 때 충돌이 나지 않게 namespace로 감싸게 하여 충돌나지 않게 할 수 있습니다.
  • 먼저 namespace 문법을 사용하지 않았을 때 같은 이름의 형식을 정의하여 충돌하는 예입니다.
//namespace를 사용하지 않아 이름 충돌
//Program.cpp
#include <iostream>
using namespace std;

struct Stack
{
    int top;
};

struct Stack //이미 앞에서 같은 이름으로 정의하고 있음
{
    int last;
};
int main()
{
    return 0;
}
  • 이를 다음처럼 namespace로 감싸서 정의하면 이름 충돌이 발생하지 않습니다 ``` namespace DemoA { struct Stack { int top; }; }

namespace DemoB { struct Stack //이미 앞에서 같은 이름으로 정의하고 있음 { int last; }; }

- 이제 namespace로 감싸서 정의한 이름을 사용하는 방법을 알아봅시다.
- 먼저 네임 스페이스 이름과 스코프 연산자(::)를 사용해서 접근할 수 있습니다.

//namespace를 사용하여 이름 충돌 방지 //namespace 이름과 스코프 연산으로 사용한 예 //Program.cpp #include using namespace std;

namespace DemoA { struct Stack { int top; }; }

namespace DemoB { struct Stack //이미 앞에서 같은 이름으로 정의하고 있음 { int last; }; }

int main() { DemoA::Stack stacka; //namespcae 명과 스코프 연산자로 이름 사용 DemoB::Stack stackb;

stacka.top = -1;
stackb.last = -1;

return 0; } ``` - 그리고 특정 네임 스페이스에 있는 모든 이름을 간단히 사용할 수 있게 using 문을 사용할 수 있습니다. - using namespace 뒤에 네임 스페이스 이름을 표현하면 모두 사용할 수 있습니다.
//using namespace문을 이용하여 간단히 사용
//Program.cpp
#include <iostream>
using namespace std;

namespace DemoLib
{
    struct Stack
    {
        int top;
    };
    struct Queue
    {
        int front;
        int rear;
    };
}

//DemoLib 네임 스페이스에 이름을 사용하겠다는 구문
using namespace DemoLib;

int main()
{
    Stack s; //네임 스페이스 명과 스코프 연산없이 이름을 바로 사용
    Queue q;
    s.top = -1;
    q.front = q.rear=0;

    return 0;
}
  • 그리고 using [네임 스페이스 명]::[사용할 이름]; 을 선언하여 네임 스페이스 내부에 있는 특정 이름만 간단하게 사용할 수도 있습니다.
//using [namespace 명]::사용할 이름; 으로 특정 이름만 간단히 사용
//Program.cpp
#include <iostream>
using namespace std;

namespace DemoLib
{
    struct Stack
    {
        int top;
    };
    struct Queue
    {
        int front;
        int rear;
    };
}

//DemoLib 네임 스페이스에 Stack 이름을 사용하겠다는 구문
using DemoLib::Stack;

int main()
{
    Stack s; //네임 스페이스 명과 스코프 연산없이 이름을 바로 사용
    DemoLib::Queue q; //네임 스페이스 명과 스코프 연산과 함께 이름을 사용
    s.top = -1;
    q.front = q.rear=0;

    return 0;
}

Example

#include <iostream>


/*namespaces */

namespace mySpace
{
    class MyNewLine
    {
            std::string text;
        public:
            MyNewLine(std::string text = "\n\n\n") { this->text = text;}
            std::string toString()
            {
                return text;
            }
    };

    std::ostream & operator<<(std::ostream & out, MyNewLine & o)
    {
        return out << o.toString();
    }
    MyNewLine endl("\n\n\n\n\n\n");
}
using namespace mySpace;
int main()
{
    int a = 50;


    std::cout << "this is text: " << endl;
    return 0;
}

Example 1

#include <iostream>
#include <string>
using namespace std;

void mightGoWrong() {

	bool error1 = false;
	bool error2 = true;

	if(error1) {
		throw "Something went wrong.";
	}

	if(error2) {
		//throw string("Something else went wrong.");
		throw int ("4");
	}

}

void usesMightGoWrong() {
	mightGoWrong();
}



int main() {

	try {
		usesMightGoWrong();
	}
	catch(int e) { // the throwing the value catched and apply to "int e"
		cout << "Error code: " << e << endl;
	}
	catch(char const * e) { // character, so it save one by one alpabet in one matrix place
		cout << "Error message: " << e << endl;
	}
	catch(string &e) { // c++ does not gracefully handle situation where there are two exceptions active at the same time in string.
	    //it imeediatley terminates the program without calling any destructor
		cout << "string error message: " << e << endl;
	}

	cout << "Still running" << endl;

	return 0;
}

Comment  Read more

2. Defining Reinforcement Learning

|

What is Reinforcement Learning?

  • Humans/ AIs alike never sense the entire world/universe at once
  • We have sensors which feed signals to our brain from the environment
  • We don’t even know everything that’s going on in a room
  • Thus the Sensors limit the amount of information we get
  • The measurements we get from these sensors(e.g. sight, sound touch) make up a “state”
  • we’ll only discuss finite state spaces
  • state spaces with an infinite number of states are possible too

  • what’s the # of states?
    • if we simplify the problem so that we can keep adding x’s and o’s even after a player gets 3 in a row
    • Each Location on the board has 3 possibilities: empty, X, O
    • 9 Locations on the Board
    • therefore, # states = 3 x 3 … x3 = $ 3^9 $

Recap so far

3 Important Terms

  1. Agent: thing that sense the environment, thing we’re trying to code intelligence/learning into
  2. Environment: Real World or simulated world that the agent lives in
  3. State: Different Configurations of the environment that the agent can sense
  4. Reward
    • this is what differentiates RL from other types of ML
    • An agent not only tries to maximize its immediate reward, but future rewards as well
    • RL algorithms will find novel ways of accomplishing this
    • Alphago: learning unique/unpredictable strategies that led to beating a world champion
    • Not intuitive to humans, But Rl can figure it out

Unintended consequence(의도치 않은 결과)

  • possible danger of RL: Unintended consequence
  • Commonly repeated ideaL AI could wipe out humanity if it decides that’s the best thing for us(Ex. Minimize human Deaths)
  • AI decided that since # humans grows exponentially, that more people will die in the future, then best to destroy everyone now to minimize dying in the future
  • Lower level example : robot trying to solve a maze
  • Reasonable goal: solve the maze
  • Reward = 1 if solved, reward = 0 if not solved
  • Possible solution: move randomly until maze is solved
  • is that a good strategy? No!
  • we never told the AI that it needs to solve the maze efficiently(we always get the reward in the end)
  • what about this: reward of -1 for every step taken
  • in order to maximize total reward, must minimize # steps
  • Note: reward is always a real number

Terms

So far: agent, environment, state, reward

Next : actions

Actions are what an agent does in its environment. (Ex. agent = a 2-D video game character. Action = {up, down, left, right, jump}). we look at finite sets of actions only.

Sar Triples

We often think about (state, action, reward) as a Triple Notation : (S,A,R)

Timing

  • Timing is Important in RL
  • Every game is a Sequence of states, actions, rewards.
  • Convention(관습): Start in state S(t), take action A(t), receive a reward of R(t+1)
  • Reward always result from (s,a) we took at previous time
  • S(t), A(t) also brings us to a new state, S(t+1)
  • this also makes a triple: [S(t), A(t), S(t+1)]
  • Also Denoted as : (s,a,s’)

Summary

  • Program the agent to be intelligent
  • Agent interacts with its environment by being in a state, taking action based on that state, which brings it to a new state
  • Environment gives the agent a reward, can be +ve or -ve(but must be real number)
  • Reward is received in next state

Reference:

Artificial Intelligence Reinforcement Learning

Advance AI : Deep-Reinforcement Learning

Cutting-Edge Deep-Reinforcement Learning

Comment  Read more

19. Class-Templates & Typedef

|

Templates

  • 템플릿(template)이란 매개변수의 타입에 따라 함수나 클래스를 생성하는 메커니즘을 의미합니다.
  • 템플릿은 타입이 매개변수에 의해 표현되므로, 매개변수화 타입(parameterized type)이라고도 불립니다
  • 템플릿을 사용하면 타입마다 별도의 함수나 클래스를 만들지 않고, 여러 타입에서 동작할 수 있는 단 하나의 함수나 클래스를 작성하는 것이 가능합니다.

2. Function Template(함수 템플릿)

  • C++에서 함수 템플릿(function template)이란 함수의 일반화된 선언을 의미합니다
  • 함수 템플릿을 사용하면 같은 알고리즘을 기반으로 하면서, 서로 다른 타입에서 동작하는 함수를 한 번에 정의할 수 있습니다.
  • 임의의 타입으로 작성된 함수에 특정 타입을 매개변수로 전달하면, C++ 컴파일러는 해당 타입에 맞는 함수를 생성해 줍니다

문법 ``` template

함수의 원형

{

// 함수의 본체

}


- 위에서 정의된 타입 이름은 함수의 원형과 본체에서 임의의 타입으로 사용할 수 있습니다
- **이렇게 정의된 함수 템플릿을 호출할 때 매개변수로 int형을 전달하면, 함수의 원형과 본체에서 정의된 타입 이름은 모두 int형으로 바뀌게 됩니다.**

> 예제

template

void Swap(T& a, T& b);

int main(void)

{

int c = 2, d = 3;

cout << "c : " << c << ", d : " << d << endl;

Swap(c, d);

cout << "c : " << c << ", d : " << d << endl;



string e = "hong", f = "kim";

cout << "e : " << e << ", f : " << f << endl;

Swap(e, f);

cout << "e : " << e << ", f : " << f << endl;

return 0;

}

template

void Swap(T& a, T& b)

{

T temp;

temp = a;

a = b;

b = temp;

}


> 실행 결과

c : 2, d : 3

c : 3, d : 2

e : hong, f : kim

e : kim, f : hong


- 함수 템플릿이 각각의 타입에 대해 처음으로 호출될 때, C++ 컴파일러는 해당 타입의 인스턴스를 생성합니다.
- 이렇게 생성된 인스턴스는 해당 타입에 대해 특수화된 템플릿 함수입니다.
- 이 인스턴스는 함수 템플릿에 해당 타입이 사용될 때마다 호출됩니다.

## 3. 명시적 특수화(explicit specialization)
- C++의 함수 템플릿은 특정 타입에 대한 명시적 특수화를 제공하여, 해당 타입에 대해 특별한 동작을 정의할 수 있게 해줍니다.
- 컴파일러는 호출된 함수에 정확히 대응하는 특수화된 정의를 발견하면, 더는 템플릿을 찾지 않고 해당 정의를 사용합니다.
- 앞서 정의된 함수 템플릿 Swap의 double형에 대한 명시적 특수화는 다음과 같습니다.

> 함수 템플릿 원형

template

void Swap(T& a, T& b);

template void Swap(T& a, T& b);


> double형을 위한 명시적 특수화

template <> void Swap(double&, double&) { ... };


# [Typedef](https://wikidocs.net/419)
- typedef는 새로운 타입을 만드는 것이 아니라 타입의 새로운 별칭을 정의하는 키워드 입니다

typedef int TypedefInt; TypedefInt a;


- 이 키워드가 템플릿과 무슨 관계인지 설명하겠습니다
- typedef는 클래스 안에서 타입의 새로운 별칭을 지을 수 있습니다

class MyTypeClass { public: typedef int Type1; }; int main() { MyTypeClass a; MyTypeClass::Type1 b; return 0; }

- a는 MyTypeClass의 객체, b는 int 변수

class MyTypeClass { public: typedef int Type1; private: typedef double Type2; }; int main() { MyTypeClass a; MyTypeClass::Type1 b; MyTypeClass::Type2 c; //에러 return 0; }


class MyTypeClass { public: typedef int Type1; void f() { Type2 c; } private: typedef double Type2; }; int main() { MyTypeClass a; MyTypeClass::Type1 b; return 0; }

- typedef은 클래스 안에서도 타입의 별칭을 만들 수 있을 뿐 아니라 외부접근 제한 까지 영향을 받습니다.
- typedef는 템플릿 파라미터로 받은 데이터 타입이 필요할 때가 있습니다

#include

template class MyTempClass { public: typedef T TempType; }; int main() { MyTempClass a; MyTempClass::TempType b; MyTempClass c; MyTempClass::TempType d; return 0; }

- 이렇게 타입안에 타입의 객체를 호출 할 수 있습니다. **이렇게 템플릿 매개변수에 종속된 것을 의존 이름(dependent name)** 이라고 합니다
- 클래스안에 중첩된 경우가 있는데 **중첩 의존 이름(nested dependent name)** 이라고 합니다.
- 확히 하면 클래스 안에 TempType 이라는 타입이 있으니까 **중첩 의존 타입 이름(nested dependent type name)** 이라고 합니다.

# Exercise 1

> main.cpp

#include #include "point.h"

using namespace std; /* function templates generalization*/

void operationOnPoints();

template<typename T, typename T2> T add(T var1, T2 var2) { return var1 + var2; } /* template<> Point2D add(Point2D var1, Point2D var2) { Point2D tmp;

tmp.setX(var1.getX() + var2.getX());
tmp.setY(var1.getY() + var2.getY());

return tmp; } */ typedef Point<int> PointInt; int main() {
operationOnPoints();

//cout << add<double, double>(2, 5.6) << endl;

// cout « static_cast(6.5) << endl;

return 0; } void operationOnPoints() {  //   PointInt a(5);
Point<int*> b(49);

//cout << a.getX() << endl;
//cout << b.getX() << endl; }

> point.h

#ifndef POINT_H_INCLUDED #define POINT_H_INCLUDED #include

using namespace std;

template class Point //base, parent, superclass { protected: T x; public: Point(T =0); ~Point(); T getX(); void setX(T); }; template Point::Point(T x) { this->x = x; cout << "The constructor from the Point class has just been invoked" << endl; } template Point::~Point() { cout << "The destructor from the Point class has just been invoked" << endl; } template void Point::setX(T x) { this->x = x; cout << "Im from Point" << endl; } template T Point::getX() { return this->x; } template<> double Point::getX() { cout <<"this function will be executed only when Point" << endl; return this->x; }

template class Point<K*> { public: Point(K a=0) { cout << "you can't use pointers here"; } };

template class Point2D : public Point //derived, child, subclass { protected: T y; public: Point2D(T =0, T =0); ~Point2D(); T getY() { return y; } void setY(T); void setX(T); void setXY(T, T); Point2D operator+(Point2D);

}; template Point2D::Point2D(T x, T y) : Point(x) { this->y = y; cout << "The constructor from the Point2D class has just been invoked" << endl; } template Point2D::~Point2D() { cout << "The destructor from the Point2D class has just been invoked" << endl; } template void Point2D::setY(T y) { this->y = y; } template void Point2D::setXY(T x, T y) { setX(x); setY(y); } template void Point2D::setX(T x) { this->x = x; cout << "Im from Point2D" << endl; } template Point2D Point2D::operator+(Point2D o) { Point2D tmp;

tmp.setX(this->getX() + o.getX());
tmp.setY(this->getY() + o.getY());

return tmp; } /* class Point3D : public Point2D {

}; */

template<> class Point { public: Point(char a=0) { cout << "this is from Point";} }; /* class Point2D : public Point everything what is inside Point (excluding constructor and destructor) will be in Point2D private - CANNOT ACCESS protected - protected public - public

class Point2D : protected Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - protected
public - protected


class Point2D : private Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - private
public - private

*/ #endif // POINT_H_INCLUDED


# Exercise 2

> main.cpp

#include #include "point.h"

using namespace std; /* function templates generalization*/

void operationOnPoints();

template<typename T, typename T2> T add(T var1, T2 var2) { return var1 + var2; } /* template<> Point2D add(Point2D var1, Point2D var2) { Point2D tmp;

tmp.setX(var1.getX() + var2.getX());
tmp.setY(var1.getY() + var2.getY());

return tmp; } */ int main() {
operationOnPoints();

//cout << add<double, double>(2, 5.6) << endl;

// cout « static_cast(6.5) << endl;

return 0; } void operationOnPoints() {
Point2D p1(10, 67);
Point2D p2(50, 3); // 60,70

Point2D sum = add(p1,p2);

cout << sum.getX() << endl;
cout << sum.getY() << endl;

}


> point.h

#ifndef POINT_H_INCLUDED #define POINT_H_INCLUDED

class Point //base, parent, superclass { protected: int x; public: Point(int =0); ~Point(); int getX() { return x; } void setX(int); }; class Point2D : public Point //derived, child, subclass { protected: int y; public: Point2D(int =0, int =0); ~Point2D(); int getY() { return y; } void setY(int); void setX(int); void setXY(int, int); Point2D operator+(Point2D);

}; class Point3D : public Point2D {

};

/* class Point2D : public Point everything what is inside Point (excluding constructor and destructor) will be in Point2D private - CANNOT ACCESS protected - protected public - public

class Point2D : protected Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - protected
public - protected


class Point2D : private Point
everything what is inside Point (excluding constructor and destructor) will be in Point2D
private - CANNOT ACCESS
protected - private
public - private

*/ #endif // POINT_H_INCLUDED


> point.cpp

#include #include "point.h"

using namespace std;

Point::Point(int x) { this->x = x; cout « “The constructor from the Point class has just been invoked” « endl; } Point::~Point() { cout « “The destructor from the Point class has just been invoked” « endl; } void Point::setX(int x) { this->x = x; cout « “Im from Point” « endl; }

Point2D::Point2D(int x, int y) : Point(x) { this->y = y; cout « “The constructor from the Point2D class has just been invoked” « endl; } Point2D::~Point2D() { cout « “The destructor from the Point2D class has just been invoked” « endl; }

void Point2D::setY(int y) { this->y = y; } void Point2D::setXY(int x, int y) { setX(x); setY(y); } void Point2D::setX(int x) { this->x = x; cout « “Im from Point2D” « endl; } Point2D Point2D::operator+(Point2D o) { Point2D tmp;

tmp.setX(this->getX() + o.getX());
tmp.setY(this->getY() + o.getY());

return tmp; } ```

Comment  Read more

1. Reinforcement Learning Introduction

|

What is Reinforcement Learning?

There are 3 big part in AI

  • Supervised Learning (i.e. Spam Detection, Image Classification)
  • Unsupervised Learning(i.e Topic Modeling Web Pages, Clustering Genetic Sequences)
  • Reinforcement Learning(i.e Tic-Tac-Toe,Go,Chess, Walking, Super mario, Doom, Starcraft)

1. Supervised/Unsupervised Interfaces

  • as we know about ML Theory and Function
    class SupervisedModel:
    def fit(X,y):
    def predict(x):
    
    class UnsupervisedModel:
    def fit(x):
    def transform(x): #(e.g cluster assignment)
    
  • common theme is “training data”
  • input data: X(N x D Matrix)
  • Tragets: Y (N x 1 vector)
  • “all data is the same”
  • Format doesn’t change whether you’re in biology, finance, economics, etc.
  • fits neatly into one library: scikit-Learn
  • “simplistic”, but still useful:
    • Face Detection
    • Speech Recognition

2. Reinforcement Learning

  • Not just a static table of data
  • An agent interacts with the world(environment)
  • Can be simulated or real(E.g Vacuum robot)
  • Data comes from sensors
    • Cameras, Microphones, GPS, accelerometer
  • Continuous stream of data
    • Consider past and future
  • RL agent is “thing” with a lifetime
    • At each step, decide what to do
  • An (un)supervised model is just a static object -> input -> output

3. isn’t it still supervised learning?

  • X can represent the state i’m in, Y represent the Target (ideal action to perform in that state)
    • state = sensor recording from self-driving car
    • state = Video Game ScreenShot
    • state = Chess Board Positions
  • Yes it is, but for example, consider GO: $ N = 8 * 10^100 $
  • ImageNet, the image Classification benchmark, has $ N=10^6 $ images
    • Go is 94 orders of magnitude larger
    • Takes ~1 day with good hardware
  • 1 order of magnitude Larger -> 10 days
  • 2 order of magnitude Larger -> 100 days

4. Rewards

  • sometimes you’ll see reference to psychology; RL has been used to model animal behavior
  • RL agent’s goal is in the future
    • in contrast, a supervised model simply tried to get good accuracy / minimized cost on current input
  • Feedback Signals(Rewards) come from the environment (i.e the agent experiences them)

5. Rewards vs Targets

  • you might think of supervised Targets/labels as something like rewards. but these handmade labels are coded by humans - they do not come from environment
  • Supervised inputs/targets are just database tables
  • Supervised models instantly know if it is wrong/right, because inputs + targets are provided simultaneously
  • RL is dynamic - if an agent solves a maze, it only know its decisions were correct if it eventually solves the maze

6. On Unusual or Unexpected Strategies of RL

  • Goal of AlphaGO is to win Go, and the goal of a video game agent is high score/live as long as possible
  • what is the goal of an animal/human?
  • Evolutionary psychologists believe in the “selfish Gene” Theory
    • Rechard Dawkins - The Selfish Gene
  • Genes simply want to make more of themselves
  • We humans(conscious living beings) are totally unaware of this
  • we can’t ask our genes how they feel
  • we are simply a vessel for our genes’ proliferation(급증)
  • is consciousness just an illusion?
  • Disconnect between what we think we want vs “true goal”

  • Like Alphago, we’ve found roundabout and unlikely ways of achieving our Goal
  • The action taken doesn’t necessarily have to have an obvious / explicit relationship to the Goal
  • we might desire riches/money -but why? Maybe natural selection or leads to better health and social status. there are no laws physics which govern riches and gene replication
  • it’s a novel solution to the problem
  • AI can also find such strange or unusual ways to achieve a goal
  • we can replace “getting rich” with any trait(특성) we want
    • being healthy and strong
    • Having strong analytical skills
  • That’s a sociologist(사회학자)’s job
  • Our interest lies in the fact that there are multiple novel strangies of achieving the same goal(gene replication)
  • What is considered a good strategy can fluctuate
  • Ex. Sugar:
    • our brain runs on sugar, it gives us energy
    • today, it causes disease and death
  • Thus, a Strategy that seems good right now may not be globally optimal

7. Speed of Learning and Adaption

Comment  Read more

18. Library 연습문제

|

Exercise

main.cpp

#include <iostream>
#include <conio.h>
#include <cstdlib>
#include "library.h"
#include "book.h"
#include "user.h"

using namespace std;


int main()
{
    const Book book1("Arkadiusz Wlodarczyk", "C++ course", 2009);
    const Book book2("Wioletta Kozik", "JAVA course", 2016);
    const Book book3("Adrian Szuszkiewicz", "C# course", 2002);
    const Book book4 = book3;
    const Book book5 = book3;
    const Book book6 = book3;

    Library library(5);
    Librarian librarian("Foo", "Bar", 5);
    Borrower borrower("Edek", "Czytacz", 5);

    library.addBook(book1);
    library.addBook(book2);
    library.addBook(book3);
    library.addBook(book4);
    library.addBook(book6);

    int position;
    char choice;

    while (true)
    {
        library.showBooks();
        borrower.showBooks();
        cout << "Would you like to Borrow - B/b or Return - R/r: ";
		cin >> choice;

        switch(choice)
        {
        case 'b':
        case 'B':
            {
                cout << "Which book would you like to rent, POSITION IN LIBRARY: ";
                cin >> position;
                librarian.lendBook(library, borrower, position);
                break;
            }
        case 'r':
        case 'R':
            {
                cout << "Which book would you like to return, POSITION IN USER: ";
                cin >> position;
                borrower.returnBook(library, position);
                break;
            }
		default:
			break;
        }
        system("cls");
    }
    return 0;
}

library.h

#ifndef LIBRARY_H_INCLUDED
#define LIBRARY_H_INCLUDED

#include "book.h"
#include "user.h"

class Library
{
    private:
        int currentAmountOfBooks;
        int maxAmountOfBooks;
        Book* books;

    public:
        void addBook(const Book&);
        Book& getBook(int);
        void showBooks();

        friend void Librarian::lendBook(Library&, Borrower&, int);

        Library(int);
        ~Library();
};


#endif // LIBRARY_H_INCLUDED

book.h

#ifndef BOOK_H_INCLUDED
#define BOOK_H_INCLUDED

#include <iostream>

class Book
{
    private:
        std::string title;
        std::string author;
        int publicationYear;
        int bookId;

    public:
        static int numberOfBooks;

        std::string getTitle() const;
        std::string getAuthor() const;
        int getPublicationYear() const;
        int getBookId() const;

        Book(const Book&);
        Book(std::string, std::string, int);
        Book();
        ~Book();
};


#endif // BOOK_H_INCLUDED

user.h

#ifndef USER_H_INCLUDED
#define USER_H_INCLUDED
#include <string>
#include "book.h"

class Library;

class User
{
protected:
    std::string name;
    std::string lastName;

public:
    std::string getName();
    std::string getLastName();
    User(std::string, std::string);
};

class Borrower: public User
{
protected:
    friend class Librarian;
    int userAmountOfBooks;
    int maxAmountOfBooks;
    Book* booksInPossesion;

public:
    Borrower(std::string, std::string, int);

    ~Borrower();
    Borrower(const Borrower&) = delete;
    Borrower& operator= (const Borrower&) = delete;

    void returnBook(Library&, int);
    Book& getBook(int id);
    void showBooks();
};

class Librarian: public Borrower
{

public:
    Librarian(std::string, std::string, int);
    void lendBook(Library&, Borrower&, int);
};


#endif // USER_H_INCLUDED

book.cpp

#include "book.h"

int Book::numberOfBooks = 0;

std::string Book::getTitle() const
{
    return this->title;
}

std::string Book::getAuthor() const
{
    return this->author;
}

int Book::getPublicationYear() const
{
    return this->publicationYear;
}

int Book::getBookId() const
{
    return this->bookId;
}

Book::Book(const Book& bookToCopy)
{
    this->title = bookToCopy.getTitle();
    this->author = bookToCopy.getAuthor();
    this->publicationYear = bookToCopy.getPublicationYear();
    this->bookId = Book::numberOfBooks++;
}

Book::Book(std::string author, std::string title, int publicationYear)
{
    this->author = author;
    this->title = title;
    this->publicationYear = publicationYear;
    this->bookId = numberOfBooks++;
}

Book::Book()
{

}

Book::~Book()
{

}

library.cpp

#include "library.h"


void Library::addBook(const Book& book)
{
    if (currentAmountOfBooks < maxAmountOfBooks)
    {
        this->books[currentAmountOfBooks] = book;
        this->currentAmountOfBooks++;
    }
    else
    {

    }
}

Book& Library::getBook(int position)
{
    if (position < currentAmountOfBooks)
    {
        return books[position];
    }
    else
    {
        return books[0];
    }
}

void Library::showBooks()
{
    std::cout << "LIBRARY BOOKS: " << std::endl;
    for (int i = 0; i < currentAmountOfBooks; i++)
    {
        std::cout << "BOOK ID: " << getBook(i).getBookId() << "  ";
        std::cout << "POSITION IN LIBRARY: " << i << "  ";
        std::cout << "Author: " << getBook(i).getAuthor() << "  ";
        std::cout << "Title: " << getBook(i).getTitle() << "  ";
        std::cout << "Publication Year: " << getBook(i).getPublicationYear() << std::endl;
    }
    std::cout << std::endl;
}

Library::Library(int maxAmountOfBooks)
{
    this->currentAmountOfBooks = 0;
    this->maxAmountOfBooks = maxAmountOfBooks;
    this->books = new Book[maxAmountOfBooks];
}

Library::~Library()
{
    delete[] books;
}

user.cpp

#include "user.h"

#include "library.h"

std::string User::getName()
{
    return this->name;
}

std::string User::getLastName()
{
    return this->lastName;
}

User::User(std::string name, std::string lastName)
{
    this->name = name;
    this->lastName = lastName;
}

Borrower::Borrower(std::string name, std::string lastName, int maxAmountOfBooks)
        : User (name, lastName)
{
    this->userAmountOfBooks = 0;
    this->maxAmountOfBooks = maxAmountOfBooks;
    booksInPossesion = new Book[maxAmountOfBooks];
}

Borrower::~Borrower()
{
    delete[] booksInPossesion;
}

void Borrower::returnBook(Library& libraryToReturnTo, int position)
{
    if (position < this->userAmountOfBooks && this->userAmountOfBooks > 0)
    {
        libraryToReturnTo.addBook(booksInPossesion[position]);

        for(int i = 0; i < maxAmountOfBooks-1; i++)
        {
            if (i >= position)
                booksInPossesion[i] = booksInPossesion[i+1];
        }
        this->userAmountOfBooks--;
    }
    else
    {
    }
}

Book& Borrower::getBook(int position)
{
    if (position < this->userAmountOfBooks)
    {
        return booksInPossesion[position];
    }
    else
    {
        return booksInPossesion[0];
    }
}

void Borrower::showBooks()
{
    std::cout << getName() << " " << getLastName() << " BOOKS: " << std::endl;
    for (int i = 0; i < userAmountOfBooks; i++)
    {
        std::cout << "BOOK ID: " << getBook(i).getBookId() << "  ";
        std::cout << "POSITION IN USER: " << i << "  ";
        std::cout << "Author: " << getBook(i).getAuthor() << "  ";
        std::cout << "Title: " << getBook(i).getTitle() << "  ";
        std::cout << "Publication Year: " << getBook(i).getPublicationYear() << std::endl;
    }
    std::cout << std::endl;
}

Librarian::Librarian(std::string name, std::string lastName, int maxAmountOfBooks)
        : Borrower(name, lastName, maxAmountOfBooks)
    {}

void Librarian::lendBook(Library& libraryToLendFrom, Borrower& personToLendTo, int position)
{
    if (libraryToLendFrom.currentAmountOfBooks > 0)
    {
        if (personToLendTo.userAmountOfBooks < personToLendTo.maxAmountOfBooks && position < libraryToLendFrom.currentAmountOfBooks)
        {
            personToLendTo.booksInPossesion[personToLendTo.userAmountOfBooks] = libraryToLendFrom.books[position];

            for(int i = 0; i < libraryToLendFrom.maxAmountOfBooks-1; i++)
            {
                if (i >= position)
                    libraryToLendFrom.books[i] = libraryToLendFrom.books[i+1];
            }

            libraryToLendFrom.currentAmountOfBooks--;
            personToLendTo.userAmountOfBooks++;
        }
        else
        {
        }
    }
    else
    {
    }
}

Comment  Read more