﻿/*
*
* Happy number
* 
* In number theory, a happy number is a number which eventually reaches 1 when replaced by the sum of the square of each digit. 
* For instance, 13 is a happy number because 1^{2}+3^{2}=10   and  1^{2}+0^{2}=1. 
* On the other hand, 4 is not a happy number because the sequence starting with 4^{2}=16 and  1^{2}+6^{2}=37 
* eventually reaches 2^{2}+0^{2}=4 , the number that started the sequence, 
* and so the process continues in an infinite cycle without ever reaching 1. 
* A number which is not happy is called sad or unhappy. 
* 
* 
* https://en.wikipedia.org/wiki/Happy_number
* 
* 
* MB
* 10.21
* 
*/


#include <iostream>     // std::cout
#include <vector>       // std::vector  
#include <algorithm>    // std::find
#include <string>       // std:to_string

using namespace std;

// rozbija liczbę na cyfry i umieszcza je w wektorze digits
void splitNumberIntoDigits(int number, vector<int>& digits);
// sprawdza czy sumy potęg poszczagólnych liczb nie powtarzają się
bool checkRepetition(int number, vector<int>& tmpNumbers);

int main()
{
    cout << "Happy number\n\n\n";

    // tablica na cyfry
    // (po rozbiciu danej liczby na cyfry)
    vector<int> digits;

    // tablica na liczby, które pojawią się w trakcie obliczeń
    // (musimy sprawdzic czy liczby sie nie powtarzają)
    vector<int> tmpNumbers;
    
    // zadana liczba 
    int number = 0;

    // pobieramy liczbę do sprawdzenia
    cout << "Podaj liczbe do sprawdzenia czy jest happy: ";
    cin >> number;

    // zmienna tymczasowa
    int tmpNumber = number;

    // pętla do obliczeń
    while (1) {
        cout << "\nNumber to check: " << tmpNumber << endl;

        // rozbijamy liczbę na cyfry, cyfry trafiają do wektora digits
        splitNumberIntoDigits(tmpNumber, digits);

        // sprawdzamy cyfry, na które została rozbita liczba
        cout << "digits:  ";
        for (int a : digits)
            cout << a;
        cout << endl;

        // czyscimy number    
        tmpNumber = 0;

        // wpisujemy do number sumę poteg poszczególnych cyfr
        for (int i = 0; i < digits.size(); i++) {
            tmpNumber += digits[i] * digits[i];
        }

        cout << "new number (the sum of the square of each digit) : " << tmpNumber << endl;

        // czyscimy tablicę digits
        digits.clear();

        // sprawdzamy czy liczba jest wesoła
        if (tmpNumber == 1) {
            cout << "number " << number << " is happy :)" << endl;
            break;
        }
        // zapisujemy liczbe do tablicy
        else {
            //sprawdzamy, czy w tablicy jest juz taka liczba
            bool isRepeating = checkRepetition(tmpNumber, tmpNumbers);
            // jesli liczba sie powtarza kończymy obliczenia
            if (isRepeating) {
                // przerywamy pętlę while
                cout << "\nnumber " << number << " is unhappy :(" << endl;
                break;
            }
            // ponieważ liczby nie ma w tablicy to mozemy ją do niej wpisać
            else {
                tmpNumbers.push_back(tmpNumber);
            }
            
        }

    }
}


void splitNumberIntoDigits(int number, vector<int>& digits) {
    // sprawdzamy ile cyfr ma liczba
    int numberOfDigits = to_string(number).length();
    cout << "numberOfDigits: " << numberOfDigits << endl;
    int mnoznik = 1;
    for (int i = 0; i < numberOfDigits; i++) {
        digits.push_back((number / mnoznik) % 10);
        mnoznik = mnoznik * 10;
    }
}

bool checkRepetition(int tmpNumber, vector<int>& tmpNumbers) {
    vector<int>::iterator it;
    it = find(tmpNumbers.begin(), tmpNumbers.end(), tmpNumber);
    if (it != tmpNumbers.end()) {
        cout << "Number " << tmpNumber << " found in tmpNumbers: " << *it << '\n';
        // wyswietlamy tymczasowe liczby z wektora tmpNumbers
        cout << "vector tmpNumbers: " << endl;    
        for (int i : tmpNumbers) {
            cout << i << " ";
        }
        return true;
    }
    else {
        cout << "Number " << tmpNumber << " not found in tmpNumbers\n";
        // wyswietlamy tymczasowe liczby z wektora tmpNumbers
        cout << "vector tmpNumbers: " << endl;       
        for (int i : tmpNumbers) {
            cout << i << " ";
        }
        return false;
    }

}