小型直线(Yahtzee)算法

Small Straight (Yahtzee) Algorithm

本文关键字:算法 Yahtzee 小型      更新时间:2023-09-26

在我正在制作的Yahtzee游戏中,我创建了一个有效的javascript函数来检查一个由5个数字组成的数组中的小直。我已经对它进行了无休止的测试,我相信它100%有效,但就效率而言,它可能也是有史以来最差的算法。以下是它的样子:

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) Remove duplicates by adding numbers to a new array as they occur
2) Make sure the new array is at least 4 in length (4 different numbers)
3) Sort the array from least to greatest
4) Check if the first 4 OR last 4 (if 5 in length) numbers are in order

我的问题:

有人知道我可以改进这种方法的方法吗?这对我来说似乎可怕得离谱,但我想不出更好的方法来做到这一点,而且它至少有效。

考虑到您正在实现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提供了一个。

编辑:如果你假设你可以像上面那样把五个值作为一个字符串,你就可以像下面这样对所有可能的组合进行测试:

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.

演示:http://jsfiddle.net/4Qzfw/

为什么不使用一个六元素的布尔值数组来指示是否存在一个数字,然后检查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,但我会打牌,而且算法可能类似。这个用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;
}

它可能不像上面使用的正则表达式那样简洁,但可能更可读,更容易修改。可以做的一个改变是传入一组卡片,而不是每个卡片的离散变量。