// module1.code




void podgotovka(var SYS){
	SYS->functions=((map)({}));
	if(isset(SYS->filename))filename=SYS->filename;else filename=getThisFileName();
	params={"toString","priznakfinish","control","compare","correctir"};
	i=0;
	while(i<params.size()){
		if(SYS->isset(params[i]))SYS->functions[params[i]]=getFunction((*SYS)[params[i]],filename);
		++i;
		}
	SYS->functions.methods={};
	if(isset(SYS->methods)){
		i=0;
		while(i<SYS->methods.length()){
			SYS->functions.methods.push(getFunction(SYS->methods[i],filename));
			++i;
			}
		}
	SYS->functions.parameters={};
	if(isset(SYS->parameters)){
		i=0;
		while(i<SYS->parameters.length()){
			SYS->functions.parameters.push(getFunction(SYS->parameters[i],filename));
			++i;
			}
		}
	if(!isset(SYS->pirmision))SYS->pirmision=((map)0);
	if(!SYS->pirmision.isset("prosmotr-new"))SYS->pirmision["prosmotr-new"]=0;
}



var poisk(var SYS){
	if(!isset(SYS->functions))podgotovka(SYS);
	b=1;
	if(isset(SYS->namemodele)){
		str=SYS->namemodele;
		if(isset(SYS->ver))str+=SYS->ver;
		b=include(WAY+"\\code\\Deployment\\Buffer\\"+str+".txt");
		}
	if(!b){
		LoadSystem(SYS);
		k=SYS->k;
		if(SYS->good)return 1;
		if(isset(SYS->filename)){
			s=SYS->filename;
			s=s.substr(WAY.length()+1);
			if(isset(SYS->predoxranitelfilename)){if(s!=SYS->predoxranitelfilename){
				trace("Поменяйте имя модели 'namemodele' или версию 'ver'.");
				return 0;
				}}
			}
		}else {
		SYS->m={SYS->starter};
		SYS->timezatratil=0;
		SYS->G=((graf)0);
		SYS->G.MARKER(0,0,"",0,"START");
		k=0;
		}
	good=1;
	timeLabel=starttime=getTime();
	while(k<SYS->m.size()){
		X= &SYS->m[k];
		if(isset(SYS->functions.control)){
			f=SYS->functions.control;
			if(!f.run(X)){
				SYS->G.MARKER(k,0,"",0,"END");
				++k;
				continue;
				}
			}
		i=0;
		while(i<SYS->functions.methods.size()){
			methodX=SYS->functions.parameters[i];
			args=methodX.run(X);
			methodX=SYS->functions.methods[i];
			j=0;
			while(j<args.size()){
				Y=( *X);
				methodX.run1({&Y}+args[j]);
				if(addUnitX(SYS,&Y,k))break 3;
				++j;
				}
			++i;
			}
		++k;
		if(isset(SYS->timeLimitForSave)){if(getTime()-timeLabel>=SYS->timeLimitForSave){
			SYS->k=k;
			SYS->good=0;
			SYS->timezatratil+=getTime()-timeLabel;
			UnloadSystem(SYS);
			timeLabel=getTime();
			trace("Текущее состояние системы разворачивания сохранено.");
			}}
		if(isset(SYS->timeborder));else continue;
		if(getTime()-starttime>=SYS->timeborder);else continue;
		good=0;
		break;
		}
	SYS->k=k;
	SYS->good=good;
	SYS->timezatratil+=getTime()-timeLabel;
	UnloadSystem(SYS);
	if(good)SYS->tolkochto=1;
	return good;
}



string getAuthorForm(var X){
	t=typeof((*X));
	if(t=="map"){
		s="{";
		keys=X->getKeys();
		i=0;
		while(i<keys.size()){
			if(i)s+=",";
			s+=keys[i];
			s+=":";
			s+=getAuthorForm(&(*X)[keys[i]]);
			++i;
			}
		s+="}";
		return s;
		}
	if(t=="vector"){
		s="{";
		i=0;
		while(i<X->size()){
			if(i)s+=",";
			s+=getAuthorForm(&(*X)[i]);
			++i;
			}
		s+="}";
		return s;
		}
	if(t=="string")return X->export();
	return (*X);
}



var printer(var SYS){
	R="";
	fine={};
	nets=SYS->G.getMARKER(# ,0,"",0,"FINISH");
	i=0;
	for(;i<nets.size();++i)fine.push(nets[i][0]);
	zapret={};
	nets=SYS->G.getMARKER(# ,0,"",0,"END");
	t=0;
	for(;t<nets.size();++t)zapret.push(nets[t][0]);
	n=((string)SYS->m.size()).length();
	i=0;
	for(;i<SYS->m.size();++i){
		str=((string)i);
		while(str.length()<n)str="0"+str;
		str+=") ";
		if(isset(SYS->functions.toString))str+=SYS->functions.toString.run(&SYS->m[i]);else str+=getAuthorForm(&SYS->m[i]);
		str+=" ";
		if(!i)str+="старт ";
		if(fine.indexOf(i)>=0)str+="финиш ";
		if(zapret.indexOf(i)>=0)str+="недопустимо ";
		nets=SYS->G.getNET(i,0,"",1,# );
		go={};
		t=0;
		for(;t<nets.size();++t)go.push(nets[t][0]);
		if(go.size())str+=go.export();
		str+="\n";
		R+=str;
		}
	return R;
}



bool addUnitX(var SYS,var X,var n){
	i=0;
	for(;i<SYS->m.size();++i){
		if(isset(SYS->functions.compare)){
			if(SYS->functions.compare.run(&SYS->m[i],X))break;
			}else {if(SYS->m[i]==( *X))break;}
		}
	okadd=0;
	if(i==SYS->m.size()){
		SYS->m.push((*X));
		if(SYS->pirmision["prosmotr-new"]){
			ok=0;
			if(isset(SYS->functions.control)){
				f=SYS->functions.control;
				if(!f.run(X))ok=1;
				}
			trace(getAuthorForm(X)+(ok?" тупик":""));
			}
		okadd=1;
		}else {
		if(!SYS->G.getNET(n,0,"",1,i).size())okadd=1;
		}
	if(okadd)SYS->G.NET(n,0,"",1,i);
	b=0;
	if(isset(SYS->functions.priznakfinish)){if(b=SYS->functions.priznakfinish.run(X)){
		SYS->G.MARKER(i,0,"",0,"FINISH");
		if(b){if(isset(SYS->firstFineEndOK)){if(SYS->firstFineEndOK)return 1;}}
		}}
	return 0;
}



void FindWAYS(var SYS,var NxFinish){
	if(isset(SYS->tableWAY))return;
	G= &SYS->G;
	a=G->getMARKER(# ,0,"",0,"START")[0][0];
	b={};
	if(isset(NxFinish)){
		if(typeof(NxFinish)=="vector")b=NxFinish;else b={NxFinish};
		}else {
		bb=G->getMARKER(# ,0,"",0,"FINISH");
		i=0;
		for(;i<bb.size();++i)b.push(bb[i][0]);
		}
	if(!b.size())return;
	q=G->getUnits();
	m=((map)0);
	i=0;
	for(;i<q.size();++i)m[q[i]]=0;
	m[a]=n=1;
	xb= -1;
	while(1){
		i=0;
		for(;i<b.size();++i)if(m[b[i]]){
			xb=b[i];
			break 2;
			};
		ok=0;
		i=0;
		for(;i<q.size();++i)if(m[q[i]]==n){
			W=G->getNET(q[i],0,# ,1,# );
			t=0;
			for(;t<W.size();++t){
				k=W[t][1];
				if(!m[k]){
					m[k]=n+1;
					ok=1;
					}
				}
			};
		++n;
		if(!ok)break;
		}
	n=m[xb];
	if(!n)return;
	m2=((map)0);
	i=0;
	for(;i<b.size();++i)m2[b[i]]=n;
	while(n>1){
		i=0;
		for(;i<q.size();++i)if(m[q[i]]==n&&m2.isset(q[i])){
			W=G->getNET(# ,0,# ,1,q[i]);
			t=0;
			for(;t<W.size();++t){
				k=W[t][0];
				if(m[k]==n-1)m2[k]=n-1;
				}
			};
		--n;
		}
	SYS->tableWAY=m2;
}



var DefineRandomWAY(var SYS){
	if(!isset(SYS->tableWAY))return;
	G= &SYS->G;
	table= &SYS->tableWAY;
	q=SYS->tableWAY.getKeys();
	m={};
	pos=n=1;
	i=0;
	for(;i<q.size();++i)if((*table)[q[i]]==n){
		n=q[i];
		break;
		};
	while(1){
		m.push(n);
		++pos;
		next={};
		W=G->getNET(n,0,# ,1,# );
		t=0;
		for(;t<W.size();++t){
			k=W[t][1];
			if(isset((*table)[k])){if((*table)[k]==pos)next.push(k);}
			}
		if(!next.size())break;
		x=rand()%next.size();
		n=next[x];
		}
	return m;
}



var GetAllWaysForUnitN(var SYS,var NxFinish){
	FindWAYS(SYS,NxFinish);
	if(!isset(SYS->tableWAY))return;
	G= &SYS->G;
	table= &SYS->tableWAY;
	n=0;
	ways={};
	SubGetAllWaysForUnitN(&ways,G,table,{},n);
	return ways;
}



void SubGetAllWaysForUnitN(var ways,var G,var table,var way,var n){
	way.push(n);
	pos=way.size()+1;
	next={};
	W=G->getNET(n,0,# ,1,# );
	t=0;
	for(;t<W.size();++t){
		k=W[t][1];
		if(isset((*table)[k])){if((*table)[k]==pos)next.push(k);}
		}
	if(!next.size()){
		ways->push(way);
		return;
		}
	t=0;
	for(;t<next.size();++t)SubGetAllWaysForUnitN(ways,G,table,way,next[t]);
}



var printWAY(var SYS,var way){
	ok=1;
	if(!isset(way))ok=0;
	if(ok){if(!way.size())ok=0;}
	if(!ok)return "Нет пути трансформации заданной системы.";
	f=0;
	fzadan=0;
	if(isset(SYS->functions.toString)){
		fzadan=1;
		f=SYS->functions.toString;
		}
	first=1;
	row={};
	i=0;
	while(i<way.size()){
		n=way[i];
		R="";
		acces= &SYS->m[n];
		if(isset(SYS->functions.correctir)){if(first){
			first=0;
			PREV=( *acces);
			}else {
			SYS->functions.correctir.run(&PREV,(*acces));
			acces= &PREV;
			}}
		if(fzadan)R+=f.run(acces);else R+=getAuthorForm(acces);
		R+="\n";
		row.push(R);
		++i;
		}
	formatZvitov=0;
	if(isset(SYS->formatZvitov))formatZvitov=SYS->formatZvitov;
	if(formatZvitov)return getzvit(row);
	str="";
	i=0;
	while(i<row.length()){
		str+=row[i];
		++i;
		}
	return str;
}



void Prorabotka(var SYS,var f){
	mp=reserve(SYS->m.size());
	iterator=1;
	n=1;
	while(n){
		n=0;
		i=0;
		for(;i<mp.size();++i)if(!mp[i]){
			nets=SYS->G.getNET(i,0,"",1,# );
			ok=1;
			S={};
			j=0;
			for(;j<nets.size();++j){
				p=nets[j][0];
				S.push(&SYS->m[p]);
				if(!mp[p])ok=0;
				}
			if(!ok)continue;
			f.run(&SYS->m[i],S);
			mp[i]=iterator;
			++n;
			};
		++iterator;
		}
}



void UstanovkaNETS(var SYS,var f,var name){
	S={0};
	while(S.size()){
		W={};
		i=0;
		for(;i<S.size();++i){
			nets=SYS->G.getNET(S[i],0,"",1,# );
			if(!nets.size())continue;
			SS={};
			j=0;
			for(;j<nets.size();++j)SS.push(&SYS->m[nets[j][0]]);
			Q=f.run(&SYS->m[S[i]],SS);
			j=0;
			for(;j<Q.size();++j){
				p=nets[Q[j]][0];
				nets2=SYS->G.getNET(S[i],0,name,1,p);
				if(nets2.size())continue;
				SYS->G.NET(S[i],0,name,1,p);
				W.push(p);
				}
			}
		S=((vector)((set)W));
		}
}



var ComputeSpaceWAYS(var SYS,var name){
	table=((map)0);
	meway={};
	n=SubComputeSpaceWAYS(&SYS->G,0,name,&table,&meway);
	return n;
}



var SubComputeSpaceWAYS(var G,var n,var name,var table,var meway){
	if(meway->indexOf(n)>=0)return 0;
	if(table->isset(n))return (*table)[n];
	nets=G->getMARKER(n,0,"",0,"END");
	if(nets.length())return 0;
	nets=G->getNET(n,0,name,1,# );
	if(!nets.size()){
		(*table)[n]=1;
		return 1;
		}
	meway->push(n);
	s=0;
	i=0;
	for(;i<nets.size();++i)s+=SubComputeSpaceWAYS(G,nets[i][0],name,table,meway);
	if(s)(*table)[n]=s;
	meway->pop();
	return s;
}



void ComputeAllWAYS(var SYS,var name){
	SYS->WAYS={};
	S={0};
	SubComputeAllWAYS(SYS,S,name);
}



void SubComputeAllWAYS(var SYS,var S,var name){
	nets=SYS->G.getNET(S[S.size()-1],0,name,1,# );
	if(!nets.size()){
		SYS->WAYS.push(S);
		return;
		}
	i=0;
	for(;i<nets.size();++i)SubComputeAllWAYS(SYS,S+{nets[i][0]},name);
}



void PrintSolutesCompact(var SYS){
	razdel="";
	i=0;
	for(;i<80;++i)razdel+="=";
	i=0;
	for(;i<SYS->WAYS.size();++i){
		row={};
		first=1;
		t=1;
		for(;t<SYS->WAYS[i].size();++t){
			acces= &SYS->m[SYS->WAYS[i][t]];
			if(isset(SYS->functions.correctir)){
				if(first){
					first=0;
					PREV=( *acces);
					}else {
					SYS->functions.correctir.run(&PREV,(*acces));
					acces= &PREV;
					}
				}
			if(isset(SYS->functions.toString))str=SYS->functions.toString.run(acces);else str=getAuthorForm(acces);
			row.push(str);
			}
		Q=getzvit(row);
		trace(Q);
		tracex(razdel);
		echo(Q);
		echo(razdel+"\n");
		}
}



void UnloadSystem(var SYS,var reservcopy){
	if(!isset(SYS->namemodele))return;
	Q=getThisFileName().split("\\");
	Q[Q.size()-1]="Buffer";
	str=SYS->namemodele;
	if(isset(SYS->ver))str+=SYS->ver;
	if(isset(reservcopy))str+="_"+reservcopy;
	Q.push(str);
	Q=Q.implode("\\");
	str="G=(graf)0;\n";
	str+=SYS->G.export("G");
	str+="return G;";
	f=((function)0);
	f.setName("getbuffergraf");
	f.import(PROGRAM(str));
	f.integrate(Q);
	str="X={};";
	i=0;
	for(;i<SYS->m.size();++i){
		str+="X.push("+getAuthorForm(&SYS->m[i])+");";
		}
	str+="return X;";
	f=((function)0);
	f.setName("getbufferunits");
	f.import(PROGRAM(str));
	f.integrate(Q);
	str="M=(map)0;";
	if(isset(SYS->filename)){
		s=SYS->filename;
		SYS->predoxranitelfilename=s.substr(WAY.length()+1);
		}
	tosave={"k","good","timezatratil","predoxranitelfilename"};
	i=0;
	for(;i<tosave.size();++i)if(SYS->isset(tosave[i])){
		str+="M["+tosave[i].export()+"]="+getAuthorForm(&(*SYS)[tosave[i]])+";";
		};
	str+="return M;";
	f=((function)0);
	f.setName("getbufferparams");
	f.import(PROGRAM(str));
	f.integrate(Q);
	uninclude(Q+".txt");
}



void LoadSystem(var SYS){
	Q=getThisFileName().split("\\");
	Q[Q.size()-1]="Buffer";
	Q.push(SYS->namemodele+SYS->ver);
	Q=Q.implode("\\");
	f=getFunction("getbuffergraf",Q);
	SYS->G=f.run();
	f=getFunction("getbufferunits",Q);
	SYS->m=f.run();
	f=getFunction("getbufferparams",Q);
	M=f.run();
	keys=M.getKeys();
	i=0;
	while(i<keys.size()){
		(*SYS)[keys[i]]=M[keys[i]];
		++i;
		}
}


// module1.code	:-|