Javascript - 尝试通过递归调用进行引用传递
Javascript - trying to do reference passing with recursive calls
在 2 人游戏的上下文中,我有一个执行递归调用的 C 函数,对于每次调用,它从全局数组变量和当前局部数组执行 memcpy
。这是这个 C 函数(“game”数组在函数外声明为全局变量):
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)
坐标并使 link 等同于 上方的 game
变量
HitTemp.coordPlaybles
是 (x,y)
坐标并使 link 等同于 上方的 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:
感谢您的帮助。但是,我对建议的解决方案有疑问
@西尔塔。的确,如果我用 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 而“HitTemp.currentPlayer
”的“BEFORE
”值设置为“playerBlack
”。
我必须注意 recursive_function
是在 main(
) 中使用全局对象 Hit
调用的,例如:
//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);
然后切换工作:用三元运算符的条件来测试相等性的正确语法(一个或两个“=”符号)是什么?
Object.assign 执行浅拷贝。根据您上面的评论,您似乎想要一份深层副本。如果你知道这个数据结构不会改变,那么像这样的东西会起作用:
var HitTemp = Object.assign({}, Hit, {
coordPlayable: Hit.coordPlayable.slice(0),
coordCurrent: Hit.coordCurrent.slice(0)
});
如果您想要一个更简洁、更通用的解决方案,请查看 cloneDeep from lodash. Since this is a game and performance may be a concern this question 值得一试。
MDN Object.assign()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Warning for Deep Clone
For deep cloning, we need to use other alternatives because
Object.assign() copies property values. If the source value is a
reference to an object, it only copies that reference value.
在你的情况下,currentPlayer: playerBlack
没有被深度复制。
解决方案如:
obj = JSON.parse(JSON.stringify(o));
这里被告知:What is the most efficient way to deep clone an object in JavaScript?
关于 更新 1:您比较两个不同的对象,它们是具有相同值的副本,但内存中的对象不同。尝试只比较字符串或整数以区分您的玩家。 – Siltaar 2 分钟前编辑
Regardine 更新 2 : 只有一个等号“=”的语法是一种归属声明。归因通常 return 正确。您正在尝试进行比较,所以我建议坚持使用“==”或“===”(如果对象类型很重要)。
在 2 人游戏的上下文中,我有一个执行递归调用的 C 函数,对于每次调用,它从全局数组变量和当前局部数组执行 memcpy
。这是这个 C 函数(“game”数组在函数外声明为全局变量):
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)
坐标并使 link 等同于 上方的 HitTemp.coordPlaybles
是(x,y)
坐标并使 link 等同于 上方的
game
变量
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:
感谢您的帮助。但是,我对建议的解决方案有疑问
@西尔塔。的确,如果我用 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 而“HitTemp.currentPlayer
”的“BEFORE
”值设置为“playerBlack
”。
我必须注意 recursive_function
是在 main(
) 中使用全局对象 Hit
调用的,例如:
//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);
然后切换工作:用三元运算符的条件来测试相等性的正确语法(一个或两个“=”符号)是什么?
Object.assign 执行浅拷贝。根据您上面的评论,您似乎想要一份深层副本。如果你知道这个数据结构不会改变,那么像这样的东西会起作用:
var HitTemp = Object.assign({}, Hit, {
coordPlayable: Hit.coordPlayable.slice(0),
coordCurrent: Hit.coordCurrent.slice(0)
});
如果您想要一个更简洁、更通用的解决方案,请查看 cloneDeep from lodash. Since this is a game and performance may be a concern this question 值得一试。
MDN Object.assign() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Warning for Deep Clone
For deep cloning, we need to use other alternatives because Object.assign() copies property values. If the source value is a reference to an object, it only copies that reference value.
在你的情况下,currentPlayer: playerBlack
没有被深度复制。
解决方案如:
obj = JSON.parse(JSON.stringify(o));
这里被告知:What is the most efficient way to deep clone an object in JavaScript?
关于 更新 1:您比较两个不同的对象,它们是具有相同值的副本,但内存中的对象不同。尝试只比较字符串或整数以区分您的玩家。 – Siltaar 2 分钟前编辑
Regardine 更新 2 : 只有一个等号“=”的语法是一种归属声明。归因通常 return 正确。您正在尝试进行比较,所以我建议坚持使用“==”或“===”(如果对象类型很重要)。