什么是表示游戏状态的良好数据结构Dots and Boxes?
我提出使用2个布尔矩阵,用于水平和垂直线,但也许有更优雅的方法(以及操作:添加行,检查行< / em>, check square )。
答案 0 :(得分:2)
使用一对名为linesX
和linesY
的二维布尔数组对我来说很有意义。在给定的X / Y方向上,每个阵列将比板上的方块总数多一行/列。以下是使用该解决方案的 check square 的代码示例:
bool isSquareComplete(int x, int y) {
return linesX[x][y] && linesX[x + 1][y] && linesY[x][y] && linesY[x][y + 1];
}
答案 1 :(得分:2)
我最近这样做并使用了盒子对象的地图。地图是一个元组和框对象。这允许非常快速的访问并且更容易实现边缘算法。对于&lt; -1,0&gt;检查失败要容易得多。而不是特殊情况下的左边缘。为避免数据重复,有一个表示边的数组,而且框对象知道如何访问它。
使用box对象而不仅仅是数组的一个优点是它使策略算法更容易。您经常希望跟踪接近满的盒子列表等。这在数组中不能轻易完成。
答案 2 :(得分:1)
我会使用一个与游戏区域大小相对应的二维数组。然后,数组中的每个元素都可以存储包含4个bool的对象(或结构,具体取决于所使用的语言),每个元素一个。检查框是否完整就像在给定坐标处返回对象的逻辑和那样简单。
单个二维阵列使维护和故障排除错误变得更加容易。
答案 3 :(得分:1)
我的可玩游戏,可调节的W,H和numPlayers,在这里: http://pconstrictor.github.io/cellsurround/
(源代码也在那里。仍然需要重构为ES6模块语法,并希望使用FP重写。所以,如果有更简单的模型设计,我很乐意知道。)
对于数据模型,我使用了一个大小为w乘以h的单个2D数组。每个单元格都有一个边的列表(在这个正方形网格的情况下为四个)并且变为“填充”。当所有方面都被填满时#39;请注意,然后用户获得额外的转弯。此外,有时单个动作会导致两个单元同时被填充。
// MODEL
exports.SquareGrid = function(width, height, players) {
// reset (also serves as init)
this.reset = function(w, h, players) {
this.players = players;
this.player = players.firstPlayer();
var m = [];
this.matrix = m; // will be a 2D array (well, array of arrays)
this.height = h;
this.width = w;
// fill matrix
var toLeft = null, above = null; // these will be used for cells
// sharing sides
for (var row = 0; row < h; row++) {
m[row] = [];
for (var col = 0; col < w; col++) {
toLeft = col ? m[row][col - 1] : null;
above = row ? m[row - 1][col] : null;
m[row][col] = exports.createSquareCell(above, toLeft);
}
}
}
...
}
对于实际显示 UI,我使用单个2D数组(大小为2w + 1乘2h + 1)作为视图模型,其中点,边和单元都被简单地表示无论是填充还是空。 (点开始填充并始终保持如此。)这很好地转换为一个HTML表,可以使用两个循环轻松渲染,没有额外的逻辑。这是与9x4模型相对应的7乘9阵列。请注意,理想情况下,这些伪列和行应以交替的大小显示,只是出于视觉原因。
(w = 3, h = 4) so (ww = 7, hh = 9)
. ___ . ___ . ___ .
| | | |
| | p1 | p1 |
. . ___ . ___ .
| | | |
| | p1 | p2 |
. . ___ . ___ .
| | |
| | |
. . ___ . .
| |
| |
. ___ . ___ . ___ .
这是实际的视图模型。
// VIEW MODEL
exports.SquareGridView = function(gameModel, appId, resetFuncString) {
// prepare to render the latest of whatever is in the model
this.refresh = function() {
var h = this.gridModel.height;
var w = this.gridModel.width;
// Initialize the UI table, whose dimensions are bigger than the
// model's.
var viewPm = [];
var hh = viewCoord(h);
var ww = viewCoord(w);
for (var i = 0; i < hh; i++) {
viewPm[i] = [];
}
// But loop over the model when actually filling it in. (Shared
// cells cause double writes to viewPm, but oh well.)
for (var row = 0; row < h; row++) {
for (var col = 0; col < w; col++) {
var cell = this.gridModel.matrix[row][col];
var i = viewCoord(row), j = viewCoord(col);
viewPm[i][j] = cell.owner;
viewPm[i - 1][j] = cell.sides['top'];
viewPm[i + 1][j] = cell.sides['bottom'];
viewPm[i][j - 1] = cell.sides['left'];
viewPm[i][j + 1] = cell.sides['right'];
// Note: vertices can be either filled or left undefined here (and hard-coded as filled in the HTML).
}
}
...
这里是实际的render-as-html步骤:
var t = []; // the html text
// TODO: split the HTML bits out into a template file? Use React or Elm?
...
t.push('<table class="squaregrid">\n');
var tdClass, tdId; // 'vertex', '0.0';
for (var i = 0; i < hh; i++) {
t.push(" <tr> \n");
for (var j = 0; j < ww; j++) {
t.push(this.tdHtml(viewPm, i, j));
}
t.push(" </tr>\n");
}
t.push("</table>\n");
...
省略tdHtml()
函数 - 它生成一个具有正确ID和类的TD。