基本的扫雷。炸弹计数器功能不起作用

时间:2018-01-17 15:50:38

标签: c++ numbers srand tracker

我一直在研究基本扫雷程序的一些代码,此时我自满地迷失了。炸弹周围的数字不会正常生成,甚至似乎都没有出现错误的模式。我需要帮助找到解决此问题的方法,而无需重新调整我的输入程序。我的老师不能找到一种方法来帮助我,并建议我使用我所拥有的基于运气的游戏感觉它应该在星期二。请帮忙。

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <conio.h>
#include <windows.h>
#include <ctime>
using namespace std;
int main()
{
int GameBoard [9] [9] = { };
int BombTracker [20] = { };
srand(time(0));
for (int c = 0; c <= 10; c++ ) //generates 10 bombs
{
    int TX;
    int TY;
    int MX = rand() % 8;
    int MY = rand() % 8;

    for ( TY = 1, TX = 0; TY <= 19; TX+=2, TY+=2)//cycle through array 
    {
        if (MY == BombTracker [TY] && MX == BombTracker [TX])//Regenerate and restart count if found true
            {
              MX = rand() % 8;
              MY = rand() % 8;
                TY = -1;
                TX = -2;
            }
    }
    GameBoard [MX] [MY] = 9;
if (MY == 0 && MX == 0) //(0,0)
    {
        MX = MX + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //5: my,mx+1
        MY = MY + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //7: my+1,mx+1
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //6: my+1,mx
    }
if (MY == 0 && MX == 8) //(8,0)
    {
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //1: my,mx-1
        MY = MY -1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //2: my-1,mx-1
        MY = MY + 2;
        MX = MX + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //6: my+1,mx
    }
if (MY == 8 && MX == 0) //(0,8)
    {
        MY = MY - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //3: my-1,mx
        MX = MX + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //4: my-1,mx+1
        MY = MY + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //5: my,mx+1
    }
if (MY == 8 && MX == 8) //(8,8)
    {
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //1: my,mx-1
        MY = MY -1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //2: my-1,mx-1
        MX = MX + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //3: my-1,mx
    }
if ((MX >= 1 && MX < 8) && (MY > 7)) //  bottom row
    {
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //1: my,mx-1
        MY = MY -1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //2: my-1,mx-1
        MX = MX + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //3: my-1,mx
        MX = MX + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //4: my-1,mx+1
        MY = MY + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //5: my,mx+1
    }
if ((MX >= 1 && MX < 8) && (MY < 1)) // top row
    {
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //1: my,mx-1
        MX = MX + 2;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //5: my,mx+1
        MY = MY + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //7: my+1,mx+1
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //6: my+1,mx
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //8: my+1,mx-1
    }
if ((MX > 7) && (MY >= 1 &&MY < 8)) // right column
    {
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //1: my,mx-1
        MY = MY -1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //2: my-1,mx-1
        MX = MX + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //3: my-1,mx
        MY = MY + 2;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //6: my+1,mx
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //8: my+1,mx-1
    }
if ((MX > 7) && (MY >= 1 &&MY < 8)) // left column
    {
        MY = MY - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //3: my-1,mx
        MX = MX + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //4: my-1,mx+1
        MY = MY + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //5: my,mx+1
        MY = MY + 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //7: my+1,mx+1
        MX = MX - 1;
        GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //6: my+1,mx
    }
if ((MX >= 1 && MX < 8)&&(MY >= 1 && MY < 8)) // middle of the board
{
    MX = MX - 1;
    GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //1: my,mx-1
    MY = MY -1;
    GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //2: my-1,mx-1
    MX = MX + 1;
    GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //3: my-1,mx
    MX = MX + 1;
    GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //4: my-1,mx+1
    MY = MY + 1;
    GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //5: my,mx+1
    MY = MY + 1;
    GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //7: my+1,mx+1
    MX = MX - 1;
    GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //6: my+1,mx
    MX = MX - 1;
    GameBoard [MY] [MX] = GameBoard [MY] [MX] + 1; //8: my+1,mx-1
}
}
    int width = 9;
    int height = 9;
for (int i = 0; i < height; ++i)
{
    for (int j = 0; j < width; ++j)
    {
        cout <<GameBoard[i][j] << "  ";
    }
    cout << endl;
    }
    }

1 个答案:

答案 0 :(得分:0)

你在这里发布的源代码很难理解,有很多神奇的数字。支持此类代码是一项维护噩梦。

尝试为变量赋予好的名称,描述变量的实体 表示。

尝试将每个小任务封装在自己的例程中。

例如,用于确定目标单元的相邻单元的逻辑非常简单,可以使用Compass隐喻来实现。所以这里我们有八个方向 - 每个主要方向一个

enter image description here

#include <vector>
#include <random>
#include <array>
#include <iostream>
#include <sstream>

enum Compass
{
  North,
  NorthEast,
  East,
  SouthEast,
  South,
  SouthWest,
  West,
  NorthWest
};

然后为雷区板的每个边缘定义枚举,方向类和索引板单元的类型。

enum BoardEdge
{
  Inside,
  Top,
  TopRight,
  Right,
  BottomRight,
  Bottom,
  BottomLeft,
  Left,
  TopLeft
};

struct CellIndex2D;

using IndexType = std::size_t;
using CellIndex2DList = std::vector<CellIndex2D>;
using CellIndex1D = std::size_t;

struct CellIndex2D
{
  IndexType X;
  IndexType Y;
};

struct Direction
{
  explicit Direction(CellIndex2D targetCell) noexcept
    :cell_(targetCell) {}

  template <Compass C>
  CellIndex2D To() const;

private:
  CellIndex2D cell_;
};

现在我们有了所有的比特和碎片来确定相邻细胞的每个目标细胞的索引。遵循我们的Compass隐喻北方单元格的X坐标等于目标单元格X坐标,Y坐标距离目标单元格小1:

template <>
inline CellIndex2D Direction::To<North>() const
{
  return{ cell_.X, (cell_.Y - 1) };
}
template <>
inline CellIndex2D Direction::To<NorthEast>() const
{
  return{ (cell_.X + 1), (cell_.Y - 1) };
}
template <>
inline CellIndex2D Direction::To<East>() const
{
  return{ (cell_.X + 1), cell_.Y };
}
template <>
inline CellIndex2D Direction::To<SouthEast>() const
{
  return{ (cell_.X + 1), (cell_.Y + 1) };
}
template <>
inline CellIndex2D Direction::To<South>() const
{
  return{ cell_.X, (cell_.Y + 1) };
}
template <>
inline CellIndex2D Direction::To<SouthWest>() const
{
  return{ (cell_.X - 1), (cell_.Y + 1) };
}
template <>
inline CellIndex2D Direction::To<West>() const
{
  return{ (cell_.X - 1), cell_.Y };
}
template <>
inline CellIndex2D Direction::To<NorthWest>() const
{
  return{ (cell_.X - 1), (cell_.Y - 1) };
}

现在让我们描述电路板每种边缘类型的相邻单元格,例如左上角的单元格只有三个相邻的单元格:

template <BoardEdge BE = Inside>
struct AdjacentCells
{
  static CellIndex2DList Get(CellIndex2D targetCell)
  {
    Direction direction{ targetCell };

    return CellIndex2DList{
      CellIndex2D(direction.To<North>()),
      CellIndex2D(direction.To<NorthEast>()),
      CellIndex2D(direction.To<East>()),
      CellIndex2D(direction.To<SouthEast>()),
      CellIndex2D(direction.To<South>()),
      CellIndex2D(direction.To<SouthWest>()),
      CellIndex2D(direction.To<West>()),
      CellIndex2D(direction.To<NorthWest>())
    };
  }
};

template <>
struct AdjacentCells<Top>
{
  static CellIndex2DList Get(CellIndex2D targetCell)
  {
    Direction direction{ targetCell };

    return CellIndex2DList{
      CellIndex2D(direction.To<East>()),
      CellIndex2D(direction.To<SouthEast>()),
      CellIndex2D(direction.To<South>()),
      CellIndex2D(direction.To<SouthWest>()),
      CellIndex2D(direction.To<West>())
    };
  }
};
template <>
struct AdjacentCells<TopRight>
{
  static CellIndex2DList Get(CellIndex2D targetCell)
  {
    Direction direction{ targetCell };

    return CellIndex2DList{
      CellIndex2D(direction.To<South>()),
      CellIndex2D(direction.To<SouthWest>()),
      CellIndex2D(direction.To<West>())
    };
  }
};
template <>
struct AdjacentCells<Right>
{
  static CellIndex2DList Get(CellIndex2D targetCell)
  {
    Direction direction{ targetCell };

    return CellIndex2DList{
      CellIndex2D(direction.To<North>()),
      CellIndex2D(direction.To<South>()),
      CellIndex2D(direction.To<SouthWest>()),
      CellIndex2D(direction.To<West>()),
      CellIndex2D(direction.To<NorthWest>())
    };
  }
};
template <>
struct AdjacentCells<BottomRight>
{
  static CellIndex2DList Get(CellIndex2D targetCell)
  {
    Direction direction{ targetCell };

    return CellIndex2DList{
      CellIndex2D(direction.To<North>()),
      CellIndex2D(direction.To<West>()),
      CellIndex2D(direction.To<NorthWest>())
    };
  }
};
template <>
struct AdjacentCells<Bottom>
{
  static CellIndex2DList Get(CellIndex2D targetCell)
  {
    Direction direction{ targetCell };

    return CellIndex2DList{
      CellIndex2D(direction.To<North>()),
      CellIndex2D(direction.To<NorthEast>()),
      CellIndex2D(direction.To<East>()),
      CellIndex2D(direction.To<West>()),
      CellIndex2D(direction.To<NorthWest>())
    };
  }
};
template <>
struct AdjacentCells<BottomLeft>
{
  static CellIndex2DList Get(CellIndex2D targetCell)
  {
    Direction direction{ targetCell };

    return CellIndex2DList{
      CellIndex2D(direction.To<North>()),
      CellIndex2D(direction.To<NorthEast>()),
      CellIndex2D(direction.To<East>())
    };
  }
};
template <>
struct AdjacentCells<Left>
{
  static CellIndex2DList Get(CellIndex2D targetCell)
  {
    Direction direction{ targetCell };

    return CellIndex2DList{
      CellIndex2D(direction.To<North>()),
      CellIndex2D(direction.To<NorthEast>()),
      CellIndex2D(direction.To<East>()),
      CellIndex2D(direction.To<SouthEast>()),
      CellIndex2D(direction.To<South>())
    };
  }
};
template <>
struct AdjacentCells<TopLeft>
{
  static CellIndex2DList Get(CellIndex2D targetCell)
  {
    Direction direction{ targetCell };

    return CellIndex2DList{
      CellIndex2D(direction.To<East>()),
      CellIndex2D(direction.To<SouthEast>()),
      CellIndex2D(direction.To<South>())
    };
  }
};

我们已经准备好定义例程,它实际上为我们提供了目标细胞的相邻细胞指数列表:

CellIndex2DList GetAdjacentCellIndices(CellIndex2D targetCell, std::size_t mfWidth, std::size_t mfHeight)
{
  //TODO: check that targetCell is within minefield bounds

  //Check if cell lies on one of the board edges (left, right, top, bottom)
  bool le = targetCell.X == 0;
  bool re = (targetCell.X + 1) == mfWidth;
  bool te = targetCell.Y == 0;
  bool be = (targetCell.Y + 1) == mfHeight;

  bool inc = !te && !be; //cell is between top and bottom edges
  bool inr = !le && !re; //cell is between left and right edges

  //cell is inside board
  if (inc && inr)
    return AdjacentCells<Inside>::Get(targetCell);

  //left edge cell
  if (le && inc)
    return AdjacentCells<Left>::Get(targetCell);
  //right edge cell
  if (re && inc)
    return AdjacentCells<Right>::Get(targetCell);
  //top edge cell
  if (te && inr)
    return AdjacentCells<Top>::Get(targetCell);
  //bottom edge cell
  if (be && inr)
    return AdjacentCells<Bottom>::Get(targetCell);

  //topleft corner cell
  if (te && le)
    return AdjacentCells<TopLeft>::Get(targetCell);
  //bottomleft corner cell
  if (be && le)
    return AdjacentCells<BottomLeft>::Get(targetCell);
  //topright corner cell
  if (te && re)
    return AdjacentCells<TopRight>::Get(targetCell);
  //bottomright corner cell
  if (be && re)
    return AdjacentCells<BottomRight>::Get(targetCell);

  return{};
}

让我们创建一个Minefield类,Generate函数将为创建雷区做一切艰苦的工作。我们只是在没有放置所有地雷的情况下循环。在每次迭代中,我们在板内生成随机索引,如果没有已经存在的矿,则按此索引放置并增加所有相邻单元的权重:

class MineField
{
public:
  MineField(std::size_t width, std::size_t height)
      :
  width_{ width },
  height_{ height },
  cells_{ width *height }
  {  }

  void Generate(std::size_t mineCount)
  {
    using unsigned_distribution = std::uniform_int_distribution<std::size_t>;

    std::random_device    rand;
    std::mt19937          engine(rand());

    unsigned_distribution xDist(0u, width_ - 1);
    unsigned_distribution yDist(0u, height_ - 1);

    std::uint16_t mc = 0;
    while (mc != mineCount)
    {
      CellIndex2D cellIndex{ xDist(engine), yDist(engine) };
      CellIndex1D index = convertIndex2DTo1D(cellIndex);

      if (hasMine(index))
        continue;

      putMine(index);

      //Increase weight for all adjacent squares around mine
      auto&& adjacentCellsList = GetAdjacentCellIndices(cellIndex, width_, height_);
      for (auto adjIndex : adjacentCellsList)
        increaseCellWeightByOne(convertIndex2DTo1D(adjIndex));

      ++mc;
    }
  }

  void Print() const
  {
    std::stringstream out{};

    std::size_t rowCellsCount = 0;
    for (auto&& cell : cells_)
    {
      if (cell.HasMine)
        out << "* ";
      else
        out << cell.Weight << " ";

      rowCellsCount++;
      if (rowCellsCount == width_)
      {
        out << '\n';
        rowCellsCount = 0;
      }
    }

    std::cout << out.str();
  }

private:
  struct Cell
  {
    std::size_t Weight;
    bool        HasMine;
  };

  bool hasMine(CellIndex1D cellIndex) const
  {
    return cells_[cellIndex].HasMine;
  }

  void putMine(CellIndex1D cellIndex)
  {
    cells_[cellIndex].HasMine = true;
  }

  void increaseCellWeightByOne(CellIndex1D cellIndex)
  {
    cells_[cellIndex].Weight = cells_[cellIndex].Weight + 1;
  }

  CellIndex1D convertIndex2DTo1D(CellIndex2D targetCell) const
  {
    return{ (targetCell.X + targetCell.Y * width_) };
  }

private:
  std::vector<Cell> cells_;
  std::size_t       width_;
  std::size_t       height_;
};

实际上是主要的应用程序。您可以在此处定义任何雷区大小和矿井数量:

int main()
{
  const std::size_t MfWidth = 9;
  const std::size_t MfHeight = 9;
  const std::size_t MineCount = 10;

  MineField mf{ MfWidth,MfHeight };

  mf.Generate(MineCount);
  mf.Print();

  return 0;
}

输出(地雷标有星星):

2 * 2 1 3 * 2 0 0
2 * 2 1 * * 2 0 0
1 1 1 1 2 2 1 0 0
0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 1 * 2
0 0 0 1 1 1 1 2 *
1 1 0 1 * 2 1 2 1
* 1 0 1 1 2 * 1 0
1 1 0 0 0 1 1 1 0

这段代码也不完美,可以通过重构得到很大改进,但我认为它更具可读性,可以轻松调试和测试。