Javascript 小直线(Yahtzee)算法
在我正在制作的Yahtzee游戏中,我创建了一个javascript函数来检查5个数字组成的数组中的小直线。我已经对它进行了无休止的测试,我相信它在100%的时间内都能工作,但就效率而言,它也可能是有史以来最差的算法。下面是它的外观:Javascript 小直线(Yahtzee)算法,javascript,algorithm,Javascript,Algorithm,在我正在制作的Yahtzee游戏中,我创建了一个javascript函数来检查5个数字组成的数组中的小直线。我已经对它进行了无休止的测试,我相信它在100%的时间内都能工作,但就效率而言,它也可能是有史以来最差的算法。下面是它的外观: function calcSmstraight() { var sum = 0; var r = new Array(); var r2 = new Array(); var counter = 0;
function calcSmstraight() {
var sum = 0;
var r = new Array();
var r2 = new Array();
var counter = 0;
var temp;
var bool = false;
var bool2 = false;
r[0] = document.getElementById('setKeep1').value;
r[1] = document.getElementById('setKeep2').value;
r[2] = document.getElementById('setKeep3').value;
r[3] = document.getElementById('setKeep4').value;
r[4] = document.getElementById('setKeep5').value;
// Move non-duplicates to new array
r2[0] = r[0];
for(var i=0; i<r.length; i++) {
for(var j=0; j<r2.length; j++) {
if(r[i] == r2[j]) {
bool2 = true; // Already in new list
}
}
// Add to new list if not already in it
if(!bool2) {
r2.push(r[i]);
}
bool2 = false;
}
// Make sure list has at least 4 different numbers
if(r2.length >= 4) {
// Sort dice from least to greatest
while(counter < r2.length) {
if(r2[counter] > r2[counter+1]) {
temp = r2[counter];
r2[counter] = r2[counter+1];
r2[counter+1] = temp;
counter = 0;
} else {
counter++;
}
}
// Check if the dice are in order
if(((r2[0] == (r2[1]-1)) && (r2[1] == (r2[2]-1)) && (r2[2] == (r2[3]-1)))
|| ((r2[1] == (r2[2]-1)) && (r2[2] == (r2[3]-1)) && (r2[3] == (r2[4]-1)))) {
bool = true;
}
}
if(bool) {
// If small straight give 30 points
sum = 30;
}
return sum;
}
我的问题:
有人知道我可以改进这种方法的方法吗?对我来说,这似乎太可怕了,但我想不出更好的方法来做到这一点,至少它是有效的。为什么不用一个六元素布尔数组来指示是否存在一个数字,然后检查1-4、2-5和3-6是否都是真的?在伪代码中:
numFlags = array(6);
foreach(dice)
numFlags[die.value-1] = true;
if(numFlags[0] && numFlags[1] && numFlags[2] && numFlags[3]) return true
//Repeat for 1-4 and 2-5
return false
如果你使用的是百万面骰子,这不是一个有用的算法,但是对于六面骰子来说,只有三个可能的小直线可以检查,所以它简单而直接。为什么你不用一个六元素布尔数组来指示一个数是否存在,然后检查1-4、2-5和3-6是否都是真的?在伪代码中:
numFlags = array(6);
foreach(dice)
numFlags[die.value-1] = true;
if(numFlags[0] && numFlags[1] && numFlags[2] && numFlags[3]) return true
//Repeat for 1-4 and 2-5
return false
如果你使用的是百万面骰子,这不是一个有用的算法,但是对于六边形来说,只有三个可能的小直道需要检查,因此它简单而直接。考虑到你正在实现一个Yahtzee游戏,你可能需要测试除小直道之外的其他模式,因此,最好在调用函数之前创建值数组,以便可以在所有测试中使用它们,而不是从小型直接测试中的DOM元素获取值 无论如何,我想到的第一种方法是在一个数组中测试一条小直线,代表五个六面骰子的值:
// assume r is an array with the values from the dice
r.sort();
if (/1234|2345|3456/.test(r.join("").replace(/(.)\1/,"$1") {
// is a small straight
}
请注意,您可以使用以下代码对数字数组进行排序:
r2.sort(function(a,b){return a-b;});
…但在您的例子中,数组中的值是字符串,因为它们来自DOM元素的.value
属性,因此默认字符串排序将与r2.sort()一起使用。无论哪种方式,您都不需要自己的排序例程,因为JavaScript
编辑:如果您假设您可以将五个值作为一个字符串,如上所述,那么您可以对所有可能的组合实施测试,作为一个大的If/else,如下所示:
r.sort();
r = r.join("");
if (/(.)\1{4}/.test(r)) {
alert("Five of a Kind");
} else if (/(.)\1{3}/.test(r)) {
alert("Four of a Kind");
} else if (/(.)\1{2}(.)\2|(.)\3(.)\4{2}/.test(r)) {
alert("Full House");
} else if (/(.)\1{2}/.test(r)) {
alert("Three of a Kind");
} else if (/1234|2345|3456/.test( r.replace(/(.)\1/,"$1") ) {
alert("Small Straight");
} // etc.
演示:鉴于您正在实现一个Yahtzee游戏,您可能需要测试除小直道之外的其他模式,因此最好在调用函数之前创建值数组,以便您可以在所有测试中使用它们,而不是从小直道测试中的DOM元素获取值
无论如何,我想到的第一种方法是在一个数组中测试一条小直线,代表五个六面骰子的值:
// assume r is an array with the values from the dice
r.sort();
if (/1234|2345|3456/.test(r.join("").replace(/(.)\1/,"$1") {
// is a small straight
}
请注意,您可以使用以下代码对数字数组进行排序:
r2.sort(function(a,b){return a-b;});
…但在您的例子中,数组中的值是字符串,因为它们来自DOM元素的.value
属性,因此默认字符串排序将与r2.sort()一起使用。无论哪种方式,您都不需要自己的排序例程,因为JavaScript
编辑:如果您假设您可以将五个值作为一个字符串,如上所述,那么您可以对所有可能的组合实施测试,作为一个大的If/else,如下所示:
r.sort();
r = r.join("");
if (/(.)\1{4}/.test(r)) {
alert("Five of a Kind");
} else if (/(.)\1{3}/.test(r)) {
alert("Four of a Kind");
} else if (/(.)\1{2}(.)\2|(.)\3(.)\4{2}/.test(r)) {
alert("Full House");
} else if (/(.)\1{2}/.test(r)) {
alert("Three of a Kind");
} else if (/1234|2345|3456/.test( r.replace(/(.)\1/,"$1") ) {
alert("Small Straight");
} // etc.
演示:我不玩Yahtzee,但我会玩纸牌,看起来算法可能类似。这个用ActionScript编写的例程(我的JavaScript有点生疏)已经编译过了,但没有经过测试。它应该接受5张卡片作为输入,对于大于3张卡片或成对或更高的直线,它应该返回一条消息
private function checkCards(card1:int,card2:int,card3:int,card4:int,card5:int):String
{
// Assumes that the 5 cards have a value between 0-12 (Ace-King)
//The key to the routine is using the card values as pointers into an array of possible card values.
var aryCardValues:Array = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
var aryCardNames:Array = new Array("Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King");
var strOutMessage:String;
var intCardCount:int = 0;
var strSeperator:String;
var strHighCard:String;
for (var i:int = 0;i < aryCardValues.length;i++)
{
//Check for runs of three of a kind or greater.
if (aryCardValues[i] >= 2)
{
strOutMessage = strOutMessage + strSeperator + i + "-" + aryCardNames[i] + "s";
strSeperator = " & ";
}
//Check for values in a straight.
if (aryCardValues[i] > 0)
{
intCardCount++;
if (intCardCount > 3)strHighCard = aryCardNames[i];
}
else
{
if (intCardCount < 3)intCardCount = 0;
}
}
if (intCardCount > 3) strOutMessage = intCardCount + " run " + strHighCard + " High."
return strOutMessage;
}
专用函数检查卡(card1:int、card2:int、card3:int、card4:int、card5:int):字符串
{
//假设这5张牌的值在0-12之间(王牌)
//该例程的关键是使用卡片值作为指向可能的卡片值数组的指针。
var aryCardValues:Array=新数组(0,0,0,0,0,0,0,0,0,0,0,0);
aryCardValues[card1]+=1;
aryCardValues[card1]+=1;
aryCardValues[card1]+=1;
aryCardValues[card1]+=1;
aryCardValues[card1]+=1;
变量aryCardNames:Array=新数组(“Ace”、“2”、“3”、“4”、“5”、“6”、“7”、“8”、“9”、“10”、“Jack”、“Queen”、“King”);
var strOutMessage:字符串;
var intCardCount:int=0;
var-stroperator:String;
var-strHighCard:字符串;
for(变量i:int=0;i=2)
{
strOutMessage=strOutMessage+stroperator+i+“-”+aryCardNames[i]+“s”;
stroperator=“&”;
}
//检查直线中的值。
如果(值[i]>0)
{
intCardCount++;
如果(intCardCount>3)strHighCard=aryCardNames[i];
}
其他的
{
如果(intCardCount<3)intCardCount=0;
}
}
如果(intCardCount>3)strOutMessage=intCardCount+“运行”+strHighCard+“高”
返回strOutMessage;
}
它可能不像上面使用的正则表达式那样简洁,但它可能更可读,更容易修改。可以做的一个改变是传入一个卡片数组,而不是每张卡片的离散变量。我不玩Yahtzee,但我玩纸牌,看起来算法可能类似。这个用ActionScript编写的例程(我的JavaScript有点生疏)已经编译过了,但没有经过测试。它应该接受5张卡片作为输入,对于大于3张卡片或成对或更高的直线,它应该返回一条消息
private function checkCards(card1:int,card2:int,card3:int,card4:int,card5:int):String
{
// Assumes that the 5 cards have a value between 0-12 (Ace-King)
//The key to the routine is using the card values as pointers into an array of possible card values.
var aryCardValues:Array = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
aryCardValues[card1] += 1;
var aryCardNames:Array = new Array("Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King");
var strOutMessage:String;
var intCardCount:int = 0;
var strSeperator:String;
var strHighCard:String;
for (var i:int = 0;i < aryCardValues.length;i++)
{
//Check for runs of three of a kind or greater.
if (aryCardValues[i] >= 2)
{
strOutMessage = strOutMessage + strSeperator + i + "-" + aryCardNames[i] + "s";
strSeperator = " & ";
}
//Check for values in a straight.
if (aryCardValues[i] > 0)
{
intCardCount++;
if (intCardCount > 3)strHighCard = aryCardNames[i];
}
else
{
if (intCardCount < 3)intCardCount = 0;
}
}
if (intCardCount > 3) strOutMessage = intCardCount + " run " + strHighCard + " High."
return strOutMessage;
}
专用函数检查卡(card1:int、card2:int、card3:int、card4:int、card5:int):字符串
{
//假设这5张牌的值在0-12之间(王牌)
//该例程的关键是使用卡片值作为指向可能的卡片值数组的指针。
var aryCardValues:Array=新数组(0,0,0,0,0,0,0,0,0,0,0,0);
aryCardValues[card1]+=1;