代码之家  ›  专栏  ›  技术社区  ›  Steerpike

确定网格上允许的移动

  •  2
  • Steerpike  · 技术社区  · 17 年前

    有人能提出一个合适的方法来计算出一个可以在网格上移动的部件,类似于下面的图片。

    grid layout

    假设piece1在位置a1,piece2在位置c3,如果piece1可以移动(比如说)3个正方形,piece2可以移动2,我如何确定哪些网格正方形是允许移动的?

    我花了太长的时间来开发基于文本的muds,看起来,我根本无法让我的大脑进入下一步,如何可视化潜在的运动,即使是在最简单的情况下。

    如果这很重要的话,我正在尝试用JavaScript实现这一点,但老实说,我认为我在这里的失败是概念化的失败,而不是语言理解的失败。

    更新-我正在添加在发布以下响应之后编写的第一轮代码。我认为在与我类似的情况下,看到代码可能对人们有用

    它很马虎,目前只适用于一个放在板上的项目,但至少 check_allowable_moves() 函数用于此初始运行。对于那些想知道为什么我要创建那些奇怪的字母数字对象而不仅仅是使用数字X轴和Y轴的人来说,这是因为HTML中的ID不能以数字开头。其实假装我 能够 使用数字启动ID在很大程度上有助于理解我得到的奇妙答案所描述的功能和概念。

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
    <meta http-equiv="Content-Type" content="application/xhtml+xml;utf-8"/>
    
    <title>Test page</title>
    <style> 
    
        #chessboard { clear: both; border:solid 1px black; height: 656px; 
                      width:656px; /*width = 8*40 + 16 for border*/ }
        #chessboard .row { overflow: auto; clear: both; }
        #chessboard .row span { display: block; height: 80px; 
                                width: 80px; float: left; 
                                border:solid 1px black; }
        .allowable { background: blue; }
    </style>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">
        google.load("jquery", "1.2.6");
        google.load("jqueryui", "1.5.3");
    </script>
    <script type="text/javascript">
    $(document).ready(function() {
        (function() {
        var global = this;
        global.Map = function(container) {
            function render_board() {
            var max_rows = 8;
            var cols = new Array('a','b', 'c', 'd', 'e', 'f', 'g', 'h');
            var jqMap = $('<div />');
            jqMap.attr('id', 'chessboard');
            var x=0;
            for(x; x<max_rows; x++) {
                var jqRow = $('<span />');
                jqRow.addClass('row');
                var i=0;
                for(i; i<cols.length; i++) {
                    var jqCol = $('<span />');
                    jqCol.attr('id', cols[i]+(x+1));
                    jqCol.addClass(cols[i]);
                    jqRow.append(jqCol);
                }
              jqMap.append(jqRow);
            }
         $('#'+container).append(jqMap);
       }
       function add_piece(where, id) {
         var jqPiece = $('<div>MY PIECE'+id+'</div>');
         var jqWhere = $('#'+where);
         jqPiece.attr('id', 'piece-'+id);
         jqPiece.addClass('army');
         jqPiece.draggable({cursor: 'move',
                                  grid:[82, 82],
                                  containment: '#chessboard',
                                  revert: 'invalid',
                                  stop: function(ev, ui) {
                                    //console.log(ev.target.id);
                                  }
                                });
         jqWhere.append(jqPiece);
         check_allowable_moves(where);
        }
        function check_allowable_moves(location) {
         var x_axis = { 'a':1,'b':2, 'c':3, 'd':4, 'e':5, 'f':6, 'g':7, 'h':8 };
         var x_axis_alpha = { 1:'a',2:'b', 3:'c', 4:'d', 5:'e', 6:'f', 7:'g', 8:'h' };
         $('.allowable').droppable("destroy");
         $('.allowable').removeClass('allowable');
         //get the x,y values of the piece just placed
         var x = parseInt(x_axis[location[0]], 10);
         var y = parseInt(location[1], 10);
         var x_min = x-2;
         var y_min = y-2;
          for(x_min; x_min<=x+2; x_min++) {
            for(y_min; y_min<=y+2; y_min++) {
               var jqCell = $('#'+x_axis_alpha[x_min]+y_min)
               jqCell.addClass('allowable');
               jqCell.droppable({ accept: '.army',
                  drop: function(ev, ui) {
                    //console.log(ev, ui, $(this));
                    //handle_drop(ev, ui, $(this));
                    check_allowable_moves($(this).attr('id'));
                  }
                });
            }
            y_min = parseFloat(y)-2;
          }
        }
        render_board();
        add_piece('d5', '2');
       }
     })();
    var map = new Map('content');
    });
    </script>
    </head>
    
    <body id="debug">
        <div id="page">
            <div id="content"> </div>
        </div><!-- end page -->
    </body>
    </html>
    
    4 回复  |  直到 12 年前
        1
  •  3
  •   Dan Lew    17 年前

    假设工件P在位置X,Y,并且可以将N个正方形移到位置X2,Y2。这意味着(x-x2)和(y-y2)之间的绝对差之和不能大于n。

    如果你要显示哪些方块可以移动(而不是接受输入x2和y2),我认为最好是在一个方块中的所有位置上绕一圈。那是…

    for (x - n TO x + n):
        for (y - n TO x + n):
            if (abs(x - x2) + abs(y - y2) <= n):
                mark as okay.
    

    这个答案假设棋子只能移动到相邻的正方形,而不能对角移动。

    编辑:如果你想要对角线移动,沿着对角线移动的成本和水平或垂直移动的成本一样多,那么问题实际上要容易得多——工件P可以在(x-n,x+n)和(y-n,y+n)之间移动。

    如果对角移动的成本没有水平+垂直移动的成本高(例如,如果对角移动的成本为1.5,而H/V的成本为1),那么答案就变得更加复杂。

        2
  •  2
  •   Loren Pechtel    17 年前

    一般来说,这些问题涉及到一个可以到达的合理有限的区域网格。采用网格大小的数据结构,其元素能够以足够的精度保存剩余移动点的数量。

    将网格初始化为未访问的值。这不得在零到最大可能移动速度的范围内。负值是理想值。

    将起始位置初始化为剩余移动数。

    此时,有三种可能的方法:

    1)每一步重新扫描整个网格。简单但较慢。终止是指没有任何一点产生合法的行动。

    2)将点存储在堆栈上。比1快,但仍然不是最好的。当堆栈为空时终止。

    3)将点存储在队列中。这是最好的。当队列为空时终止。

    Repeat
       ObtainPoint {From queue, stack or brute force}
       For Each Neighbor do
          Remaining = Current - MovementCost
          If Remaining > CurrentValue[Neighbor] then
             CurrentValue[Neighbor] = Remaining
             Push or Queue Neighbor
    Until Done
    

    请注意,使用基于堆栈的方法,您总是会遇到一些情况,最终会抛出旧的计算并再次执行它们。只有在某些情况下,绕过坏地形比穿过坏地形便宜时,才会采用基于队列的方法。

    仅在循环结束时检查终止条件,否则在ObtainPoint尝试使用空队列或堆栈时终止。ObtainPoint之后的空队列/堆栈 不是 意思是你完了!

    (请注意,这是对伊恩答案的相当大的扩展。)

        3
  •  1
  •   Ian Jacobs    17 年前

    这纯粹是在概念层面上的,但请尝试以下逻辑:

    1. 把所有可能的位置都放在离起点一步远的地方,然后把它们放在堆栈上(移动量=0)

    2. 从堆栈中弹出一个并重复,使用新坐标作为新的起点。(移动=1)。您必须确保不会在堆栈上放置任何重复的坐标。

    3. 重复第2步,直到你用尽了所有可用的动作。

    我可能没有解释清楚,如果你对我想说的有任何疑问,请告诉我。

        4
  •  0
  •   Chris Nava    17 年前

    您可以使用上面的方法,但使用递归。

    递归“深度”是移动距离。

    深度移动时中断。

    每次迭代都应该返回一个空间向量并添加自己的位置。

    删除重复项

    推荐文章