#include <iostream>
#include <string>
#include <cmath>
#include <atomic>
#include <cstdlib>
#include <ctime>
using namespace std;

namespace ProtocolOmega{
	template<class T>
	class ServerNode{
		public:
			T x,y,z;
			ServerNode(T startX=0,T startY=0,T startZ=0):x(startX),y(startY),z(startZ){}
			T getManhattanDistance(ServerNode<T> target){
				return abs(x-target.x)+abs(y-target.y)+abs(z-target.z);
			}
	};
	class Engineer{
		private:
			string name;
			int maxCoolantTanks;
			int* coolantReserves;
			Engineer(){}
		public:
			Engineer(string empName,int tanks){
				name=empName;
				maxCoolantTanks=tanks;
				coolantReserves=new int[maxCoolantTanks];
				for(int i=0;i<maxCoolantTanks;i++){
					coolantReserves[i]=1000;
				}
			}
			~Engineer(){
				delete[] coolantReserves;
			}
			inline string getName(){
				return name;
			}
			int useCoolant(){
				for(int i=0;i<maxCoolantTanks;i++){
					if(coolantReserves[i]>0){
						int coolingPower=coolantReserves[i];
						coolantReserves[i]=0;
						return coolingPower;
					}
				}
				return 0;
			}
			int getRemainingTanks(){
				int count=0;
				for(int i=0;i<maxCoolantTanks;i++){
					if(coolantReserves[i]>0) count++;
				}
				return count;
			}
	};

	class AICore{
		private:
			AICore(){
				cout<<"\n[AI VOICE]: Protocol Omega active. The Core is being sheilded."<<endl;
			}
			AICore(const AICore&)=delete;
			AICore& operator=(const AICore&)=delete;
			static AICore* instance;
		public:
			volatile double coreTemperature=3000.0;
			atomic<int> criticalErrors{0};
			static AICore* getInstance(){
				if(instance==nullptr){
					instance=new AICore();
				}
				return instance;
			}
			void increaseTemp(double amount){
				coreTemperature+=amount;
			}
			bool applyCoolant(int coolingPower){
				if(coolingPower>0){
					coreTemperature-=(coolingPower*1.5);
					cout<<"  [+] Pooring coolant! Temperature decreased to "<<coreTemperature<<" C."<<endl;
					return true;
				}
				cout<<"  [-] FAILURE: There is no more coolant!"<<endl;
				return false;
			}
			bool bypassPrimeLock(int p){
				if(p<=1) return false;
				auto limit=sqrt(p);
				for(int i=2;i<=limit;i++){
					if(p%i==0) return false;
				}
				return true;
			}
			bool bypassChudnovskyLock(long answer){
				if(answer==640320){
					return true;
				}
				return false;
			}
	};

	AICore* AICore::instance=nullptr;
}

using namespace ProtocolOmega;

int main(){
	srand(time(NULL));
	cout<<"\n================================================="<<endl;
	cout<<"    [***] PROTOCOL OMEGA: REACTOR MELTDOWN [***]   "<<endl;
	cout<<"=================================================\n"<<endl;
	string pName;
	cout<<"> Enter Engineer Name: ";
	cin>>pName;
	Engineer player(pName,3);
	AICore* reactor=AICore::getInstance();
	ServerNode<int> playerPos(0,0,0);
	ServerNode<int> corePos(5,5,5);
	bool isAlive=true;
	bool coreReached=false;
	while(isAlive){
		reactor->increaseTemp(350.0+(rand()%200));
		cout<<"\n-------------------------------------------"<<endl;
		cout<<" [!] ATTENTION: Core Temperature: "<<reactor->coreTemperature<<" C"<<endl;
		cout<<" [!] Available Coolant Tanks: "<<player.getRemainingTanks()<<endl;
		if(reactor->coreTemperature>=10000.0){
			cout<<"\n[!!!] CRITICAL TEMPERATURE REACHED [!!!]"<<endl;
			cout<<"[!!!] CORE DESTRUCTION... GAME OVER."<<endl;
			break;
		}
		cout<<"-------------------------------------------"<<endl;
		cout<<" COICES:"<<endl;
		if(!coreReached){
			cout<<" 1. Advance to the Core (Requires Time/Temperature)"<<endl;
		} else{
			cout<<" 1. [LOCKED] You already reached the core."<<endl;
		}
		cout<<" 2. Aply Coolant"<<endl;
		if(coreReached){
			cout<<" 3. Attempt to Deactivate"<<endl;
		} else{
			cout<<" 3. [LOCKED] You must reach the core first."<<endl;
		}
		cout<<" 4. Abbandon Station"<<endl;
		cout<<"-------------------------------------------"<<endl;
		cout<<"> Choice: ";
		int choice;
		cin>>choice;
		switch(choice){
			case 1:{
				if(!coreReached){
					int dist=playerPos.getManhattanDistance(corePos);
					cout<<"\n[>] Distance from the core: "<<dist<<" points."<<endl;
					cout<<"[>] Moving 5 points... Time passes."<<endl;
					playerPos.x=5;
					playerPos.y=5;
					playerPos.z=5;
					coreReached=true;
					reactor->increaseTemp(800.0);
				} else{
					cout<<"\n[-] You already are in the core's room!"<<endl;
				}
				break;
			}
			case 2:{
				cout<<"\n[>] Activating cooling valves..."<<endl;
				int power=player.useCoolant();
				reactor->applyCoolant(power);
				break;
			}
			case 3:{
				if(!coreReached){
					cout<<"\n[-] You must reach the core in order to hack the system!"<<endl;
					break;
				}
				cout<<"\n[AI VOICE]: I won't let you power me down, "<<player.getName()<<"."<<endl;
				cout<<"[AI VOICE]: Activating Prime Number Encryption."<<endl;
				int primeGuess;
				cout<<"> Give a Prime Number BIGGER than 1000 to break the chain: ";
				cin>>primeGuess;
				if(primeGuess>1000&&reactor->bypassPrimeLock(primeGuess)){
					cout<<"\n   [+] Success! The first shield is down."<<endl;
					cout<<"\n[AI VOICE]: Impressive... But let's see if you can solve this."<<endl;
					cout<<"[AI VOICE]: Activating Protocol 'Pi Day'."<<endl;
					cout<<"Question: Which is the largest base term in the denominator of the Chudnovsky algorithm?\n Answer: ";
					long chudnovskyAns;
					cin>>chudnovskyAns;
					if(reactor->bypassChudnovskyLock(chudnovskyAns)){
						cout<<"\n[$$$] PASSWORD ACCEPTED. CORE STABILIZED! [$$$]"<<endl;
						cout<<"[$$$] Congratulations, you saved the station! [$$$]"<<endl;
						isAlive=false;
					} else{
						cout<<"\n[-] WRONG ANSWER. The AI locked you out!"<<endl;
						reactor->criticalErrors++;
						reactor->increaseTemp(2000.0);
					}
				} else{
					cout<<"\n   [-] FAILURE. Not a valid prime number > 1000!"<<endl;
					reactor->criticalErrors++;
					reactor->increaseTemp(1500.0);
				}
				break;
			}
			case 4:{
				cout<<"\n[>] Entered escape pod. The station exploded behind you. Coward!"<<endl;
				isAlive=false;
				break;
			}
			default:
				cout<<"\n[-] Invalid choice. Did you panick?"<<endl;
				reactor->increaseTemp(500.0);
				break;
		}
	}
	cout<<"\n[SYSTEM]: Terminating. Number of critical Errors: "<<reactor->criticalErrors<<endl;
	return 0;
}
