Javascript - 尝试使用递归调用进行引用传递

问题描述 投票:1回答:2

在2个玩家游戏的上下文中,我有一个C函数执行递归调用,并且对于每个调用,它从全局数组变量和当前本地数组执行memcpy。这是这个C函数(“游戏”数组在函数外声明为全局变量):

int game[8][8];

int recursive_function(int player, int *mx, int *my, int depth)                           

{                                                                                        
  int x, y;
  int eval, e;                                                                           
  int mx2, my2;                                                                          
  int game2[8][8];

  // TERMINAL CASE
  if (depth == 0) {
    return 1;
  }

  memcpy(game2, game, sizeof(game));                                                     
  eval = -INFINITY;                                                                        

  for (x = 0; x < 8; x++)       
    for (y = 0; y < 8; y++) {
      if (isplayabe((x, y, player)) {                                                    
        e = -recursive_function(OTHER(player), &mx2, &my2, depth-1);                          
      }
      if (e > eval) {                                                                    
        *mx = x; *my = y;
        eval = e;
      }                                                                                  
      memcpy(game, game2, sizeof(game));                                                 
      }                                                                                  
  return eval;
}

现在,我想在javascript中实现相同的功能。

我想我必须使用对象进行引用传递。所以我为它们中的每一个创建了对象HitHitTemp,数组的坐标作为属性:

  1. Hit.coordPlaybles(x,y)坐标,并使链接相当于上面的game变量
  2. HitTemp.coordPlaybles(x,y)坐标,并使链接相当于上面的game2变量

从这开始,我尝试使用Object Hit定义:

// Player white and black
var playerWhite = ['white', 'black'];
var playerBlack = ['black', 'white'];

var Hit = {
 currentPlayer: playerBlack,
 coordPlayable: ['0', '0'],
 coordCurrent: ['0', '0'],
};

对象Hit在recursive_function(全局变量)之外声明,而HitTemp仅在此函数(局部变量)中定义。

这是我做的:

// Object Hit passed by reference
function recursive_function(Hit, depth) {
  // Evaluation
  var eval, e;

   // TERMINAL CASE
      if (depth == 0) {
        return 1;
      }

  // Local Hit object : EQUIVALENT OF "memcpy" ??
  var HitTemp = Object.assign({}, Hit);

  eval = -infinity;       

  for (var x = 0; x < 8; x++)
    for (var y = 0; y < 8; y++) {
      if (isplayabe((x, y, HitTemp)) { 
        // CALL RECURSIVE WITH OPPOSITE PLAYER (SWITCHING PLAYER)                                                   
        e = -recursive_function(OTHER(HitTemp.currentPlayer), depth-1);  
        if (e > eval) {
                  // HitTemp.coordCurrent[0] = *mx
                  // HitTemp.coordPlayable[0] = x
                  // HitTemp.coordCurrent[1] = *my
                  // HitTemp.coordPlayable[1] = y
                  HitTemp.coordCurrent[0] = HitTemp.coordPlayable[0];
                  HitTemp.coordCurrent[1] = HitTemp.coordPlayable[1];
                  eval = e;
                }
   // Final copy from HitTemp to Hitobject : Here also, equivalent to 
   // the final memcpy of C version ??
   Hit = Object.assign({}, HitTemp);
  }
return eval;
}

不幸的是,两个版本之间的结果是完全不同的(我确信C版本工作正常)。

谁能告诉我,如果Javascript“assign”方法是重现C“memcpy”功能的行为的正确方法?

如果没有,你能给我一些线索来通过递归调用来解决它吗?

更新1:

谢谢你的帮助。但是,@Siltaar提出的解决方案存在问题。事实上,如果我使用JSON.parse(JSON.stringify(HitCurrent))进行深度复制:

// Global variables : Player white and black
var playerWhite = ['white', 'black'];
var playerBlack = ['black', 'white'];

//Global variable Hit 
var Hit = {
 currentPlayer: playerBlack,
 coordPlayable: ['0', '0'],
 coordCurrent: ['0', '0'],
};

function recursive_function(HitCurrent, depth) {

// Deep copy
var HitTemp = JSON.parse(JSON.stringify(HitCurrent));

// Switch color for player

// BEFORE
console.log('BEFORE = ', HitTemp.currentPlayer);

// Switch
HitTemp.currentPlayer = (HitTemp.currentPlayer == playerBlack) ? playerWhite : playerBlack;

// AFTER : expected the opposite of BEFORE
console.log('AFTER = ', HitTemp.currentPlayer);

...
}

我得到了BEFOREAFTER

BEFORE =  
Array [ "black", "white" ]

AFTER =  
Array [ "black", "white" ]

如您所见,“HitTemp.currentPlayer”的值未切换,似乎“HitTemp.currentPlayer == playerBlack”设置为false,而“BEFORE”的“HitTemp.currentPlayer”值设置为“playerBlack”。

我必须注意recursive_function是用Hit中的全局对象main(调用的,例如:

    //Global variable Hit 
    var Hit = {
     currentPlayer: playerBlack,
     coordPlayable: ['0', '0'],
     coordCurrent: ['0', '0'],
    };

    // Main function
    function main() {

        recursive_function(Hit, maxDepth);
    ...

    }

这个问题是否与HitCurrentHitTemp对象的深层副本有关系?

更新2:

如果我只使用一个“=”(而不是两个“==”),如下所示:

console.log('BEFORE = ', HitTemp.currentPlayer);
HitTemp.currentPlayer = (HitTemp.currentPlayer = playerBlack) ? playerWhite : playerBlack;
console.log('AFTER = ', HitTemp.currentPlayer);

然后切换工作:什么是正确的语法(一个“=”符号或两个)与三元运算符的条件来测试相等?

javascript recursion memcpy
2个回答
0
投票

MDN Object.assign()https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

深度克隆警告

对于深度克隆,我们需要使用其他替代方法,因为Object.assign()复制属性值。如果源值是对象的引用,则它仅复制该引用值。

在你的情况下,currentPlayer: playerBlack没有被深层复制。

解决方案如:

obj = JSON.parse(JSON.stringify(o));

在这里建议:What is the most efficient way to deep clone an object in JavaScript?

关于UPDATE 1:您比较两个不同的对象,它们是具有相同值但内存中不同对象的副本。尽量只比较字符串或整数来区分你的玩家。 - Siltaar 2分钟前编辑

Regardine UPDATE 2:只有一个等号“=”的语法是归属语句。归因通常会返回true。您正在尝试进行比较,因此我建议您坚持使用“==”或“===”(如果对象类型很重要)。


0
投票

Object.assign执行浅拷贝。根据您上面的评论,您似乎想要一份深层副本。如果你知道这个数据结构不会改变那么这样的东西会起作用:

var HitTemp = Object.assign({}, Hit, {
    coordPlayable: Hit.coordPlayable.slice(0),
    coordCurrent: Hit.coordCurrent.slice(0)
});

如果你想要一个更清洁,更通用的解决方案,请查看来自lodash的cloneDeep。由于这是一场比赛而且表现可能是一个问题,这个question值得一试。

© www.soinside.com 2019 - 2024. All rights reserved.