2

我正在尝试用 Java 编写一个递归函数,以确定如何完成飞镖游戏。基本上,你最多有 3 支飞镖,你必须以双打结束。

如果你不知道 Double Out 完成的 Darts x01 游戏规则,这个问题很难理解……让我试着解释一下。为简单起见,我暂时不考虑公牛的眼睛。

规则:

1) 你有三个飞镖,你可以在 1 到 20 号投掷

2) 单打可以有单打、双打或三打

例如,您可以打:单 20 = 20 分或双 20 = 40 分或三联 20 = 60 分

3)一回合最多可以得到180分(3x三倍20=3*60=180)。任何高于 180 的东西都是不可能的。这并不意味着低于 180 IS 的任何事情都是可能的。例如 179 也是不可能的,因为下一个最好的分数是triple20+triple20+triple19 = 167

4) 通常,您从 501 开始,然后投掷 3 支飞镖,直到您正好剩下 0 分。

5) 现在,在 Double Out 中,要求最后一镖击中 Double Out

例如,如果您还剩 180 分,您将无法完成,因为您的最后一镖必须是双镖。所以最大值(忽略靶心)=triple20 + Triple20 + double20 = 160 如果你的分数是 16,你可以通过击中双 8 来完成使用 1 镖。另一个例子,如果你的分数是 61,你可以打三重17 + 双5(= 51 + 10)

当前代码

无论如何,以下是我到目前为止所拥有的。我知道这远非我所需要的,但无论我尝试什么,我总是卡住。也许有人可以分享他对另一种方法的想法

private class Score{
    int number;    // the actual number, can be 1...20
    int amount;    // multiplier, can be 1, 2 or 3
    public Score(int number, int amount){
        this.number = number;    // the actual number, can be 1...20
        this.amount = amount;    // multiplier, can be 1, 2 or 3
    }
    public int value()
    {
        return number * amount;   // the actual score
    }

    public void increment()
    {
        if(this.amount == 0)
            this.amount = 1;

        this.number++;
        if(this.number >= 20)
        {
            this.number = 0;
            this.amount++;

            if(this.amount >= 3)
                 this.amount = 3;
        }
    }
}

public ArrayList<Score> canFinish(int desired, ArrayList<Score> score){

        // If this is the case -> we have bingo
        if(eval(score) == desired) return score;

        // this is impossible -> return null
        if(eval(score) > 170) return null;

        // I can't figure out this part!!
        Score dart3 = score.remove(2);
        Score dart2 = score.remove(1);

        if(dart2.eval() < 60){
            dart2.increment();
        }
        else if(dart3.eval() < 60){
            dart3.increment();
        }

        score.add(dart2);
        score.add(dart3);

        return canFinish(desired, score);
}

public int eval(ArrayList<Score> scores)
{
    int total = 0;
    for(Score score : scores){
        total += score.value();
    }
    return total;
}

我想简单地打电话:

ArrayList<Score> dartsNeeded = new ArrayList<Score>();
dartsNeeded.add(new Score(16, 2));   // Add my favourite double
dartsNeeded.add(new Score(0, 0));
dartsNeeded.add(new Score(0, 0));

// and call the function
dartsNeeded = canFinish(66, dartsNeeded);

// In this example the returned values would be:
// [[16,2],[17,2],[0,0]] -> 2*16 + 2*17 + 0*0 = 66
// So I can finish, by throwing Double 17 + Double 16

因此,如果不可能完成,该函数将返回 null,但如果有任何可能的完成,我会用 3 个飞镖来获取 ArrayList,我需要达到我想要的分数......

简短的摘要

问题是上面的代码只有助于找到 1 个 dart,而不是两个 dart 的组合。所以 canFinish(66, darts) 有效 -> 但 canFinish(120, darts) 给出了 StackOverflow 异常。对于 120,我希望得到类似 Triple20、double14、double16 或任何其他有效组合的东西。

4

3 回答 3

1

如果您记录 canFinish 尝试的分数,您会发现有很多可能性被遗漏了。值 20 被忽略,一个 dart 在修改其他 dart 值之前完全递增。

相反,它可以递归地解决如下。canFinish(desired, score)返回可以添加到score总计的飞镖的任何组合desired。用你知道的飞镖列表或任何空列表来调用它以找到任何可能性。

canFinish(desired, score)
    if darts sum to desired, return desired
    if there are fewer than 3 darts in score
        for each possible value of a dart (if it's the last dart, check for a double)
            add dart to score
            if canFinish(desired, score) != null
                return canFinish(desired, score)
            end
            remove dart from score
        end
    end
    return null
end
于 2012-11-01T23:52:01.840 回答
1

我最终使用了以下功能。哪种是开关语句和递归的组合......希望有人发现它和我一样有用

public static void getCheckout(int score, int fav_double, ICheckOutEvent listener)
{
    if(score > 170) return;
    if(score == 170) listener.onCheckOut("T20 T20 Bull");

    ArrayList<Dart> darts = new ArrayList<Dart>();
    darts.add(new Dart(fav_double, 2));
    darts.add(new Dart(0,0));
    darts.add(new Dart(0,0));

    darts = getDarts(score, darts);

    if(darts != null) {
        listener.onCheckOut(toString(darts));
        return;
    }

    for(int dubble = 20 ; dubble >= 1 ; dubble--)
    {
        if(dubble == fav_double) continue;

        darts = new ArrayList<Dart>();
        darts.add(new Dart(dubble, 2));
        darts.add(new Dart(0,0));
        darts.add(new Dart(0,0));
        darts = getDarts(score, darts);

        if(darts != null){
            listener.onCheckOut(toString(darts));
            return;
        }
    }   
}

public static ArrayList<Dart> getDarts(int desired, ArrayList<Dart> score)
{
    Dart dart1 = canFinish(desired);
    if(dart1 != null){
        score.set(0, dart1);
        return score;
    }

    int rest = desired - score.get(0).value();
    Dart dart2 = canScore(rest);
    if(dart2 != null)
    {
        score.set(0, score.get(0));
        score.set(1, dart2);
        return score;
    }

    Dart temp = score.get(1);

    if(temp.increment())
    {
        rest = desired - score.get(0).value() - temp.value();
        score.set(0, score.get(0));
        score.set(1, temp);

        Dart dart3 = canScore(rest);
        if(dart3 != null)
        {
            score.set(2, dart3);
            return score;
        }

        if(rest > 60 && temp.increment()) 
            temp.estimate(rest / 2);

        score.set(1, temp);
        return getDarts(desired, score);
    }

    return null;
}

public static int eval(ArrayList<Dart> scores)
{
    int total = 0;
    for(Dart score : scores){
        total += score.value();
    }
    return total;
}

public static Dart canFinish(int points)
{
    switch(points)
    {
        case 2: return new Dart(1, 2);
        case 4: return new Dart(2, 2);
        case 6: return new Dart(3, 2);
        case 8: return new Dart(4, 2);
        case 10: return new Dart(5, 2);
        case 12: return new Dart(6, 2);
        case 14: return new Dart(7, 2);
        // etc. etc.
        case 40: return new Dart(20, 2);
        case 50: return new Dart(25, 2);
    }

    return null;
}

public static Dart canScore(int points)
{
    switch(points)
    {
        case 1: return new Dart(1, 1);
        case 2: return new Dart(2, 1);
        case 3: return new Dart(3, 1);
        // etc. etc.
        case 20: return new Dart(20, 1);
        case 21: return new Dart(7, 3);
        case 22: return new Dart(11, 2);
        //case 23: impossible
        case 24: return new Dart(12, 2);
        // etc. etc.
        case 57: return new Dart(19, 3);
        case 60: return new Dart(20, 3);
    }

    return null;
}

为了完整起见,这是我作为助手创建的 Dart 类

private static class Dart{
    int number;
    int amount;
    public Dart(int number, int amount){
        this.number = number;
        this.amount = amount;
    }
    public int value()
    {
        return number * amount;
    }

    public void estimate(int estimate)
    {
        Dart temp = canScore(estimate);
        if(temp != null){
            this.amount = temp.amount;
            this.number = temp.number;
        } else{
            this.number = estimate / 3;
            if(number >= 19)
                this.number = 19;

            this.amount = 3;
        }
    }

    public boolean increment()
    {   
        if(this.amount == 3 && this.number == 20)
            return false;

        if(this.amount == 0)
            this.amount = 1;

        this.number++;
        if(this.number >= 20)
        {
            this.number = 20;
            this.amount++;

            if(this.amount >= 3){
                this.amount = 3;
            }
        }

        return true;
    }

    public String toString()
    {
        return "["+number+","+amount+"]";
    }
}
于 2012-11-08T20:24:17.183 回答
0
class RecursiveDartboard {

    public Set<Out> outsFor(int target) {
        HashSet<Out> outs = new HashSet<>();

        for (Score doubleScore : doubles()) {
            List<Score> scores = new ArrayList();
            scores.add(doubleScore);

            outs.addAll(recursiveOutsFor(target, scores)
                .stream()
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(toList())
            );
        }

        return outs;
    }

    private List<Optional<Out>> recursiveOutsFor(int target, List<Score> scores) {
        List<Optional<Out>> outs = new ArrayList<>();

        Out possibleOut = new Out(scores);
        if (possibleOut.target() == target) {
            outs.add(of(possibleOut));
        } else if (scores.size() == 3) {
            outs.add(empty());
        } else {
            for (Score score : allPossibleScores()) {
                List<Score> nextScores = new ArrayList<>();
                nextScores.addAll(scores);
                nextScores.add(score);
                outs.addAll(recursiveOutsFor(target, nextScores));
            }
        }

        return outs;
    }
}
于 2017-08-05T16:59:40.493 回答