📄 squirmchemistry.h
字号:
// SquirmChemistry.h
#ifndef SquirmChem
#define SquirmChem 1
#include "SquirmReaction.h"
#include "SquirmCell.h"
#include "SquirmError.h"
typedef CArray<SquirmReaction,SquirmReaction&> ReactionArray;
inline bool TestProb(unsigned long cases)
{
return((rand()+(unsigned long)rand()*RAND_MAX)%cases==0);
}
class SquirmChemistry
{
private:
ReactionArray reactions;
int first_enzyme;
public:
SquirmChemistry()
{
first_enzyme=7;
}
//---------------------------------interface functions---------------------------
void SetFirstEnzymeState(int s) { this->first_enzyme=s; }
int GetFirstEnzymeState() { return this->first_enzyme; }
void removeAllReactions()
{
reactions.RemoveAll();
}
void addReaction(SquirmReaction r)
{
reactions.Add(r);
}
//--------------------------------------------------------------------------------
int react(SquirmCell *cell,const SquirmCellList &unbonded_neighbours,float REACTION_RANGE2)
{
// try all the programmed reactions in turn
// (only for cells with state <first_enzyme)
if(cell->GetState()<first_enzyme)
{
for(int i=0;i<reactions.GetSize();i++)
{
if(tryReaction(cell,unbonded_neighbours,reactions[i],REACTION_RANGE2))
return i;
// only one reaction should apply per iteration
// (also, unbonded_neighbours may now be wrong)
}
}
else if(true) { // state>=first_enzyme
// try the reactions that prime the enzymes
if(tryProteinArithmeticReactions(cell))
return reactions.GetSize();
else if(tryEnzymeReactions(cell,unbonded_neighbours))
return reactions.GetSize()+1;
}
if(true && cell->GetState()==-1 && unbonded_neighbours.GetCount()>0) {
// try the special destructive reaction
SquirmCell* first = unbonded_neighbours.GetHead();
if(first->GetState()>0 && first->GetState()!=8 &&
!(first->GetState()>=10 && first->GetState()<=13))
{
first->SetState(0);
first->BreakAllBonds();
return reactions.GetSize()+1;
}
}
return -1; // no reaction could be applied
}
private:
bool tryProteinArithmeticReactions(SquirmCell *cell);
bool tryEnzymeReactions(SquirmCell *cell,
const SquirmCellList& unbonded_neighbours);
bool tryReaction(SquirmCell *cell,
const SquirmCellList& unbonded_neighbours,
SquirmReaction r,float REACTION_RANGE2)
{
// can this reaction apply to this cell based on the cells it is
// bonded to and its unbonded neighbours?
// the 3-nhood reaction can apply in any orientation, so this is
// much more difficult to work out than for the 2-nhood reactions
// we are checking this for every atom, therefore it suffices here to
// check whether this reaction applies to this atom as the 'a' atom
if( (r.a_type=='x' || r.a_type==cell->GetType()) && r.a_state==cell->GetState() )
{
// collect the possible candidates for b
SquirmCellList b_candidates;
{
SquirmCellList& possibles = r.current_ab_bond?(cell->GetBondedCells()):unbonded_neighbours;
// look for matches in the bonded_cells list
if( r.b_type=='y' || (r.b_type=='x' && r.a_type!='x') )
{
// b can be of any type
getThoseOfState(possibles,r.b_state,b_candidates);
}
else if(r.b_type=='x' && r.a_type=='x')
{
// b must be of a's type
getThoseOfTypeAndState(possibles,
cell->GetType(),r.b_state,
b_candidates);
}
else
{
// b must be of specified type and state
getThoseOfTypeAndState(possibles,
r.b_type,r.b_state,
b_candidates);
}
}
// for each b candidate (if any) can we find a suitable c?
// apply the reaction and return if we find one
POSITION pos = b_candidates.GetHeadPosition();
while(pos)
{
SquirmCell *b_candidate = b_candidates.GetNext(pos);
if(r.n_inputs==3)
{
SquirmCellList& possibles = r.current_ac_bond?cell->GetBondedCells():unbonded_neighbours;
SquirmCellList c_candidates;
if(r.c_type=='z' || (r.c_type=='x' && r.a_type!='x' && r.b_type!='x') ||
(r.c_type=='y' && r.a_type!='y' && r.b_type!='y'))
{
// c can be of any type
getThoseOfState(possibles,r.c_state,c_candidates);
}
else if(r.c_type=='x' && r.a_type=='x')
{
// c must be of a's type
getThoseOfTypeAndState(possibles,
cell->GetType(),r.c_state,c_candidates);
}
else if( (r.c_type=='x' && r.b_type=='x') ||
(r.c_type=='y' && r.b_type=='y') )
{
// c must be of b's type
getThoseOfTypeAndState(possibles,
b_candidate->GetType(),r.c_state,c_candidates);
}
else
{
// c must be of type and state specified
getThoseOfTypeAndState(possibles,
r.c_type,r.c_state,c_candidates);
}
// consider each candidate c in turn (if any)
POSITION pos2 = c_candidates.GetHeadPosition();
while(pos2)
{
SquirmCell *c_candidate = c_candidates.GetNext(pos2);
// cannot be the same candidate cell as b!
if(c_candidate!=b_candidate)
{
// also the bond/not between b and c must be correct, and all the players must be within range
if( r.current_bc_bond == b_candidate->HasBondWith(c_candidate) &&
Length2(c_candidate->location-b_candidate->location)<REACTION_RANGE2 )
{
if(TestProb(r.cases))
{
// apply the reaction and return
cell->SetState(r.future_a_state);
b_candidate->SetState(r.future_b_state);
c_candidate->SetState(r.future_c_state);
if(cell->HasBondWith(b_candidate) && !r.future_ab_bond)
cell->Debond(b_candidate);
else if(!cell->HasBondWith(b_candidate) && r.future_ab_bond)
cell->BondTo(b_candidate);
if(b_candidate->HasBondWith(c_candidate) && !r.future_bc_bond)
b_candidate->Debond(c_candidate);
else if(!b_candidate->HasBondWith(c_candidate) && r.future_bc_bond)
b_candidate->BondTo(c_candidate);
if(cell->HasBondWith(c_candidate) && !r.future_ac_bond)
cell->Debond(c_candidate);
else if(!cell->HasBondWith(c_candidate) && r.future_ac_bond)
cell->BondTo(c_candidate);
return true;
}
}
}
}
}
else // n_inputs==2
{
if(TestProb(r.cases))
{
// apply the reaction and return
cell->SetState(r.future_a_state);
b_candidate->SetState(r.future_b_state);
if(cell->HasBondWith(b_candidate) && !r.future_ab_bond)
cell->Debond(b_candidate);
else if(!cell->HasBondWith(b_candidate) && r.future_ab_bond)
cell->BondTo(b_candidate);
return true;
}
}
}
}
return false; // this reaction was not possible
}
// ----------------------------------------------------------------------------------------
public:
static void getThoseOfTypeAndState(const SquirmCellList& cells,
char type,int state,SquirmCellList &dest)
{
if(type=='x' || type=='y' || type=='z')
{
SquirmError("getThoseOfTypeAndState : cannot pass a type variable to this function!");
return;
}
// do any of these cells match the type and state specified?
// if so return all that match (empty list if none)
dest.RemoveAll();
SquirmCell *c;
POSITION pos = cells.GetHeadPosition();
while(pos)
{
c = cells.GetNext(pos);
if(c->GetType()==type && c->GetState()==state)
dest.AddTail(c);
}
}
// ----------------------------------------------------------------------------------------
static void getThoseOfState(const SquirmCellList& cells,int state,
SquirmCellList& dest)
{
// do any of these cells match the state specified? (any type)
// if so return all that match (empty list if none)
dest.RemoveAll();
SquirmCell *c;
POSITION pos = cells.GetHeadPosition();
while(pos)
{
c = cells.GetNext(pos);
if(c->GetState()==state)
dest.AddTail(c);
}
}
};
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -