In the game Yahtzee, players take turns rolling 5 6-sided dice up to three times per turn, possibly saving dice between rolls, and then selecting a category they wish to use for their roll. This continues until there are no more categories (which happens after 13 turns). Then, players' scores are tallied, and the player with the highest score wins.
The categories are as follows ("sum of dice" means adding up the number of pips on the specified dice):
- Upper Section
- Aces: sum of the dice showing 1 pip
- Twos: sum of the dice showing 2 pips
- Threes: sum of the dice showing 3 pips
- Fours: sum of the dice showing 4 pips
- Fives: sum of the dice showing 5 pips
- Sixes: sum of the dice showing 6 pips
- Lower Section
- Three of a Kind: 3 dice with same value, score is sum of all dice
- Four of a Kind: 4 dice with same value, score is sum of all dice
- Full House: 3 dice with one value and 2 with another, score is 25
- Small Straight: 4 sequential dice, score is 30
- Large Straight: 5 sequential dice, score is 40
- Yahtzee: all 5 dice with same value, score is 50
- Chance: any combination of dice, score is sum of all dice
There are a few rules about the category choices:
- If a player chooses a category that does not match their roll, they receive a score of 0 for that category.
- If a player earns a score of at least 63 in the upper section, they receive 35 bonus points.
- If a player has rolled a Yahtzee but the Yahtzee category is already taken (by another Yahtzee - filling in 0 for a miss doesn't count), they receive a bonus of 100 points. This bonus is awarded for every Yahtzee after the first.
- Additionally, the player must still choose to fill in a category. They must choose the upper section category corresponding to their roll (e.g. a roll of 5 6's must be placed in the Sixes category). If the corresponding upper section category has already been used, the Yahtzee may be used for a lower section category (in this case, choosing Full House, Small Straight, or Large Straight awards the normal amount of points rather than 0). If all of the lower section categories are taken, then the Yahtzee may be applied to an unused upper section category, with a score of 0.
The Challenge
In this challenge, the competitors will play 1000 games of Yahtzee. At the end of each game, the submission(s) that scored the highest will receive 1 point. After all of the games are finished, the submission with the most points will win. If there is a tie, additional games will be played with only the tied submissions until the tie is broken.
Controller
The complete controller code can be found on this GitHub repository. Here are the public interfaces with which players will be interacting:
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);
}
Additionally, there are some utility methods in Util.java
. They are mainly there to simplify the controller code, but they can be used by players if they desire.
Rules
- Players are not allowed to interact in any way except using the
Scorecard.getScores
method to see the current scores of all players. This includes colluding with other players or sabotaging other players via manipulating parts of the system that are not part of the public interface. - If a player makes an illegal move, they will not be allowed to compete in the tournament. Any issues that cause illegal moves must be resolved prior to the running of the tournament.
- If additional submissions are made after the tournament is run, a new tournament will be run with the new submission(s), and the winning submission will be updated accordingly. I make no guarantee of promptness in running the new tournament, however.
- Submissions may not exploit any bugs in the controller code that cause it to deviate from the actual game rules. Point out bugs to me (in a comment and/or in a GitHub issue), and I'll fix them.
- Use of Java's reflection tools is forbidden.
- Any language which runs on the JVM, or can be compiled to Java or JVM bytecode (such as Scala or Jython) can be used, so long as you supply any additional code needed to interface it with Java.
Final Comments
If there is any utility method you would like me to add to the controller, simply ask in the comments and/or make an issue on GitHub, and I'll add it, assuming it doesn't allow for rule breaking or expose information to which players are not privy. If you want to write it yourself and create a pull request on GitHub, even better!
ACES
? You meanONES
? These are dice, not cards. \$\endgroup\$