在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中实现相同的功能。
我想我必须使用对象进行引用传递。所以我为每个对象创建了对象Hit
和HitTemp
,将数组的坐标作为属性:
Hit.coordPlaybles
是(x,y)
坐标,并将该链接视为上面game
变量的等效内容HitTemp.coordPlaybles
是(x,y)
坐标,并将该链接视为上面game2
变量的等效内容从此,我尝试使用以下定义的对象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);
...
}
我得到了BEFORE
和AFTER
:
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);
...
}
此问题是否与HitCurrent
到HitTemp
对象的深层副本有关?
更新2:
如果我只使用一个“=”(而不是两个“==”):
console.log('BEFORE = ', HitTemp.currentPlayer);
HitTemp.currentPlayer = (HitTemp.currentPlayer = playerBlack) ? playerWhite : playerBlack;
console.log('AFTER = ', HitTemp.currentPlayer);
然后切换工作:什么是正确的语法(一个“=”符号或两个)与三元运算符的条件来测试相等?
答案 0 :(得分:0)
Object.assign执行浅拷贝。根据您上面的评论,您似乎想要一份深层副本。如果你知道这个数据结构不会改变那么这样的东西就可以了:
var HitTemp = Object.assign({}, Hit, {
coordPlayable: Hit.coordPlayable.slice(0),
coordCurrent: Hit.coordCurrent.slice(0)
});
如果您想要更清洁,更通用的解决方案,请查看来自lodash的cloneDeep。由于这是游戏,性能可能是一个问题,因此question值得一试。
答案 1 :(得分:0)
MDN Object.assign() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
深度克隆警告
对于深度克隆,我们需要使用其他替代方法,因为 Object.assign()复制属性值。如果源值是a 引用一个对象,它只复制该引用值。
在您的情况下,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。您正在尝试进行比较,因此我建议您坚持使用“==”或“===”(如果对象类型很重要)。