用Javascript和不一致的数组值混洗牌?
我正在JavaScript中构建一个小模块以充当一副卡片。我的第一种方法很有效,但很简单,所以我想创建一些模仿真实世界卡洗牌背后思想的洗牌方法。用Javascript和不一致的数组值混洗牌?
其中一些其他有用的功能,我创建了riffle,上手和削减功能,似乎都在那里工作,但当按顺序重复调用它们时,返回的包数量不一致,从反复运行它似乎是某种竞争条件,但似乎无法让我的头脑如何避免它。
相关的私有方法是:
riffle : function riffle() {
var top = Pack.slice(0, 26);
var bottom = Pack.slice(26, 52);
Pack = [];
console.log('top is '+top.length+" and bottom is "+bottom.length);
var hand = 'right';
var result = [];
var i = 52;
while (i > 0) {
var drop = Math.floor(Math.random()*3)+1;
var cards;
if (hand === 'right') {
if (drop >= top.length) {
cards = top;
} else {
cards = top.splice(0, drop);
}
hand = 'left';
} else {
if (drop >= bottom.length) {
cards = bottom;
} else {
cards = bottom.splice(0, drop);
}
hand = 'right';
}
result = result.concat(cards);
i -= drop;
}
Pack = result;
console.log(Pack.length+" after riffle");
return this;
},
cut : function cut(fn) {
var top = Pack.slice(0, 26);
var bottom = Pack.slice(26, 52);
Pack = [];
console.log(top);
Pack = bottom.concat(top);
console.log(Pack.length+" after cut");
if (fn && typeof(fn) === 'function') { fn(); }
return this;
}
后来我有一个叫洗牌特权的方法来调用它们:
shuffle : function shuffle(cb) {
State.cardsOut = [];
Internal.generatePack().cut().riffle().riffle()
.riffle().riffle().riffle();
if (cb && typeof(cb) === 'function') { cb(); }
}
注:我先说一个生成函数创建的arrray代表全套52张卡片的物品。当我在洗牌和裁员后的不同时间登录游戏包时,我得到的结果各不相同,我似乎无法弄清楚原因。
你可以看到什么i'km工作就在这里
https://gist.github.com/Pushplaybang/66bc7a1fa5d84eee2236
任何帮助将真棒。
drop
变量存储了您应该从左手或右手轻松抽出的牌的数量。然而,有两种情况:
if (drop >= top.length) {
cards = top;
}
和
if (drop >= bottom.length) {
cards = bottom;
}
其中drop
可以比其余的卡包这么多卡将从i
减去比你的一半数量越多实际上是轻微的。你可以解决这个问题的:
if (drop >= top.length) {
drop = top.length;
cards = top;
top = [];
}
和
if (drop >= bottom.length) {
drop = top.length;
cards = bottom;
bottom = [];
}
(你需要清空阵列或者你可能最终加入同一卡的两倍)。
其他问题
- 你的代码(
26
和52
),这些可以在类中的常量定义,并给出相应的名称(即PACK_SIZE = 52
),这将意味着,如果你创建一个有魔力的数字子类代表不同数量的卡,那么它仍然可以工作。 -
hand
有两个可能的值,可以表示为一个布尔值,但是可以将其赋值为字符串(也可以使用常量LEFT_HAND = true, RIGHT_HAND = !LEFT_HAND
)。 -
Pack
似乎是一个全局变量 - 我原以为它应该是该类的成员。 - 您不需要命名函数,因为这只是污染全局命名空间:
riffle : function riffle() {
可以只是一个匿名函数riffle : function() {
。 - 性能 - 您可以在每次迭代时创建额外的阵列,并且卡片会多次移动。这可能更有效率。
事情是这样的:
PACK_SIZE: 52,
riffle : function() {
var index_of_cards_riffled_from_top = 0;
var index_of_cards_riffled_from_bottom = this.PACK_SIZE/2;
var riffled_cards = [];
while (index_of_cards_riffled_from_top < this.PACK_SIZE/2
|| index_of_cards_riffled_from_bottom < this.PACK_SIZE) {
var num_cards_to_riffle_top = Math.min(this.PACK_SIZE/2 - index_of_cards_riffled_from_top, Math.floor(Math.random() * 3) + 1);
var num_cards_to_riffle_bottom = Math.min(this.PACK_SIZE - index_of_cards_riffled_from_bottom, Math.floor(Math.random() * 3) + 1);
while (num_cards_to_riffle_top > 0) {
riffled_cards.push(this.Pack[ index_of_cards_riffled_from_top++ ]);
num_cards_to_riffle_top--;
}
while (num_cards_to_riffle_bottom > 0) {
riffled_cards.push(this.Pack[ index_of_cards_riffled_from_bottom++ ]);
num_cards_to_riffle_bottom--;
}
}
this.Pack = riffled_cards;
}
这是一个很好的答案,谢谢你,我完全按照你的建议努力做到这一点。我也开始为我的裁剪方法和裁减裁剪添加随机性。制作包装大小也是很重要的,因为我想要选择排除卡片或包括特定游戏的玩家。 – pushplaybang
请注意,实际问题是当顶部和底部数组低于或等于丢弃量时,不会清空顶部和底部数组。但其他信息也很有见地。 – pushplaybang
而@MTO的回答没有解决我的问题,我想阐明我如何选择开始重构这一功能的一些情况。
riffle : function riffle() {
var cutPos = Math.floor(Math.random()*rv)+((cardCount-rv)/2);
var splitPack = {
left : Pack.splice(0, cutPos),
right : Pack.splice(0, Pack.length)
};
var hand = 'right',result = [], i = 52, cards;
while(i > 0) {
drop = Math.floor(Math.random()*3)+1;
if (drop >= splitPack[ hand ].length) {
drop = splitPack[ hand ].length;
}
cards = splitPack[ hand ].splice(0, drop);
hand = (hand === 'left') ? 'right' : 'left';
result = result.concat(cards);
cards = [];
i -= drop;
}
Pack = result;
console.log(Pack.length+" after riffle");
return this;
},
几件事情:
- ,似乎全球都算不上,因为这是所有创建了一个新的“甲板”对象的函数内包裹的元素,有些元素需要以民间,例如一旦交易开始后仍然在包中的卡片。
- 尽管布尔值可以很好地用于手中,但我还是想稍微调整一下,并使用这些字符串来选择obj属性。
- MTO所说的关于使用常量的说法绝对有效。
- 现在每次拼接,我们将从数组中删除元素。
- 我更喜欢这种方法,因为它只使用一个while循环。
- 最后,这种类型的洗牌是为了模仿手洗牌,并且必须与其他手洗牌方法结合,理想情况下以重复的顺序,以产生一些有用的东西,如果你想要一致的随机和有效使用fischer的东西-yates算法。
我明白动机,但真正的随机洗牌后面有[数学理论](http://eli.thegreenplace.net/2010/05/28/the-intuition-behind-fisher-yates-shuffling/) 。 – Pointy
不是你的问题的答案,但当我看着你的要点,我看到一个奇怪的语法错误,我认为。 第104行:var drop z = Math.floor(Math.random()* 9)+1; –
你用'drop'中的值减少'i',但'drop'可能比实际卡片拼接的数量要高。在你的drop> = top.length'(和bottom)块中,你应该将drop设置为top.length(或bottom.length)。或测试顶部和底部的长度,即'while(top.length && bottom.length)' –