在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
变量从这开始,我尝试使用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);
...
}
我得到了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);
然后切换工作:什么是正确的语法(一个“=”符号或两个)与三元运算符的条件来测试相等?
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。您正在尝试进行比较,因此我建议您坚持使用“==”或“===”(如果对象类型很重要)。