เล่นเกม Yahtzee


18

ในเกม Yahtzee ผู้เล่นผลัดกันกลิ้งลูกเต๋า 6 ด้าน 5 ข้างได้ถึงสามครั้งต่อรอบอาจช่วยลูกเต๋าระหว่างม้วนจากนั้นเลือกหมวดหมู่ที่พวกเขาต้องการใช้สำหรับการหมุนของพวกเขา สิ่งนี้จะดำเนินต่อไปจนกว่าจะไม่มีหมวดหมู่เพิ่มเติม (ซึ่งเกิดขึ้นหลังจาก 13 รอบ) จากนั้นคะแนนของผู้เล่นจะถูกนับและผู้เล่นที่มีคะแนนสูงสุดจะเป็นผู้ชนะ

หมวดหมู่มีดังนี้ ("ผลรวมของลูกเต๋า" หมายถึงการเพิ่มจำนวนของลูกเต๋าบนลูกเต๋าที่ระบุ):

  • ส่วนบน
    • Aces : ผลรวมของลูกเต๋าที่แสดง 1 pip
    • Twos : ผลรวมของลูกเต๋าที่แสดง 2 pips
    • Threes : ผลรวมของลูกเต๋าที่แสดง 3 pips
    • Fours : ผลรวมของลูกเต๋าที่แสดง 4 pips
    • Fives : ผลรวมของลูกเต๋าที่แสดง 5 pips
    • Sixes : ผลรวมของลูกเต๋าที่แสดง 6 pips
  • ส่วนล่าง
    • Three of a Kind : 3 ลูกเต๋าที่มีค่าเท่ากันคะแนนคือผลรวมของลูกเต๋าทั้งหมด
    • สี่ชนิด : 4 ลูกเต๋าที่มีค่าเท่ากันคะแนนคือผลรวมของลูกเต๋าทั้งหมด
    • Full House : 3 ลูกเต๋าโดยมีหนึ่งค่าและอีก 2 แต้มมีคะแนนเท่ากับ 25
    • เส้นตรงเล็ก : 4 ลูกเต๋าเรียงตามลำดับคะแนนคือ 30
    • Large Straight : 5 ลูกเต๋าเรียงตามลำดับ, คะแนนคือ 40
    • Yahtzee : ลูกเต๋าทั้ง 5 ลูกที่มีค่าเท่ากันให้คะแนน 50
    • โอกาส : การรวมกันของลูกเต๋าใด ๆ คะแนนคือผลรวมของลูกเต๋าทั้งหมด

มีกฎบางอย่างเกี่ยวกับตัวเลือกหมวดหมู่:

  • หากผู้เล่นเลือกหมวดหมู่ที่ไม่ตรงกับม้วนของพวกเขาพวกเขาได้รับคะแนน 0 สำหรับหมวดหมู่นั้น
  • หากผู้เล่นได้รับคะแนนอย่างน้อย 63 ในส่วนบนพวกเขาจะได้รับ 35 คะแนนโบนัส
  • หากผู้เล่นได้โยน Yahtzee แต่หมวด Yahtzee ถูกนำไปแล้ว (โดย Yahtzee อื่น - การกรอก 0 เพื่อพลาดไม่นับ) พวกเขาจะได้รับโบนัส 100 คะแนน โบนัสนี้จะมอบให้กับทุก Yahtzee หลังจากครั้งแรก
    • นอกจากนี้ผู้เล่นจะต้องเลือกที่จะกรอกหมวดหมู่ พวกเขาจะต้องเลือกหมวดส่วนบนที่สอดคล้องกับม้วนของพวกเขา (เช่นต้องวางม้วน 5 6 ในหมวด Sixes) หากหมวดหมู่ส่วนบนที่สอดคล้องกันได้ถูกใช้ไปแล้ว Yahtzee อาจถูกใช้สำหรับหมวดหมู่ส่วนล่าง (ในกรณีนี้เลือก Full House, Small Straight หรือ Large Straight ให้คะแนนปกติมากกว่า 0) หากหมวดหมู่ส่วนล่างทั้งหมดถูกนำมาใช้ Yahtzee อาจถูกนำไปใช้กับหมวดส่วนบนที่ไม่ได้ใช้ด้วยคะแนน 0

ความท้าทาย

ในการท้าทายนี้คู่แข่งจะเล่นเกมของ Yahtzee 1,000 เกม ในตอนท้ายของแต่ละเกมการส่งที่ทำคะแนนสูงสุดจะได้รับ 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) และฉันจะแก้ไขพวกเขา
  • ห้ามใช้เครื่องมือสะท้อนของจาวา
  • ภาษาใดก็ตามที่ทำงานบน JVM หรือสามารถรวบรวมเป็น Java หรือ JVM bytecode (เช่น Scala หรือ Jython) สามารถใช้ได้ตราบใดที่คุณระบุรหัสเพิ่มเติมใด ๆ ที่จำเป็นในการเชื่อมต่อกับ Java

ความคิดเห็นสุดท้าย

หากมีวิธียูทิลิตี้ใด ๆ ที่คุณต้องการให้ฉันเพิ่มไปยังตัวควบคุมเพียงแค่ถามในความคิดเห็นและ / หรือทำให้ปัญหาใน GitHub และฉันจะเพิ่มมันสมมติว่ามันไม่อนุญาตให้มีการทำลายกฎหรือเปิดเผยข้อมูล ผู้เล่นคนไหนไม่เป็นส่วนตัว ถ้าคุณต้องการเขียนด้วยตัวเองและสร้างคำขอดึงบน GitHub ยิ่งดีกว่า!


ACES? คุณหมายถึงONESอะไร นี่คือลูกเต๋าไม่ใช่ไพ่
mbomb007

@ mbomb007 Yahtzee ดัชนีชี้วัดเรียกว่าเอซ
Mego

ฉันจำไม่ได้ว่ามันเรียกว่าเมื่อฉันเล่น แต่ก็โอเค
mbomb007

มีวิธีในการรับคะแนนสำหรับหมวดหมู่ที่กำหนดให้ชุดของลูกเต๋าหรือไม่?
mbomb007

@ mbomb007 ไม่ แต่ฉันสามารถสร้างได้อย่างแน่นอน :)
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.