⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 squirmgrid.cpp

📁 本程序模拟细胞的自我繁殖
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			a=b;
		}
		// up the right
		for(i=length-1;i>=0;i--)
		{
			b = CreateNewCell(start_x+(width+1)*RADIUS*2.0F,start_y+(i+1)*RADIUS*2.0F,'a',S);
			b->BondTo(a);
			a=b;
		}
		// along the top
		for(i=width;i>=0;i--)
		{
			b = CreateNewCell(start_x+(i+1)*RADIUS*2.0F,start_y,'a',S);
			b->BondTo(a);
			a=b;
		}
		// link to the start of the loop
		a->BondTo(start);
	}

    // create some random cells around the place
    for(int i=0;i<n;i++)
        CreateRandomCell();

    this->initial_population = n;
}

float sqr(float x) { return x*x; }

void SquirmGrid::DoTimeStep()
{
    RecomputeVelocitiesAndReact();
    MoveCells();
    EdgeEffect();
    if( this->do_flood && (this->iterations%this->FLOOD_PERIOD)==0 && this->iterations>0 )
        DoFlood();
    this->iterations++;
}

SquirmCell* SquirmGrid::CreateRandomCell()
{
    // pick a random position
    C2dVector loc;
    loc.x = RandomX();
    loc.y = RandomY();
	return CreateNewCell(loc,"abcdef"[RandomN(6)],0);//RandomN(4)!=0?'c':(RandomN(2)==0?'a':'b'),0);
}

SquirmCell* SquirmGrid::CreateRandomCellOfType(char type)
{
    // pick a random  position
    C2dVector loc;
    loc.x = RandomX();
    loc.y = RandomY();
    return CreateNewCell(loc.x,loc.y,type,0);
}

SquirmCell* SquirmGrid::CreateNewCell(C2dVector loc,char type,int state)
{
    // only proceed if this location is empty
    if(Valid(loc))
    {
        SquirmCell *cell = new SquirmCell(loc,type,state);

        this->PutCell(cell);
        this->cell_list.AddTail(cell);

        return cell;
    }
    else
    {
        // this position is taken!
        SquirmError("CreateNewCell : slot taken!");
        return NULL;
    }
}

void SquirmGrid::PutCell(SquirmCell *cell)
{
	// put the cell into a slot
	int cx = (int)floor(cell->location.x/slot_size);
	int cy = (int)floor(cell->location.y/slot_size);
    cx = max(0,cx);
    cx = min(cx,this->slots_X);
    cy = max(0,cy);
    cy = min(cy,this->slots_Y);
	cell_grid[cx][cy].addOccupant(cell);
}

void SquirmGrid::RemoveCell(SquirmCell *cell)
{
	// clear the slot it is in
	int cx = (int)floor(cell->location.x/slot_size);
	int cy = (int)floor(cell->location.y/slot_size);
    cx = max(0,cx);
    cx = min(cx,this->slots_X);
    cy = max(0,cy);
    cy = min(cy,this->slots_Y);
	cell_grid[cx][cy].removeOccupant(cell);
}
void SquirmGrid::Draw(CDC* pDC,float scale)
{
    //if(this->iterations%10!=0) return;

    if(!this->created) return;

    // outline the area
    pDC->Rectangle(0,0,(int)(this->size.x*scale)+OFFSET*2,
		(int)(this->size.y*scale)+OFFSET*2);

    if(this->probe)
    {
        // draw the probe
        pDC->FillSolidRect((int)(probe->location.x*scale)-2+OFFSET,
		    (int)(probe->location.y*scale)-2+OFFSET,6,6,
		    probe->GetColour());
    }

    // draw the other atoms
    POSITION pos = this->cell_list.GetHeadPosition();
    SquirmCell *cell,*other;
    bool first=true;
    while(pos)
    {
        cell = this->cell_list.GetNext(pos);
        // draw the cell as a filled box or a pixel if window is small
        if(scale>=0.5F)
            pDC->FillSolidRect((int)(cell->location.x*scale)-1+OFFSET,
			  (int)(cell->location.y*scale)-1+OFFSET,3,3,
			  cell->GetColour());
        else
            pDC->SetPixelV((int)(cell->location.x*scale)+OFFSET,
			  (int)(cell->location.y*scale)+OFFSET,cell->GetColour());
        // optionally, draw as a RADIUS circle
        if(true && cell->GetState()!=0)
        {
            CRect r(int(cell->location.x*scale-scale*RADIUS)+OFFSET,int(cell->location.y*scale-scale*RADIUS)+OFFSET,
                int(cell->location.x*scale+scale*RADIUS)+OFFSET,int(cell->location.y*scale+scale*RADIUS)+OFFSET);
            CPen pen(PS_SOLID,1,cell->GetColour()),*old_pen;
            CBrush brush,*old_brush;
            brush.CreateSolidBrush(cell->GetColour());
            old_brush = pDC->SelectObject(&brush);
            old_pen = pDC->SelectObject(&pen);
            pDC->Ellipse(&r);
            pDC->SelectObject(old_pen);
            pDC->SelectObject(old_brush);
        }
		// draw the cell's state
		if(false)
		{
			CString text;
			text.Format("%d",cell->GetState());
			pDC->TextOut((int)(cell->location.x*scale)+OFFSET,
				(int)(cell->location.y*scale)+OFFSET,text);
		}
        // draw the cell's bonds as lines
		if(true) {
			POSITION bonds_pos = cell->GetBondedCells().GetHeadPosition();
			while(bonds_pos)
			{
				other = cell->GetBondedCells().GetNext(bonds_pos);
				pDC->MoveTo(int(cell->location.x*scale)+OFFSET,
					int(cell->location.y*scale)+OFFSET);
				pDC->LineTo(int(other->location.x*scale)+OFFSET,
					int(other->location.y*scale)+OFFSET);
			}
		}
    }
}

void SquirmGrid::DoFlood()
{
    // for all the atoms in one part of the area:
    // - remove all their bonds
    // - set their state to 0
    SquirmCell *cell;

    float left[4]={0,this->GetSize().x/2.0F,this->GetSize().x/2.0F,0};
    float top[4]={0,0,this->GetSize().y/2.0F,this->GetSize().y/2.0F};


    POSITION pos = this->cell_list.GetHeadPosition();
	while(pos)
	{
		cell = this->cell_list.GetNext(pos);
        if( cell->location.x>=left[this->flood_sector] && 
            cell->location.x<=left[this->flood_sector]+this->GetSize().x/2.0F &&
            cell->location.y>=top[this->flood_sector] && 
            cell->location.y<=top[this->flood_sector]+this->GetSize().y/2.0F )
        {
			// break all of its bonds
			cell->BreakAllBonds();
			// set its state to 0
			cell->SetState(0);
            // assign a random velocity
            cell->AssignRandomVelocity();
        }
    }

    // do the flood on the other side next time
    this->flood_sector = (this->flood_sector+1)%4;
}


float SquirmGrid::RandomX()
{
    return rand()*size.x/RAND_MAX;
}

float SquirmGrid::RandomY()
{
    return rand()*size.y/RAND_MAX;
}

int SquirmGrid::RandomN(int n)
{
    return (rand()*100+rand()) % n;
}

/*CString SquirmGrid::GetReport(CPoint p,int scale)
{
    int x,y;
    x = p.x/scale;
    y = p.y/scale;
    if(!Valid(x,y) || cell_grid[x][y].queryEmpty())
        return "";
    else
    {
        CString report;
        report.Format("%c%d",cell_grid[x][y].getOccupant()->GetType(),
            cell_grid[x][y].getOccupant()->GetState());
        return report;
    } 
}*/

void SquirmGrid::GetAllWithinRadius(C2dVector loc,float r,
											  SquirmCellList &dest)
{
	dest.RemoveAll();
	// which slot is at the centre?
	int cx = (int)floor(loc.x/slot_size);
	int cy = (int)floor(loc.y/slot_size);
    float r2 = r*r;
	if(cx>=0 && cy>=0 && cx<this->slots_X && cy<this->slots_Y)
	{
		int search_slots = (int)ceil(r / slot_size);
		int x,y;
        SquirmCellSlot *slot;
		SquirmCell *cell;
        POSITION pos;
		for(x=max(0,cx-search_slots);x<=min(this->slots_X-1,cx+search_slots);x++)
		{
			for(y=max(0,cy-search_slots);y<=min(this->slots_Y-1,cy+search_slots);y++)
			{
                slot = &cell_grid[x][y];
				if(!slot->queryEmpty())
				{
					// now do a more expensive test
					pos = slot->occupants.GetHeadPosition();
					while(pos)
					{
						cell = slot->occupants.GetNext(pos);
                        if(C2dVector::Dist2(cell->location,loc)<r2)
							dest.AddTail(cell);
					}
				}
			}
		}
	}
	/* case below if required
    else {
		AfxMessageBox("Out of area in GetAllWithinRadius!");
		ASSERT(false);
		return;
	}*/
}

void SquirmGrid::InitSearchArea(int cx,int cy,int search_slots,SquirmCellList*& central_cells,
                                SquirmCellList &nearby_cells)
{
    // assuming the cx,cy is valid
    central_cells = &this->cell_grid[cx][cy].occupants;
    nearby_cells.RemoveAll();
    int i,j;
    for(i=max(0,cx-search_slots);i<=min(this->slots_X-1,cx+search_slots);i++)
        for(j=max(0,cy-search_slots);j<=min(this->slots_Y-1,cy+search_slots);j++)
            nearby_cells.AddTail(&this->cell_grid[i][j].occupants);
}

void SquirmGrid::RecomputeVelocitiesAndReact()
{
    const float PHYS_RANGE = RADIUS*2.0F; // how far out do the physical forces extend?
    const float PHYS_RANGE2 = PHYS_RANGE*PHYS_RANGE;

    const float REACTION_RANGE = RADIUS*2.5F; // how far out can reactions extend?
    const float REACTION_RANGE2 = REACTION_RANGE*REACTION_RANGE;

	const float MAX_RANGE = max(PHYS_RANGE2,REACTION_RANGE2); // no effect acts beyond this distance

    // find the search radius distance in terms of the number of slots
	int search_slots = (int) ceil( MAX_RANGE / this->slot_size);

    // for each slot in the grid, get the list of cells within the neighbourhood
    // use this list to recompute the velocities of the cells in the central slot

    int cx,cy; // central square 
    SquirmCellList *central_cells; // the cells in the central square
    SquirmCellList nearby_cells; // the cells in the search area (including central_cells)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -