如何随机生成一条狭窄的路径?

时间:2015-08-29 21:00:17

标签: algorithm random artificial-intelligence path-finding

我正在编写一个样本游戏,其中一个块永远落下,你需要从一侧到另一侧操纵它。如果你撞到墙壁,你会输。我正在尝试随机并不断地生成关卡,因此总会有一条路,所以路径逐渐变窄。

#       #
#       #
#      ##
#     ###
#    ####
#   #####
##  #####
##  #####
##   ####
###  ####
###   ###
####  ###
####  ###
###   ###
###   ###
##   ####
##   ####
##  #####
##  #####
## ######
## ######
## ######
## ######

我目前的方法是拥有一系列可能的路径,然后我随机选择一行。问题是路径不平滑,有时候变得不可能:

#       #
#    ####
#   #####
###   ###
##  #####
###  ####
#     ###
##  #####
####  ### <--- can't get through here
##   ####
####  ###
###   ###
#      ##
## ######
##  #####
## ######
##  #####
##  #####
##   ####
##   ####
#       #
###   ###
## ###### <--- or here
#       #
## ######
## ######

哪种算法可以帮助我开始使用它?

3 个答案:

答案 0 :(得分:2)

这里是一个简单算法的基础,可以通过改进来获得更具挑战性和趣味性的游戏。这里没有IA 它只是生成路径,由于路径较旧,所以总是可以实现。

基本思想是坚持使用将成为路径中间的索引 在那里你随机停留或向右或向左移动这个中间索引。 我已经在我的实现中选择随机获得更窄的路径。一种可能的改进是通过考虑到这种具有连贯路径的方式的广泛性来做出更深入和更聪明的动作(如果需要,可以做到这一点)。

// path is a vector of booleans
// wideness tells how narrow the path is
// middle represents the middle of the path
while wideness > 0
{
  thicken wideness sometimes
  move middle to the right, left, or do not move it
  print the path
}

你可以看一下 的 Live C++ code and algorithm here

结果可能如下所示:

|#      #########|
|##      ########|
|##      ########|
|###      #######|
|####      ######|
|###      #######|
|###      #######|
|####      ######|
|#####      #####|
|#####      #####|
|#####      #####|
|####      ######|
|#####      #####|
|######      ####|
|#######      ###|
|#######    #####|
|########    ####|
|#########    ###|
|########    ####|
|#########    ###|
|########    ####|
|#########    ###|
|#########    ###|
|########    ####|
|#########    ###|
|#########    ###|
|##########    ##|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|##########    ##|
|##########    ##|
|##########    ##|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|##########    ##|
|#########    ###|
|#########    ###|
|#########    ###|
|##########    ##|
|##########    ##|
|##########    ##|
|#########    ###|
|########    ####|
|#######    #####|
|######    ######|
|#######    #####|
|########    ####|
|#########    ###|
|########    ####|
|#########    ###|
|#########    ###|
|##########    ##|
|###########    #|
|##########    ##|
|##########    ##|
|###########    #|
|##########    ##|
|#########    ###|
|##########    ##|
|##########    ##|
|##########    ##|
|##########    ##|
|#########    ###|
|##########    ##|
|###########    #|
|##########    ##|
|###########    #|
|###########    #|
|###########    #|
|##########    ##|
|###########    #|
|##########    ##|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|###########    #|
|##########    ##|
|###########    #|
|###########    #|
|##########    ##|
|#########    ###|
|#########    ###|
|##########    ##|
|#########    ###|
|##########    ##|
|##########  ####|
|##########  ####|
|#########  #####|
|########  ######|
|#########  #####|
|#########  #####|
|########  ######|
|#########  #####|
|##########  ####|
|#########  #####|
|########  ######|
|########  ######|
|########  ######|
|#########  #####|
|#########  #####|
|##########  ####|
|#########  #####|
|##########  ####|
|##########  ####|

答案 1 :(得分:2)

我不确定课程,但可能适用以下原则。

你可以跟踪一个“洞中心指数”,i,它将跟踪任何给定水平的洞的中心,以及“当前洞口宽度”(将逐渐变小的东西),w

At each level:
 i <- i +/- (w / 2)
 w <- widthModify(w) //decreases width sometimes  
 for all "tokens" n on level
     if [n < i - (w / 2)] or [n > i + (w / 2)] print("#")
     else print(" ")

这意味着后续孔之间必须有一些重叠,因为下面的中心位于前一级的“孔的范围”。

答案 2 :(得分:1)

算法本身非常简单,正如其他人所建议的那样,要注意的要点是路径的连续性,这可以通过首先计算每行路径的宽度然后定位它来保证它。重叠前一行的间隙。

我们定义:

  • W f 是一个代表全宽的静态自然数(“级别宽度”)
  • W i 是一个小于或等于 W f 的自然数大于0表示第i行的路径宽度
  • X i MAX之间的自然数(0,X i-1 - W i + 1) MIN(W f - W i ,X i-1 < / sub> + W i-1 - 1)表示路径从第i行开始的行的位置

接下来,要生成 W i ,我们定义:

  • P 是一个介于0和1之间的实数,表示进度(随着时间,距离,得分而增长......适用于您的游戏)水平。
  • R w 是0(包括)和1(不包括)之间随机生成的实数。
  • F w i (W f ,P,R w )< / em> 计算 W i 。您需要一些非线性函数,允许所有 P 的全宽范围,但随着 P 前进,概率会下降。
    例如,您可以使用: W f (1 - (P(1 - R w )) 0.65 即可。您可以使用功率常数,或定义完全不同的功能来控制宽度。重要的是要记住将结果向上舍入为自然数。

最后,要生成 X i ,我们定义:

  • R x 是0(含)和1(独占)之间随机生成的实数。
  • F x i (W i ,W i-1 ,X i-1 ,R x ,它计算 X i
    函数是: R x MIN(W f - W i ,X i-1 + W i-1 - 1)+(1 - R x )MAX(0,X i-1 - W + 1) 。将结果舍入为自然数非常重要。

将所有这些放在一起,这是一个实时的JavaScript实现:

function PathRow(fullWidth, progress, prevRow) {
  var Rw = Math.random();
  var Rx = Math.random();
  this.width = Math.ceil(fullWidth * (1 - Math.pow(progress * (1 - Rw), 0.65)));
  if(prevRow) {
    this.x = Math.round(Rx * Math.min(fullWidth - this.width, prevRow.x + prevRow.width - 1) +
      (1 - Rx) * Math.max(0, prevRow.x - this.width + 1));
  }
  else {
    this.x = Math.round(Rx * (fullWidth - this.width));
  }
}

function Game(width, height, target) {
  this.progress = 0;
  this.width = width;
  this.height = height;
  this.target = target;
  this.path = [];
}
Game.prototype.next = function(progress) {
  this.progress = progress;
  this.path.push(new PathRow(this.width, this.progress, this.path[this.path.length - 1]));
  this.draw();
}
Game.prototype.draw = function() {
  var pathString = '';
  for(var i = Math.max(0, this.path.length - this.height + 1); i < this.path.length; i++) {
    pathString += '|' + new Array(this.path[i].x + 1).join('#') + new Array(this.path[i].width + 1).join(' ') + new Array(this.width - this.path[i].x - this.path[i].width + 1).join('#') + '|\r\n';
  }
  this.target.innerHTML = pathString;
}

var path = document.getElementById('path');
var go = document.getElementById('go');
go.onclick = function() {
  go.disabled = true;

  var game = new Game(20, 20, path);
  var progress = 0;
  var totalSteps = 480;
  var interval = setInterval(function() {
    game.next(progress++ / totalSteps);
    if(progress == totalSteps) {
      clearInterval(interval);
      go.disabled = false;
    }
  }, 125);
}
#path {
  white-space: pre;
  font-family: monospace;
}
<div id="path"></div>
<br/><br/>
<button id="go">Go!</button>