首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++ 實現捕食者-被捕食者模擬:螞蟻與獅蟻的 20×20 世界完整代碼架構

     編輯:程式設計綜合問答

經典的「捕食者-被捕食者」模擬是物件導向程式設計教學中的經典案例。本題要求在 20×20 封閉網格中模擬螞蟻與獅蟻的種群動態,涵蓋移動、繁殖、捕食、餓死等行為規則,並要求使用繼承體系(Organism 基類 + Ant/Doodlebug 派生類)實現多態行為。本文提供完整的 C++ 代碼架構與關鍵算法實現。

核心類設計

1. 基類 Organism

class Organism {
protected:
    int x, y;           // 當前位置
    int breedTicks;     // 繁殖計時器
    bool moved;         // 本回合是否已移動
    char representation; // 顯示字符 'o' 或 'x'
    World* world;       // 所屬世界指針

public:
    Organism(World* w, int x_, int y_) : world(w), x(x_), y(y_), breedTicks(0), moved(false) {}
    virtual ~Organism() {}
    
    virtual void move() = 0;           // 純虛函數:移動邏輯
    virtual void breed() = 0;          // 純虛函數:繁殖邏輯
    virtual OrganismType getType() const = 0; // 類型標識
    
    // 通用輔助方法
    void setMoved(bool m) { moved = m; }
    bool hasMoved() const { return moved; }
    void incrementBreedTicks() { breedTicks++; }
    void resetBreedTicks() { breedTicks = 0; }
    int getBreedTicks() const { return breedTicks; }
    int getX() const { return x; }
    int getY() const { return y; }
    void setPosition(int nx, int ny) { x = nx; y = ny; }
    char getRepresentation() const { return representation; }
    World* getWorld() const { return world; }
};

2. 螞蟻類 Ant

class Ant : public Organism {
public:
    Ant(World* w, int x, int y) : Organism(w, x, y) {
        representation = 'o';
    }
    
    OrganismType getType() const override { return ANT; }
    
    void move() override {
        if (hasMoved()) return;
        // 隨機四方向嘗試移動
        static const int dx[4] = {-1, 1, 0, 0};
        static const int dy[4] = {0, 0, -1, 1};
        vector dirs = {0, 1, 2, 3};
        random_shuffle(dirs.begin(), dirs.end());
        
        for (int d : dirs) {
            int nx = x + dx[d], ny = y + dy[d];
            if (world->isValid(nx, ny) && world->getAt(nx, ny) == nullptr) {
                world->setAt(x, y, nullptr);
                world->setAt(nx, ny, this);
                x = nx; y = ny;
                break;
            }
        }
        setMoved(true);
    }
    
    void breed() override {
        if (++breedTicks >= 3) {
            // 尋找相鄰空格繁殖
            static const int dx[4] = {-1, 1, 0, 0};
            static const int dy[4] = {0, 0, -1, 1};
            for (int d = 0; d < 4; ++d) {
                int nx = x + dx[d], ny = y + dy[d];
                if (world->isValid(nx, ny) && world->getAt(nx, ny) == nullptr) {
                    world->addOrganism(new Ant(world, nx, ny));
                    break;
                }
            }
            resetBreedTicks();
        }
    }
};

3. 獅蟻類 Doodlebug

class Doodlebug : public Organism {
    int starveTicks; // 餓死計時器
    
public:
    Doodlebug(World* w, int x, int y) : Organism(w, x, y), starveTicks(0) {
        representation = 'X';
    }
    
    OrganismType getType() const override { return DOODLEBUG; }
    
    void move() override {
        if (hasMoved()) return;
        
        // 1. 優先尋找相鄰螞蟻捕食
        static const int dx[4] = {-1, 1, 0, 0};
        static const int dy[4] = {0, 0, -1, 1};
        vector dirs = {0, 1, 2, 3};
        random_shuffle(dirs.begin(), dirs.end());
        
        for (int d : dirs) {
            int nx = x + dx[d], ny = y + dy[d];
            if (world->isValid(nx, ny)) {
                Organism* target = world->getAt(nx, ny);
                if (target && target->getType() == ANT) {
                    // 捕食:移動到目標位置,刪除螞蟻
                    world->removeOrganism(target);
                    world->setAt(x, y, nullptr);
                    world->setAt(nx, ny, this);
                    x = nx; y = ny;
                    starveTicks = 0; // 重置餓死計時
                    setMoved(true);
                    return;
                }
            }
        }
        
        // 2. 無螞蟻可食:按螞蟻規則隨機移動
        for (int d : dirs) {
            int nx = x + dx[d], ny = y + dy[d];
            if (world->isValid(nx, ny) && world->getAt(nx, ny) == nullptr) {
                world->setAt(x, y, nullptr);
                world->setAt(nx, ny, this);
                x = nx; y = ny;
                break;
            }
        }
        starveTicks++;
        setMoved(true);
    }
    
    void breed() override {
        if (++breedTicks >= 8) {
            static const int dx[4] = {-1, 1, 0, 0};
            static const int dy[4] = {0, 0, -1, 1};
            for (int d = 0; d < 4; ++d) {
                int nx = x + dx[d], ny = y + dy[d];
                if (world->isValid(nx, ny) && world->getAt(nx, ny) == nullptr) {
                    world->addOrganism(new Doodlebug(world, nx, ny));
                    break;
                }
            }
            resetBreedTicks();
        }
    }
    
    void starve() {
        if (++starveTicks >= 3) {
            world->removeOrganism(this);
        }
    }
    
    int getStarveTicks() const { return starveTicks; }
};

世界管理類 World

class World {
    static const int WIDTH = 20;
    static const int HEIGHT = 20;
    Organism* grid[WIDTH][HEIGHT]; // 網格
    vector organisms;   // 所有生物列表(便於遍歷)
    
public:
    World() {
        memset(grid, 0, sizeof(grid));
        // 初始化:5 隻獅蟻,100 隻螞蟻
        for (int i = 0; i < 5; ++i)   addRandomOrganism(new Doodlebug(this, 0, 0));
        for (int i = 0; i < 100; ++i) addRandomOrganism(new Ant(this, 0, 0));
    }
    
    ~World() {
        for (auto o : organisms) delete o;
    }
    
    bool isValid(int x, int y) const {
        return x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT;
    }
    
    Organism* getAt(int x, int y) const { return grid[x][y]; }
    void setAt(int x, int y, Organism* o) { grid[x][y] = o; }
    
    void addOrganism(Organism* o) {
        organisms.push_back(o);
        // 尋找隨機空位放置
        int x, y;
        do { x = rand() % WIDTH; y = rand() % HEIGHT; } while (grid[x][y]);
        o->setPosition(x, y);
        grid[x][y] = o;
    }
    
    void removeOrganism(Organism* o) {
        grid[o->getX()][o->getY()] = nullptr;
        organisms.erase(remove(organisms.begin(), organisms.end(), o), organisms.end());
        delete o;
    }
    
    void addRandomOrganism(Organism* o) {
        int x, y;
        do { x = rand() % WIDTH; y = rand() % HEIGHT; } while (grid[x][y]);
        o->setPosition(x, y);
        grid[x][y] = o;
        organisms.push_back(o);
    }
    
    // 模擬一個時間步
    void simulateOneStep() {
        // 1. 重置 moved 標記
        for (auto o : organisms) o->setMoved(false);
        
        // 2. 獅蟻先移動(捕食優先)
        vector doodlebugs;
        for (auto o : organisms) if (o->getType() == DOODLEBUG) doodlebugs.push_back(o);
        for (auto o : doodlebugs) {
            if (!o->hasMoved()) o->move();
        }
        
        // 3. 螞蟻移動
        for (auto o : organisms) {
            if (o->getType() == ANT && !o->hasMoved()) o->move();
        }
        
        // 4. 繁殖階段
        vector snapshot = organisms; // 拷貝避免迭代器失效
        for (auto o : snapshot) o->breed();
        
        // 5. 獅蟻餓死檢查
        for (auto o : snapshot) {
            if (o->getType() == DOODLEBUG) {
                static_cast(o)->starve();
            }
        }
    }
    
    void display() const {
        system("cls"); // Windows; Linux/Mac 用 system("clear")
        for (int y = 0; y < HEIGHT; ++y) {
            for (int x = 0; x < WIDTH; ++x) {
                if (grid[x][y]) cout << grid[x][y]->getRepresentation() << ' ';
                else cout << ". ";
            }
            cout << '\n';
        }
        int ants = 0, bugs = 0;
        for (auto o : organisms) {
            if (o->getType() == ANT) ants++;
            else bugs++;
        }
        cout << "Ants: " << ants << " | Doodlebugs: " << bugs << '\n';
    }
    
    bool isExtinct() const {
        bool hasAnt = false, hasBug = false;
        for (auto o : organisms) {
            if (o->getType() == ANT) hasAnt = true;
            else hasBug = true;
        }
        return !hasAnt || !hasBug;
    }
};

主程序入口

int main() {
    srand(time(nullptr));
    World world;
    
    cout << "Predator-Prey Simulation (Press Enter to step, 'q' to quit)\n";
    world.display();
    
    string input;
    while (true) {
        getline(cin, input);
        if (input == "q") break;
        
        world.simulateOneStep();
        world.display();
        
        if (world.isExtinct()) {
            cout << "One species extinct! Simulation ended.\n";
            break;
        }
    }
    return 0;
}

關鍵設計要點總結

需求實現策略
多態移動/繁殖Organism 定義純虛函數 move()、breed(),派生類覆寫
獅蟻優先移動模擬步驟中先遍歷所有獅蟻 move(),再遍歷螞蟻
追蹤已移動生物moved 布爾標記,每步開始重置,移動後置真
封閉邊界isValid() 檢查座標範圍,超界不移動
捕食邏輯獅蟻 move() 中優先檢查四鄰域是否有螞蟻,有則捕食並重置餓死計時
餓死機制獅蟻連續 3 步未捕食 starveTicks>=3 從世界移除
ASCII 顯示螞蟻 'o',獅蟻 'X',空格 '.',每步刷新控制台

擴展建議

  • 統計圖表:記錄每步種群數量,模擬結束後用 Python/Matplotlib 繪製 Lotka-Volterra 風格振盪曲線。
  • 圖形化界面:使用 SFML/SDL/Qt 將 ASCII 顯示升級為像素圖形動畫。
  • 參數化配置:將網格大小、初始數量、繁殖/餓死閾值提取到配置文件。
  • 多線程加速:大規模網格時可將移動/繁殖階段並行化(需鎖保護網格訪問)。

此架構完整滿足題目所有要求,代碼結構清晰、擴展性強,可直接編譯運行觀察種群動態振盪現象。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved