ヤッツィーのゲームをプレイする


17

ゲームヤッツィーでは、プレイヤーはターンごとに5面のサイコロを5回転させ、1ターンにつき3回までダイスを振って、ロール間でダイスを節約し、次にロールに使用するカテゴリを選択します。これは、カテゴリがなくなるまで続きます(13ターン後に発生します)。次に、プレイヤーのスコアが集計され、最高スコアのプレイヤーが勝ちます。

カテゴリは次のとおりです(「サイコロの合計」は、指定されたサイコロのピップ数を合計することを意味します)。

  • 上段
    • エース:1ピップを示すサイコロの合計
    • Twos:2ピップを示すサイコロの合計
    • Threes:3ピップを示すサイコロの合計
    • Fours:4ピップを示すサイコロの合計
    • ファイブ:5ピップを示すサイコロの合計
    • Sixes:6ピップを示すサイコロの合計
  • 下段
    • スリーオブカインド:同じ値を持つ3つのサイコロ、スコアはすべてのサイコロの合計
    • フォーオブカインド:同じ値を持つ4つのサイコロ、スコアはすべてのサイコロの合計
    • フルハウス:1つの値を持つ3つのサイコロと別の値を持つ2つのサイコロ、スコアは25
    • スモールストレート:4つの連続したサイコロ、スコアは30
    • ラージストレート:5連続ダイス、スコアは40
    • ヤッツィー:同じ値を持つ5つのサイコロすべて、スコアは50
    • チャンス:サイコロの任意の組み合わせ、スコアはすべてのサイコロの合計

カテゴリの選択に関するいくつかのルールがあります。

  • プレイヤーがロールと一致しないカテゴリーを選択した場合、そのカテゴリーのスコアは0になります。
  • プレイヤーが上部セクションで少なくとも63のスコアを獲得した場合、35ボーナスポイントを受け取ります。
  • プレイヤーがヤッツィーを振ったが、ヤッツィーのカテゴリーがすでに取られている場合(別のヤッツィーが-ミスで0を入力してもカウントされません)、100ポイントのボーナスを受け取ります。このボーナスは、最初の後にすべてのヤッツィーに対して授与されます。
    • さらに、プレーヤーはカテゴリの入力を選択する必要があります。ロールに対応する上部セクションのカテゴリーを選択する必要があります(たとえば、5 6のロールをSixesカテゴリーに配置する必要があります)。対応する上部セクションカテゴリが既に使用されている場合、下部セクションカテゴリにYahtzeeを使用できます(この場合、フルハウス、スモールストレート、またはラージストレートを選択すると、0ではなく通常のポイントが付与されます)。下位セクションのカテゴリがすべて使用された場合、ヤッツィーはスコア0の未使用の上位セクションカテゴリに適用されます。

チャレンジ

このチャレンジでは、競技者はヤッツィーの1000ゲームをプレイします。各ゲームの終了時に、最高得点の提出物は1ポイントを受け取ります。すべてのゲームが終了した後、最も多くのポイントを持つ提出が勝ちます。同点がある場合、同点が壊れるまで、同点提出物のみで追加のゲームがプレイされます。

コントローラ

完全なコントローラコードは、このGitHubリポジトリにあります。プレイヤーが対話するパブリックインターフェイスは次のとおりです。

public interface ScorecardInterface {

    // returns an array of unused categories
    Category[] getFreeCategories();

    // returns the current total score
    int getScore();

    // returns the current Yahtzee bonus
    int getYahtzeeBonus();

    // returns the current Upper Section bonus
    int getUpperBonus();

    // returns the current Upper Section total
    int getUpperScore();

}
public interface ControllerInterface {

    // returns the player's scorecard (cloned copy, so don't try any funny business)
    ScorecardInterface getScoreCard(Player p);

    // returns the current scores for all players, in no particular order
    // this allows players to compare themselves with the competition,
    //  without allowing them to know exactly who has what score (besides their own score),
    //  which (hopefully) eliminates any avenues for collusion or sabotage
    int[] getScores();

}
public enum Category {
    ACES,
    TWOS,
    THREES,
    FOURS,
    FIVES,
    SIXES,
    THREE_OF_A_KIND,
    FOUR_OF_A_KIND,
    FULL_HOUSE,
    SMALL_STRAIGHT,
    LARGE_STRAIGHT,
    YAHTZEE,
    CHANCE;

    // determines if the category is part of the upper section
    public boolean isUpper() {
        // implementation
    }

    // determines if the category is part of the lower section
    public boolean isLower() {
        // implementation
    }

    // determines if a given set of dice fits for the category
    public boolean matches(int[] dice) {
        // implementation
    }

    // calculates the score of a set of dice for the category
    public int getScore(int[] dice) {
        // implementation
    }

    // returns all categories that fit the given dice
    public static Category[] getMatchingCategories(int[] dice) {
        // implementation
    }
}
public class TurnChoice {

    // save the dice with the specified indexes (0-4 inclusive)
    public TurnChoice(int[] diceIndexes) {
        // implementation
    }

    // use the current dice for specified category
    public TurnChoice(Category categoryChosen) {
        // implementation
    }

}

public abstract class Player {

    protected ControllerInterface game;

    public Player(ControllerInterface game) {
        this.game = game;
    }

    public String getName() {
        return this.getClass().getSimpleName();
    }

    // to be implemented by players
    // dice is the current roll (an array of 5 integers in 1-6 inclusive)
    // stage is the current roll stage in the turn (0-2 inclusive)
    public abstract TurnChoice turn(int[] dice, int stage);

}

さらに、にはいくつかのユーティリティメソッドがありUtil.javaます。これらは主にコントローラーのコードを単純化するためにありますが、必要に応じてプレイヤーが使用できます。

ルール

  • プレイヤーは、Scorecard.getScoresメソッドを使用してすべてのプレイヤーの現在のスコアを見る以外の方法で相互作用することはできません。これには、他のプレイヤーと共謀したり、パブリックインターフェイスの一部ではないシステムの一部を操作して他のプレイヤーを妨害したりすることが含まれます。
  • プレーヤーが違法な動きをした場合、トーナメントに参加することはできません。違法な動きを引き起こす問題は、トーナメントの実行前に解決する必要があります。
  • トーナメントの実行後に追加の提出が行われた場合、新しいトーナメントは新しい提出で実行され、勝った提出はそれに応じて更新されます。ただし、私は新しいトーナメントの実行を迅速に行うことを保証しません。
  • 提出は、実際のゲームルールから逸脱する原因となるコントローラーコードのバグを悪用することはできません。バグを(コメントやGitHubの問題で)指摘してください。修正します。
  • Javaのリフレクションツールの使用は禁止されています。
  • JVMとのインターフェースに必要な追加コードを提供する限り、JVM上で実行される言語、またはJavaまたはJVMバイトコード(ScalaやJythonなど)にコンパイルできる言語を使用できます。

最終コメント

コントローラーに追加したいユーティリティメソッドがある場合は、コメントを入力するか、GitHubで問題を作成します。ルール違反や情報の公開が許可されていない場合は追加します。プレイヤーは誰でもありません。自分で作成して、GitHubでプルリクエストを作成する場合は、さらに良い方法です!


ACES?もしかしてONESですか?これらはサイコロであり、カードではありません。
mbomb007


私がそれをプレイしたときにそれが呼ばれたのを覚えていませんが、大丈夫です。
mbomb007

サイコロのセットを与えられた特定のカテゴリのスコアを取得する方法はありますか?
mbomb007

@ mbomb007いいえ、しかし私は確かに1つを作ることができます:)
Mego

回答:


4

DummyPlayer

package mego.yahtzee;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class DummyPlayer extends Player {

    public DummyPlayer(ControllerInterface game) {
        super(game);
    }

    @Override
    public TurnChoice turn(int[] dice, int stage) {
        Category[] choices = game.getScoreCard(this).getFreeCategories();
        Category choice = choices[new Random().nextInt(choices.length)];
        if(IntStream.of(dice).allMatch(die -> die == dice[0])) {
            if(Stream.of(choices).filter(c -> c == Category.YAHTZEE).count() > 0) {
                choice = Category.YAHTZEE;
            } else if(Stream.of(choices).filter(c -> c == Util.intToUpperCategory(dice[0])).count() > 0) {
                choice = Util.intToUpperCategory(dice[0]);
            } else {
                choices = Stream.of(game.getScoreCard(this).getFreeCategories()).filter(c -> c.isLower()).toArray(Category[]::new);
                if(choices.length > 0) {
                    choice = choices[new Random().nextInt(choices.length)];
                } else {
                    choices = game.getScoreCard(this).getFreeCategories();
                    choice = choices[new Random().nextInt(choices.length)];
                }
            }
        }
        return new TurnChoice(choice);
    }

}

このプレーヤーは、Yahtzeeコントローラーに存在するツールの使用方法の基本的なアウトラインとして機能します。可能な限りYahtzeeを選択し、そうでない場合はランダムな選択を行い、厳格なジョーカールールを順守します。


1

エースとエイト

まあ、これは私が最近忙しかったおかげで、私が好きだったよりもはるかに時間がかかりました。

package mego.yahtzee;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import static mego.yahtzee.Category.*;

public class AcesAndEights extends Player {
    private Category[] freeCategories, matchingCategories, usableCategories;

    public AcesAndEights(ControllerInterface game) {
        super(game);
    }

    @Override
    public TurnChoice turn(int[] dice, int stage) {
        List<Integer> holdIndices = new java.util.ArrayList<>();

        freeCategories = game.getScoreCard(this).getFreeCategories();

        matchingCategories = Category.getMatchingCategories(dice);
        Arrays.sort(matchingCategories);

        usableCategories = Arrays.stream(freeCategories)
                                 .filter(this::isMatchingCategory)
                                 .toArray(Category[]::new);
        Arrays.sort(usableCategories);

        if (isMatchingCategory(YAHTZEE))
            return doYahtzeeProcess(dice);

        if (isUsableCategory(FULL_HOUSE))
            return new TurnChoice(FULL_HOUSE);

        if (stage == 0 || stage == 1) {
            if (isMatchingCategory(THREE_OF_A_KIND)) {
                int num = 0;
                for (int i : dice) {
                    if (Util.count(Util.boxIntArray(dice), i) >= 3) {
                        num = i;
                        break;
                    }
                }
                for (int k = 0; k < 5; k++) {
                    if (dice[k] == num)
                        holdIndices.add(k);
                }
                return new TurnChoice(toIntArray(holdIndices.toArray(new Integer[0])));
            }

            if (isFreeCategory(LARGE_STRAIGHT) || isFreeCategory(SMALL_STRAIGHT)) {
                if (isUsableCategory(LARGE_STRAIGHT))
                    return new TurnChoice(LARGE_STRAIGHT);

                if (isMatchingCategory(SMALL_STRAIGHT)) {
                    if (!isFreeCategory(LARGE_STRAIGHT))
                        return new TurnChoice(SMALL_STRAIGHT);

                    int[] arr = Arrays.stream(Arrays.copyOf(dice, 5))
                                      .distinct()
                                      .sorted()
                                      .toArray();
                    List<Integer> l = Arrays.asList(Util.boxIntArray(dice));
                    if (Arrays.binarySearch(arr, 1) >= 0 && Arrays.binarySearch(arr, 2) >= 0) {
                        holdIndices.add(l.indexOf(1));
                        holdIndices.add(l.indexOf(2));
                        holdIndices.add(l.indexOf(3));
                        holdIndices.add(l.indexOf(4));
                    }
                    else if (Arrays.binarySearch(arr, 2) >= 0 && Arrays.binarySearch(arr, 3) >= 0) {
                        holdIndices.add(l.indexOf(2));
                        holdIndices.add(l.indexOf(3));
                        holdIndices.add(l.indexOf(4));
                        holdIndices.add(l.indexOf(5));
                    }
                    else {
                        holdIndices.add(l.indexOf(3));
                        holdIndices.add(l.indexOf(4));
                        holdIndices.add(l.indexOf(5));
                        holdIndices.add(l.indexOf(6));
                    }
                    return new TurnChoice(toIntArray(holdIndices.toArray(new Integer[0])));
                }
            }

            if (isFreeCategory(FULL_HOUSE)) {
                int o = 0, t = o;
                for (int k = 1; k <= 6; k++) {
                    if (Util.count(Util.boxIntArray(dice), k) == 2) {
                        if (o < 1)
                            o = k;
                        else
                            t = k;
                    }
                }

                if (o > 0 && t > 0) {
                    for (int k = 0; k < 5; k++) {
                        if (dice[k] == o || dice[k] == t)
                            holdIndices.add(k);
                    }
                    return new TurnChoice(toIntArray(holdIndices.toArray(new Integer[0])));
                }
            }
        }
        else {
            Arrays.sort(freeCategories, Comparator.comparingInt((Category c) -> c.getScore(dice))
                                                  .thenComparingInt(this::getPriority)
                                                  .reversed());
            return new TurnChoice(freeCategories[0]);
        }

        return new TurnChoice(new int[0]);
    }

    private TurnChoice doYahtzeeProcess(int[] dice) {
        if (isUsableCategory(YAHTZEE))
            return new TurnChoice(YAHTZEE);

        Category c = Util.intToUpperCategory(dice[0]);
        if (isUsableCategory(c))
            return new TurnChoice(c);

        Category[] arr = Arrays.stream(freeCategories)
                               .filter(x -> x.isLower())
                               .sorted(Comparator.comparing(this::getPriority)
                                                 .reversed())
                               .toArray(Category[]::new);
        if (arr.length > 0)
            return new TurnChoice(arr[0]);

        Arrays.sort(freeCategories, Comparator.comparingInt(this::getPriority));
        return new TurnChoice(freeCategories[0]);
    }

    private boolean isFreeCategory(Category c) {
        return Arrays.binarySearch(freeCategories, c) >= 0;
    }

    private boolean isMatchingCategory(Category c) {
        return Arrays.binarySearch(matchingCategories, c) >= 0;
    }

    private boolean isUsableCategory(Category c) {
        return Arrays.binarySearch(usableCategories, c) >= 0;
    }

    private int getPriority(Category c) {
        switch (c) {
            case YAHTZEE: return -3;        // 50 points
            case LARGE_STRAIGHT: return -1; // 40 points
            case SMALL_STRAIGHT: return -2; // 30 points
            case FULL_HOUSE: return 10;     // 25 points
            case FOUR_OF_A_KIND: return 9;  // sum
            case THREE_OF_A_KIND: return 8; // sum
            case SIXES: return 7;
            case FIVES: return 6;
            case FOURS: return 5;
            case THREES: return 4;
            case TWOS: return 3;
            case ACES: return 2;
            case CHANCE: return 1;          // sum
        }
        throw new RuntimeException();
    }

    private int[] toIntArray(Integer[] arr) {
        int[] a = new int[arr.length];
        for (int k = 0; k < a.length; k++)
            a[k] = arr[k];
        return a;
    }
}

ボットは、特定のカテゴリに一致する可能性のあるサイコロのパターンを探し、必要なものを保持します。見つかった場合は、すぐに優先順位の高い一致するカテゴリが選択されます。それ以外の場合は、最高のスコアが得られるカテゴリを選択します。ゲームあたり平均200ポイント近く得点します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.