# -*- coding: utf-8 -*-
"""
Created on Fri Aug  3 12:29:48 2018

@author: SKY_SHY
"""
from functools import reduce
import os
import time

base = os.getcwd()

# Инициализация первого миллиона цифр иррациональных чисел 
# (используются мантиссы):
PI = open(os.path.join(base, 'Our_Pi.txt'), 'r').read()
EE = open(os.path.join(base, 'Our_E.txt'), 'r').read()
S2 = open(os.path.join(base, 'Our_S2.txt'), 'r').read()

MODULE = 100
XOR_NUMBERS = 3
INCREMENT = 16
IRR_NUMBER_NAME = 'pi'

class Digit():    
    """
    Класс для формирования разрядов чисел

    Attributes
    ----------
    irr_number_name : str
        Сокращённое название иррационального числа
    seed : int
        Значение посева
    init_seed : int
        Значение посева, которое было задано в начале алгоритма
    next : int
        Индекс цифры в поле `dataTempDigits`
    A : int
        Множитель линейного конгруэнтного генератора
    seek : int
        Индекс цифры в базе цифр мантиссы иррационального числа
    self.dataTempDidits : str
        Строка из цифр, из которых формируются разряды чисел
    """

    def __init__(self, irr_number_name):
        self.irr_number = self.getMantiss(irr_number_name)
        self.seed = int(str("%.21f" % time.time())[-21:]) % MODULE
        self.init_seed = self.seed
        self.next = self.seed
        self.A = INCREMENT + (self.seed // MODULE)
        self.seek = MODULE - 1
        self.dataTempDigits = self.irr_number[:MODULE]

    def getMantiss(self, irr_number_name):
        """
        Возвращает первый миллион цифр мантиссы иррац. числа
        по имени иррационального числа `irr_number_name`
        """
        if irr_number_name == 'pi':
            return PI
        elif irr_number_name == 'e':
            return EE
        elif irr_number_name == 'sqrt2':
            return S2
        else:
            print("Иррационального числа с таким именем нет" \
                  "Будет использоваться мантисса числа pi")
            return PI
    
    def generOneDigit(self, X_i):
        """
        Возвращает одну псевдослучайную цифру для 
        формирования разряда числа
        """
        self.next = (self.A * X_i + 51) % MODULE
        return self.dataTempDigits[self.next]
          
    def resetParams(self, step_seek=1):
        """
        Переопределение настроек, если на j-м генерировании 
        разряда уже использованы все цифры из первого 
        миллиона цифр мантиссы иррационального числа:
        
            * Новая пара параметров линейного конгруэнтного генератора
              множителя `A` и посева `seed`.
            * Индекс `seek` мантиссы для выбора цифры.
        Поле цифр `dataTempDigits` и индекс `seek` меняются после каждого 
        генерирования цифры.
        """
        if self.seek >= 10**6 - 1:
            #инкрементируем посев:
            self.seed +=1
            # если использовали все цифры мантиссы, устанавливаем указатель в 0:
            self.seek = 0
            if self.seed % MODULE == self.init_seed:
                self.A +=1
        else:
            self.seek += step_seek

        self.dataTempDigits = self.dataTempDigits[:self.next] \
            + self.dataTempDigits[self.next+1:]
        self.dataTempDigits += self.irr_number[self.seek]

        if self.seek == 0:
            self.next = self.seed % MODULE   
            
    def __call__(self, digCapacity):
        """
        Возвращает разряды числа, используемого в `xor`
        """
        number = ''
        for _ in range(digCapacity):
            number += self.generOneDigit(self.next)
            self.resetParams()
        return int(number)

class PRING_Generator():
    """
    Класс с реализацией генератора `based on irrational number`.
    Генерирует заданное количество `XOR_NUMBERS` чисел для
    операции `xor` в результате которой получается одно случайное 
    число

    Attributes
    ----------
    digits : list
        Экземпляры класса `Digit` с настройками генерирования 
        разрядов чисел для `xor`
    """
    def __init__(self, digits):
        self.digits = digits

    def set_seed(self, seed):
        """
        Настраивает генератор `based on irrational number` на заданную 
        последовательность через параметры линейного конгруэнтного 
        генератора в экземплярах классов `Digit`
        """
        attributes = ("A", "seed", "init_seed", "next")
        seed = seed % pow(MODULE, XOR_NUMBERS)
        for i in range(XOR_NUMBERS):

            for attr in attributes:
                value = seed // MODULE
                if attr == "A":
                    value = seed
                setattr(self.digits[i], attr, value)

            seed = seed % MODULE
            if seed < MODULE:
                seed = 0

	#ver.14
    def generateNumber(self, digCapacity=1):
        """
        Возвращает одно псевдослучайное число
        """
        numbers = list(map(lambda digit: digit(digCapacity), self.digits))
        return reduce(lambda a, b: a ^ b, numbers)
    
    def randint(self, minNumber, maxNumber, numbers=1):
        """
        Возвращает последовательность псевдослучайных чисел
        
        Принимает на вход параметры `minNumber`, `maxNumber` интервала 
        генерируемых случайных чисел [`minNumber`, `maxNumber`], 
        количество чисел numbers
        """
        assert minNumber < maxNumber, f"Начальная граница интервала minNumber={minNumber}"\
                                      f" задана больше чем maxNumber={maxNumber}"
        for i in range(XOR_NUMBERS):
            self.digits[i].resetParams(step_seek=i)
        dig_capacity = len(str(maxNumber))
        for _ in range(numbers):
            number = int(self.generateNumber(dig_capacity))
			
            while number < minNumber or number > maxNumber:
                number = int(self.generateNumber(dig_capacity))
            else:
                yield number

digits = [Digit(IRR_NUMBER_NAME) 
          for _ in range(XOR_NUMBERS)]
irandom = PRING_Generator(digits)
# -*- coding: utf-8 -*-
"""
Created on Fri Aug  3 12:29:48 2018

@author: SKY_SHY
"""
from functools import reduce
import os
import time

base = os.getcwd()

# Инициализация первого миллиона цифр иррациональных чисел 
# (используются мантиссы):
PI = open(os.path.join(base, 'Our_Pi.txt'), 'r').read()
EE = open(os.path.join(base, 'Our_E.txt'), 'r').read()
S2 = open(os.path.join(base, 'Our_S2.txt'), 'r').read()

MODULE = 100
XOR_NUMBERS = 3
INCREMENT = 16
IRR_NUMBER_NAME = 'pi'

class Digit():    
    """
    Класс для формирования разрядов чисел

    Attributes
    ----------
    irr_number_name : str
        Сокращённое название иррационального числа
    seed : int
        Значение посева
    init_seed : int
        Значение посева, которое было задано в начале алгоритма
    next : int
        Индекс цифры в поле `dataTempDigits`
    A : int
        Множитель линейного конгруэнтного генератора
    seek : int
        Индекс цифры в базе цифр мантиссы иррационального числа
    self.dataTempDidits : str
        Строка из цифр, из которых формируются разряды чисел
    """

    def __init__(self, irr_number_name):
        self.irr_number = self.getMantiss(irr_number_name)
        self.seed = int(str("%.21f" % time.time())[-21:]) % MODULE
        self.init_seed = self.seed
        self.next = self.seed
        self.A = INCREMENT + (self.seed // MODULE)
        self.seek = MODULE - 1
        self.dataTempDigits = self.irr_number[:MODULE]

    def getMantiss(self, irr_number_name):
        """
        Возвращает первый миллион цифр мантиссы иррац. числа
        по имени иррационального числа `irr_number_name`
        """
        if irr_number_name == 'pi':
            return PI
        elif irr_number_name == 'e':
            return EE
        elif irr_number_name == 'sqrt2':
            return S2
        else:
            print("Иррационального числа с таким именем нет" \
                  "Будет использоваться мантисса числа pi")
            return PI
    
    def generOneDigit(self, X_i):
        """
        Возвращает одну псевдослучайную цифру для 
        формирования разряда числа
        """
        self.next = (self.A * X_i + 51) % MODULE
        return self.dataTempDigits[self.next]
          
    def resetParams(self, step_seek=1):
        """
        Переопределение настроек, если на j-м генерировании 
        разряда уже использованы все цифры из первого 
        миллиона цифр мантиссы иррационального числа:
        
            * Новая пара параметров линейного конгруэнтного генератора
              множителя `A` и посева `seed`.
            * Индекс `seek` мантиссы для выбора цифры.
        Поле цифр `dataTempDigits` и индекс `seek` меняются после каждого 
        генерирования цифры.
        """
        if self.seek >= 10**6 - 1:
            #инкрементируем посев:
            self.seed +=1
            # если использовали все цифры мантиссы, устанавливаем указатель в 0:
            self.seek = 0
            if self.seed % MODULE == self.init_seed:
                self.A +=1
        else:
            self.seek += step_seek

        self.dataTempDigits = self.dataTempDigits[:self.next] \
            + self.dataTempDigits[self.next+1:]
        self.dataTempDigits += self.irr_number[self.seek]

        if self.seek == 0:
            self.next = self.seed % MODULE   
            
    def __call__(self, digCapacity):
        """
        Возвращает разряды числа, используемого в `xor`
        """
        number = ''
        for _ in range(digCapacity):
            number += self.generOneDigit(self.next)
            self.resetParams()
        return int(number)

class PRING_Generator():
    """
    Класс с реализацией генератора `based on irrational number`.
    Генерирует заданное количество `XOR_NUMBERS` чисел для
    операции `xor` в результате которой получается одно случайное 
    число

    Attributes
    ----------
    digits : list
        Экземпляры класса `Digit` с настройками генерирования 
        разрядов чисел для `xor`
    """
    def __init__(self, digits):
        self.digits = digits

    def set_seed(self, seed):
        """
        Настраивает генератор `based on irrational number` на заданную 
        последовательность через параметры линейного конгруэнтного 
        генератора в экземплярах классов `Digit`
        """
        attributes = ("A", "seed", "init_seed", "next")
        seed = seed % pow(MODULE, XOR_NUMBERS)
        for i in range(XOR_NUMBERS):

            for attr in attributes:
                value = seed // MODULE
                if attr == "A":
                    value = seed
                setattr(self.digits[i], attr, value)

            seed = seed % MODULE
            if seed < MODULE:
                seed = 0

	#ver.14
    def generateNumber(self, digCapacity=1):
        """
        Возвращает одно псевдослучайное число
        """
        numbers = list(map(lambda digit: digit(digCapacity), self.digits))
        return reduce(lambda a, b: a ^ b, numbers)
    
    def randint(self, minNumber, maxNumber, numbers=1):
        """
        Возвращает последовательность псевдослучайных чисел
        
        Принимает на вход параметры `minNumber`, `maxNumber` интервала 
        генерируемых случайных чисел [`minNumber`, `maxNumber`], 
        количество чисел numbers
        """
        assert minNumber < maxNumber, f"Начальная граница интервала minNumber={minNumber}"\
                                      f" задана больше чем maxNumber={maxNumber}"
        for i in range(XOR_NUMBERS):
            self.digits[i].resetParams(step_seek=i)
        dig_capacity = len(str(maxNumber))
        for _ in range(numbers):
            number = int(self.generateNumber(dig_capacity))
			
            while number < minNumber or number > maxNumber:
                number = int(self.generateNumber(dig_capacity))
            else:
                yield number

digits = [Digit(IRR_NUMBER_NAME) 
          for _ in range(XOR_NUMBERS)]
irandom = PRING_Generator(digits)
# -*- coding: utf-8 -*- Created on Fri Aug  3 12:29:48 2018  @author: SKY_SHY # Инициализация первого миллиона цифр иррациональных чисел # (используются мантиссы): Класс для формирования разрядов чисел      Attributes     ----------     irr_number_name : str         Сокращённое название иррационального числа     seed : int         Значение посева     init_seed : int         Значение посева, которое было задано в начале алгоритма     next : int         Индекс цифры в поле `dataTempDigits`     A : int         Множитель линейного конгруэнтного генератора     seek : int         Индекс цифры в базе цифр мантиссы иррационального числа     self.dataTempDidits : str         Строка из цифр, из которых формируются разряды чисел Возвращает первый миллион цифр мантиссы иррац. числа         по имени иррационального числа `irr_number_name` Возвращает одну псевдослучайную цифру для          формирования разряда числа Переопределение настроек, если на j-м генерировании          разряда уже использованы все цифры из первого          миллиона цифр мантиссы иррационального числа:                      * Новая пара параметров линейного конгруэнтного генератора               множителя `A` и посева `seed`.             * Индекс `seek` мантиссы для выбора цифры.         Поле цифр `dataTempDigits` и индекс `seek` меняются после каждого          генерирования цифры. #инкрементируем посев: # если использовали все цифры мантиссы, устанавливаем указатель в 0: Возвращает разряды числа, используемого в `xor` Класс с реализацией генератора `based on irrational number`.     Генерирует заданное количество `XOR_NUMBERS` чисел для     операции `xor` в результате которой получается одно случайное      число      Attributes     ----------     digits : list         Экземпляры класса `Digit` с настройками генерирования          разрядов чисел для `xor` Настраивает генератор `based on irrational number` на заданную          последовательность через параметры линейного конгруэнтного          генератора в экземплярах классов `Digit` #ver.14 Возвращает одно псевдослучайное число Возвращает последовательность псевдослучайных чисел                  Принимает на вход параметры `minNumber`, `maxNumber` интервала          генерируемых случайных чисел [`minNumber`, `maxNumber`],          количество чисел numbers