簡體   English   中英

C ++ Console Conway的生活游戲更新非常慢

[英]C++ Console Conway's Game of Life very slow updates

我目前正在使用C ++的Conway的《人生游戲》的控制台版本。

回購鏈接

問題是我的Draw()方法無法盡快繪制下一代圖像。

我記得在某處讀過,與獲取控制台緩沖區相比,使用GotoXY相當慢。

問題是我沒有一個想法如何實現控制台緩沖區以使用我的代碼。

我不是要你們這樣做,但我只是想讓您看看我的Draw()和Update()方法,看看我是否正在做一些嚴重的內存占用問題。

我的代碼可能不是最好的,因為我還是C ++的“合理新手”,因此請在批評之前記住這一點。 :')

細胞結構

struct Cell
{
int x, y; // Cell X, Y coordiantes
bool IsAlive; // Cell life state

string ToString()
{
    return "X: " + to_string(x) + "\tY" + to_string(y) + "\tAlive State: " + to_string(IsAlive);
}

void Die()
{
    IsAlive = false;
}

void Resurrect()
{
    IsAlive = true;
}
};

更新

void Update()
{
// Update Cells
CalculateNextGeneration(CellMap);
}

void Draw()
{
for (auto cell : CellMap) // Iterate through all cells in CellMap vector
{
    // Draw Cell if Alive
    // If a cell was alive upto 10th generation, display cell as '1'.
    if (cell.IsAlive)
        GotoXY(cell.x, cell.y, AliveCell);
    // If a cell is dead, display cell as ' '.
    else
        GotoXY(cell.x, cell.y, DeadCell);
}
}

CalculateNextGeneration

 /* 
TODO: Encapsulate IF Statements

Game Rules
1: Any Live Cell which has < 2 Live Neighbours, die [ Underpopulation ]
2: Any Live Cell which has 2 OR 3 Neighbours, live
3: Any Live Cell which has > 3 Neighbours, die [ Overpopulation ]
4: Any Dead Cell which has EXACTLY 3 Neighbours, resurrect [ Reporduciton ]

*/
void CalculateNextGeneration(vector<Cell> &map)
{
    for (auto& cell : map) // Iterate through all cells as references
    {
        if ((cell.IsAlive && GetAdjacentCellCount(cell, map) < 2) || (cell.IsAlive && GetAdjacentCellCount(cell, map) > 3)) // If current cell has < 2 neighbours OR current cell has > 3 neighbours, die [ Underpopulation & Overpopulation ] 
        {
            // Die
            cell.Die();
        }
        if (cell.IsAlive && GetAdjacentCellCount(cell, map) == 2 || GetAdjacentCellCount(cell, map) == 3) // If current cell has 2 OR 3 adjacent neighbours, live until next generation.
        {
            // Live Until Next Generation
        }
        if (!cell.IsAlive && GetAdjacentCellCount(cell, map) == 3) // If current cell has EXACTLY 3 adjacent neighbours, resurrect [ Reproduciton ]
        {
            // Resurrect
            cell.Resurrect();
        }
    }
}

GetAdjacentCellCount

/* Count Adjacent cells

Long version of counting adjacent cells.
TODO: Clean up code.

Example:

0 = Dead Cell
1 = Alive Cell
X = Current Cell

    1   0   1
    0   X   0
    1   1   0

Return would be 4 in this case. Since There are 4 alive cells surround the current cell (X).

The function doesn't consider the current cell's life state.

*/
int GetAdjacentCellCount(Cell &currentCell, vector<Cell> &map)
{
    int aliveCount = 0;

    int currentX = currentCell.x;
    int currentY = currentCell.y;

    vector<Cell> adjacentCells; // Create temporary vector with all adjacent cells

    adjacentCells.push_back(GetCellAtXY(currentX - 1, currentY - 1, map));  // - - // TOP LEFT CELL
    adjacentCells.push_back(GetCellAtXY(currentX, currentY - 1, map));      // 0 - // TOP MIDDLE CELL
    adjacentCells.push_back(GetCellAtXY(currentX + 1, currentY - 1, map));  // + - // TOP RIGHT CELL
    adjacentCells.push_back(GetCellAtXY(currentX + 1, currentY, map));      // + 0 // MIDDLE LEFT CELL
    adjacentCells.push_back(GetCellAtXY(currentX + 1, currentY + 1, map));  // + + // MIDDLE RIGHT CELL
    adjacentCells.push_back(GetCellAtXY(currentX, currentY + 1, map));      // 0 + // BOTTOM LEFT CELL
    adjacentCells.push_back(GetCellAtXY(currentX - 1, currentY + 1, map));  // - + // BOTTOM MIDDLE CELL
    adjacentCells.push_back(GetCellAtXY(currentX - 1, currentY, map));      // - - // BOTTOM RIGHT CELL

    for (auto adjCell : adjacentCells) // Iterate through all adjacent cells
    {
        if (adjCell.IsAlive == true) // Count how many are alive
            aliveCount++;
    }

    return aliveCount;
}

GetCellAtXY

Cell GetCellAtXY(int x, int y, vector<Cell> &map)
{
    Cell retrievedCell = { 0, 0, false }; // Create a default return cell

    for (auto cell : map) // Iterate through all cells in the map
    {
        if (cell.x == x && cell.y == y) // If Cell is found at coordinate X, Y
            retrievedCell = cell; // Set found Cell to return Cell
    }

    return retrievedCell;
}

您可能會花費很多時間來重寫GetAdjacentCellCount函數:

if (GetCellAtXY(currentX - 1, currentY - 1, map)  // - - // TOP LEFT CELL
   aliveCount++;
if (GetCellAtXY(currentX, currentY - 1, map));    // 0 - // TOP MIDDLE CELL
   aliveCount++;
if (GetCellAtXY(currentX + 1, currentY - 1, map)  // + - // TOP RIGHT CELL
   aliveCount++;
if (GetCellAtXY(currentX + 1, currentY, map)      // + 0 // MIDDLE LEFT CELL
   aliveCount++;
if (GetCellAtXY(currentX + 1, currentY + 1, map)  // + + // MIDDLE RIGHT CELL
   aliveCount++;
if (GetCellAtXY(currentX, currentY + 1, map)      // 0 + // BOTTOM LEFT CELL
   aliveCount++;
if (GetCellAtXY(currentX - 1, currentY + 1, map)  // - + // BOTTOM MIDDLE CELL
   aliveCount++;
if (GetCellAtXY(currentX - 1, currentY, map)      // - - // BOTTOM RIGHT CELL
   aliveCount++;

使用push_back填充向量會使每次迭代的每個單元發生多個堆分配。

我不知道這是否是代碼的瓶頸部分,您必須進行概要分析才能知道,但這似乎是一項容易的改進。

編輯

我發布得太早了。 您的問題出在GetCellAtXY函數中。 您(平均)遍歷一半的單元以找到您的鄰居。 在每次迭代中,您對每個單元執行8次此操作!

而是創建一個直接指向其8個鄰居的單元對象,例如使用:

struct Cell
{
  int x, y; // Cell X, Y coordiantes
  bool IsAlive; // Cell life state
  std::array<Cell*,8> neighbors;
}

然后,您遍歷循環一次查找鄰居(或者在創建它們時填充它們,這可能更好)。 請注意,當您設置A.neighbor[left]=&B ,您還設置了B.neighbor[right]=&A

我確定您會得到在沒有指針的情況下執行此操作的建議,即使用指針不是正確的C ++。 但是我喜歡指針。

有很多選擇:一個2D單元格網格,您可以通過計算了解每個鄰居的索引,一個std :: map位置,您可以根據坐標的哈希值對一個單元進行索引,等等。

編輯

這是索引鄰居的一種方法。 這不一定是較為冗長的方法,但可以使您理解所有想法:

struct FieldSize {
  int x, y;
}
FieldSize fieldSize{ 40, 20 };

struct Cell {
  int x, y; // Cell X, Y coordiantes
  bool IsAlive; // Cell life state
  // ...
  bool HasLeftNeighbor() {
    return x != 0;
  }
  bool HasRightNeighbor() {
    return x != fieldSize.x-1;
  }
  bool HasTopNeighbor() {
    return y != 0;
  }
  bool HasTopLeftNeighbor() {
    return HasLeftNeighbor() && HasTopNeighbor();
  }
  // ... etc.
  int GetLeftNeighbor() {
    return (x-1) + y * fieldSize.x;
  }
  int GetTopNeighbor() {
    return x + (y-1) * fieldSize.x;
  }
  int GetTopLeftNeighbor() {
    return (x-1) + (y-1) * fieldSize.x;
  }
  // ... etc.
}

然后在GetAdjacentCellCount中:

if (HasLeftNeighbor() && map[GetLeftNeighbor()].IsAlive)
  aliveCount++;
// etc.

再次,這是非常冗長的,可以很容易地變得更緊湊,也可能更有效率,但是我想為您強調邏輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM