2

ダーツのゲームを終了する方法を決定するために、Java で再帰関数を作成しようとしています。基本的にダーツは3本までで、ダブルでフィニッシュする必要があります。

ダーツx01のダブルアウトフィニッシュのルールを知らないと、この質問はわかりにくいですよね… 説明してみましょう。簡単にするために、ここでは雄牛の目を方程式から除外します。

ルール:

1) 1 番から 20 番まで投げることができるダーツが 3 本あります。

2) 1 回のヒットで、シングル、ダブル、またはトリプルのスコアを獲得できます。

例: シングル 20 = 20 ポイント、ダブル 20 = 40 ポイント、トリプル 20 = 60 ポイント

3) 1 回のターンで、最大 180 ポイントを獲得できます (3x トリプル 20 = 3*60 = 180)。180以上は無理です。これは、180 IS 未満が可能であることを意味するものではありません。たとえば、179 も同様に不可能です。次の最高のスコアは triple20+triple20+triple19 = 167 であるためです。

4) 通常、501 から開始し、残りのポイントがちょうど 0 になるまで 3 ダーツを投げます。

5) ダブルアウトでは、最後のダーツがダブルにヒットする必要があります。

たとえば、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 つのダーツを見つけるのに役立つだけで、2 つのダーツの組み合わせには役立たないことです。したがって、canFinish(66, darts) は機能しますが、canFinish(120, darts) は StackOverflow Exception を返します。120 の場合、triple20、double14、double16、またはその他の有効な組み合わせのようなものが得られると期待しています。

4

3 に答える 3

1

canFinish が試行したスコアをログに記録すると、多くの可能性が失われていることがわかります。20 の値は無視され、他のダーツ値が変更される前に、1 つのダーツが完全にインクリメントされます。

代わりに、次のように再帰的に解決できます。合計 を与えるためcanFinish(desired, score)に追加できるダーツの任意の組み合わせを返します。あなたが知っているダーツの数のリスト、または可能性を見つけるための空のリストで呼び出します。scoredesired

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 に答える